Como obtenho a soma MD5 do conteúdo de um diretório como uma soma?

171

O programa md5sum não fornece somas de verificação para diretórios. Desejo obter uma única soma de verificação MD5 para todo o conteúdo de um diretório, incluindo arquivos em subdiretórios. Ou seja, uma soma de verificação combinada composta por todos os arquivos. Existe uma maneira de fazer isso?


fonte

Respostas:

186

O caminho certo depende exatamente do motivo pelo qual você está perguntando:

Opção 1: comparar apenas dados

Se você apenas precisar de um hash do conteúdo do arquivo da árvore, isso funcionará:

$ find -s somedir -type f -exec md5sum {} \; | md5sum

Isso primeiro resume todo o conteúdo do arquivo individualmente, em uma ordem previsível, depois passa a lista de nomes de arquivos e os hashes MD5 para serem separados por hash, fornecendo um valor único que muda apenas quando o conteúdo de um dos arquivos na árvore é alterado.

Infelizmente, find -ssó funciona com o BSD find (1), usado no macOS, FreeBSD, NetBSD e OpenBSD. Para obter algo comparável em um sistema com GNU ou SUS find (1), você precisa de algo um pouco mais feio:

$ find somedir -type f -exec md5sum {} \; | sort -k 2 | md5sum

Substituímos find -spor uma chamada para sort. O -k 2bit diz para pular o hash MD5, classificando apenas os nomes dos arquivos, que estão no campo 2 até o final da linha, pelo sortcálculo da conta.

Há uma fraqueza nessa versão do comando, que é susceptível de ficar confusa se você tiver algum nome de arquivo com novas linhas, porque parecerá várias linhas para a sortchamada. A find -svariante não tem esse problema, porque a travessia e a classificação da árvore acontecem dentro do mesmo programa find,.

Em ambos os casos, a classificação é necessária para evitar falsos positivos: os sistemas de arquivos Unix / Linux mais comuns não mantêm as listas de diretórios em uma ordem estável e previsível. Você pode não perceber isso usando lse tal, que silenciosamente classifica o conteúdo do diretório para você. findsem -sou uma sortchamada imprimirá os arquivos na ordem em que o sistema de arquivos subjacente os retornar, o que fará com que esse comando dê um valor de hash alterado se a ordem dos arquivos fornecidos como entrada for alterada.

Pode ser necessário alterar os md5sumcomandos para md5ou alguma outra função de hash. Se você escolher outra função de hash e precisar da segunda forma do comando para o seu sistema, poderá ser necessário ajustá-lo sortadequadamente. Outra armadilha é que alguns programas de soma de dados não escrevem o nome de um arquivo, um excelente exemplo sendo o antigo sumprograma Unix .

Esse método é um pouco ineficiente, chamando md5sumN + 1 vezes, em que N é o número de arquivos na árvore, mas esse é um custo necessário para evitar o hash de metadados de arquivos e diretórios.

Opção 2: comparar dados e metadados

Se você precisar detectar que alguma coisa em uma árvore mudou, não apenas o conteúdo do arquivo, peça tarpara embalar o conteúdo do diretório e envie-o para md5sum:

$ tar -cf - somedir | md5sum

Como tartambém vê permissões de arquivos, propriedade etc., isso também detectará alterações nessas coisas, não apenas alterações no conteúdo do arquivo.

Esse método é consideravelmente mais rápido, pois faz apenas uma passagem pela árvore e executa o programa de hash apenas uma vez.

Como no findmétodo baseado acima, tarele processará os nomes de arquivos na ordem em que o sistema de arquivos subjacente os retorna. Pode ser que, no seu aplicativo, você tenha certeza de que não fará com que isso aconteça. Posso pensar em pelo menos três padrões de uso diferentes, onde é provável que seja esse o caso. (Não vou listá-los, porque estamos entrando em território de comportamento não especificado. Cada sistema de arquivos pode ser diferente aqui, mesmo de uma versão do sistema operacional para a próxima.)

Se você se encontrar com falsos positivos, recomendo ir com a find | cpioopção na resposta de Gilles .

