一个 tarball 竟有 8 种解压结果

The Hardest Tarball?

我构建了一个名为 hardest.tar 的档案,它利用 GNU tar 的特定参数组合,制造出一种在 8 种不同工具下解压结果截然不同的“最硬”tarball。这个档案包含一个硬链接和一个空文件,但通过 pax header 的巧妙设置,让硬链接拥有了 512 字节的数据大小。结果令人咋舌:GNU tar、Python 和 Go 等工具正常提取;macOS 的 bsdtar 将空文件的头写入硬链接;7-Zip 和 Rust 直接跳过数据导致文件丢失;Java 甚至创建了包含头数据的独立文件;而 R 语言则错误地将大小应用于空文件。这一案例揭示了 POSIX 标准在硬链接数据块处理上的模糊地带,以及各语言库在实现上的巨大差异。

这个档案给出了我迄今遇到的最丰富且最令人惊讶的解压结果。
  1. Joker_vD

    现在,POSIX 规定硬链接的数据块“可以”包含在 pax 归档中,但这点的含义并不完全清楚。

    为何如此?如果数据块被包含在内,那么这些就是该硬链接背后文件的预期内容。它们应该覆盖该文件之前的内容。

    那么,硬链接之后的 512 字节是它的数据,而不是我们归档时的 empty 文件的头部?

    是的,正是如此。

    硬链接的内容怎么会与其之前的对应文件不同?

    很简单:在创建归档的过程中,两个不同硬链接背后的文件发生了变化;归档工具注意到了这一点,并将该文件的新内容作为第二个硬链接的内容包含进去,而不是倒带并覆盖归档中的原始文件(你知道这在磁带上是不可能的)。至少我相信这就是允许这样做的理由,也是提取时的预期行为。

  2. JdeBP

    这里少了一个著名的 tar 实现。paxmirabilis 是一个多调用二进制文件,集成了 tar、cpio 和 pax。事实上,Debian 中的 pax 就是它。

    * https://mbsd.evolvis.org/pax.htm

    * https://manpages.debian.org/trixie/pax/index.html

    不,它不是 libarchive 的 bsdtar。BSD 世界里不止一个 tar。

  3. bartvk

    这位老兄,真是个英雄。他甚至加了一张小图来展示这个“最难解的 tarball”长什么样。

    底部还有一个链接,指向更多边缘情况。

    这让我想起了这篇佳作:“解析 JSON 如同雷区”

    https://news.ycombinator.com/item?id=16897061

  4. molticrystal

    >NET、Julia 和 uv 的 tar-codec - 这些实现会拒绝该 tarball。我认为这是你能做的最好的事,即使这在技术上不符合 POSIX 标准。

    虽然这是最安全的选择,但它也是帮助最小的。我总是宁愿从归档中取出点什么,也不愿一无所获。归档的损坏或不规则不应阻止数据检查,只需发出警告并提供一种带注意事项的回退方式来提取内容即可。

  5. zahlman

    > 这个 tarball 是我正在收集并分类在我的测试套件 haampie/tar-minefield 中的 134 个棘手 tarball 之一。

    “tarpit”(焦油坑)是不是个更自然的名字?

同日更多故事

2026-11-10