2009-11-04 3 views
5

Мой код-то вроде этого:Удаление файлов во время чтения каталога с 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); 

(этот код не тестировался и чисто пример)

Дело в том: Является ли это разрешено удалять файл в каталоге при циклическом переходе через каталог с помощью readdir()? Или будет readdir() все еще найти удаленный файл .log?

ответ

5

Цитата POSIX readdir:

Если файл удаляется из добавлен или директории после последнего вызова opendir() или rewinddir(), ли последующий вызов READDIR() возвращает запись для этого файла: не указано.

Итак, моя догадка ... это зависит.

Это зависит от операционной системы, от времени суток, на относительном порядке файлов, добавленных/удален, ...

И, как еще один момент, между временем readdir() функция возвращает и вы попробуйте unlink() файл, какой-то другой процесс мог удалить этот файл, а ваш unlink() терпит неудачу.


Редактировать

я тестировал с этой программой:

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

На моем компьютере readdir() находит удалённые файлы и не находит файлы, созданные между opendir() и readdir(). Но это может быть другим на другом компьютере; на моем компьютере может быть другим, если я компилирую с различными параметрами; это может быть другим, если я обновляю ядро; ...

+1

LOL @ 'man 2 readdir':« Это не функция, которая вас интересует ». – pmg

+1

На той же странице руководства говорится: «Записи каталога представляют файлы, файлы могут быть удалены из каталога или добавлены в каталог асинхронно к операции readdir()« Но, может быть, лучше избегать этого !? – To1ne

1

Я проверяю мой новый Linux справочник. Интерфейс программирования Linux по Майкл Керриск и говорит следующее:

SUSv3 явно отмечает, что не определено ли READDIR() возвращает имя файла, который был добавлен или удален с тех пор последнего момента последнего вызова opendir() или rewinddir(). Все имена файлов, которые не были добавлены или удалены со времени последнего такого звонка, являются гарантировано для возврата.

Я думаю, что то, что неуточнено, происходит с тем, что еще не проверено. Как только запись будет возвращена, на 100% гарантируется, что она больше не будет возвращена, независимо от того, отмените ли вы текущий дирент.

Также обратите внимание на гарантию, предусмотренную вторым предложением.Поскольку вы оставляете в покое другие файлы и только отменяете текущую запись для zip-файла, SUSv3 гарантирует, что все остальные файлы будут возвращены. Что происходит с файлом журнала, не определено. он может быть или не быть возвращен readdir(), но в вашем случае это не должно быть вредным.

Причина, по которой я исследовал вопрос, заключается в том, чтобы найти эффективный способ закрыть дескрипторы файлов в дочернем процессе до exec().

Предложенный способ APUE от Стивенс сделать следующее:

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

, но я имею в виду, используя код, подобный тому, что находится в ОП для сканирования/Dev/FD/каталог, чтобы точно знать, какие Мне нужно закрыть. (Особое примечание для меня, пропустите dirfd, содержащиеся в дескрипторе DIR.)

Смежные вопросы