2009-11-04 62 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

報價:

如果一個文件是從rewinddir()去除或添加 目錄最近 調用後執行opendir()或 是否後續調用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 2009-11-04 21:05:51

+1

相同的手冊頁說:「目錄條目代表文件;文件可能會從目錄中刪除或添加到目錄異步的操作readdir()」 但也許最好避免這個!? – To1ne 2009-11-05 19:25:25

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); 

,但我使用類似於在OP發現掃描的/ dev/FD /目錄確切地知道代碼想着這我需要關閉。 (特別說明一下,跳過DIR處理中包含的dirfd。)