2009-11-04 6 views
5

Mon code est quelque chose comme ceci:Supprimer les fichiers en lecture du répertoire avec 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); 

(ce code est non testé et purement un exemple)

Le point est: Est-il permis de supprimer un fichier dans un répertoire en boucle dans le répertoire avec readdir()? Ou readdir() trouvera-t-il toujours le fichier .log supprimé?

Répondre

5

Citation de POSIX readdir:

Si un fichier est supprimé ou ajouté à le répertoire après le dernier appel à opendir() ou rewinddir(), si un appel suivant à readdir() renvoie une entrée pour ce fichier est non spécifié.

Donc, je suppose que ... cela dépend.

Cela dépend du système d'exploitation, à l'heure du jour, de l'ordre relatif des fichiers ajoutés/supprimés, ...

Et, comme un autre point, entre le moment où la fonction retourne readdir() et vous essayer de unlink() le fichier, un autre processus pourrait avoir supprimé ce fichier et votre unlink() échoue.


Modifier

Je l'ai testé avec ce programme:

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

Sur mon ordinateur, readdir() trouve les fichiers supprimés et ne trouve pas les fichiers créés entre opendir() et readdir(). Mais il peut être différent sur un autre ordinateur; il peut être différent sur mon ordinateur si je compile avec différentes options; cela peut être différent si je mets à jour le noyau; ...

+1

LOL @ 'man 2 readdir':" Ce n'est pas la fonction qui vous intéresse. " – pmg

+1

La même page de manuel indique: "Les entrées du répertoire représentent les fichiers, les fichiers peuvent être supprimés d'un répertoire ou ajoutés à un répertoire de manière asynchrone à readdir()" Mais peut-être vaut mieux éviter cela !? – To1ne

1

Je teste mon nouveau livre de référence Linux. L'interface de programmation Linux par Michael Kerrisk et il dit ce qui suit:

SUSv3 note explicitement qu'il est précisé si readdir() retourne un nom de fichier qui a été ajouté ou retiré depuis le dernier depuis le dernier appel à opendir() ou rewinddir(). Tous les noms de fichiers qui n'ont été ni ajoutés ni supprimés depuis le dernier appel de ce type sont garanti à retourner.

Je pense que ce qui n'est pas spécifié est ce qui arrive aux droites qui n'ont pas encore été analysées. Une fois qu'une entrée a été retournée, il est garanti à 100% qu'elle ne sera plus retournée, que vous dissociez ou non le courant actuel.

Notez également la garantie fournie par la deuxième phrase.Puisque vous laissez seuls les autres fichiers et que vous ne faites que dissocier l'entrée actuelle du fichier zip, SUSv3 garantit que tous les autres fichiers seront retournés. Ce qui arrive au fichier journal n'est pas défini. il peut ou non être retourné par readdir() mais dans votre cas, il ne devrait pas être dangereux.

La raison pour laquelle j'ai exploré la question est de trouver un moyen efficace de fermer des descripteurs de fichiers dans un processus fils avant exec().

La façon suggérée dans APUE de Stevens est de faire ce qui suit:

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

mais je pense en utilisant un code similaire à ce qui se trouve dans l'OP pour scanner/dev/fd/répertoire pour savoir exactement ce qui J'ai besoin de fermer. (Remarque spéciale à moi-même, passez sur dirfd contenue dans la poignée DIR.)

Questions connexes