maneira rápida de encontrar grandes extensões de zeros em arquivos

4

Eu recentemente recuperei parcialmente um disco defeituoso de 2,5 TB. ddrescue criou uma imagem, que eu posso montar no modo de loopback, 2.1TB são recuperados, 450GB estão faltando, infelizmente espalhados por todo o disco.

Para ver quais arquivos são afetados, eu posso usar filefrag -v e ver o arquivo de mapa gerado por ddrescue .

MAS isso demoraria séculos. Descobri que, como são apenas arquivos de vídeo que estou recuperando, grandes extensões de zeros não são esperadas, mas estão presentes, onde ddrescue não leu dados do disco.

Então eu precisaria de um comando para escanear um arquivo se houvesse um grande patch (arbitrário) de todos os zeros no arquivo. Na realidade, esses seriam sempre um múltiplo de 512 bytes e sempre começariam em um endereço de 512 bytes. Existe um comando que pode varrer um arquivo para uma seqüência de bytes binários (por exemplo, 512 × '\ 0')?

    
por Ro-ee 19.08.2017 / 18:03

5 respostas

4

Modifiquei a resposta do xenoid para procurar especificamente por bytes nulos, com base em < a href="https://superuser.com/a/612336/764326"> a resposta desta outra pergunta sobre como grep para bytes nulos:

grep -Pal '\x00{512}' the_files
    
por 23.08.2017 / 23:12
2

Fazer grep parecer explicitamente para caracteres nulos me escapa. No entanto, fazer com que ele procure por 512 caracteres idênticos consecutivos (que são quase tão improváveis) é um pouco mais simples:

grep -Eal '(.){511}' the_files

lista os arquivos onde uma sequência de 512 caracteres idênticos foi encontrada. O parâmetro -a é necessário para fazer com que ele corresponda a caracteres nulos (caso contrário, eles são considerados caracteres de fim de linha e ignorados).

    
por 19.08.2017 / 22:09
2

a resposta do xenoid provavelmente encontrará arquivos afetados para você rapidamente. Para confirmar e analisar mais, você pode executar:

<"file" tr '
<"file" tr '%pre%0-7' 'oL' | fold -w 512 | grep -vn 'L' | cut -f 1 -d ':'
0-7' 'oL' | fold -w 512 | grep -vn 'L' | cut -f 1 -d ':'

Funciona da seguinte forma:

  1. "file" é aberto e transmitido para o primeiro comando.
  2. tr converte cada caractere nulo para o , cada caractere não nulo para L .
  3. fold insere uma nova linha a cada 512 caracteres. Neste momento, o fluxo pode ser tratado como texto puro.
  4. grep usa linhas que não contêm L e as imprime com seus números.
  5. cut isola esses números (expurgos ooo… ).

Dessa forma, você obtém números ordinais de blocos de 512 bytes preenchidos com zeros. A numeração começa com 1 . Passe a saída para wc -l para ver quantos fragmentos são afetados em um determinado arquivo.

    
por 19.08.2017 / 23:20
1

Eu fiquei intrigado com isso, já que é algo que eu sempre quis, e eu pesquisei um pouco, encontrando este Python 3 programa .

Eu executei o comando wget na parte inferior da página e ele funciona perfeitamente (embora você possa precisar de um sudo , dependendo de suas permissões). Como grep , ele possui muitas opções poderosas, incluindo pesquisas de Expressões Regulares: os exemplos no cabeçalho mostram alguns deles; bgrep --help fornece a lista completa.

Para seu uso, você precisará de uma string de execução com 512 zeros duplos: não os digite, use algo como:

bgrep -l $(for f in {0..511}; do echo -n 00; done) files...

Você pode querer usar a opção -r para percorrer uma árvore completa de diretórios.

Eu adicionei esta resposta, não porque os outros são inadequados (eu particularmente gostei da engenhosidade da sequência de comando de Kamil Maciorowski), mas porque pode ser de valor para outros (como eu) com problemas relacionados que se deparam com essa questão .

    
por 20.08.2017 / 03:01
1

Diferente abordagem, portanto, outra resposta minha.

Você pode usar o ddrescue para procurar zeros. Use --generate-mode .

When ddrescue is invoked with the --generate-mode option it operates in "generate mode", which is different from the default "rescue mode". That is, if you use the --generate-mode option, ddrescue does not rescue anything. It only tries to generate a mapfile for later use.

[…]

ddrescue can in some cases generate an approximate mapfile, from infile and the (partial) copy in outfile, that is almost as good as an exact mapfile. It makes this by simply assuming that sectors containing all zeros were not rescued.

[…]

ddrescue --generate-mode infile outfile mapfile

( fonte )

Vamos fingir que seu arquivo é outfile da execução anterior de ddrescue . Não podemos usá-lo como infile (porque ddrescue se recusa a trabalhar quando infile e outfile são o mesmo arquivo), precisamos de um falso, /dev/zero serve. Para encontrar todos os zero, você precisa de -b 1 . Este é o comando ( mapfile não deve existir):

ddrescue -b 1 --generate-mode /dev/zero file mapfile

Toda entrada com ? na lista de blocos de dados dentro de mapfile significa um bloco de zeros (com -b 1 um zero também é um bloco). Consulte estrutura do arquivo de mapas para ddrescue . Você pode então recuperar informações do mapfile .

Por exemplo, o seguinte comando lhe dará o comprimento (hexadecimal, em bytes por causa de -b 1 ) do maior bloco de zeros (saída vazia significa que não houve nenhum):

grep '0x.*0x.*[?]' mapfile | awk -F ' ' '{print $2}' | sort -ru | head -n 1

Para acelerar as coisas, você pode querer usar tamanho de bloco maior ( -b ), mas blocos de zeros que começam dentro de um bloco e terminam dentro do próximo podem passar despercebidos mesmo que sejam ligeiramente maiores que o tamanho de bloco escolhido ; seu deslocamento se torna importante.

Para não perder nenhum trecho de zeros de comprimento N bytes ou mais, você precisa de um tamanho de bloco de no máximo M=$(((N+1)/2)) bytes (por exemplo, no máximo 5 para N=10 , 6 para N=11 ). O comando

ddrescue -b "$M" --generate-mode /dev/zero file mapfile

gerará um arquivo de mapeamento onde cada linha com ? na lista de blocos de dados significa pelo menos M zeros (no deslocamento à direita), mas cada trecho de N zeros (independentemente de seu deslocamento) gerará tal linha com certeza. Como dois blocos de M são pelo menos N , o seguinte raciocínio se aplica:

Colocar linhas com ? da lista de blocos de dados,

  • se o comprimento (segunda coluna no mapfile , lembre-se de que a unidade é M ) for 0x2 ou maior, você terá N ou mais zeros nessa posição;
  • se o tamanho for 0x1 , você deverá investigar mais se houver pelo menos N zeros ao redor dessa posição;
  • se não houver essa linha, não haverá trecho de N zeros no arquivo com certeza.

In reality, these would be always a multiple of 512 bytes, and always begin at a 512 byte address

Neste caso

ddrescue -b 512 --generate-mode /dev/zero file mapfile

irá encontrar e mapear todos eles.

    
por 30.10.2018 / 08:58