Warren Young
fonte
7
Eu acho que é melhor navegar para o diretório que está sendo comparado e usar em find .vez de find somedir. Dessa forma, os nomes dos arquivos são os mesmos ao fornecer diferentes especificações de caminho a serem encontradas; isso pode ser complicado :-)
Abbafei
Também devemos classificar os arquivos?
precisa saber é o seguinte
@CMCDragonkai: Como assim? No primeiro caso, temos que classificar a lista de nomes de arquivo. No segundo caso, que propositadamente não fazer, porque parte do enfatizou nada na primeira frase é que a ordem de arquivos em um diretório mudou, para que você não gostaria de classificar qualquer coisa.
perfil completo de Warren Young
@WarrenYoung Você pode explicar um pouco mais detalhadamente por que a opção 2 nem sempre é melhor? Parece ser mais rápido, mais simples e mais multiplataforma. Nesse caso, não deveria ser a opção 1?
22416 Robin Winslow
Opção 1 alternativa: find somedir -type f -exec sh -c "openssl dgst -sha1 -binary {} | xxd -p" \; | sort | openssl dgst -sha1para ignorar todos os nomes de arquivos (deve trabalhar com várias linhas)
windm
38

A soma de verificação precisa ter uma representação determinística e inequívoca dos arquivos como uma sequência. Determinístico significa que se você colocar os mesmos arquivos nos mesmos locais, obterá o mesmo resultado. Não ambíguo significa que dois conjuntos diferentes de arquivos têm representações diferentes.

Dados e metadados

Criar um arquivo contendo os arquivos é um bom começo. Essa é uma representação inequívoca (obviamente, pois você pode recuperar os arquivos extraindo o arquivo morto). Pode incluir metadados de arquivo, como datas e propriedade. No entanto, isso ainda não está certo: um arquivo é ambíguo, porque sua representação depende da ordem em que os arquivos são armazenados e, se aplicável, da compactação.

Uma solução é classificar os nomes dos arquivos antes de arquivá-los. Se os nomes dos seus arquivos não contiverem novas linhas, você poderá executá find | sort-las para listá-las e adicioná-las ao arquivo nesta ordem. Tome cuidado para informar ao arquivador para não recursar nos diretórios. Aqui estão alguns exemplos com POSIX pax, GNU tar e cpio:

find | LC_ALL=C sort | pax -w -d | md5sum
find | LC_ALL=C sort | tar -cf - -T - --no-recursion | md5sum
find | LC_ALL=C sort | cpio -o | md5sum

Somente nomes e conteúdos, da maneira de baixa tecnologia

Se você quiser apenas levar em consideração os dados do arquivo e não os metadados, poderá criar um arquivo que inclua apenas o conteúdo do arquivo, mas não há ferramentas padrão para isso. Em vez de incluir o conteúdo do arquivo, você pode incluir o hash dos arquivos. Se os nomes dos arquivos não contiverem novas linhas e houver apenas arquivos e diretórios regulares (sem links simbólicos ou arquivos especiais), isso é bastante fácil, mas você precisa cuidar de algumas coisas:

{ export LC_ALL=C;
  find -type f -exec wc -c {} \; | sort; echo;
  find -type f -exec md5sum {} + | sort; echo;
  find . -type d | sort; find . -type d | sort | md5sum;
} | md5sum

Incluímos uma lista de diretórios além da lista de somas de verificação, caso contrário, diretórios vazios seriam invisíveis. A lista de arquivos é classificada (em um local específico e reproduzível - graças a Peter.O por me lembrar disso). echosepara as duas partes (sem isso, você pode criar alguns diretórios vazios cujo nome se parece com uma md5sumsaída que também pode passar para arquivos comuns). Também incluímos uma lista de tamanhos de arquivo, para evitar ataques de extensão .

A propósito, o MD5 está obsoleto. Se estiver disponível, considere usar SHA-2, ou pelo menos SHA-1.

Nomes e dados, suportando novas linhas em nomes

Aqui está uma variante do código acima, que depende das ferramentas GNU para separar os nomes dos arquivos com bytes nulos. Isso permite que os nomes de arquivos contenham novas linhas. Os utilitários Digest GNU citam caracteres especiais em sua saída, para que não haja novas linhas ambíguas.

