2013-03-27 19 views
6

Sotto Linux, ho due percorsi di file A e B:Determinare se due percorsi di file puntano allo stesso file sotto Linux/C?

const char* A = ...; 
const char* B = ...; 

Ora voglio stabilire, dovrei entrambi open(2) ...

int fda = open(A, ...); 
int fdb = open(B, ...); 

... posso ottenere due filehandles aprire lo stesso file nel filesystem?

per determinare questo ho pensato di stat(2):

struct stat 
{ 
    dev_t st_dev; 
    ino_t st_ino; 
    ... 
} 

Qualcosa di simile (pseudo-codice):

bool IsSameFile(const char* sA, const char* sB) 
{ 
    stat A = stat(sA); 
    stat B = stat(sB); 

    return A.st_dev == B.st_dev && A.st_ino == B.st_ino; 
} 

Esistono casi in cui A e B sono gli stessi file, ma IsSameFile avrebbero ritorno falso?

Esistono casi in cui A e B sono file diversi ma IsSameFile restituisce true?

C'è un modo migliore per fare ciò che sto cercando di fare?

+0

È possibile avere più descrittori di file che si riferiscono allo stesso file, sì. – teppic

+0

@teppic: Sì, e puoi anche avere più descrittori di file che fanno riferimento a file diversi. La mia domanda è: come determinare quale di questi due universi sono in (o sarebbe in) –

+0

Se i descrittori di file sono aperti, si può semplicemente usare 'fstat' direttamente su di essi - se gli inode e i numeri dei dispositivi sono uguali , è impossibile che i due percorsi facciano riferimento a file diversi. – teppic

risposta

4

Il tuo programma funzionerà correttamente in tutti i casi perché A.st_ino restituirà il numero di inode inode dei file nel sistema. Poiché il numero di inode è univoco, il programma identificherà correttamente se i due file aperti sono uguali o meno.

È anche possibile controllare il valore di A.st_mode per scoprire se il file è un collegamento simbolico .

+2

Puoi solo scoprire che un nome è un link simbolico (interrotto) tramite 'stat()' se è in realtà un link simbolico non funzionante. Se è non interrotto, 'stat()' riporta sul file o sul dispositivo alla fine del collegamento; 'lstat()' riporta sul (primo) link simbolico se il nome è un link simbolico. –

0

Dipende dal motivo per cui si desidera evitare di aprire due volte lo stesso file. La soluzione è solitamente quella corretta, ma ci sono alcune situazioni in cui i file dovrebbero essere considerati uguali se hanno lo stesso percorso assoluto ma non se sono collegamenti allo stesso inode. In questo caso è necessario convertire i percorsi di percorsi assoluti e confrontarli ... vedere Getting absolute path of a file

È inoltre necessario decidere se si considera un link simbolico a un file equivalente al file o di un altro link simbolico ad esso. Per l'equivalenza inode, che determina se utilizzare stat o lstat. Per l'equivalenza del percorso, determina se è possibile utilizzare realpath o se è necessario ottenere il percorso assoluto senza seguire i collegamenti simbolici.

+1

Usando 'stat()', il codice sarà ignaro dei collegamenti simbolici (tranne forse quelli spezzati). Puoi approfondire "alcune situazioni in cui i file dovrebbero essere considerati uguali se hanno lo stesso percorso assoluto ma non se sono link allo stesso inode"? –

+0

@JonathanLeffler "Usando stat(), il codice sarà ignaro dei collegamenti simbolici" - ma non usando * lstat * - questa è esattamente la distinzione che ho fatto.Elaborazione: alcuni schemi di backup richiedono che i file vengano copiati una volta per ogni percorso (specialmente se il ripristino verrà eseguito su un file system che non supporta i collegamenti fisici), mentre non è necessario salvare due volte lo stesso percorso. Possono essere altri casi d'uso. Ma come ho detto, l'equivalenza inode è ** di solito ** ciò che è voluto. –

+0

@JonathanLeffler E in realtà è 'lstat' che è ignaro dei collegamenti simbolici, mentre' stat' fa un 'readlink' efficace su di essi e li segue. In effetti, l'implementazione di 'lstat' è proprio ciò che l'implementazione di' stat' era prima che ci fossero i collegamenti simbolici (ad esempio, stavo scrivendo il codice del kernel UNIX in quel momento). –