【问题标题】:Recursive file delete in C on LinuxLinux上C中的递归文件删除
【发布时间】:2011-04-19 12:21:11
【问题描述】:

我有一个 C 程序,在程序中的某一时刻有这个:

system("rm -rf foo");

其中 foo 是一个目录。我决定,与其调用系统,不如直接在代码中进行递归删除。我假设一段代码很容易找到。傻我。无论如何,我最终写了这个:

#include <stdio.h>
#include <sys/stat.h>
#include <dirent.h>
#include <libgen.h>

int recursiveDelete(char* dirname) {

  DIR *dp;
  struct dirent *ep;

  char abs_filename[FILENAME_MAX];

  dp = opendir (dirname);
  if (dp != NULL)
    {
      while (ep = readdir (dp)) {
        struct stat stFileInfo;

        snprintf(abs_filename, FILENAME_MAX, "%s/%s", dirname, ep->d_name);

        if (lstat(abs_filename, &stFileInfo) < 0)
          perror ( abs_filename );

        if(S_ISDIR(stFileInfo.st_mode)) {
          if(strcmp(ep->d_name, ".") && 
             strcmp(ep->d_name, "..")) {
            printf("%s directory\n",abs_filename);
            recursiveDelete(abs_filename);
          }
        } else {
          printf("%s file\n",abs_filename);
                  remove(abs_filename);
        }
          }
      (void) closedir (dp);
        }
  else
    perror ("Couldn't open the directory");


  remove(dirname);
  return 0;

}

这似乎可行,但我太害怕在生产中实际使用它。我确定我做错了什么。有谁知道一个 C 库来执行我错过的递归删除,或者有人能指出我犯的任何错误吗?

谢谢。

【问题讨论】:

  • 实际上,当您将某些内容传递给 shell 时,它会进入操作系统并以机器代码运行。 Unix 内核经过了极大的优化,因此即使您完全按照 Unix 内核中的编码方式对其进行编码,您也可能只会看到 5-10% 的性能提升。传递给 shell 太简单方便了。
  • 有趣:remove() 的 POSIX 规范在非目录(文件、符号链接等)上表示 unlink(),在目录上表示 rmdir()。您应该检查 remove() 是否有效 - 如果没有,请报告。您应该看看如果函数的参数不是目录会发生什么 - 它抱怨它无法打开目录(但没有说哪个;这也很糟糕),然后无论如何都将其删除(或尝试)。

标签: c unix


【解决方案1】:

POSIX 有一个名为ftw(3)(文件树遍历)的函数

遍历位于目录 dirpath 下的目录树,并为树中的每个条目调用一次 fn()。

【讨论】:

  • 是的。 POSIX 来救援。它可能更安全、更快速,并且可以捕捉到在手动遍历的正常操作期间不会总是遇到的小错误。
  • 还有新的 FTW 功能 - nftw,界面略有不同。
  • nftw 是您所追求的 - 请参阅 this answer to the same question
【解决方案2】:

对被吓死的人表示敬意,在这种情况下,这是一种健康的态度。

我没有图书馆可以建议,在这种情况下你有两个选择:

1) 彻底“运行”这段代码
a) 不在机器上;在纸上,用铅笔。获取一个现有的目录树,列出所有元素并通过每个步骤运行程序,验证它是否工作
b) 编译代码,但将所有删除调用替换为执行 printf 的行 - 验证它是否执行了应执行的操作
c) 重新插入删除调用并运行

2) 使用你原来的方法(调用 system())

【讨论】:

    【解决方案3】:

    我建议您采取一项额外的预防措施。

    几乎总是在您删除多个文件和/或目录时,最好先将 chroot() 放入该目录,然后再执行任何可能破坏此目录之外的数据的操作。

    【讨论】:

      【解决方案4】:

      我认为你需要在 recursiveDelete() 之前调用 closedir() (因为你不希望/不需要在进入它们时打开所有目录。在调用 remove() 之前还关闭了 closedir() 因为 remove() 会可能会在打开的目录上出现错误。您应该仔细检查一遍以确保 readdir() 不会拾取“..”。还要警惕链接目录,您可能不想递归到那些是 符号或硬链接。

      【讨论】:

        猜你喜欢
        • 2011-01-02
        • 1970-01-01
        • 1970-01-01
        • 2020-11-22
        • 2012-10-18
        • 2011-12-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多