Rufen Sie den Dateinamen aus dem Dateideskriptor in C ab

Lesezeit: 7 Minuten

Benutzeravatar von adk
adk

Ist es möglich, den Dateinamen eines Dateideskriptors (Linux) in C zu erhalten?

  • Ich denke, die gewählte Antwort sollte an zneak gegeben werden, da seine Lösung eine bessere Portabilität aufweist und keine bekannten Zugriffsprobleme aufweist.

    – Sergej Krivonos

    4. September 2016 um 7:31 Uhr


  • Es wird von Ubuntu 14.04 (Kernel 3.16.0-76-generic) nicht unterstützt. Ich vermute, dass es unter Linux überhaupt nicht unterstützt wird.

    – felipou

    19. Oktober 2016 um 16:50 Uhr

  • Für macOS siehe diese Antwort auf eine andere Frage von D.Nathanael.

    – Jonathan Leffler

    24. September 2019 um 16:05 Uhr


Benutzeravatar von bdonlan
bdonlan

Sie können verwenden readlink an /proc/self/fd/NNN wobei NNN der Dateideskriptor ist. Dadurch erhalten Sie den Namen der Datei, wie er beim Öffnen war. Wenn die Datei jedoch seitdem verschoben oder gelöscht wurde, ist sie möglicherweise nicht mehr korrekt (obwohl Linux in einigen Fällen Umbenennungen nachverfolgen kann). Verifizieren, stat der angegebene Dateiname und fstat die fd haben sie, und stellen sie sicher st_dev und st_ino sind gleich.

Natürlich beziehen sich nicht alle Dateideskriptoren auf Dateien, und für diese werden Sie einige seltsame Textzeichenfolgen sehen, wie z pipe:[1538488]. Da alle echten Dateinamen absolute Pfade sind, können Sie leicht feststellen, welche das sind. Außerdem können Dateien, wie andere angemerkt haben, mehrere Hardlinks haben, die auf sie verweisen – dies wird nur denjenigen melden, mit dem sie geöffnet wurde. Wenn Sie alle Namen für eine bestimmte Datei finden möchten, müssen Sie nur das gesamte Dateisystem durchlaufen.

  • Solange die Originaldatei noch Verweise darauf hat (eine open fd wäre eine solche Referenz), die Inode-Nummer kann nicht wiederverwendet werden. Jede Software, die eine Inode-Nummer verwendet, nachdem sie die Datei geschlossen oder bevor sie sie geöffnet hat, unterliegt von Natur aus Race-Bedingungen.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    29. November 2010 um 16:03 Uhr

  • Gefahr, Will Robinson! Das tut nicht stets arbeiten — wenn ja setuid() Tricks, es ist möglich für /proc/self/fd von Ihrem Prozess nicht zugänglich sein. Sehen: permalink.gmane.org/gmane.linux.kernel/1302546

    – David gegeben

    16. Mai 2013 um 13:28 Uhr

  • @bdonlan: und falls /proc nicht gemountet ist?

    – Benutzer2284570

    2. Juni 2015 um 1:04 Uhr

  • @ user2284570, diese Antwort ist Linux-spezifisch. Ich weiß nicht, ob NetBSD überhaupt procfs unterstützt – wenn Ihr gemeinsam genutzter Host es nicht bereitstellt, liegt es wahrscheinlich daran, dass NetBSD es überhaupt nicht unterstützt und stattdessen einen anderen Mechanismus verwendet. Vielleicht möchten Sie eine weitere Frage mit einem NetBSD-Fokus stellen, um zu sehen, ob jemand weiß, wie NetBSD diese Informationen offenlegt (Sie sollten auch die Antwort von zneak unten ausprobieren, OS X ist BSD ähnlicher als Linux).

    – bdonlan

    19. Juni 2015 um 7:38 Uhr


  • @bdonlan : NetBSD unterstützt /proc, aber es ist nicht zwingend erforderlich, es zu mounten. Jedes Mal, wenn ich es erwähnte, war die Antwort “Wechseln Sie zu einem teureren Anbieter und Sie erhalten /proc”. Also suche ich nach einer prozesslosen Lösung.

    – Benutzer2284570

    19. Juni 2015 um 7:44 Uhr

