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

系统是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 

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

 La-critic\363-al-servicio-la-privacidad-300x160.jpg 

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

 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) 

我试着改变在这个手册页上find的代码,并修改代码来为每个文件调用unlink。 我从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) 

我还摸索了一下“触摸”,抓住了它所制作的系统调用并复制了它们,然后试图通过名称取消所得到的文件的链接。 这工作正常,但该文件夹仍然包含一个名称相同的名称,操作完成后,程序运行一个任意长的时间(strace输出结束了20GB 5分钟后,我停止了进程)。

我很困惑这一点,我真的不想让这个生产机器(数百名客户)离线,以fsck文件系统,但我倾向于这是唯一的select在这一点上。 如果任何人使用其他方法删除文件(通过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); 

我认为你正在做一个ACTIVE文件系统。 因此,当你正在执行查找操作时,文件被删除,然后才能被查找处理。 这将是好的。

我可能做什么来获取文件列表是不使用ls。 ls试图做一个sorting,并有一个目录,这将需要相当长的时间才能得到列表,然后进行sorting。

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

  find dirname -ls >outfile 

如果你想删除基于时间的东西:

  find dirname -type f -mtime +60 -print0 | xargs -0 rm -f 

顺便说一句,-0和-print0是Linux中的选项,因此具有“特殊”字符的文件名被正确地传递给xargs。 上面的过程当然会删除大于60天之前修改过的文件。

这里有一个简单的方法来确定文件系统是否需要修复,或者至less了解损坏的程度。

下载(免费) R1Soft / Idera Hot Copy快照实用程序 。 这是一个RPM和内核模块,它提供了Linux文件系统的写时复制快照,而无需使用LVM等。

假设您的文件系统如下所示:

 Filesystem Size Used Avail Use% Mounted on /dev/sda2 12G 4.4G 7.0G 39% / tmpfs 14G 0 14G 0% /dev/shm /dev/sda1 291M 166M 110M 61% /boot /dev/sda3 9.9G 2.5G 7.0G 26% /usr /dev/sdb1 400G 265G 135G 67% /home 

您可以使用热复制来快照/home而无需安装生成的文件系统…然后运行fsck以查看是否有任何问题。

 hcp --skip-mount /dev/sdb1 fsck -a /dev/hcp1 

这可以为您节省重新启动的时间,并帮助您在调度客户端停机之前评估严重性。

长期来说,我只是使用XFS作为文件系统…但这是另一个话题…

不要使用“ find … -exec rm -fv {};而是使用“ find … -delete