【问题标题】:Remove all files before application exits在应用程序退出之前删除所有文件
【发布时间】:2012-02-09 11:06:28
【问题描述】:

我正在编写一些作为工具后端的代码。该工具在固定目录中创建其所有输出。现在假设在任何时候客户想要杀死它的所有应用程序,那么所有文件都应该被删除。所以我使用系统命令(rm -rf)来删除目录,但是打开的文件不会被删除,因此目录也不会被删除。我怎样才能聪明地做到这一点?

一个选项似乎是使用一个表来维护所有打开的文件并在对目录触发rm -rf 之前将它们全部关闭。但是,这可能会减慢整个应用程序的速度。

我探索的另一个选项是使用lsof 查找打开文件的列表并在rm -rf 之前将它们全部关闭。

我的问题的另一个限制是我在一个进程中打开了几个不同的文件,其中一个正在被另一个进程使用。使用上述方法,如果我关闭所有文件描述符并尝试删除目录,从逻辑上讲它不应该被删除,因为还有其他进程打开的文件。

任何建议将不胜感激。

【问题讨论】:

  • @all 请帮我解决这个问题....
  • 谁能告诉我 open_max=sysconf(_SC_OPEN_MAX);通过使用这个,我得到的数字是当前进程或系统中所有进程的打开文件描述符数。
  • 还有一件事假设我在一个进程中打开了三个不同的文件,其中一个由另一个进程打开,如果我关闭所有 FD 并尝试删除目录,则使用上述方法,从逻辑上讲它不应该因为它仍然被另一个进程打开..请建议
  • 打开的文件可以像 linux 上的任何其他文件一样被删除。我认为您忽略了部分问题。文件是否需要超过工具的寿命,或者它们永远不应该超过工具?

标签: c linux


【解决方案1】:

为什么不将程序包装在脚本中?

例如

#!/bin/sh

mkdir <some directory>
/path/to/program <some directory to let the program know where to put stuff>
rm -fr <the same directory>

并运行这个而不是直接运行程序

【讨论】:

  • 这将如何解决仍然打开的文件的问题,我想在退出我的应用程序之前将它们全部关闭
  • 问题说您要删除所有这些文件。当程序终止时,所有文件都将关闭,控制权返回到脚本。然后脚本将它们删除。
【解决方案2】:

在 *nix 系统上,您可以使用掩码和signal 系统调用来捕获应用程序的终止信号。示例代码见this question

要列出打开的文件,您只需查看/proc/**PID**/fd。您将拥有与 lsof 相同的内容:

lr-x------ 1 user user 64 2012-02-09 08:40 0 -> /dev/null
l-wx------ 1 user user 64 2012-02-09 08:40 1 -> /home/user/.xsession-errors
lrwx------ 1 user user 64 2012-02-09 08:40 11 -> /etc/passwd
l-wx------ 1 user user 64 2012-02-09 08:40 2 -> /home/user/.xsession-errors
lrwx------ 1 user user 64 2012-02-09 08:40 3 -> socket:[15449]
lr-x------ 1 user user 64 2012-02-09 08:40 4 -> socket:[15450]
l-wx------ 1 user user 64 2012-02-09 08:40 5 -> pipe:[11740]
l-wx------ 1 user user 64 2012-02-09 08:40 6 -> socket:[15448]
lrwx------ 1 user user 64 2012-02-09 08:40 7 -> anon_inode:[eventfd]
lrwx------ 1 user user 64 2012-02-09 08:40 8 -> pipe:[11740]
lrwx------ 1 user user 64 2012-02-09 08:40 9 -> /dev/urandom

使用此列表,您将能够 grep 感兴趣的文件,并在信号处理程序中通过 fd 关闭它们,就在离开之前。

