Existe uma ferramenta como diff -r que compara uma árvore de diretórios com um arquivo de manifesto usando hashes?

Existe uma ferramenta como diff -r que compara uma árvore de diretórios com um arquivo de manifesto usando hashes?

Aqui está minha situação. Eu tenho dois volumes de arquivo de armazenamento frio que (deveriam) conter conjuntos idênticos de dados. Esses volumes contêm backups acessados ​​com pouca frequência. Estou preocupado que, eventualmente, o bitrot chegue a um ou ambos e corrompa sutilmente os dados contidos neles. Eu sei que posso encontrar diff -ros dois volumes e encontrar arquivos que foram alterados ou desapareceram entre os dois, mas não recebo nenhuma indicação útil sobre qual volume possui a cópia "boa". Estes são discos USB, e convertê-los para algo como ZFS parece... oneroso.

O que eu gostaria é de uma ferramenta que percorra recursivamente a árvore de diretórios e escreva um arquivo de manifesto contendo o caminho e o nome do arquivo junto com um hash do conteúdo do arquivo. Eu executaria essa ferramenta imediatamente após gravar os dados em cada volume e armazenaria o arquivo de manifesto resultante em armazenamento quente, talvez sob algum tipo de controle de revisão.

A partir deste arquivo, eu gostaria de poder executar algo que funcionasse exatamente como diff -r- ele me diria se os arquivos foram adicionados, removidos ou se seu conteúdo foi alterado. Somente em vez de comparar um volume com o outro, ele compararia um volume com o arquivo de manifesto em bom estado. Usando esse método, devo saber se os dados que estou lendo no disco meses/anos no futuro são idênticos aos dados que coloquei originalmente nele.

Eu teria que pensar que algo assim já existe. Posso obter algo parecido com um arquivo de manifesto usando:

find /mnt/my-volume -type f -exec md5sum {} + > manifest.txt

mas até agora não descobri uma boa maneira de analisar esse arquivo e verificar cada hash recursivamente. Além disso, um pouco menos importante, isso não me dirá se um diretório vazio apareceu ou desapareceu. (Não consigo imaginar por que isso importaria, mas seria bom saber que isso ocorreu.)

Estou no caminho certo com isso ou existe uma ferramenta mais apropriada que possa fazer esse tipo de coisa?

Responder1

Você está certo, essa ferramenta já existe. Embora eu veja que sua postagem está marcada como 'linux', talvez uma solução orientada a BSD seja edificante.

Utilitário mtree(8) do FreeBSDpode fazer exatamente o que você está pedindo.

Suponha:

$ find .
.
./c
./c/file3
./b
./b/file2
./a
./a/file1

Para criar um manifesto dessa hierarquia de arquivos, incluindo um hash sha256 de cada arquivo, seria necessário:

$ mtree -c -K sha256 > /tmp/manifest.txt
$ cat /tmp/manifest.txt
#          user: diego
#       machine: myhost.example.com
#          tree: /data/home/diego/foo
#          date: Wed Mar 28 10:31:17 2018

# .
/set type=file uid=1001 gid=1001 mode=0710 nlink=1 flags=uarch
.               type=dir nlink=5 time=1522257963.738221000

# ./a
/set type=file uid=1001 gid=1001 mode=0600 nlink=1 flags=uarch
a               type=dir mode=0710 nlink=2 time=1522257932.680802000
    file1       size=29 time=1522257932.682389000 \
                sha256digest=6b4114c4f12e63c0ca44073de5ca0a2b39fedaceaa533af3dfdc89f00039c973
# ./a
..


# ./b
b               type=dir mode=0710 nlink=2 time=1522257937.929131000
    file2       size=29 time=1522257937.930666000 \
                sha256digest=9f7a0a49475bb6f98e609a4e057f0bc702c5e4706be5bd656a676fd8d15da7ef
# ./b
..


# ./c
c               type=dir mode=0710 nlink=2 time=1522257942.064315000
    file3       size=29 time=1522257942.065882000 \
                sha256digest=bd617f47217ef0605d3aff036778d10bf18cb2f415c45e8e362e2c091df19491
# ./c
..

Pode-se então verificar a hierarquia do arquivo em relação ao manifesto canalizando o manifesto para o mtree:

$ mtree < /tmp/manifest.txt || echo fail

Arquivos adicionados, excluídos, renomeados ou modificados causarão falha na verificação:

$ touch foo
$ mtree < /tmp/manifest.txt || echo fail
.:      modification time (Wed Mar 28 10:34:56 2018, Wed Mar 28 10:37:01 2018)
extra: foo
fail
$ rm foo; touch b/file2; mtree < /tmp/manifest.txt || echo fail
.:      modification time (Wed Mar 28 10:34:56 2018, Wed Mar 28 10:39:39 2018)
b/file2: 
        modification time (Wed Mar 28 10:25:37 2018, Wed Mar 28 10:39:39 2018)
fail
$ mv c/file3 c/FILE3; rm a/file1; date >> b/file2; mtree < /tmp/manifest.txt || echo fail
.:      modification time (Wed Mar 28 10:34:56 2018, Wed Mar 28 10:39:39 2018)
c:      modification time (Wed Mar 28 10:25:42 2018, Wed Mar 28 10:41:59 2018)
extra: c/FILE3
b/file2:
        size (29, 58)
        modification time (Wed Mar 28 10:25:37 2018, Wed Mar 28 10:47:31 2018)
        sha256digest (0x9f7a0a49475bb6f98e609a4e057f0bc702c5e4706be5bd656a676fd8d15da7ef, 0x569c17bd1a1ca2447fd8167f103531bf3a7b7b4268f0f68b18506e586e7eea94)
a:      modification time (Wed Mar 28 10:25:32 2018, Wed Mar 28 10:41:59 2018)
./a/file1 missing
./c/file3 missing
fail

Responder2

Eles md5sum -c manifest.txthonrariam os caminhos armazenados em manifest.txt. O findprograma substitui {}o caminho completo do arquivo encontrado incluindo qualquer local de pesquisa especificado na findlinha de comando, ou seja, para o arquivo ./a/b/c/d/eele substituirá o mesmo ./a/b/c/d/epelo comando find ./a -type f -exec md5sum {} \;

O possível problema são os caminhos absolutos, então o 'comando de criação de manifesto' mais apropriado é:

cd /mnt/my-volume; find  -type f -exec md5sum {} + > manifest.txt

no entanto, você sempre pode corrigir os caminhos seddentro de mainfest.txt

informação relacionada