2009-11-04 14 views
5

Mój kod jest coś takiego:Usuwanie plików podczas odczytu katalogu z readdir()

DIR* pDir = opendir("/path/to/my/dir"); 
struct dirent pFile = NULL; 
while ((pFile = readdir())) { 
    // Check if it is a .zip file 
    if (subrstr(pFile->d_name,".zip") { 
     // It is a .zip file, delete it, and the matching log file 
     char zipname[200]; 
     snprintf(zipname, sizeof(zipname), "/path/to/my/dir/%s", pFile->d_name); 
     unlink(zipname); 
     char* logname = subsstr(zipname, 0, strlen(pFile->d_name)-4); // Strip of .zip 
     logname = appendstring(&logname, ".log"); // Append .log 
     unlink(logname); 
} 
closedir(pDir); 

(kod ten jest niesprawdzone i wyłącznie przykładem)

Chodzi o to: Czy wolno usunąć plik w katalogu podczas przeglądania katalogu za pomocą readdir()? Czy też readdir() nadal znajdzie usunięty plik .log?

Odpowiedz

5

Cytat POSIX readdir:

Jeżeli plik zostanie usunięty z lub dodane do katalogu po ostatniej wezwanie do opendir() lub rewinddir(), czy późniejsze wywołanie readdir() zwraca nieokreślony wpis dla tego pliku: .

Zgaduję, że ... to zależy.

To zależy od systemu operacyjnego, na pory dnia, od względnej kolejności pliki dodane/usunięte ...

, aw kolejnym punkcie, pomiędzy chwilą readdir() powraca funkcyjne i ty spróbuj unlink() plik, niektóre inne procesy mogły usunąć ten plik, a twoja unlink() uległa awarii.


Edit

testowałem z tym programem:

#include <dirent.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/types.h> 
#include <unistd.h> 

int main(void) { 
    struct dirent *de; 
    DIR *dd; 

    /* create files `one.zip` and `one.log` before entering the readdir() loop */ 
    printf("creating `one.log` and `one.zip`\n"); 
    system("touch one.log"); /* assume it worked */ 
    system("touch one.zip"); /* assume it worked */ 

    dd = opendir("."); /* assume it worked */ 
    while ((de = readdir(dd)) != NULL) { 
    printf("found %s\n", de->d_name); 
    if (strstr(de->d_name, ".zip")) { 
     char logname[1200]; 
     size_t i; 
     if (*de->d_name == 'o') { 
     /* create `two.zip` and `two.log` when the program finds `one.zip` */ 
     printf("creating `two.zip` and `two.log`\n"); 
     system("touch two.zip"); /* assume it worked */ 
     system("touch two.log"); /* assume it worked */ 
     } 
     printf("unlinking %s\n", de->d_name); 
     if (unlink(de->d_name)) perror("unlink"); 
     strcpy(logname, de->d_name); 
     i = strlen(logname); 
     logname[i-3] = 'l'; 
     logname[i-2] = 'o'; 
     logname[i-1] = 'g'; 
     printf("unlinking %s\n", logname); 
     if (unlink(logname)) perror("unlink"); 
    } 
    } 
    closedir(dd); /* assume it worked */ 
    return 0; 
} 

Na moim komputerze, readdir() wyszukuje usunięte pliki i nie znajduje plików utworzonych pomiędzy opendir() i readdir(). Ale może być inny na innym komputerze; może się różnić na moim komputerze, jeśli kompiluję z różnymi opcjami; może być inaczej, jeśli zaktualizuję jądro; ...

+1

LOL @ 'man 2 readdir':" To nie jest funkcja, którą jesteś zainteresowany. " – pmg

+1

Ta sama strona podręcznika mówi: "Pozycje katalogu reprezentują pliki, pliki mogą być usunięte z katalogu lub dodane do katalogu asynchronicznie do operacji readdir()" Ale może lepiej tego uniknąć !? – To1ne

1

ja testuje moją nową książkę odniesienia Linux. Linux Programming Interface Michael Kerrisk i mówi co następuje:

SUSv3 wyraźnie stwierdza, że ​​to jest określone, czy readdir() zwraca nazwę pliku, który został dodany do lub usunięty z od ostatniego od ostatniego wywołania opendir() lub rewinddir(). Wszystkie nazwy plików, które nie zostały dodane ani usunięte od czasu ostatniego takiego połączenia, są objęte gwarancją: , która ma zostać zwrócona w postaci.

Myślę, że to, co jest nieokreślone, dotyczy tego, co dzieje się z direntami, które nie zostały jeszcze zeskanowane. Po zwróceniu hasła jest ono w 100% gwarantowane, że nie zostanie ono już zwrócone bez względu na to, czy odłączysz bieżącą dyrektywę, czy nie.

Należy również zwrócić uwagę na gwarancję przewidzianą w drugim zdaniu.Ponieważ pozostawiasz same pliki i tylko odłączasz bieżący wpis dla pliku zip, SUSv3 gwarantuje, że wszystkie inne pliki zostaną zwrócone. Co dzieje się z plikiem dziennika, jest niezdefiniowane. może zostać lub nie może zostać zwrócone przez readdir(), ale w twoim przypadku nie powinno to być szkodliwe.

Powodem, dla którego zbadałem pytanie, jest znalezienie skutecznego sposobu zamknięcia deskryptorów plików w procesie potomnym przed exec().

Sugerowany sposób APUE od Stevens jest wykonanie następujących czynności:

int max_open = sysconf(_SC_OPEN_MAX); 
for (int i = 0; i < max_open; ++i) 
    close(i); 

ale myślę użyciu kodu podobnego do tego, co znajduje się w PO do skanowania/dev/fd/katalog aby dokładnie wiedzieć, które fds muszę zamknąć. (Zwróć uwagę na siebie, przejdź do dirfd zawartego w uchwycie DIR.)