压缩一个文件夹来创buildtgz文件

我有一个文件夹,我想要创buildtgz文件并计算其sha256:

该文件夹使用以下命令转换为tgz

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

现在我运行上面的过程使用2个单独的用户,它给了我2个文件:1和2

两个tgz文件的大小不同:

 -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 

如果我尝试计算文件之间的差异,我没有看到任何diff.Diff使用以下命令获得。

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

如果我使用这两个文件的ruby来计算sha256,那么它是不同的。

问题是:为什么我从不同的用户运行tgz文件时会出现差异。

编辑:读取评论和一些谷歌search后,我发现文件添加的顺序并不是每次都是固定的。

看到这个https://reproducible-builds.org/docs/archives/#file-ordering 。

我会尝试这个并添加细节。

这可能是由于许多事情。

  • tar存储的元数据(以及gzip存储的元数据,可能包括tar存档的修改时间)。 我看到你正在使用一些GNU tar选项,可能会重置这个元数据的某些部分,但是我敢打赌,这些选项并不是穷举所有的variables属性。

  • 文件的顺序。 将文件提取到文件系统时,顺序对于大多数应用程序来说并不重要(尽pipe每个目录条目通常位于底层文件系统的相同dirent中的任何其他条目之前或之后)。 但是,tar文件中的文件的顺序不能保证。

  • gzip压缩。 文件格式保证压缩文件将被解压缩到原始文件,但不一定保证它们的压缩格式必须相同。 而且,如果input的内容不同(即使保持相同的大小),那么同样的,你会发现这两个档案甚至会有不同的文件大小。

总之,如果你想确定两个文件夹的内容是否相同,那么使用.tgz文件可能不是最好的方式。

TL; DR:是的,正如您猜测的那样,导致文件大小差异的用户ID差异很大。

这是一个在C结构中定义的tar文件格式:

https://www.gnu.org/software/tar/manual/html_node/Standard.html

您可能会注意到,即使在这个“定义”中,也有关于tar文件头和元数据信息的细节,存储什么以及在哪里的论点。 但是,虽然tar文件格式有不同的实现方式,但至less有一致意见,确实存在关于tar文件内每个文件或对象的元数据信息,存储在文件内容之前的专用标题块中。 对于您的用例,存储在tar元数据块中的两个项目是用户和组文件和目录所有者是相关的。

更多的细节也可以从tar的FreeBSD项目手册中find:

https://www.freebsd.org/cgi/man.cgi?query=tar&sektion=5&manpath=FreeBSD+8-current

焦油历史悠久,历史悠久,自20世纪70年代以来,随着计算机系列非随机存取存储技术的发展,出现了许多转折点。 向后兼容的要求可能会导致这种事情。 🙂

ProTip:使用散列比较目录,md5deep是你的答案。 http://md5deep.sourceforge.net/ 🙂

如果在运行diff命令时不对tar进行sorting呢? 它可能只是以不同的顺序添加文件,gzip然后以不同的方式进行压缩。

一旦方法来处理这个问题,将是以特定的顺序添加文件:(假设GNU tar和一个基于Bourne的shell)(这使用find来获取文件列表,然后在特定的语言环境中进行sorting)

 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 

随着更多function被添加到tar和文件系统,需要更新--no- stuff列表…

在大多数情况下,如果你所关心的是文件名和内容, diff -r可能更适合…对于比较sha256sumsha256sum列表的所有文件可能更可靠。

我不确定焦油是这样做的最好方法。 引擎盖下太多的variables,而不是真的用它似乎devise的方式使用它。 压缩更是如此。

根据你的目录结构和时间可用,这可能是不可行的,但你有没有考虑散列每个文件,然后哈希列表?

一个这样的scheme可能是:列出所有文件,确定性地sorting,散列每个文件,然后散列这个散列/文件名组合的输出。

这种技术忽略了所有的元数据,并纯粹处理文件的内容和名称。

这里是一个示例命令(我将通过下面的单个步骤)

 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` – find所有文件的列表,忽略错误
  • sort – 按名称sorting文件列表避免文件系统返回顺序差异问题
  • awk '{ print "\""$0"\""}' – 在每一行的周围添加引号。 不是严格要求的,但如果你的路上有任何空间或特殊字符,就会有麻烦。
  • xargs md5sum 2> /dev/null > /tmp/out – 实际上计算每一行的散列值,并将散列值返回给文件。
  • md5sum /tmp/out | awk '{print $1}' md5sum /tmp/out | awk '{print $1}' – 散列最终的散列表。 awk是可选的,但清理了一下输出。
  • rm -rf /tmp/out &> /dev/null – 清理临时文件

就我所知,这将导致目录树的“散列”。

根据我的testing,它返回了一个未触摸的目录树(甚至允许一段时间后通过)相同的散列,但更改任何单个文件,甚至创build一个新的空白文件时更改散列。 然后在删除新文件并撤消更改后,哈希将返回原始文件。

因人而异。