{ export LC_ALL=C;
  du -0ab | sort -z; # file lengths, including directories (with length 0)
  echo | tr '\n' '\000'; # separator
  find -type f -exec sha256sum {} + | sort -z; # file hashes
  echo | tr '\n' '\000'; # separator
  echo "End of hashed data."; # End of input marker
} | sha256sum

Uma abordagem mais robusta

Aqui está um script Python minimamente testado que cria um hash descrevendo uma hierarquia de arquivos. Leva os diretórios e o conteúdo do arquivo para as contas, ignora os links simbólicos e outros arquivos e retorna um erro fatal se algum arquivo não puder ser lido.

#! /usr/bin/env python
import hashlib, hmac, os, stat, sys
## Return the hash of the contents of the specified file, as a hex string
def file_hash(name):
    f = open(name)
    h = hashlib.sha256()
    while True:
        buf = f.read(16384)
        if len(buf) == 0: break
        h.update(buf)
    f.close()
    return h.hexdigest()
## Traverse the specified path and update the hash with a description of its
## name and contents
def traverse(h, path):
    rs = os.lstat(path)
    quoted_name = repr(path)
    if stat.S_ISDIR(rs.st_mode):
        h.update('dir ' + quoted_name + '\n')
        for entry in sorted(os.listdir(path)):
            traverse(h, os.path.join(path, entry))
    elif stat.S_ISREG(rs.st_mode):
        h.update('reg ' + quoted_name + ' ')
        h.update(str(rs.st_size) + ' ')
        h.update(file_hash(path) + '\n')
    else: pass # silently symlinks and other special files
h = hashlib.sha256()
for root in sys.argv[1:]: traverse(h, root)
h.update('end\n')
print h.hexdigest()
Gilles
fonte
OK, isso funciona, obrigado. Mas existe alguma maneira de fazer isso sem incluir metadados? No momento, preciso apenas do conteúdo real.
Que tal LC_ALL=C sortpara a verificação de ambientes diferentes ... (+ 1 btw)
Peter.O
Você criou um programa inteiro em Python para isso? Obrigado! Isso é realmente mais do que eu esperava. :-) De qualquer forma, vou verificar esses métodos, bem como a nova opção 1 de Warren.
Boa resposta. Definir a ordem de classificação com LC_ALL=Cé essencial se estiver sendo executado em várias máquinas e sistemas operacionais.
Davor Cubranic
O que cpio -o -significa isso ? O cpio não usa stdin / out por padrão? Produz GNU cpio 2.12cpio: Too many arguments
Jan Tojnar 12/08
12

Dê uma olhada no md5deep . Alguns dos recursos do md5deep que podem lhe interessar:

Operação recursiva - o md5deep é capaz de examinar recursivamente uma árvore de diretórios inteira. Ou seja, calcule o MD5 para cada arquivo em um diretório e para cada arquivo em cada subdiretório.

Modo de comparação - o md5deep pode aceitar uma lista de hashes conhecidos e compará-los com um conjunto de arquivos de entrada. O programa pode exibir os arquivos de entrada que correspondem à lista de hashes conhecidos ou aqueles que não correspondem.

...

servidor defeituoso
fonte
Legal, mas não dá para fazer funcionar, o .../foo: Is a directoryque dá?
Camilo Martin
3
Por si só, o md5deep não resolve o problema do OP, pois não imprime um md5sum consolidado, apenas imprime o md5sum para cada arquivo no diretório. Dito isto, você pode md5sumir a saída do md5deep - não exatamente o que o OP queria, mas está próximo! por exemplo, para o diretório atual: md5deep -r -l -j0 . | md5sum(onde -ré recursivo, -lsignifica "usar caminhos relativos", para que o caminho absoluto dos arquivos não interfira ao tentar comparar o conteúdo de dois diretórios, e -j0significa usar 1 thread para evitar o não determinismo devido para md5sums individuais sendo retornados em ordens diferentes).
Stevie
Como ignorar alguns arquivos / diretórios no caminho?
Sandeepan Nath
9

Se seu objetivo é apenas encontrar diferenças entre dois diretórios, considere usar diff.

Tente o seguinte:

diff -qr dir1 dir2
Deepak Mittal
fonte
Sim, isso também é útil. Eu acho que você quis dizer dir1 dir2 nesse comando.
1
Normalmente não uso GUIs quando posso evitá-las, mas para diferenciar diretórios o kdiff3 é ótimo e também funciona em muitas plataformas.
precisa saber é
Arquivos diferentes também são relatados com este comando.
Serge Stroobandt
7

