Gibt es einen besseren Weg als einfach zu versuchen, die Datei zu öffnen?
int exists(const char *fname)
{
FILE *file;
if ((file = fopen(fname, "r")))
{
fclose(file);
return 1;
}
return 0;
}
c
filesystems
cross-platform
Dave Marshall
quelle
quelle
fopen()
/fclose()
-Methode falsch ist, ist, dass Sie möglicherweise keine Datei zum Lesen öffnen können, obwohl sie existiert. Zum Beispiel/dev/kmem
existiert, aber die meisten Prozesse können es nicht einmal zum Lesen öffnen./etc/shadow
ist eine andere solche Datei. Natürlich beidesstat()
und daraufaccess()
angewiesen, auf das Verzeichnis zugreifen zu können, das die Datei enthält; Alle Wetten sind deaktiviert, wenn Sie dies nicht tun können (keine Ausführungsberechtigung für das Verzeichnis, das die Datei enthält).if (file = fopen(fname, "r"))
wird eine Warnung geben. Verwenden Sie Klammern um Anweisung innerhalb der if-Anweisungif ((file = fopen(fname, "r")))
Antworten:
Suchen Sie nach der
access()
Funktion inunistd.h
. Sie können Ihre Funktion durch ersetzenSie können auch verwendet werden
R_OK
,W_OK
undX_OK
anstelle derF_OK
für die Leseberechtigung zu überprüfen, Schreibrechte und Ausführungsrechte (jeweils) statt Existenz, und Sie können oder ein von ihnen zusammen (dh sowohl für Prüflesevorgang und Schreibberechtigung mitR_OK|W_OK
)Update : Beachten Sie, dass Sie unter Windows nicht
W_OK
zuverlässig auf Schreibberechtigung testen können, da die Zugriffsfunktion DACLs nicht berücksichtigt.access( fname, W_OK )
Möglicherweise wird 0 (Erfolg) zurückgegeben, da für die Datei kein schreibgeschütztes Attribut festgelegt ist, Sie jedoch möglicherweise noch keine Berechtigung zum Schreiben in die Datei haben.quelle
access()
meinen Code gebrochen hat. Ich bin von DevC ++ zu CodeBlocks gewechselt und es hat nicht mehr funktioniert. Es ist also nicht unfehlbar; +1 mehr an @Leffler.access()
die Existenz einer Datei zu überprüfen), aber in einem SUID- oder SGID-Programm kann auch das falsch sein. Wenn sich die getestete Datei in einem Verzeichnis befindet, auf das die echte UID oder die echte GID nicht zugreifen kann, wirdaccess()
möglicherweise keine solche Datei gemeldet, wenn sie vorhanden ist. Esoterisch und unwahrscheinlich? Ja.Verwenden Sie
stat
wie folgt:und nenne es so:
quelle
access()
auch Probleme auftreten, und es gibt Optionen zum Erstellenaccess()
undstat()
Arbeiten mit großen Dateien (größer als 2 GB).stat
nicht unter der gleichen TOCTOU-Sicherheitslücke wieaccess
? (Mir ist nicht klar, dass es besser wäre.)stat()
undaccess()
leiden unter der TOCTOU Verwundbarkeit (so tutlstat()
, aberfstat()
ist sicher). Es hängt davon ab, was Sie tun werden, basierend auf dem Vorhandensein oder Fehlen der Datei. Die Verwendung der richtigen Optionenopen()
ist normalerweise der beste Weg, um mit den Problemen umzugehen, aber es kann schwierig sein, die richtigen Optionen zu formulieren. Siehe auch Diskussionen zu EAFP (leichter um Vergebung zu bitten als um Erlaubnis) und LBYL (Look Before You Leap) - siehe beispielsweise LBYL vs EAFP in Java .Wenn Sie überprüfen möchten, ob eine Datei vorhanden ist, möchten Sie diese Datei normalerweise erstellen , wenn dies nicht der Fall ist. Die Antwort von Graeme Perrow ist gut, wenn Sie diese Datei nicht erstellen möchten, aber sie ist anfällig für eine Race-Bedingung, wenn Sie dies tun: Ein anderer Prozess könnte die Datei zwischen Ihnen erstellen, indem Sie prüfen, ob sie vorhanden ist, und Sie sie tatsächlich öffnen, um darauf zu schreiben . (Nicht lachen ... dies könnte schlechte Auswirkungen auf die Sicherheit haben, wenn die erstellte Datei ein Symlink ist!)
Wenn Sie die Existenz überprüfen und die Datei erstellen möchten, wenn sie nicht vorhanden ist, atomar, damit keine Rennbedingungen vorliegen, verwenden Sie Folgendes :
quelle
open(2)
(unter Linux; die Manpages Ihres Betriebssystems können variieren), aber sie ist ziemlich hässlich und möglicherweise nicht resistent gegen einen böswilligen Angreifer.FILE*
Sie dazu die Posix-Methode verwenden müssenfdopen(fd,"flags")
, um einenFILE*
Ja. Verwenden Sie
stat()
. Siehe die Manpage fürstat(2)
.stat()
schlägt fehl, wenn die Datei nicht vorhanden ist, andernfalls ist dies höchstwahrscheinlich erfolgreich. Wenn es vorhanden ist, Sie aber keinen Lesezugriff auf das Verzeichnis haben, in dem es vorhanden ist, schlägt es ebenfalls fehl. In diesem Fall schlägt jedoch jede Methode fehl (wie können Sie den Inhalt eines Verzeichnisses überprüfen, das Sie möglicherweise nicht nach Zugriffsrechten sehen? Einfach nicht).Oh, wie jemand anderes erwähnt hat, können Sie auch verwenden
access()
. Ich bevorzuge jedochstat()
, dass die Datei, wenn sie existiert, sofort viele nützliche Informationen enthält (wann sie zuletzt aktualisiert wurde, wie groß sie ist, Eigentümer und / oder Gruppe, der die Datei gehört, Zugriffsberechtigungen usw.).quelle
access()
werden die Dateizugriffsberechtigungen einer Datei überprüft. Diese werden im Inode für diese Datei gespeichert und befinden sich nicht in ihrem Verzeichniseintrag (zumindest für alle Dateisysteme mit inodeähnlichen Strukturen). . Soaccess()
hat die Inode für den Zugriff auf genau die gleiche Art und Weise , diestat()
es zuzugreifen. Was Sie also sagen, gilt nur, wenn Sie nicht nach Berechtigungen suchen! Und tatsächlich wird auf einigen Systemenaccess()
sogar zusätzlich implementiertstat()
(z. B. glibc auf GNU Hurd macht es so), so dass es überhaupt keine Garantie gibt.quelle
(fopen_s(file, "sample.txt", "r"))
dafopen()
gilt als veraltet (oder deaktivieren Sie veraltete Fehler, dies wird jedoch nicht empfohlen).fopen()
ist Standard C, es geht nirgendwo hin. Es ist nur von Microsoft "veraltet". Verwendenfopen_s()
Sie diese Option nur, wenn Sie plattformspezifischen, nicht portablen Code möchten.In der Visual C ++ - Hilfe würde ich eher mitgehen
Erwähnenswert sind auch die Moduswerte von :
_access(const char *path,
int mode
)
00: Nur Existenz
02: Schreibberechtigung
04: Erlaubnis lesen
06: Lese- und Schreibberechtigung
Als Ihr
fopen
könnte in Situationen versagen , wo die Datei existiert , aber nicht geöffnet , wie verlangt werden könnte.Edit: Lies einfach Meckis Beitrag.
stat()
sieht aus wie ein ordentlicher Weg zu gehen. Ho hum.quelle
Sie können die Funktion realpath () verwenden.
quelle
Ich denke, dass die access () -Funktion, die in gefunden
unistd.h
wird, eine gute Wahl ist fürLinux
(Sie können auch stat verwenden ).Sie können es so verwenden:
Und Sie erhalten die folgende Ausgabe:
quelle