我有一个文件夹,我想要创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可能更适合…对于比较sha256sum的sha256sum列表的所有文件可能更可靠。
我不确定焦油是这样做的最好方法。 引擎盖下太多的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一个新的空白文件时更改散列。 然后在删除新文件并撤消更改后,哈希将返回原始文件。
因人而异。