Você pode fazer o hash de todos os arquivos recursivamente e, em seguida, o texto resultante:

> md5deep -r -l . | sort | md5sum
d43417958e47758c6405b5098f151074 *-

md5deep é necessário.

Pavel Vlasov
fonte
1
em vez de md5deepusar hashdeepno ubuntu 16.04 porque o pacote md5deep é apenas um manequim de transição para o hashdeep.
Palik
1
Eu tentei hashdeep. Ele gera não apenas hashes, mas também algum cabeçalho, incluindo ## Invoked from: /home/myuser/dev/qual é o seu caminho atual e ## $ hashdeep -s -r -l ~/folder/. Isso precisa ser ordenado, portanto o hash final será diferente se você alterar sua pasta ou linha de comando atual.
truf 23/08/18
3

Apenas conteúdo do arquivo , excluindo nomes de arquivos

Eu precisava de uma versão que apenas verificasse os nomes dos arquivos porque o conteúdo reside em diretórios diferentes.

Essa versão (resposta de Warren Young) ajudou muito, mas minha versão do md5sumresultado gera o nome do arquivo (relativo ao caminho do qual executei o comando) e os nomes das pastas eram diferentes, portanto, mesmo que as somas de verificação de arquivos individuais correspondam, a soma de verificação final não 't.

Para corrigir isso, no meu caso, eu só precisava retirar o nome do arquivo de cada linha da findsaída (selecione apenas a primeira palavra separada por espaços usando cut):

find -s somedir -type f -exec md5sum {} \; | cut -d" " -f1 | md5sum
Nicole
fonte
Pode ser necessário ordenar as somas de verificação para obter uma lista reproduzível.
Eckes
3

solução :

$ pip install checksumdir
$ checksumdir -a md5 assets/js
981ac0bc890de594a9f2f40e00f13872
$ checksumdir -a sha1 assets/js
88cd20f115e31a1e1ae381f7291d0c8cd3b92fad

funciona solução rápida e mais fácil do que bash scripts.

consulte doc: https://pypi.python.org/pypi/checksumdir/1.0.5

DmitrySemenov
fonte
Se você não tem pip pode ser necessário instalá-lo com yum -y instalar python-pip (ou DNF / apt-get)
DmitrySemenov
3

nix-hashdo gerenciador de pacotes Nix

O comando nix-hash calcula o hash criptográfico do conteúdo de cada caminho e o imprime na saída padrão. Por padrão, ele calcula um hash MD5, mas outros algoritmos de hash também estão disponíveis. O hash é impresso em hexadecimal.

O hash é calculado através de uma serialização de cada caminho: um despejo da árvore do sistema de arquivos enraizado no caminho. Isso permite que diretórios e links simbólicos sejam hash, bem como arquivos regulares. O dump está no formato NAR produzido pelo nix-store --dump. Portanto, o caminho nix-hash produz o mesmo hash criptográfico que o caminho nix-store --dump | md5sum.

Igor
fonte
2

Eu uso esse meu snippet para volumes moderados :

find . -xdev -type f -print0 | LC_COLLATE=C sort -z | xargs -0 cat | md5sum -

e este para XXXL :

find . -xdev -type f -print0 | LC_COLLATE=C sort -z | xargs -0 tail -qc100 | md5sum -

poige
fonte
O que a -xdevbandeira faz?
Czerasz 4/17
Ele pede que você digite: man finde ler esse manual bem;)
poige
Bom ponto :-). -xdev Don't descend directories on other filesystems.
Czerasz 16/04/19
1
Observe que isso ignora arquivos novos e vazios (como se você tocar em um arquivo).
31418 RonJohn
Existem muitos casos em que isso produzirá o mesmo md5sum com uma estrutura de arquivos e diretórios completamente diferente. Renomear arquivos e diretórios não mudará isso se não alterar a ordem de classificação dos arquivos. Portanto, eu não recomendaria essa abordagem.
Hans-Peter Störr
2

Uma boa soma de verificação de árvore é o ID da árvore do Git.

