Não é possível listar o conteúdo / remover o diretório (linux ext3)

5

O sistema é o CentOS5 x86_64, completamente atualizado.

Eu tenho uma pasta que não pode ser listada (apenas pendura, comendo memória até ser morta). O tamanho do diretório é quase 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

Eu posso ver os nomes dos arquivos se eu usar ls -1f , mas ele repete os mesmos 48 arquivos ad infinitum, todos com caracteres não ascii em algum lugar no nome do arquivo:

La-critic3-al-servicio-la-privacidad-300x160.jpg

Quando tento acessar os arquivos (digamos, para copiá-los ou removê-los), recebo mensagens como as seguintes:

lstat("/home/user/public_html/domain.com/wp-content/uploads/2010/03/Sebast5an-Pi1era-el-balc3n-150x120.jpg", 0x7fff364c52c0) = -1 ENOENT (No such file or directory)

Eu tentei alterar o código encontrado em esta página man e modifiquei o código para chamar o unlink para cada arquivo. Eu recebo o mesmo erro ENOENT da chamada de desconexão:

unlink("/home/user/public_html/domain.com/wp-content/uploads/2010/03/Marca-naci3n-Madrid-150x120.jpg") = -1 ENOENT (No such file or directory)

Eu também criei um "toque", peguei o syscalls que ele fez e os repliquei, depois tentei desvincular o arquivo resultante pelo nome. Isso funciona bem, mas a pasta ainda contém uma entrada com o mesmo nome depois que a operação é concluída e o programa é executado por um tempo arbitrariamente longo (a saída strace acabou em 20 GB após 5 minutos e eu parei o processo).

Eu estou perplexo com este, eu realmente prefiro não ter que deixar esta máquina de produção (centenas de clientes) offline para fsck o sistema de arquivos, mas eu estou inclinado a ser a única opção neste momento. Se alguém tiver tido sucesso usando outros métodos para remover arquivos (por número de inode, posso obtê-los com o código getdents) Eu adoraria ouvi-los.

(Sim, eu tentei find . -inum <inode> -exec rm -fv {} \; e ainda tem o problema com unlink retornando ENOENT)

Para os interessados, aqui está a diferença entre o código dessa página e o meu. Eu não me incomodei com a verificação de erros em mallocs, etc, porque eu sou preguiçoso e isso é um caso único:

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 
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
+ 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);
    
por RedKrieg 23.10.2012 / 21:12

3 respostas

1

Eu presumo que você esteja fazendo isso em um sistema de arquivos ACTIVE. Assim, é possível que, enquanto você estiver fazendo a descoberta e tal, o arquivo tenha sido excluído antes que possa ser processado por find. Isso seria ok.

O que devo fazer para obter uma lista de arquivos NÃO é usar ls. O ls tenta fazer uma ordenação e, com um diretório desse tamanho, levaria muito tempo para obter a lista e depois ordená-la.

O que eu faço nesses casos é (como usuário root):

 find dirname -ls >outfile

Se você quiser excluir algo com base nos horários:

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

BTW, o -0 e -print0 são opções no Linux para que nomes de arquivos com caracteres "especiais" sejam passados corretamente para xargs. O acima, é claro, remove arquivos que foram modificados MAIOR DE 60 dias antes.

    
por 23.10.2012 / 21:57
1

Aqui está uma maneira fácil de determinar se o sistema de arquivos precisa de reparo, ou pelo menos entender quão extenso o dano é ...

Faça o download do (gratuito) utilitário de instantâneo R1Soft / Idera Hot Copy . Este é um módulo RPM e kernel que fornece snapshots de copy-on-write de sistemas de arquivos Linux sem a necessidade de ter LVM, etc. no lugar.

Digamos que seus sistemas de arquivos sejam semelhantes:

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

Você pode usar o Hot Copy para o instantâneo /home sem montar o sistema de arquivos resultante ... Em seguida, execute um fsck para ver se há algum problema.

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

Isso pode economizar o tempo de reinicialização e ajudar você a avaliar a gravidade antes de agendar o tempo de inatividade do cliente.

A longo prazo, eu acabei de usar o XFS como o sistema de arquivos ... Mas isso é outro tópico ...

    
por 23.10.2012 / 22:22
0

Não use " find ... -exec rm -fv {} \; " use " encontre ... -delete " em vez

    
por 05.12.2012 / 22:12