Czy istnieje lepszy sposób niż próba otwarcia pliku?
int exists(const char *fname)
{
FILE *file;
if ((file = fopen(fname, "r")))
{
fclose(file);
return 1;
}
return 0;
}
c
filesystems
cross-platform
Dave Marshall
źródło
źródło
fopen()
/fclose()
jest to, że możesz nie być w stanie otworzyć pliku do odczytu, nawet jeśli on istnieje. Na przykład/dev/kmem
istnieje, ale większość procesów nie może go otworzyć nawet do odczytu./etc/shadow
to kolejny taki plik. Oczywiście zarównostat()
iaccess()
polegają na możliwości uzyskania dostępu do katalogu zawierającego plik; wszystkie zakłady są wyłączone, jeśli nie możesz tego zrobić (brak uprawnień do wykonania w katalogu zawierającym plik).if (file = fopen(fname, "r"))
da ostrzeżenie. Użyj nawiasów wokół instrukcji wewnątrz instrukcji ifif ((file = fopen(fname, "r")))
Odpowiedzi:
Wyszukaj
access()
funkcję znajdującą się wunistd.h
. Możesz zamienić swoją funkcję naMożesz również użyć
R_OK
,W_OK
aX_OK
zamiastF_OK
sprawdzać uprawnienia do odczytu, uprawnienia do zapisu i wykonać uprawnienia (odpowiednio) zamiast istnienia, i możesz LUB dowolne z nich razem (tj. Sprawdzić zarówno uprawnienia do odczytu, jak i zapisu za pomocąR_OK|W_OK
)Aktualizacja : należy pamiętać, że w systemie Windows nie można używać
W_OK
do niezawodnego testowania uprawnień do zapisu, ponieważ funkcja dostępu nie uwzględnia list DACL.access( fname, W_OK )
może zwrócić 0 (sukces), ponieważ plik nie ma ustawionego atrybutu tylko do odczytu, ale nadal możesz nie mieć uprawnień do zapisu do pliku.źródło
access()
włamania do mojego kodu. Przeprowadziłem się z DevC ++ do CodeBlocks i przestało działać. Więc to nie jest nieomylne; +1 więcej dla @Leffler.access()
Przez większość czasu tak (można sprawdzać istnienie pliku), ale w programie SUID lub SGID nawet to może być niepoprawne. Jeśli testowany plik znajduje się w katalogu, do którego prawdziwy UID lub prawdziwy GID nie ma dostępu,access()
może nie zgłosić żadnego takiego pliku, jeśli taki istnieje. Ezoteryczny i nieprawdopodobny? Tak.Użyj w
stat
ten sposób:i nazwij to tak:
źródło
access()
również szanse, że występują problemy, i istnieją opcje do tworzeniaaccess()
istat()
pracy z dużymi plikami (większymi niż 2 GB).stat
cierpi z powodu tej samej podatności na zagrożenia TOCTOU coaccess
? (Nie jest dla mnie jasne, że byłoby lepiej.)stat()
i na niąaccess()
cierpi (taklstat()
, alefstat()
jest bezpieczna). To zależy od tego, co będziesz robić, w zależności od obecności lub braku pliku. Użycie prawidłowych opcjiopen()
jest zwykle najlepszym sposobem radzenia sobie z problemami, ale sformułowanie właściwych opcji może być trudne. Zobacz także dyskusje na temat EAFP (łatwiej prosić o przebaczenie niż pozwolenie) i LBYL (Look Before You Leap) - patrz na przykład LBYL vs EAFP w Javie .Zwykle, gdy chcesz sprawdzić, czy plik istnieje, to dlatego, że chcesz go utworzyć , jeśli nie istnieje. Odpowiedź Graeme Perrow jest dobra, jeśli nie chcesz utworzyć tego pliku, ale jeśli to zrobisz , jest podatny na warunki wyścigu: inny proces może utworzyć plik między tobą, sprawdzając, czy istnieje, a faktycznie otwierając go, aby do niego napisać . (Nie śmiej się ... może to mieć zły wpływ na bezpieczeństwo, jeśli utworzony plik był dowiązaniem symbolicznym!)
Jeśli chcesz sprawdzić istnienie i utworzyć plik, jeśli nie istnieje, atomowo , aby nie było warunków wyścigu, użyj tego:
źródło
open(2)
(w systemie Linux; strony podręcznika systemu operacyjnego mogą się różnić), ale jest raczej brzydkie i może nie być odporne na złośliwego atakującego.FILE*
, musisz użyć metody posix,fdopen(fd,"flags")
aby wygenerowaćFILE*
Tak. Zastosowanie
stat()
. Zobacz stronę podręcznika dlastat(2)
.stat()
zawiedzie, jeśli plik nie istnieje, w przeciwnym razie najprawdopodobniej się uda. Jeśli istnieje, ale nie masz dostępu do odczytu katalogu, w którym on istnieje, również się nie powiedzie, ale w takim przypadku żadna metoda zawiedzie (w jaki sposób możesz sprawdzić zawartość katalogu, którego możesz nie zobaczyć zgodnie z prawami dostępu? Po prostu nie możesz).Och, jak ktoś wspomniał, możesz także użyć
access()
. Jednak wolęstat()
, jak gdyby plik istniał, natychmiast dostarczy mi wiele użytecznych informacji (kiedy był ostatnio aktualizowany, jak duży jest, właściciel i / lub grupa, która jest właścicielem pliku, uprawnienia dostępu itp.).źródło
access()
sprawdza on uprawnienia dostępu do pliku, które są przechowywane w i-węźle dla tego pliku i nie znajdują się we wpisie katalogu (przynajmniej dla wszystkich systemów plików, które mają struktury podobne do i-węzłów) .access()
Musi więc uzyskać dostęp do i-węzła dokładnie w taki sam sposób, jakstat()
ma do niego dostęp. To, co mówisz, ma zastosowanie tylko wtedy, gdy nie sprawdzasz żadnych uprawnień! W rzeczywistości na niektórych systemachaccess()
jest nawet zaimplementowanystat()
(np. Glibc na GNU Hurd robi to w ten sposób), więc nie ma żadnej gwarancji.źródło
(fopen_s(file, "sample.txt", "r"))
ponieważfopen()
jest to uznawane za przestarzałe (lub wyłącz przestarzałe błędy, ale nie jest to zalecane).fopen()
jest standardem C, nigdzie się nie wybiera. Jest to „przestarzałe” przez Microsoft. Nie używaj,fopen_s()
chyba że chcesz mieć nieprzenośny kod specyficzny dla platformy.Z pomocy Visual C ++ zwykle bym się przyłączył
Warto również zwrócić uwagę na wartości trybu :
_access(const char *path,
int mode
)
00: tylko istnienie
02: Napisz pozwolenie
04: Czytaj zezwolenie
06: Pozwolenie na odczyt i zapis
Ponieważ twój
fopen
może zawieść w sytuacjach, w których plik istniał, ale nie można go otworzyć zgodnie z żądaniem.Edycja: wystarczy przeczytać post Mecki.
stat()
wygląda na lepszy sposób. Ho hum.źródło
Możesz użyć funkcji realpath ().
źródło
Myślę, że funkcja access () , którą można znaleźć,
unistd.h
jest dobrym wyborem dlaLinux
(możesz także użyć statystyki ).Możesz użyć tego w następujący sposób:
Otrzymujesz następujące dane wyjściowe:
źródło