2009-10-21 21 views
15

Come si può creare un nuovo descrittore di file da un descrittore di file esistente in modo che il nuovo descrittore non condivida la stessa struttura/voce di file interna nella tabella dei file? In particolare, attributi come l'offset di file (e preferibilmente permessi, condivisione e modalità) non dovrebbero essere condivisi tra i descrittori di file nuovi e vecchi.Descrittore di file duplicato con il proprio file offset

Sotto Windows e Linux, dup() duplicherà il descrittore di file, ma entrambi i descrittori puntano ancora alla stessa struttura di file nella tabella dei file del processo. Qualsiasi ricerca su entrambi i descrittori regolerà anche la posizione per gli altri descrittori.

Nota

allora ho risposte ricevute sia per Windows e Linux e regolato la questione un po 'troppo spesso, il che ha reso difficile per le persone a rispondere. Regolare i miei voti e accettare la risposta più pulita che copre sia Windows e Linux. Scusa a tutti, sono ancora nuovo al paradigma SO. Grazie per le grandi risposte!

risposta

12

Quindi, in pratica, quello che vuoi è avere un descrittore di file e in pratica aprire di nuovo lo stesso file per ottenere una posizione, condivisione, modalità, ecc. Separate. E vuoi farlo su Windows (dove il "descrittore di file" è fondamentalmente un oggetto estraneo, non qualcosa utilizzato direttamente dal sistema operativo o la libreria di runtime a tutti.

abbastanza sorprendentemente, c'è è un modo per farlo, almeno con MS VC++. Tutti tranne due passaggi utilizzano solo l'API Win32, quindi il porting su altri compilatori/librerie dovrebbe essere abbastanza ragionevole (penso che la maggior parte delle versioni di fornitura di queste due funzioni) .Questi sono per convertire un descrittore di file in stile Unix in un Win3 nativo L'handle di 2 file e la conversione di un file Win32 nativo vengono gestiti in un descrittore di file in stile Unix.

  1. Converti descrittori di file per file handle nativa con _get_osfhandle()
  2. ottenere un nome per il file con GetFileInformationByHandleEx (FILE_NAME_INFO)
  3. Usa CreateFile per aprire una nuova maniglia a tale file
  4. creare un descrittore di file per quella maniglia con _open_osfhandle()

Et voilà, abbiamo un nuovo descrittore di file riferimento suona allo stesso file, ma con le sue autorizzazioni, posizione, ecc.

Verso la fine della tua domanda, fai sembrare che tu voglia anche i "permessi", ma che non sembra fare alcun reale senso - le autorizzazioni si collegano al file stesso, non al modo in cui il file viene aperto, quindi l'apertura o la riapertura del file non ha alcun effetto sulle autorizzazioni del file. Se vuoi davvero conoscerlo, puoi ottenerlo con GetFileInformationByHandle, ma ricorda che i permessi dei file in Windows sono un po 'diversi dai permessi dei file (tradizionali) in Unix. Unix ha permessi di proprietario/gruppo/mondo su tutti i file, e molti sistemi hanno anche ACL (anche se ci sono più variazioni nel modo in cui funzionano). Windows non ha alcuna autorizzazione (ad es. File su FAT o FAT32) o usa ACL (ad es. File su NTFS), ma nulla che sia realmente equivalente ai permessi di proprietario/gruppo/mondo tradizionali a cui molte persone sono abituate su Unix.

Forse si sta utilizzando "autorizzazioni" per indicare se il file era aperto per la lettura, la scrittura o entrambi. Ottenere questo è considerevolmente più brutto di uno qualsiasi dei precedenti. Il problema è che la maggior parte di esso è nella libreria, non in Win32, quindi probabilmente non c'è modo di farlo che sia anche vicino al portatile tra i compilatori. Con MS VC++ 9.0 SP1 (non garantito per qualsiasi altro compilatore) si può fare questo:

#include <stdio.h> 

int get_perms(int fd) { 
    int i; 
FILE * base = __iob_func(); 

    for (i=0; i<_IOB_ENTRIES; i++) 
     if (base[i]._file == fd) 
      return base[i]._flag;  // we've found our file 
    return 0; // file wasn't found. 
} 

Dal momento che questo ha coinvolto alcuni speleologia, ho scritto un test rapido per verificare che potrebbe effettivamente funzionare:

#ifdef TEST 
#include <io.h> 

void show_perms(int perms, char const *caption) { 
printf("File opened for %s\n", caption); 
printf("Read permission = %d\n", (perms & _IOREAD)!=0); 
printf("Write permission = %d\n", (perms & _IOWRT)!=0); 
} 

int main(int argc, char **argv) { 
FILE *file1, *file2; 
int perms1, perms2; 

file1=fopen(argv[1], "w"); 
perms1 = get_perms(_fileno(file1)); 
fclose(file1); 

file2=fopen(argv[1], "r"); 
perms2 = get_perms(_fileno(file2)); 
fclose(file2); 

show_perms(perms1, "writing"); 
show_perms(perms2, "reading"); 
return 0; 
} 
#endif 

e i risultati sembrano indicare il successo:

File opened for writing 
Read permission = 0 
Write permission = 1 
File opened for reading 
Read permission = 1 
Write permission = 0 

Sarà quindi possibile testare che ha restituito bandiera contro _IOREAD, _IOWRT, e _IORW, che sono definito in stdio.h. Nonostante i miei precedenti avvertimenti, dovrei probabilmente sottolineare che sospetto (anche se certamente non posso garantire) che questa parte della biblioteca sia abbastanza stabile, quindi le reali possibilità di grandi cambiamenti sono probabilmente abbastanza minime.

Nella direzione opposta, tuttavia, non c'è praticamente nessuna possibilità su tutti che funzionerà con qualsiasi altra libreria. Si può (ma certamente non è garantito) lavorare con gli altri compilatori che usano la libreria MS, come Intel, MinGW o Comeau che usano MS VC++ come back-end. Di quelli, direi che il più probabile a lavorare sarebbe Comeau, e il meno probabile MinGW (ma è solo una supposizione, c'è una buona possibilità che non funzioni con nessuno di loro).

  1. Richiede l'ridistribuibile Win32 FileID API Library
