Ist es möglich, den Dateinamen eines Dateideskriptors (Linux) in C zu erhalten?
Rufen Sie den Dateinamen aus dem Dateideskriptor in C ab
adk
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 stat
auf 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
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