Zipando uma pasta para criar o arquivo tgz

3

Eu tenho uma pasta que eu quero criar arquivo tgz e calcular o seu sha256:

A pasta é convertida para tgz usando o seguinte comando

 "tar -c -C #{Shellwords.escape dir} #{Shellwords.escape basename} " \
        "--owner=0 --group=0 --mtime='2000-01-01 00:00:00' | gzip -n > #{Shellwords.escape file}"

Agora eu executei o processo acima usando 2 usuários separados e ele me deu 2 arquivos: 1 e 2

Ambos os arquivos tgz diferem em tamanhos:

-rw-r--r--@ 1 myuser  \Domain Users  9024 Jul 31 14:28 1.tgz
-rw-r--r--@ 1 myuser  \Domain Users  9037 Jul 31 14:29 2.tgz

Se eu tentar calcular o diff entre arquivos, não vejo nenhum diff. O diff foi obtido usando o seguinte comando.

diff  <(tar -tvf 1.tgz | sort) <(tar -tvf 2.tgz | sort)

Se eu computar o sha256 usando o ruby desses dois arquivos, então ele será diferente.

A pergunta é: Por que eu recebo diferença nos arquivos tgz quando estou usando usuários diferentes?

EDITAR: Depois de ler os comentários e alguns googling descobri que a ordem em que os arquivos são adicionados não é corrigida toda vez.

veja este link .

Vou tentar isso e adicionar detalhes.

    
por user93796 02.08.2017 / 01:41

5 respostas

2

Existem muitas coisas pelas quais isso pode ocorrer.

  • Os metadados armazenados pelo tar (assim como os metadados armazenados pelo gzip, que podem incluir a hora da modificação do arquivo tar). Vejo que você está usando algumas opções de tar GNU que potencialmente poderiam redefinir algumas partes desses metadados, mas eu aposto que as opções não são exaustivas de todos os atributos das variáveis.

  • A ordem dos arquivos. Quando você extrai os arquivos em um sistema de arquivos, a ordem dificilmente importa para a maioria dos aplicativos (embora cada entrada de diretório geralmente venha antes ou depois de qualquer outra entrada dentro do mesmo diretório no sistema de arquivos subjacente). No entanto, a ordem dos arquivos em um arquivo tar não é garantida.

  • A compactação gzip. É garantido pelo formato de arquivo que os arquivos compactados seriam descompactados para os originais, no entanto, não é necessariamente garantido que sua forma compactada tenha que ser idêntica. Além disso, se a entrada diferir no conteúdo (mesmo que permaneça no mesmo tamanho), então, da mesma forma, você verá que os dois arquivos podem ser tão diferentes a ponto de ter tamanho de arquivo diferente.

Em resumo, se você estiver tentando determinar se o conteúdo de duas pastas é o mesmo, provavelmente não é a melhor maneira de usar arquivos .tgz.

    
por 08.08.2017 / 04:53
2

TL; DR: Sim, como você adivinhou, é muito provável que a diferença em IDs de usuário cause a diferença de tamanho nos arquivos resultantes.

Aqui está uma definição, em estruturas C, do formato de arquivo tar:

link

Você pode notar que, mesmo nesta "definição", há argumentos sobre as particularidades dos cabeçalhos de arquivos tar e informações de metadados, o que exatamente é armazenado e onde. Mas, embora existam diferentes implementações do formato de arquivo tar, há pelo menos concordância de que realmente existem informações de metadados armazenadas sobre cada arquivo ou objeto dentro do arquivo tar, armazenado em um bloco de cabeçalho dedicado antes do conteúdo do arquivo. Para o seu caso de uso, é relevante que dois itens que estão armazenados nos blocos de metadados do tar sejam proprietários de arquivos e diretórios de usuários e grupos.

Mais detalhes também podem ser encontrados na página man do projeto FreeBSD no tar:

link

O tar tem uma história longa e sinuosa, que segue as muitas reviravoltas no desenvolvimento de armazenamento de acesso não-aleatório em série na computação desde a década de 1970. Os requisitos de compatibilidade com versões anteriores podem causar esse tipo de coisa. :)

ProTip: Para comparar diretórios usando hashes, o md5deep é sua resposta. link :)

    
por 13.08.2017 / 06:14
1

E se você não ordenar o tar ao executar o comando diff? Ele pode apenas ter adicionado os arquivos em uma ordem diferente e o gzip, em seguida, faz um zip de maneira diferente.

    
por 09.08.2017 / 09:30
0

Uma vez que o método para lidar com isso, seria adicionar os arquivos em uma ordem específica: (supondo GNU tar e um shell baseado em Bourne) (Isso usa find para obter a listagem de arquivos e depois classificá-la em um local específico)

d="dir1";bn="basename";( cd "$d" && find "$bn" -type f -print0 | \
LC_ALL=C sort -z | \
tar --null -T - --owner=0 --group=0 --mtime='2000-01-01 00:00:00' \
--no-acls --no-xattrs --no-selinux -c | \
gzip -n; ) > out1.tgz

A lista de --no- -stuff precisaria ser atualizada à medida que mais recursos fossem adicionados ao tar e aos sistemas de arquivos ...

Na maioria dos casos, se tudo for sobre os nomes de arquivos e conteúdo, diff -r pode ser mais adequado ... Para mais de um par, comparando a listagem sha256sum de sha256sum de todos os arquivos pode ser mais confiável.

    
por 10.08.2017 / 11:23
0

Não tenho certeza se o tar é a melhor maneira de fazer isso. Muitas variáveis sob o capô, e não realmente usá-lo de uma forma que parece ser projetado para ser usado. Ainda mais com a compressão.

Dependendo da estrutura do diretório e do tempo disponível, isso pode não ser viável, mas você considerou o hash de cada arquivo e, em seguida, o hashing dessa lista?

Um desses esquemas pode ser: listar todos os arquivos, classificar deterministicamente, dividir cada arquivo individual e, em seguida, dividir a saída dessa combinação de hash / nome de arquivo.

Essa técnica ignora todos os metadados e lida apenas com o conteúdo do arquivo e seu nome.

Aqui está um exemplo de comando (eu andarei pelas peças individuais abaixo)

find -L 'pwd' 2> /dev/null | sort | awk '{ print "\""$0"\""}' | xargs md5sum 2> /dev/null > /tmp/out; md5sum /tmp/out | awk '{print $1}'; rm -rf /tmp/out &> /dev/null;
  • find -L \ pwd '2 > / dev / null '- Localiza uma lista de todos os arquivos, ignorando erros
  • sort - Classifica a lista de arquivos por nome para evitar os problemas de diferença de ordem de retorno do sistema de arquivos
  • awk '{ print "\""$0"\""}' - Adiciona aspas em torno de cada linha. Não é estritamente necessário, mas se você tiver espaços ou caracteres especiais em seu caminho, terá problemas.
  • xargs md5sum 2> /dev/null > /tmp/out - Na verdade, calcula o hash de cada linha, retorna o hash para o arquivo.
  • md5sum /tmp/out | awk '{print $1}' - Hashes a lista final de hashes. O awk é opcional, mas limpa a saída um pouco.
  • rm -rf /tmp/out &> /dev/null - arquivos temporários de limpeza

Isso resultará em, até onde eu sei, um "hash" para a árvore de diretórios.

De acordo com o meu teste, ele retornou o mesmo hash para uma árvore de diretórios intocada (mesmo depois de passar algum tempo), mas alterou o hash ao alterar qualquer um dos arquivos individuais ou até mesmo criar um novo arquivo em branco. O hash então retornou ao original após excluir os novos arquivos e desfazer as alterações.

YMMV.

    
por 10.08.2017 / 19:06

Tags