2009-10-21 14 views
15

Wie kann man einen neuen Dateideskriptor aus einem vorhandenen Dateideskriptor erstellen, so dass der neue Deskriptor nicht die gleiche interne Dateistruktur/Eintrag in der Dateitabelle hat? Insbesondere Attribute wie Dateioffset (und vorzugsweise Berechtigungen, Freigabe und Modi) sollten nicht zwischen den neuen und alten Dateideskriptoren geteilt werden.Doppelter Dateideskriptor mit eigenem Dateioffset

Unter Windows und Linux wird dup() den Dateideskriptor duplizieren, aber beide Deskriptoren verweisen immer noch auf die gleiche Dateistruktur in der Dateitabelle des Prozesses. Jede Suche nach einem der Deskriptoren wird die Position für die anderen Deskriptoren anpassen.

Hinweis

ich seit eingegangenen Antworten haben für Windows und Linux und die Frage ein wenig zu oft angepasst, was es schwierig gemacht hat, für die Menschen zu beantworten. Ich werde meine Stimmen anpassen und die sauberste Antwort akzeptieren, die sowohl Windows als auch Linux betrifft. Entschuldigung an alle, ich bin immer noch neu im SO-Paradigma. Danke für die tollen Antworten!

Antwort

12

Also, was Sie wirklich wollen, ist eine Datei-Deskriptor gegeben werden, und grundsätzlich die gleiche Datei wieder öffnen, um eine separate Position, Freigabe, Modus usw. zu erhalten. Und Sie möchten dies unter Windows tun (wo der „Dateideskriptor“ ist im Grunde ein Fremdkörper, nicht etwas, direkt durch das O oder die Laufzeitbibliothek an allen

Erstaunlicherweise verwendet. es ist eine Art und Weise, dass zumindest mit MS zu tun VC++: Alle bis auf zwei Schritte verwenden nur die Win32-API, daher sollte die Portierung auf andere Compiler/Bibliotheken ziemlich vernünftig sein (ich denke, die meisten Versionsversionen dieser beiden Funktionen) .Diese dienen zum Konvertieren eines Unix-Style-Dateideskriptors in ein natives Win3 2 Dateizugriffsnummer und Konvertierung eines systemeigenen Win32-Dateihandle zurück in einen Unix-Style-Dateideskriptor.

  1. konvertieren Datei-Descriptor nativen Datei-Handle mit _get_osfhandle()
  2. einen Namen ein neues Handle für diese Datei zu öffnen
  3. mit GetFileInformationByHandleEx (FILE_NAME_INFO)
  4. Verwenden Createfile für die Datei Get
  5. erstellen Sie einen Dateideskriptor für das mit _open_osfhandle Griff()

Et voilà, haben wir eine neue Dateideskriptors verweisen klingeln auf die gleiche Datei, aber mit eigenen Berechtigungen, Position, etc.

Gegen Ende Ihrer Frage, Sie es klingen wie Sie wollen auch die "Berechtigungen", aber das scheint nicht real zu machen Sinn: Die Berechtigungen werden an die Datei selbst angehängt, nicht an die Art und Weise, wie die Datei geöffnet wird. Daher hat das Öffnen oder erneute Öffnen der Datei keine Auswirkungen auf die Dateiberechtigungen. Wenn Sie das wirklich wissen wollen, können Sie es mit GetFileInformationByHandle bekommen, aber seien Sie sich bewusst, dass die Dateiberechtigungen in Windows ziemlich verschieden von den (traditionellen) Dateiberechtigungen in Unix sind. Unix hat Besitzer-/Gruppen-/Weltberechtigungen für alle Dateien, und die meisten Systeme haben auch Zugriffssteuerungslisten (obwohl es mehr Unterschiede gibt, wie sie funktionieren). Windows hat entweder überhaupt keine Berechtigungen (z. B. Dateien auf FAT oder FAT32) oder verwendet ACLs (z. B. Dateien auf NTFS), aber nichts, das den traditionellen Eigentümer-/Gruppen-/Weltberechtigungen entspricht, die die meisten Benutzer unter Unix gewohnt sind.

Vielleicht verwenden Sie "Berechtigungen", um darauf zu verweisen, ob die Datei zum Lesen, Schreiben oder für beides geöffnet war. Das zu bekommen ist wesentlich hässlicher als alle anderen. Das Problem ist, dass das meiste davon in der Bibliothek ist, nicht Win32, also gibt es wahrscheinlich keine Möglichkeit, dies zu tun, die sogar zwischen Compilern in der Nähe von portierbar ist. Mit MS VC++ 9.0 SP1 (nicht garantiert für jeder andere Compiler) Sie können dies tun:

#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. 
} 

Da dies einige Spelunking beteiligt, schrieb ich einen schnellen Test zu überprüfen, ob es könnte tatsächlich funktionieren:

#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 