Ich hatte dieses Problem unter Mac OS X. Wir haben keine /proc virtuelles Dateisystem, sodass die akzeptierte Lösung nicht funktionieren kann.

Wir haben stattdessen eine F_GETPATH Befehl für fcntl:

 F_GETPATH          Get the path of the file descriptor Fildes.  The argu-
                    ment must be a buffer of size MAXPATHLEN or greater.

Um also die einem Dateideskriptor zugeordnete Datei zu erhalten, können Sie dieses Snippet verwenden:

#include <sys/syslimits.h>
#include <fcntl.h>

char filePath[PATH_MAX];
if (fcntl(fd, F_GETPATH, filePath) != -1)
{
    // do something with the file path
}

Da ich mich nie erinnere wo MAXPATHLEN ist definiert, dachte ich PATH_MAX von syslimits wäre in Ordnung.

  • @uchuugaka, wahrscheinlich nicht. Verwenden getsockname.

    – zneak

    16. Januar 2015 um 18:56 Uhr

  • Was erwartest du? Sofern es sich nicht um einen UNIX-Socket handelt, ist ihm keine Datei zugeordnet.

    – zneak

    17. Januar 2015 um 13:23 Uhr

  • @uchuugaka Ja, alles ist eine Datei, aber nicht alles ist eine Verzeichniseintrag mit einem Namen und einem Speicherort innerhalb des Dateisystembaums. Eine Datei wird durch einen Inode dargestellt, sie kann existieren, ohne dass ein Verzeichniseintrag darauf verweist.

    – lgeorget

    16. Februar 2015 um 10:09 Uhr

  • In : #define MAXPATHLEN PATH_MAX

    – Erdkrieg

    21. Juli 2015 um 15:48 Uhr


  • Ich habe das gerade getestet und es bleibt korrekt, wenn die Datei verschoben wird und Sie sie erneut aufrufen (dh Sie erhalten den neuen Pfad der Datei). Dies wird jedoch unter Linux nicht unterstützt (getestet unter Ubuntu 14.04 – F_GETPATH ​​ist nicht definiert).

    – felipou

    19. Oktober 2016 um 16:47 Uhr

Unter Windows mit GetFileInformationByHandleExVorbeigehen DateiNameInfokönnen Sie den Dateinamen abrufen.

Wie Tyler betont, gibt es keine Möglichkeit, das zu tun, was Sie “direkt und zuverlässig” benötigen, da ein bestimmter FD 0 Dateinamen (in verschiedenen Fällen) oder > 1 entsprechen kann (mehrere “harte Links”, wie die letztere Situation allgemein beschrieben wird ). Wenn Sie dennoch die Funktionalität mit allen Einschränkungen benötigen (in Bezug auf die Geschwindigkeit UND auf die Möglichkeit, 0, 2, … Ergebnisse anstelle von 1 zu erhalten), können Sie dies folgendermaßen tun: Erstens, fstat die FD — dies sagt Ihnen im Ergebnis struct statauf welchem ​​Gerät die Datei lebt, wie viele feste Links sie hat, ob es sich um eine spezielle Datei handelt usw. Dies kann Ihre Frage bereits beantworten – z. B. wenn 0 feste Links vorhanden sind, wissen Sie, dass es tatsächlich keinen entsprechenden Dateinamen auf der Festplatte gibt.

Wenn die Statistiken Ihnen Hoffnung geben, müssen Sie auf dem entsprechenden Gerät den Verzeichnisbaum “durchgehen”, bis Sie alle festen Links gefunden haben (oder nur den ersten, wenn Sie nicht mehr als einen benötigen und jeder ausreicht). ). Zu diesem Zweck verwenden Sie readdir (und natürlich opendir &c) Unterverzeichnisse rekursiv öffnen, bis Sie in a finden struct dirent erhielt also dieselbe Inode-Nummer wie im Original struct stat (Zu diesem Zeitpunkt müssen Sie, wenn Sie den gesamten Pfad und nicht nur den Namen möchten, die Verzeichniskette rückwärts durchlaufen, um sie zu rekonstruieren).

