【问题标题】:BusyBox tar: append workaround given limited disk space?BusyBox tar:在磁盘空间有限的情况下追加解决方法?
【发布时间】:2015-05-13 13:41:20
【问题描述】:

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

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

这意味着我要归档的文件最终位于两个不同的位置。但我希望生成的 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

【问题讨论】:

    标签: linux bash tar busybox


    【解决方案1】:

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

    一个 tar 文件由任意数量的 header + file 重复组成。标头始终是单个 512 字节块,文件被填充为 512 字节的倍数,因此您可以将这些单元视为可变数量的 512 字节块。每个块都是独立的;它的标题以文件的完整路径名开头。因此,不需要将目录中的文件打包在一起。

    有一个并发症。在 tar 文件的末尾,至少有两个 512 字节的块完全用 0 填充。当 tar 正在读取一个 tar 文件时,它会忽略一个零填充的标题,但第二个会导致它停止读取文件。如果遇到 EOF,它会报错,因此需要终止空头。

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

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

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

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

    我会做的是:

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

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

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

    【讨论】:

    • 该过程是否适用于所有有效的 tar 文件,无论其内容如何?
    • @user1011471:我不明白为什么不这样做。
    • 我问的原因是因为有些文件本身就是.gz文件。你写道“如果你知道文件本身没有 NUL 字节(即它们都是简单的文本文件),你可以删除空标题,直到你找到一个包含非 0 字节的块”......和 ...“如果 tar 文件的最后 512 个字节全为 0” ...
    • 啊,但压缩后的文件可能不会包含整个 512 个零的块,正在压缩。
    • @user1011471:我提出的算法不依赖于没有 nul 字节的文件。仅截断块直到找到一个不全为零的更简单算法确实取决于此功能,这就是我拒绝它的原因。
    【解决方案2】:

    最好的解决方案是剪切最后的 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 时才需要。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-03
      • 2017-07-18
      • 2021-10-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-26
      • 1970-01-01
      相关资源
      最近更新 更多