【讨论】:

    【解决方案3】:

    如果某些进程在目录中打开了文件并且该目录位于远程磁盘上,则删除整个目录应该只是一个问题。在这种情况下,删除打开的文件可能会导致它被重命名,以便远程系统可以维护其对该文件的引用。如果文件在本地磁盘上,则维护对已删除文件的引用没有问题。

    当打开文件的进程终止时,文件将被操作系统自动关闭。如果没有其他进程打开任何文件,则删除目录应该没有问题(假设没有其他问题,例如文件权限)。因此,您只需要确保打开文件的进程在目录被删除之前终止。

    【讨论】:

      【解决方案4】:

      来自“fcloseall”手册页:

      #define _GNU_SOURCE
      /* See feature_test_macros(7) *
      /#include <stdio.h>
      int fcloseall(void);
      

      假设您的应用程序使用“fopen”和朋友,这应该可以工作:)

      【讨论】:

        【解决方案5】:

        除了其他答案,如果您确定所有文件都是在已知的临时目录中创建的,并且程序正常终止(通过调用exit 或从main 返回),您可以使用@987654321 @注册一个清理函数,使用opendirreaddir收集所有文件名并删除它们,然后rmdir目录本身。

        我在我的 gcc/melt-runtime.c 文件中做类似的事情,函数 do_finalize_melt 在第 10390 行附近。

        您还可以向atexit 注册一个调用system("rm -rf /path/to/your/dir") 的函数,或者甚至可以运行一个脚本,该脚本将排队到batch 系统另一个执行rm -rf 的脚本或只是调用atexit(myexit_handler)

        void myexit_handler(void)
        {
           FILE* batchf = popen("/usr/bin/batch", "w");
           /* get some sleep to be sure our process had time to exit */
           fprintf (batchf, "/bin/sleep 5\n"); 
           fprintf (batchf, "/bin/rm -rf %s\n", yourtempdir);
           pclose (batchf);
        }
        

        我假设 yourtempdir 里面没有顽皮的字符(例如,没有空格、引号或反斜杠...)

        Linux 的语义是当程序退出时,已打开但已删除的文件将被删除。如果这些是 NFS 文件(但是在网络上放置一个临时目录是一个错误,恕我直言,因为您希望它更快!)那么确实有一些 .nfs* 文件保留在 NFS 服务器上(并且您需要一些方法来删除它们,也许是ssh)。

        您不应该尝试在应用程序退出之前删除您的目录,但在它退出之后,否则仍然打开的文件将不会被删除。

        【讨论】:

          【解决方案6】:

          我认为对您的实例使用脚本是一个好主意,Coren 的回答很准确。话虽如此,我已经看到程序只是循环通过大量文件描述符来关闭所有文件描述符。如果你有超过你循环的范围,它有可能出错,但是如果你打算关闭所有描述符,这样的事情不应该伤害应用程序,只要它们在这个限制内:

          for (int i = 0; i < 4096; i++) {
              close(i);
          }
          

          为了在您的应用程序退出之前完成此操作,您可以设置一个信号处理程序,正如 Coren 提到和链接的那样。确保您在信号处理程序中尽可能少地使用信号和处理程序,即只需设置一个标志并让您的程序进行清理。

          编辑:另外,StackOverflow 上另一篇文章中的this answer 提供了如何执行此操作的两个示例(#3 与 Coren 类似,适用于 Linux),但也有几个链接到处理这些东西的实际源代码。您可能想检查一下!

          【讨论】:

          • 我不想将我的代码包装在脚本中,我也在尝试使用您提到的相同方法,但问题是假设我在一个进程中打开了三个不同的文件,其中一个已打开由另一个进程,如果我关闭所有 FD 并尝试删除目录,则使用上述方法,从逻辑上讲它不应该因为它仍然被另一个进程打开,但它删除了......这就是问题
          • @prp 使用这些文件的所有应用程序都是您的吗?如果是这样,你为什么不在你的所有程序上使用这种方法呢?最后完成的应该最终会删除目录。
          【解决方案7】:

          tmpfile 函数可能对您有所帮助?这会创建一个在程序退出时自动删除的临时文件(我认为abort 可能会覆盖它)。

          如果这不起作用,请注意(至少在 Linux 上)可以在文件关闭之前将其删除。它们从目录列表中消失,但任何打开文件的程序仍然可以访问它。一旦所有程序关闭文件,它就永远消失了。在那之前,重新打开它们的唯一方法是查看/proc/&lt;pid&gt;/fd/&lt;num&gt;。这是 Flash 插件使用的一个技巧,可以让抓取视频流变得更加困难。

          【讨论】:

            【解决方案8】:

            使用getdtablesize,假设你不想关闭stdin、stdout、stderr:

            for(i=3;i<getdtablesize(); i++)
                 ckerr(close(i));
            

            其中 ckerr 是一个错误检查函数。请注意,这符合旧标准:

                    SVr4, 4.4BSD (the getdtablesize() function first appeared in 4.2BSD). 
                It is not specified in POSIX.1-2001; portable applications should employ
             sysconf(_SC_OPEN_MAX) instead of this call.
            

            所以这纯粹是穷人的选择......但它还没有被弃用。

            考虑调用 nftw() 或 ftw() 来清理您的工作主管,您可以在回调函数中执行 remove()。

            【讨论】:

              猜你喜欢
              • 2021-12-30
              • 2021-05-08
              • 1970-01-01
              • 2011-01-12
              • 2011-02-01
              • 2021-02-21
              • 1970-01-01
              • 1970-01-01
              • 2018-05-14
              相关资源
              最近更新 更多