Tar不保留目录权限

我正在复制两台服务器之间数以亿计的小图像的目录结构。 复制期间需要保留文件结构,所有权和权限。 我们的testing表明,执行这个副本的最快方法是tar文件,并通过像下面的命令一样通过netcatpipe道它们:

# 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 

执行复制的其他方法(例如rsync,scp)实在是太慢了,需要花费数周才能完成,因为它们不会使networking饱和,而这种方法将在几天内完成。 但是,虽然图像本身是通过正确的所有权和权限创build的,但是提取所执行的目录却不是。

如果我不提取焦油,而是查看我有的内容:

 $ 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 

但是,提取时所有由mnt和image之间的提取创build的文件夹都由root:root拥有,并具有权限0750,这意味着除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 

由于文件的数量,像chown和chmod这样的recursion操作将永远运行。 我们有一个自定义的python脚本来改变权限,但是这又增加了一些过程; 所以如果可能的话,我想立即获得权限。

注意:在研究这个时,我发现这个服务器故障问题引发了类似的问题,但是结论是这是一个在tar v1.24中修复的bug。

 $ tar --version tar (GNU tar) 1.27.1 

如果selected-images-to-copy.txt只是一个文件列表(path的最后一个元素总是一个文件,而不是一个目录),这里有一个解决scheme来创build具有正确目录权限的存档:

编辑:我最后添加了一个更好的解决scheme,同时保持中间(s)的解决scheme周围,利用dave_thompson_085的意见,并思考什么可以改善与可用的信息。
正如他写的,(正如我没有完全解释的那样),解决scheme的重要部分是使用--no-recursion 。 这允许将path中每个手动添加的目录的所有元信息保存到文件本身,而不包括所有其他不需要的目录和文件,否则将recursion添加。

 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 

如果你真的想要使用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 

awk命令只是重build和添加path,一次一个目录级别直到文件本身。

这样,要保存的文件的path中的任何目录也放在归档中,但使用--no-recursion不会发生其他任何事情。 因此,文件之前的每个目录所有权将被正确保存和恢复。

还有一个性能问题,你必须在某个地方交易:会有很多重复的树状结构,所以第二个tar通常会在同一个基本目录中重做一个chown。 您可以对awk的结果进行sorting,以删除所有这些重复项,但sorting可能需要很长时间才能将结果和传输开始。 用一个简短的perl脚本将内存中的独特元素(折衷是内存使用,但我怀疑这是一个问题),没有必要sorting,以毫不拖延地输出唯一的条目。 所以解决scheme变成:

 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 

编辑:如果selected-images-to-copy.txt的内容selected-images-to-copy.txt是文件的sorting列表( find -type f的未sorting输出types的命令是足够好的话),这里有一个解决scheme这不需要任何内存使用(这可能确实已经成为数以亿计条目的问题)只要记住最长的path,并将其与下一个path进行比较就足够了:
– 或者下一个不是前面的前缀,意味着它是一个新的树状结构(或者在同一个树状结构中的新文件)并且必须被存档,并且在这种情况下被devise为新的“最长path”。 如果初始列表至less没有被显示为树(至less在find命令输出中,或者当然是sorting列表),则会出现一些重复的重复。
– 或者它是一个前缀(与第一个字符匹配的子string),这意味着它是一个已经被看到的目录,因为它是前一个path的一部分,可以安全地忽略。

我添加了一个尾随/在比较中很容易发现mnt/a/b/foo/不是mnt/a/b/foobar的前缀。 用mnt/a/b/foobar/file4.pngmnt/a/b/foo/file5.png作为input,目录mnt/a/b/foo的所有权不会在没有这个技巧的情况下被恢复。 所以perl命令被replace为:

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

此示例:

 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 

通过这个filter:

 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 } }' 

给这些目录和文件准备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 

因此,使用全部命令的解决scheme变成(root已经使用-p--same-owner ,并且当|可以工作并且容易地允许为了可读性而打破长线的时候更好地放弃bash的花哨<()

 # 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 
  • 当创build使用-p来保留权限(tar -cpvf file.tar bla bla)
  • 当提取pass -same-owner选项到tar时。 (tar -xvf –same-owner file.tar)