stat e ls mostram tamanho de arquivo incorreto (terabytes errados)

5

Ok, eu tenho um monte de arquivos vCard, todos com cerca de 200 a 300 bytes em tamanho.

Ao tentar arquivá-los, fiquei imaginando por que demorou tanto e descobri que há um arquivo com tamanho errado. Ambos ls e stat estão mostrando um tamanho de aproximadamente 8.1 Terabytes. Isso é incrível porque meu SSD tem apenas 250 gigabytes de tamanho.

Existem outros arquivos com tamanhos errados também, mas esse é claramente o maior deles. Eu já dei um fsck, mas parece não haver erros no sistema de arquivos (ext4). Como posso me livrar desse tamanho errado?

Obrigado Wolle

    
por WolleTD 30.06.2013 / 22:49

2 respostas

1

vCard parece ser um formato de arquivo de texto. Isso é bom porque os arquivos de texto não devem conter nulos. Isso ajudará se o sistema operacional achar erroneamente que o arquivo é um arquivo esparso contendo sequências muito longas de nulos.

Você pode usar ls -lks bigfile para ver se o espaço ocupado é diferente do espaço aparente.

Você pode usar dd para extrair partes de dados (por exemplo, os primeiros 500 bytes somente) em um novo arquivo. Você pode então usar hexdump para ver se há texto recuperável naquele pedaço.

Se você achar que o arquivo está cheio de sequências longas de nulos, você pode tentar usar um script para ler o arquivo e gravar somente os dados não nulos em um novo arquivo. Dessa forma, você pode, em algum esforço, construir um arquivo vCard válido do tamanho normal.

como alternativa, use strings bigfile para extrair texto do arquivo enorme

Muitas dessas operações levarão muito tempo em um arquivo ig. Você pode querer praticar algo menor ...

Aqui está um arquivo vCard

$ cat gump.vcard
BEGIN:VCARD
VERSION:2.1
N:Gump;Forrest
FN:Forrest Gump
...
EMAIL;PREF;INTERNET:[email protected]
REV:20080424T195243Z
END:VCARD

$ file gump.vcard
gump.vcard: vCard visiting card

vamos criar uma versão esparsa corrompida

$ dd of=sparse-file bs=1k seek=5120 count=0
0+0 records in
0+0 records out
0 bytes (0 B) copied, 0 s, Infinity B/s

$ cat gump.vcard sparse-file > sparse-gump.vcard

$ cp --sparse=always sparse-gump.vcard really-sparse-gump.vcard

$ ls -lks *sparse*
   0 -rw-r--r-- 1 rgb rgb 5120 Jul 11 18:09 sparse-file
5136 -rw-r--r-- 1 rgb rgb 5121 Jul 11 18:10 sparse-gump.vcard
   4 -rw-r--r-- 1 rgb rgb 5121 Jul 11 18:18 really-sparse-gump.vcard

Observe que o tamanho no disco do último arquivo é de 4 blocos, mas contém 5121 blocos de dados.

Vamos ver o que está lá

$ hexdump really-sparse-gump.vcard | head -n 3
0000000 4542 4947 3a4e 4356 5241 0a44 4556 5352
0000010 4f49 3a4e 2e32 0a31 3a4e 7547 706d 463b
0000020 726f 6572 7473 460a 3a4e 6f46 7272 7365

$ hexdump really-sparse-gump.vcard | tail
0000230 4120 656d 6972 6163 450a 414d 4c49 503b
0000240 4552 3b46 4e49 4554 4e52 5445 663a 726f
0000250 6572 7473 7567 706d 6540 6178 706d 656c
0000260 632e 6d6f 520a 5645 323a 3030 3038 3234
0000270 5434 3931 3235 3334 0a5a 4e45 3a44 4356
0000280 5241 0a44 0000 0000 0000 0000 0000 0000
0000290 0000 0000 0000 0000 0000 0000 0000 0000
*
0500280 0000 0000
0500284

Observe a linha * entre os desvios 290 e 0500280 - é onde vivem todos os nulos imaginários.

$ strings really-sparse-gump.vcard > new-gump.vcard

$ ls -lks new-gump.vcard
4 -rw-r--r-- 1 rgb rgb 1 Jul 11 18:30 new-gump.vcard

$ cat new-gump.vcard
BEGIN:VCARD
VERSION:2.1
N:Gump;Forrest
FN:Forrest Gump
...
EMAIL;PREF;INTERNET:[email protected]
REV:20080424T195243Z
END:VCARD

Recuperamos nosso vCard de tamanho normal do arquivo enorme. Sua milhagem pode variar.

    
por 12.07.2013 / 00:07
0

No linux (desde 3.1), você pode usar lseek() com SEEK_DATA e / ou SEEK_HOLE para identificar posições de dados e falhas em um arquivo esparso. Ao repetir a chamada com um deslocamento crescente, você pode ler os bytes identificados como dados e gravá-los em outro arquivo. Talvez algo como isto (verificação de erros e outro tédio omitido pela simplicidade):

int fd0 = open(file, O_RDONLY, S_IRWXU);
int fd1 = open(newfile, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU);
off_t eof = lseek(fd0, 0, SEEK_END);
off_t cur = 0;
char buf[8192];
while (cur < eof) {
  off_t d = lseek(fd0, cur, SEEK_DATA);
  off_t h = lseek(fd0, d, SEEK_HOLE);
  lseek(fd0, d, SEEK_SET);
  size_t dlen = min(h - d, 8192);
  ssize_t rlen = read(fd0, buf, dlen);
  ssize_t r = write(fd1, buf, rlen);
  cur = d + rlen;
}
close(fd0);
close(fd1);
    
por 24.01.2014 / 17:08

Tags