und die Ergebnisse scheinen zeigen Erfolg:

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

Sie können dann Test, der Flagge gegen _IOREAD, _IOWRT zurückgekehrt und _IORW, das sind definiert in stdio.h. Trotz meiner früheren Warnungen sollte ich wahrscheinlich darauf hinweisen, dass ich (obwohl ich sicherlich nicht garantieren kann) vermute, dass dieser Teil der Bibliothek ziemlich stabil ist, so dass die wahren Chancen für größere Veränderungen wahrscheinlich ziemlich gering sind.

In der anderen Richtung gibt es jedoch im Grunde keine Chance überhaupt, dass es mit jeder anderen Bibliothek arbeiten wird. Es könnte (aber ist sicherlich nicht garantiert) mit den anderen Compilern arbeiten, die die MS-Bibliothek verwenden, wie Intel, MinGW oder Comeau mit MS VC++ als Back-End. Von diesen würde ich sagen, dass Comeau am wahrscheinlichsten arbeiten würde, und das am wenigsten wahrscheinliche MinGW (aber das ist nur eine Vermutung; es gibt eine gute Chance, dass es mit keinem von ihnen funktionieren wird).

  1. Erfordert das verteilbare Win32 FileID API Library
+0

eine gute Antwort. Mir war nicht bewusst, dass das Öffnen einer Datei verhinderte, dass die Verknüpfung aufgehoben oder umbenannt wurde, selbst wenn die vollständige Freigabe aktiviert war. Dies bedeutet, dass das Abrufen des Dateinamens, der zu einem Handle gehört, vollkommen sicher ist, da er sich nicht ändern kann, solange ein Dateideskriptor oder 'HANDLE' für diesen Pfad offen bleibt. –

+0

Wie kann ich das Gleiche unter Linux tun? danke – alaamh

+0

@alaamh: hast du die anderen Antworten durchgesehen? Ein paar von ihnen reden darüber, wie man die gleichen Dinge unter Linux macht. –

2

Also, empfehle ich, ein wenig mehr darüber zu lesen. Die dup() und verwandte Funktionen dienen zum Erstellen eines doppelten Werts in der Dateideskriptor-Tabelle, die auf den gleichen Eintrag in der geöffneten Dateitabelle verweist. Dies ist vorgesehen, um den gleichen Offset zu haben. Wenn Sie open() aufrufen, erstellen Sie einen neuen Eintrag der geöffneten Dateitabelle.

Es macht keinen Sinn, ein Duplikat eines Dateideskriptors zu erstellen, und dieser neue Dateideskriptor hat einen anderen Offset in der offenen Dateitabelle (dies scheint zu widersprechen, was das Wort "duplizieren" bedeutet).

Ich bin mir nicht sicher, was Ihre Frage eigentlich ist. Ich meine, es ist nicht dasselbe wie ein Duplikat. Sie könnten lesen:

/proc/self/fd/[descriptor]

und die Zeichenfolge erhalten, die Datei zu öffnen Descriptor verwendet wurde; Denken Sie daran, dies kann einige Fallstricke bieten, von denen einige Sie tatsächlich in Ihrer Beobachtung des Aufrufs open() wieder notiert haben.

Vielleicht können Sie ein wenig mehr erklären und ich kann versuchen, zu aktualisieren, um zu helfen.

+0

@BobbyShaftoe, haben Sie meine Frage wiederholt: P Das Verhalten der Öffnung/proc/self/fd/[deskriptor] ist, was ich danach bin, jedoch ein portabler und System-Call-orientierten Weg dies zu tun bevorzugt. –

+1

@Anacrolix, nicht wirklich. Du hast es bearbeitet, um dieses Bit hinzuzufügen. :) Jedenfalls habe ich Angst, dass es kein solches Tier gibt, sicherlich kein Systemanruf oder wirklich tragbar und zuverlässig. – BobbyShaftoe

+0

@BobbyShaftoe: Sie möchten vielleicht beobachten, dass die Frage auf "nur Windows" geändert wurde, was völlig ungerecht ist gegenüber denjenigen, die die Frage beantwortet haben, als es keine solche Qualifikation gab. –

0

Warum Sie nicht einfach die Datei öffnen, ein zweites Mal mit open() oder Createfile() auf Windows? Dies gibt Ihnen alle Freiheit von verschiedenen Zugriffsrechten und separaten Offset.

Dies hat natürlich den Nachteil, dass Sie die Datei nicht ausschließlich öffnen können, aber es löst Ihr Problem sehr einfach.

+3

Nun, ich interessiere mich für "Wiedereröffnung" bei einem Datei-Handle und sonst nichts. Unter Linux ist die ursprüngliche Datei nicht sicher verschoben oder wurde nicht verknüpft. Unter Windows scheint es nach einigen Tests nicht möglich zu sein, einen Dateisystemeintrag so lange zu manipulieren, wie jemand einen Handle dafür hält. –