使用readdir()读取目录时删除文件

时间:2009-11-04 20:51:57

标签: c

我的代码是这样的:

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文件?

3 个答案:

答案 0 :(得分:6)

引自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 :(得分:1)

我正在测试我的新Linux参考书。 Michael Kerrisk的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 /目录以确切地知道我需要关闭哪些fds。 (特别注意自己,跳过DIR手柄中的dirfd。)

答案 2 :(得分:0)

我发现以下页面描述了这个问题的解决方案。

https://support.apple.com/kb/TA21420