+0

un'ottima risposta. Non ero a conoscenza del fatto che l'apertura di un file impediva che venisse scollegato o rinominato, anche se la piena condivisione era abilitata. ciò significa che il recupero del nome del file appartiene a un handle è perfettamente sicuro, in quanto non può cambiare fintanto che un descrittore di file o 'HANDLE' rimane aperto su quel percorso. –

+0

Come posso fare lo stesso su Linux? grazie – alaamh

+0

@alaamh: hai guardato tra le altre risposte? Un paio di loro parlano di come fare lo stesso genere di cose su Linux. –

2

Quindi, vi consiglio di leggerlo un po 'di più. Lo dup() e le funzioni correlate servono a creare un valore duplicato nella tabella dei descrittori di file che punta alla stessa voce nella tabella dei file aperti. Questo è destinato allo per avere lo stesso offset. Se chiami open(), creerai una nuova voce nella tabella dei file aperti.

Non ha senso creare un duplicato di un descrittore di file e il nuovo descrittore di file ha un offset diverso nella tabella di file aperti (ciò sembra contraddire ciò che significa la parola "duplicato").

Non sono sicuro di quale sia la tua domanda. Voglio dire, non è la stessa cosa di un duplicato. Si poteva leggere:

/proc/self/fd/[descriptor]

e ottenere la stringa che è stato utilizzato per aprire quel descrittore di file; tenete a mente che questo può fornire alcune insidie, alcune delle quali avete effettivamente notato nella vostra osservazione di chiamare di nuovo open().

Forse puoi spiegare un po 'di più e posso provare ad aggiornare per aiutare.

+0

@BobbyShaftoe, hai reiterato la mia domanda: P Il comportamento di apertura/proc/self/fd/[descrittore] è quello che sto cercando, tuttavia un modo più portatile e orientato alla chiamata di sistema per fare questo preferibile. –

+1

@Anacrolix, non proprio. L'hai modificato per aggiungere quel bit lì dentro. :) Ad ogni modo, temo che non ci sia un animale del genere, certamente non una chiamata di sistema o veramente portatile e affidabile. – BobbyShaftoe

+0

@BobbyShaftoe: potresti voler osservare che la domanda è stata cambiata in "Solo Windows" che è totalmente ingiusto nei confronti di coloro che hanno risposto alla domanda quando non c'era una tale qualifica. –

0

Perché non basta aprire il file una seconda volta con open() o CreateFile() su Windows? Questo ti dà tutta la libertà di diversi diritti di accesso e offset separato.

Questo naturalmente ha lo svantaggio che non è possibile aprire il file esclusivamente, ma risolve il problema molto semplicemente.

+3

Beh, mi interessa "riaprire" dato un handle di file e nient'altro. Su Linux, non è garantito che il file originale sia stato spostato o scollegato. Su Windows, dopo alcuni test sembrerebbe che non si possa manipolare una voce del filesystem fintanto che qualcuno ne ha un handle. –

Problemi correlati