Infelizmente, não existe uma ferramenta autônoma disponível que possa fazer isso (pelo menos eu não o conheço), mas se você tem o Git à mão, pode apenas fingir configurar um novo repositório e adicionar os arquivos que deseja verificar no índice.

Isso permite que você produza o hash da árvore (reproduzível) - que inclui apenas conteúdo, nomes de arquivos e alguns modos de arquivo reduzidos (executável).

eckes
fonte
2

Como acompanhamento desta excelente resposta , se você deseja acelerar o cálculo da soma de verificação para um diretório grande, tente o GNU Parallel :

find -s somedir -type f | parallel -k -n 100 md5 {} | md5

(Este está usando um Mac com md5, substitua conforme necessário.)

O -ksinalizador é importante, que instrui parallela manter a ordem; caso contrário, a soma geral pode mudar de execução para execução, mesmo que os arquivos sejam iguais. -n 100diz para executar cada instância md5com 100 argumentos, este é um parâmetro que você pode ajustar para obter o melhor tempo de execução. Veja também -Xflag of parallel(embora no meu caso pessoal isso tenha causado um erro.)

shawkinaw
fonte
1

Um script que é bem testado e suporta várias operações, incluindo a localização de duplicatas, comparações de dados e metadados, mostrando adições, além de alterações e remoções, você pode gostar da Impressão digital .

A impressão digital no momento não produz uma única soma de verificação para um diretório, mas um arquivo de transcrição que inclui somas de verificação para todos os arquivos nesse diretório.

fingerprint analyze

Isso será gerado index.fingerprintno diretório atual, que inclui somas de verificação, nomes de arquivos e tamanhos de arquivo. Por padrão, ele usa ambos MD5e SHA1.256.

No futuro, espero adicionar suporte para Merkle Trees na impressão digital, o que fornecerá uma única soma de verificação de nível superior. No momento, você precisa reter esse arquivo para fazer a verificação.

ioquatix
fonte
1

Eu não queria novos executáveis ​​nem soluções desajeitadas, então aqui está minha opinião:

#!/bin/sh
# md5dir.sh by Camilo Martin, 2014-10-01.
# Give this a parameter and it will calculate an md5 of the directory's contents.
# It only takes into account file contents and paths relative to the directory's root.
# This means that two dirs with different names and locations can hash equally.

if [[ ! -d "$1" ]]; then
    echo "Usage: md5dir.sh <dir_name>"
    exit
fi