Wenn dieser allgemeine Ansatz akzeptabel ist, Sie aber detaillierteren C-Code benötigen, lassen Sie es uns wissen, es wird nicht schwer zu schreiben sein (obwohl ich es lieber nicht schreiben würde, wenn es nutzlos ist, dh Sie können der unvermeidlich langsamen Leistung oder dem nicht standhalten Möglichkeit, != 1 Ergebnis für Ihre Bewerbung zu erhalten;-).

Bevor Sie dies als unmöglich abschreiben, schlage ich vor, dass Sie sich den Quellcode der lsof Befehl.

Es kann Einschränkungen geben, aber lsof scheint in der Lage zu sein, den Dateideskriptor und den Dateinamen zu bestimmen. Diese Informationen sind im /proc-Dateisystem vorhanden, daher sollte es möglich sein, von Ihrem Programm darauf zuzugreifen.

Sie können fstat() verwenden, um den Inode der Datei per struct stat abzurufen. Dann können Sie mit readdir() den gefundenen Inode mit denen vergleichen, die in einem Verzeichnis existieren (struct dirent) (vorausgesetzt, Sie kennen das Verzeichnis, sonst müssen Sie das gesamte Dateisystem durchsuchen) und den entsprechenden Dateinamen finden. Böse?

Unmöglich. Ein Dateideskriptor kann mehrere Namen im Dateisystem haben oder gar keinen Namen haben.

Bearbeiten: Angenommen, Sie sprechen von einem einfachen alten POSIX-System ohne Betriebssystem-spezifische APIs, da Sie kein Betriebssystem angegeben haben.

  • dann gilt meine Antwort. Linux hat dazu keine Möglichkeiten. Dateideskriptoren von Linux (POSIX) beziehen sich nicht unbedingt auf Dateien, und selbst wenn sie es tun, beziehen sie sich auf Inodes, nicht auf Dateinamen. Ein Deskriptor kann auf eine gelöschte Datei zeigen (die daher keinen Namen hat, dies ist eine übliche Art, temporäre Dateien zu erstellen) oder er kann auf einen Inode mit mehreren Namen (harte Links) zeigen.

    – Tyler McHenry

    27. Juli 2009 um 15:29 Uhr

  • Versuchen Sie, einen Blick auf den lsof-Quellcode zu werfen. 🙂 Das habe ich getan, als ich vor einiger Zeit selbst dieselbe Frage hatte. lsof arbeitet mit schwarzer Magie und Opferziegen – Sie können nicht hoffen, sein Verhalten zu duplizieren. Genauer gesagt ist lsof eng mit dem Linux-Kernel gekoppelt und tut das, was es tut, nicht mit Hilfe einer API, die für Benutzerlandcode verfügbar ist.

    – Tyler McHenry

    27. Juli 2009 um 17:45 Uhr

  • Linux hat dafür eine nicht-portable Proc-API. Es gibt tatsächlich Einschränkungen, aber zu sagen, dass es unmöglich ist, ist einfach falsch.

    – bdonlan

    27. Juli 2009 um 17:45 Uhr

  • @Tyler – lsof läuft im Userspace. Daher gibt es für Userland-Code eine API für alles, was es tut 🙂

    – bdonlan

    27. Juli 2009 um 17:47 Uhr

  • @Duck, die Portabilität dort ist wahrscheinlich der Grund, warum die Quelle von lsof so viel schwarze Magie hat; jede UNIX-Variante macht es anders. Die Linux-Proc-Schnittstellen sind nicht allzu schlecht, wirklich, aber eher spärlich dokumentiert.

    – bdonlan

    27. Juli 2009 um 17:53 Uhr

1423120cookie-checkRufen Sie den Dateinamen aus dem Dateideskriptor in C ab

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy