O tar não retém as permissões do diretório

2

Eu estou copiando uma estrutura de diretórios de centenas de milhões de pequenas imagens entre dois servidores. A estrutura do arquivo, a propriedade e as permissões precisam ser retidas durante a cópia. Nosso teste mostrou que a maneira mais rápida de executar esta cópia é colocar os arquivos no tar e enviá-los pelo netcat com algo como os seguintes comandos:

# TARGET (extract):
$ nc -l 2222 | pigz -d | sudo tar xpf - --same-owner -C /

# SOURCE: 
$ tar -cf - -T selected-images-to-copy.txt | pigz | pv | nc 1.1.1.1 2222

Outros métodos para realizar a cópia (por exemplo, rsync, scp) são simplesmente demorados demais para serem concluídos, pois não saturam a rede, enquanto essa abordagem será concluída em questão de dias. No entanto, enquanto as próprias imagens estão sendo criadas com a propriedade e permissões corretas, os diretórios que a extração está executando não são.

Se eu não extrair o tar, visualizarei o conteúdo que tenho:

$ tar tvzf test.tar.gz
-rw-r--r-- root/www-data 319434 2017-09-23 05:47 mnt/a/b/c/0012Z.jpg
-rw-r--r-- root/www-data 323647 2017-09-23 05:47 mnt/a/b/c/0005Z.jpg
-rw-r--r-- root/www-data 315962 2017-09-23 05:47 mnt/a/b/c/0013Z.jpg
-rw-r--r-- root/www-data 313594 2017-09-23 05:47 mnt/a/b/c/0007Z.jpg

No entanto, quando extraído, todas as pastas criadas pelo extrato entre o mnt e a imagem são de propriedade de root: root e têm as permissões 0750, o que significa que são inacessíveis para qualquer pessoa, exceto root.

$ sudo ls -al mnt/a/b
total 12
drwxr-x--- 3 root root 4096 Oct  6 15:01 .
drwxr-x--- 3 root root 4096 Oct  6 15:01 ..
drwxr-x--- 3 root root 4096 Oct  6 15:01 c

Devido ao número de arquivos, operações recursivas como chown e chmod levariam uma eternidade para serem executadas. Temos um script python personalizado que altera as permissões, mas isso adiciona dias ao processo; Por isso, gostaria de obter as permissões prontas, se possível.

Observação: ao pesquisar isso, eu descobri que esta falha no servidor pergunta que levanta um problema semelhante, mas a conclusão foi que é um bug que foi corrigido no tar v1.24.

$ tar --version
tar (GNU tar) 1.27.1
    
por Dan 06.10.2017 / 16:41

2 respostas

4

Se selected-images-to-copy.txt for uma lista de arquivos apenas (o último elemento do caminho é sempre um arquivo, não um diretório), aqui está uma solução para criar o arquivo com direitos de diretório apropriados:

EDIT: Eu adicionei uma solução melhor no final, mantendo a (s) solução (ões) intermediária (s), capitalizando os comentários da dave_thompson_085 e pensando no que poderia ser melhorado com as informações disponíveis

Como ele escreveu, (e como não expliquei completamente), a parte importante da solução é usar --no-recursion . Isso permite salvar todas as meta-informações para cada diretório adicionado manualmente no caminho, até os próprios arquivos, sem incluir todos os outros diretórios e arquivos indesejados que seriam recursivamente adicionados de outra forma.

awk -F/ '{ d=$1; for (i=2; i <= NF; i++) { print d; d=d "/" $i }; print d }' selected-images-to-copy.txt > selected-images-to-copy-with-explicit-arborescences.txt
tar cf - --no-recursion -T selected-images-to-copy-with-explicit-arborescences.txt | pigz | pv | nc 1.1.1.1 2222

Se você realmente quiser fazê-lo on-the-fly, usando <() construct do bash:

tar cf - --no-recursion -T <(awk -F/ '{ d=$1; for (i=2; i <= NF; i++) { print d; d=d "/" $i }; print d }' selected-images-to-copy.txt) | pigz | pv | nc 1.1.1.1 2222

O comando awk apenas reconstrói e adiciona o caminho, um nível de diretório por vez até o próprio arquivo.

Dessa forma, qualquer diretório no caminho de um arquivo para salvar também é colocado no arquivo, mas com o --no-recursion mais nada acontecerá. Assim, toda propriedade de diretório antes do arquivo será salva e restaurada corretamente.

Ainda há um problema de desempenho que você tem que trocar em algum lugar: haverá muitos arborescences repetidos, então o segundo tar frequentemente refaz um chown no mesmo diretório base. Você poderia classificar -u o resultado do awk para remover todas as duplicatas, mas, em seguida, o tipo pode levar muito tempo antes de dar os resultados e a transferência para iniciar. Com um pequeno script em perl que armazena elementos únicos na memória (trade-off é o uso da memória, mas duvido que seja um problema), não há necessidade de ordenar a saída de entradas exclusivas sem atraso. Então a solução se torna:

tar cf - --no-recursion -T <(awk -F/ '{ d=$1; for (i=2; i <= NF; i++) { print d; d=d "/" $i }; print d }' selected-images-to-copy.txt | perl -w -e 'use strict; my %unique; while (<>) { if (not $unique{$_}++) { print } }'  ) | pigz | pv | nc 1.1.1.1 2222

EDITAR: Se o conteúdo de selected-images-to-copy.txt for mais ou menos uma lista ordenada de arquivos (a saída não ordenada de um comando find [...] -type f é boa o suficiente), aqui está uma solução que não precisa de nenhum uso de memória (o que pode de fato ter se tornado um problema com centenas de milhões de entradas) É bom o suficiente apenas lembrar o último caminho mais longo e compará-lo ao próximo caminho:
- ou o próximo não é um prefixo do anterior, o que significa que é um novo arborescente (ou novo arquivo na mesma arborescência) e tem que ser arquivado e neste caso é projetado o novo "último caminho mais longo". Se a lista inicial não foi pelo menos apresentada como uma árvore (como em pelo menos uma saída do comando find , ou, claro, uma lista ordenada), algumas repetições começam a aparecer.
- ou é um prefixo (uma correspondência de substring do primeiro caractere), o que significa que é um diretório que já foi visto, já que faz parte do caminho do anterior e pode ser ignorado com segurança.

Estou adicionando um / à direita na comparação para descobrir facilmente que mnt/a/b/foo/ não é um prefixo de mnt/a/b/foobar . Com mnt/a/b/foobar/file4.png e mnt/a/b/foo/file5.png como entrada, a propriedade do diretório mnt/a/b/foo não teria sido restaurada sem esse truque. Então o comando perl é substituído por:

awk '{ if (index(old,$0 "/") != 1) { old=$0; print } }'

Este exemplo:

file1.png
mnt/a/b/file2.png
mnt/a/b/file3.png
mnt/a/b/c/foobar/file4.png
mnt/a/b/c/foo/file5.png
mnt/a/b/file6.png
mnt/a/b/d/file7.png

Através deste filtro:

awk -F/ '{ d=$1; for (i=2; i <= NF; i++) { print d; d=d "/" $i }; print d }' | awk '{ if (index(old,$0 "/") != 1) { old=$0; print } }'

Dá esses diretórios e arquivos prontos para tar --no-recursion :

file1.png
mnt
mnt/a
mnt/a/b
mnt/a/b/file2.png
mnt/a/b/file3.png
mnt/a/b/c
mnt/a/b/c/foobar
mnt/a/b/c/foobar/file4.png
mnt/a/b/c/foo
mnt/a/b/c/foo/file5.png
mnt/a/b/file6.png
mnt/a/b/d
mnt/a/b/d/file7.png

Assim, a solução com todo o par de comandos se torna (o root já usa -p e --same-owner , e melhor a extravagante bash <() quando um | pode funcionar e facilmente permite quebrar a linha longa com \ para legibilidade):

# TARGET (extract):
$ nc -l -p 2222 | pigz -d | sudo tar xf - -C /

# SOURCE: 
$ awk -F/ '{ d=$1; for (i=2; i <= NF; i++) { print d; d=d "/" $i }; print d }' selected-images-to-copy.txt | \
      awk '{ if (index(old,$0 "/") != 1) { old=$0; print } }' | \
      tar cf - --no-recursion -T - | pigz | pv | nc -w 60 1.1.1.1 2222
    
por 07.10.2017 / 01:34
0
  • Ao criar use -p para preservar as permissões (tar -cpvf file.tar bla bla)
  • Ao extrair a opção pass --same-owner para tar. (tar -xvf --same-owner file.tar)
por 06.10.2017 / 16:46