d="$(tr '\\' / <<< "$1" | tr -s / | sed 's-/$--')"
c=$((${#d} + 35))
find "$d" -type f -exec md5sum {} \; | cut -c 1-33,$c- | sort | md5sum | cut -c 1-32
Camilo Martin
fonte
0

Uma abordagem robusta e limpa

  • Primeiras coisas primeiro, não monopolize a memória disponível ! Hash de um arquivo em pedaços em vez de alimentar o arquivo inteiro.
  • Abordagens diferentes para diferentes necessidades / propósitos (todos os itens abaixo ou escolha o que for aplicável):
    • Hash apenas o nome da entrada de todas as entradas na árvore de diretórios
    • Hash o conteúdo do arquivo de todas as entradas (deixando a meta como, número do inode, ctime, atime, mtime, tamanho, etc., você entendeu)
    • Para um link simbólico, seu conteúdo é o nome do referente. Hash ou optar por pular
    • Siga ou não seguir (nome resolvido) o link simbólico enquanto faz o hash do conteúdo da entrada
    • Se é um diretório, seu conteúdo são apenas entradas de diretório. Ao percorrer recursivamente, eles serão hash eventualmente, mas os nomes de entrada do diretório desse nível devem ser hash para marcar esse diretório? Útil nos casos de uso em que o hash é necessário para identificar uma alteração rapidamente, sem a necessidade de percorrer profundamente o hash. Um exemplo seria o nome de um arquivo alterado, mas o restante do conteúdo permanece o mesmo e todos são arquivos bastante grandes
    • Manuseie bem arquivos grandes (mais uma vez, lembre-se da RAM)
    • Lidar com árvores de diretório muito profundas (lembre-se dos descritores de arquivos abertos)
    • Manipular nomes de arquivo não padrão
    • Como proceder com arquivos que são soquetes, tubos / FIFOs, dispositivos de bloco, dispositivos de char? Deve misturá-los também?
    • Não atualize o tempo de acesso de nenhuma entrada enquanto estiver percorrendo, pois isso será um efeito colateral e contraproducente (intuitivo?) Para determinados casos de uso.

É isso que eu tenho em mente: qualquer um que tenha passado algum tempo trabalhando nisso praticamente pegaria outras pegadinhas e casos de canto.

Aqui está uma ferramenta (aviso: eu sou um colaborador). Dtreetrawl , muito leve na memória, que aborda a maioria dos casos, pode ser um pouco difícil, mas tem sido bastante útil.

Usage:
  dtreetrawl [OPTION...] "/trawl/me" [path2,...]

Help Options:
  -h, --help                Show help options

Application Options:
  -t, --terse               Produce a terse output; parsable.
  -d, --delim=:             Character or string delimiter/separator for terse output(default ':')
  -l, --max-level=N         Do not traverse tree beyond N level(s)
  --hash                    Hash the files to produce checksums(default is MD5).
  -c, --checksum=md5        Valid hashing algorithms: md5, sha1, sha256, sha512.
  -s, --hash-symlink        Include symbolic links' referent name while calculating the root checksum
  -R, --only-root-hash      Output only the root hash. Blank line if --hash is not set
  -N, --no-name-hash        Exclude path name while calculating the root checksum
  -F, --no-content-hash     Do not hash the contents of the file

Um exemplo de saída amigável para humanos:

...
... //clipped
...
/home/lab/linux-4.14-rc8/CREDITS
        Base name                    : CREDITS
        Level                        : 1
        Type                         : regular file
        Referent name                :
        File size                    : 98443 bytes
        I-node number                : 290850
        No. directory entries        : 0
        Permission (octal)           : 0644
        Link count                   : 1
        Ownership                    : UID=0, GID=0
        Preferred I/O block size     : 4096 bytes
        Blocks allocated             : 200
        Last status change           : Tue, 21 Nov 17 21:28:18 +0530
        Last file access             : Thu, 28 Dec 17 00:53:27 +0530
        Last file modification       : Tue, 21 Nov 17 21:28:18 +0530
        Hash                         : 9f0312d130016d103aa5fc9d16a2437e

Stats for /home/lab/linux-4.14-rc8:
        Elapsed time     : 1.305767 s
        Start time       : Sun, 07 Jan 18 03:42:39 +0530
        Root hash        : 434e93111ad6f9335bb4954bc8f4eca4
        Hash type        : md5
        Depth            : 8
        Total,
                size           : 66850916 bytes
                entries        : 12484
                directories    : 763
                regular files  : 11715
                symlinks       : 6
                block devices  : 0
                char devices   : 0
                sockets        : 0
                FIFOs/pipes    : 0
six-k
fonte
Aconselhamento geral é sempre bem-vindo, mas as melhores respostas são específicas e com código, quando apropriado. Se você tem experiência em usar a ferramenta a que se refere, inclua-a.
bu5hman
@ bu5hman Claro! Eu não estava muito confortável dizendo (exultando?) Mais sobre o quão bem ele funciona desde que estou envolvido no seu desenvolvimento.
six-k
0

Fazendo individualmente para todos os arquivos em cada diretório.

# Calculating
find dir1 | xargs md5sum > dir1.md5
find dir2 | xargs md5sum > dir2.md5
# Comparing (and showing the difference)
paste <(sort -k2 dir1.md5) <(sort -k2 dir2.md5) | awk '$1 != $3'
Leandro Lima
fonte
0

A migração para o formato de arquivo POSIX afeta as somas de verificação baseadas em Tar GNU

Esta resposta pretende ser uma atualização suplementar à abordagem do uso da saída Tar para misturar o conteúdo dos diretórios, como foi proposto (entre outras coisas) nas excelentes respostas de Warren Young e Gilles há algum tempo.

Desde então, pelo menos o openSUSE (desde seu lançamento 12.2) mudou o formato GNU Tar padrão de "GNU tar 1.13.x format" para o (ligeiramente) superior "formato POSIX 1003.1-2001 (pax)" superior ) . Também a montante (entre os desenvolvedores do GNU Tar) eles discutem para executar a mesma migração, veja, por exemplo, o último parágrafo desta página do manual do GNU Tar :

O formato padrão para o tar GNU é definido no momento da compilação. Você pode verificá-lo executando tar --helpe examinando as últimas linhas de sua saída. Geralmente, o GNU tar é configurado para criar arquivos no gnuformato, no entanto, a versão futura mudará para posix.

(Esta página também oferece uma boa revisão sobre os diferentes formatos de arquivo disponíveis no GNU Tar.)

No nosso caso, onde taramos o conteúdo do diretório e hash o resultado, e sem tomar medidas específicas, uma mudança do formato GNU para POSIX tem as seguintes conseqüências:

  • Apesar do conteúdo do diretório idêntico, a soma de verificação resultante será diferente.

  • Apesar do conteúdo do diretório idêntico, a soma de verificação resultante será diferente de execução para execução se os cabeçalhos pax padrão forem usados.

O último vem do fato de que o formato POSIX (pax) inclui cabeçalhos de pax estendidos, que são determinados por uma string de formato padrão %d/PaxHeaders.%p/%fno GNU Tar. Dentro dessa cadeia, o especificador %pé substituído pelo ID do processo Tar gerado, o qual, obviamente, é diferente de execução para execução. Veja esta seção do manual GNU Tar e, em particular, esta para detalhes.

Agora, datando de 28/03/2019, há um commit aceito upstream que desativa esse problema.

Portanto, para poder continuar usando o GNU Tar no caso de uso especificado, posso recomendar as seguintes opções alternativas:

  • Use a opção Tar --format=gnupara informar explicitamente o Tar para gerar o arquivo no formato "antigo". Isso é obrigatório para validar somas de verificação "antigas".

  • Use o formato POSIX mais recente, mas especifique explicitamente um cabeçalho pax adequado, por exemplo, por --pax-option="exthdr.name=%d/PaxHeaders/%f". No entanto, isso quebra a compatibilidade com versões anteriores às somas de verificação "antigas".

Aqui está um fragmento de código Bash que eu uso regularmente para calcular somas de verificação do conteúdo do diretório, incluindo metadados:

( export LC_ALL=C
  find <paths> ! -type s -print0 |
  sort -z |
  tar cp --format=gnu --numeric-owner \
         --atime-preserve \
         --no-recursion --null --files-from - |
  md5sum --binary; )

Aqui, <paths>é substituído por uma lista separada por espaços dos caminhos de todos os diretórios que eu quero que sejam cobertos pela soma de verificação. O objetivo de usar o código de idioma C, a separação de bytes nulos de nomes de arquivos e o uso de localizar e classificar para obter uma ordem independente dos sistemas de arquivos dos arquivos no arquivo morto já é suficientemente discutido em outras respostas.

Os parênteses circundantes mantêm a LC_ALLconfiguração local em um subshell.

Além disso, uso a expressão ! -type scom findpara evitar avisos do Tar que ocorrem se os arquivos de soquete fizerem parte do conteúdo do diretório: O GNU Tar não arquiva soquetes. Se você preferir ser notificado sobre soquetes ignorados, deixe essa expressão de lado.

Eu uso --numeric-ownercom o Tar, para poder verificar as somas de verificação posteriormente, mesmo em sistemas, onde nem todos os proprietários de arquivos são conhecidos.

A --atime-preserveopção para Tar é melhor omitida se alguma das <paths>mentiras estiver em um dispositivo montado somente leitura. Caso contrário, você será avisado de cada arquivo cujo carimbo de data e hora de acesso Tar não pôde restaurar. Para a gravação ativada <paths>, eu uso essa opção para preservar os carimbos de data e hora de acesso nos diretórios de hash.

A opção Tar --no-recursion, que já foi usada na proposta de Gilles , impede que o Tar desça recursivamente nos diretórios por si só e, em vez disso, opere arquivo por arquivo no que for alimentado a partir da findsaída classificada .

E, finalmente, não é verdade que eu uso md5sum: eu realmente uso sha256sum.

Jürgen
fonte
-1

Se você não precisa do md5, pode tentar

find . -type f | xargs cksum | cksum
Martin Koubek
fonte
1
A pergunta pede especificamente MD5
RalfFriedl