2009-11-04 23 views
5

Il mio codice è qualcosa di simile:Elimina file durante la lettura di directory con 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); 

(questo codice non è testato e puramente un esempio)

Il punto è: E 'permesso di eliminare un file in una directory mentre si scorre nella directory con readdir()? Oppure readdir() trova ancora il file .log cancellato?

risposta

5

Citazione di POSIX readdir:

Se un file viene rimosso o aggiunto al directory dopo il più recente chiamata a opendir() o rewinddir(), se una chiamata successiva alla readdir() restituisce una voce per quel file è non specificato.

Quindi, la mia ipotesi è ... dipende.

Dipende dal sistema operativo, il momento della giornata, l'ordine relativo dei file aggiunti/cancellati, ...

E, come un ulteriore punto, tra il tempo le readdir() funzione ritorna e si prova a unlink() il file, qualche altro processo potrebbe aver cancellato quel file e il tuo unlink() fallisce.


Modifica

ho provato con questo programma:

#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; 
} 

Sul mio computer, readdir() trova file cancellati e non trova i file creati tra il opendir() e readdir(). Ma potrebbe essere diverso su un altro computer; potrebbe essere diverso sul mio computer se compilo con diverse opzioni; potrebbe essere diverso se aggiorno il kernel; ...

+1

LOL @ 'man 2 readdir':" Questa non è la funzione che ti interessa. " – pmg

+1

La stessa pagina man dice: "Le voci della directory rappresentano i file, i file possono essere rimossi da una directory o aggiunti in una directory in modo asincrono all'operazione di readdir()" Ma forse meglio evitare questo !? – To1ne

1

sto testando il mio nuovo libro di riferimento Linux. L'interfaccia di programmazione di Linux da Michael Kerrisk e dice quanto segue:

SUSv3 rileva esplicitamente che non è specificato se readdir() restituirà un nome di file che è stato aggiunto o rimosso dal dall'ultimo dall'ultima chiamata a opendir() o rewinddir(). Tutti i nomi di file che non sono stati aggiunti né rimossi dall'ultima chiamata di questo tipo sono garantiti da restituire.

Penso che ciò che non è specificato è ciò che accade a dirents non ancora scansionate. Una volta che una voce è stata restituita, è garantito al 100% che non verrà più restituita indipendentemente dal fatto che si scolleghi o meno la corrente.

Annotare inoltre la garanzia fornita dalla seconda frase.Poiché si stanno lasciando da soli gli altri file e si scollega solo la voce corrente per il file zip, SUSv3 garantisce che verranno restituiti tutti gli altri file. Cosa succede al file di registro non è definito. può o non può essere restituito da readdir() ma nel tuo caso, non dovrebbe essere dannoso.

Il motivo per cui ho esplorato la questione è trovare un modo efficace per chiudere i descrittori di file in un processo figlio prima di exec().

Il modo suggerito APUE da Stevens è quello di effettuare le seguenti operazioni:

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

ma sto pensando utilizzando il codice simile a quello che si trova nel PO per la scansione///directory dev fd sapere esattamente quali FDS Devo chiudere. (Nota speciale a me stesso, ignora dirfd contenuto nel handle DIR.)

Problemi correlati