BusyBox tar:在给定有限磁盘 space 的情况下追加解决方法?

BusyBox tar: append workaround given limited disk space?

我在 Linux 系统上,资源和 BusyBox 有限 -- 这个版本的 tar 不支持 --append, -r。在 [2] 使 B 文件看起来来自目录 A 之后,是否有一种解决方法允许我 [1] 将目录 B 中的文件附加到目录 A 中现有的 tar 文件? (稍后,当有人提取文件时,它们应该都在同一个目录 A 中。)

情况:我有一个我想要 tar 的文件列表,但我必须先处理其中的一些文件。这些文件可能会被其他进程使用,所以我不想就地编辑它们。我想在使用磁盘 space 时保持保守,所以我的脚本只复制它需要更改的那些文件(与复制所有文件然后处理一些文件并最终使用 tar 将它们全部归档 - 如果我复制他们所有我可能 运行 进入磁盘 space 问题)。

这意味着我要存档的文件最终位于两个不同的位置。但我希望生成的 tar 文件看起来好像它们都在同一位置。在我的脚本接近尾声时,我得到了两个按名称列出 A 和 B 文件的文本文件。

我认为这对于 tar 的完整版本来说很简单,但我必须使用 BusyBox 版本(下面的用法)。提前感谢任何想法!

Usage: tar -[cxtzjaZmvO] [-X FILE] [-f TARFILE] [-C DIR] [FILE]...

Create, extract, or list files from a tar file

Operation:
   c    Create
   x    Extract
   t    List
Options:
   f    Name of TARFILE ('-' for stdin/out)
   C    Change to DIR before operation
   v    Verbose
   z    (De)compress using gzip
   j    (De)compress using bzip2
   a    (De)compress using lzma
   Z    (De)compress using compress
   O    Extract to stdout
   h    Follow symlinks
   m    Don't restore mtime
   exclude  File to exclude
   X    File with names to exclude
   T    File with names to include

原则上,您只需将包含附加文件的tar 存储库追加到tar 文件的末尾即可。只是比那个稍微难一点。

一个tar文件由任意数量的header + file重复组成。 header 始终是一个 512 字节的块,文件被填充为 512 字节的倍数,因此您可以将这些单元视为可变数量的 512 字节块。每个块都是独立的;它是 header starts 以及文件的完整路径名。所以没有要求目录中的文件一起tar红色。

有一个并发症。在 tar 文件的末尾,至少有两个 512 字节的块完全用 0 填充。当 tar 正在读取 tar 文件时,它将忽略单个 zero-filled header,但第二个将导致它停止读取文件。如果它到达 EOF,它会报错,所以终止空 headers 是必需的。

可能有两个以上的header,因为tar实际上写入的块是512字节的倍数。例如,Gnu tar,默认情况下写入 20 512 字节块的倍数,因此最小的 tar 文件通常为 10240 字节。

为了追加新数据,您需要先截断现有文件以消除空块。

我相信如果tar文件是由busybox生成的,那么只有两个空块,但我没有检查代码。那很容易;您只需在附加其他文件之前截断文件的最后 1024 个字节。

对于一般的 tar 文件,比较棘手。如果你知道文件本身没有 NUL 字节(即它们都是简单的文本文件),你可以删除空的 headers 直到你找到一个包含非 0 字节的块,这不会太难。

我会做的是:

  1. 截断 tar 文件的最后 1024 个字节。
  2. 记住 tar 文件的当前大小。
  3. 附加一个测试 tar 文件,该文件由带有简单短消息的文件 tar 组成
  4. 验证 tar tf 是否正确显示测试文件
  5. 将文件截断回记忆的长度,
    • 如果tar tf找到测试文件名,则成功
    • 如果tar文件的最后512字节全为0,则截断文件的最后512字节,return到第2步
    • 否则失败

如果上述过程成功,您可以继续将新文件附加到 tar 存储库。

不知道你有没有trunc命令。如果没有,您可以使用 dd 将文件复制到指定偏​​移量处的旧文件之上(请参阅 seek= 选项)。 dd 将在复制结束时自动截断文件。您还可以使用 dd 读取 512 字节的块(请参阅 skipcount 选项)。

最好的解决方案是将最后的 1024 个字节截断并在其后连接一个新的 tar。为了将 tar 附加到现有的 tar 文件,必须将它们解压缩。

对于像这样的文件:

$ find a b
a
a/file1
b
b/file2

您可以:

$ tar -C a -czvf a.tar.gz .
$ gunzip -c a.tar.gz | { head -c -$((512*2)); tar -C b -c .; } | gzip > a+b.tar.gz

结果:

$ tar -tzvf a+b.tar.gz 
drwxr-xr-x 0/0         0 2018-04-20 16:11:00 ./
-rw-r--r-- 0/0         0 2018-04-20 16:11:00 ./file1
drwxr-xr-x 0/0         0 2018-04-20 16:11:07 ./
-rw-r--r-- 0/0         0 2018-04-20 16:11:07 ./file2

或者您可以在同一命令中同时创建两个 tar:

$ tar -C a -c . | { head -c -$((512*2)); tar -C b -c .; } | gzip > a+b.tar.gz

尽管这是针对由 busybox tar 生成的 tar。如前一个答案所述,GNU tar 添加 20 个块的倍数。你需要强制块数为1(--blocking-factor=1)才能提前知道要切割多少块:

 $ tar --blocking-factor=1 -C a -c . | { head -c -$((512*2)); tar -C b -c .; } | gzip | tar --blocking-factor=1 -tzv

无论如何,GNU tar 确实有 --append。最后一个 --blocking-factor=1 仅当您缩进并再次附加结果 tar 时才需要。