无法列出内容/删除目录 (linux ext3)

Red*_*ieg 5 linux filesystems ext3 remove

系统为CentOS5 x86_64,完全最新。

我有一个无法列出的文件夹(ls 只是挂起,占用内存直到它被杀死)。目录大小接近500k:

root@server [/home/user/public_html/domain.com/wp-content/uploads/2010/03]# stat .
  File: `.'
  Size: 458752          Blocks: 904        IO Block: 4096   directory
Device: 812h/2066d      Inode: 44499071    Links: 2
Access: (0755/drwxr-xr-x)  Uid: ( 3292/ user)   Gid: ( 3287/ user)
Access: 2012-06-29 17:31:47.000000000 -0400
Modify: 2012-10-23 14:41:58.000000000 -0400
Change: 2012-10-23 14:41:58.000000000 -0400
Run Code Online (Sandbox Code Playgroud)

如果我使用ls -1f,我可以看到文件名,但它只是无限重复相同的 48 个文件,所有这些文件在文件名的某处都有非 ascii 字符:

La-critic\363-al-servicio-la-privacidad-300x160.jpg
Run Code Online (Sandbox Code Playgroud)

当我尝试访问文件(比如复制或删除它们)时,我收到如下消息:

lstat("/home/user/public_html/domain.com/wp-content/uploads/2010/03/Sebast\355an-Pi\361era-el-balc\363n-150x120.jpg", 0x7fff364c52c0) = -1 ENOENT (No such file or directory)
Run Code Online (Sandbox Code Playgroud)

我尝试更改此手册页上的代码并修改代码以调用每个文件的 unlink。我从取消链接调用中得到相同的 ENOENT 错误:

unlink("/home/user/public_html/domain.com/wp-content/uploads/2010/03/Marca-naci\363n-Madrid-150x120.jpg") = -1 ENOENT (No such file or directory)
Run Code Online (Sandbox Code Playgroud)

我还跟踪了一个“触摸”,抓取它生成的系统调用并复制它们,然后尝试按名称取消链接生成的文件。这工作正常,但是在操作完成并且程序运行任意长的时间后,该文件夹仍然包含同名条目(strace 输出在 5 分钟后最终为 20GB,我停止了该过程)。

我被这个难住了,我真的不想让这台生产机器(数百个客户)离线来 fsck 文件系统,但我倾向于这是目前唯一的选择。如果有人成功使用其他方法删除文件(通过 inode 编号,我可以使用 getdents 代码获取那些文件),我很想听听他们的意见。

(是的,我已经尝试过了find . -inum <inode> -exec rm -fv {} \;,它仍然存在取消链接返回 ENOENT 的问题)

对于那些感兴趣的人,这是该手册页的代码和我的代码之间的差异。我没有费心对 malloc 等进行错误检查,因为我很懒,这是一次性的:

root@server [~]# diff -u listdir-orig.c listdir.c 
--- listdir-orig.c      2012-10-23 15:10:02.000000000 -0400
+++ listdir.c   2012-10-23 14:59:47.000000000 -0400
@@ -6,6 +6,7 @@
 #include <stdlib.h>
 #include <sys/stat.h>
 #include <sys/syscall.h>
+#include <string.h>

 #define handle_error(msg) \
        do { perror(msg); exit(EXIT_FAILURE); } while (0)
@@ -17,7 +18,7 @@
    char           d_name[];
 };

-#define BUF_SIZE 1024
+#define BUF_SIZE 1024*1024*5

 int main(int argc, char *argv[])
 {
@@ -26,11 +27,16 @@
    struct linux_dirent *d;
    int bpos;
    char d_type;
+   int deleted;
+   int file_descriptor;

    fd = open(argc > 1 ? argv[1] : ".", O_RDONLY | O_DIRECTORY);
    if (fd == -1)
        handle_error("open");

+   char* full_path;
+   char* fd_path;
+
    for ( ; ; ) {
        nread = syscall(SYS_getdents, fd, buf, BUF_SIZE);
        if (nread == -1)
@@ -55,7 +61,24 @@
           printf("%4d %10lld  %s\n", d->d_reclen,
                   (long long) d->d_off, (char *) d->d_name);
           bpos += d->d_reclen;
+          if ( d_type == DT_REG )
+          {
+              full_path = malloc(strlen((char *) d->d_name) + strlen(argv[1]) + 2); //One for the /, one for the \0
+              strcpy(full_path, argv[1]);
+              strcat(full_path, (char *) d->d_name);
+
+              //We're going to try to "touch" the file.
+              //file_descriptor = open(full_path, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, 0666);
+              //fd_path = malloc(32); //Lazy, only really needs 16
+              //sprintf(fd_path, "/proc/self/fd/%d", file_descriptor);
+              //utimes(fd_path, NULL);
+              //close(file_descriptor);
+              deleted = unlink(full_path);
+               if ( deleted == -1 ) printf("Error unlinking file\n");
+              break; //Break on first try
+          }
        }
+       break; //Break on first try
    }

    exit(EXIT_SUCCESS);
Run Code Online (Sandbox Code Playgroud)

mdp*_*dpc 1

我假设您是在活动文件系统上执行此操作。因此,当您进行查找等操作时,文件可能在查找处理之前被删除。这样就可以了。

我可能会做的不是使用 ls 来获取文件列表。ls 尝试进行排序,对于这样大小的目录,仅获取列表然后对其进行排序就需要很长时间。

在这种情况下我会做的是(作为 root 用户):

 find dirname -ls >outfile
Run Code Online (Sandbox Code Playgroud)

如果你想根据时间删除某些内容:

 find dirname -type f -mtime +60 -print0 | xargs -0 rm -f
Run Code Online (Sandbox Code Playgroud)

顺便说一句,-0 和 -print0 是 Linux 中的选项,以便将具有“特殊”字符的文件名正确传递给 xargs。当然,上述内容会删除 60 天前修改过的文件。

  • 当然,您可能是对的,文件系统需要修复,在这种情况下,最好对文件系统进行完整的 fsck。 (2认同)