从理论上讲可以做到。但这非常丑陋,本质上涉及手动构建档案。
我们面对的是什么
该tar
格式适用于512字节的块。此大小是固定的,旨在与传统磁盘扇区大小匹配。将文件存储在档案中时,第一个512字节块是包含文件元数据(名称,大小,类型等)的标头,随后的块包含文件内容。因此,我们的存档数据将错位512个字节。
btrfs的块大小(“ --sectorsize”)通常为4096个字节。从理论上讲,我们可以选择此选项,但实际上,它看起来必须与CPU的页面大小相匹配。因此,我们不能缩小btrfs的块。
该tar
程序具有较大的“记录”大小的概念,定义为块大小的倍数,几乎看起来像是有用的。事实证明,这是为了指定给定磁带驱动器的扇区大小,这样tar
可以避免写入部分磁带记录。但是,数据仍以512字节为单位进行构造和打包,因此我们不能tar
像您希望的那样使用它来增加的块。
数据的最后一点知道的是,tar
的归档结束的标志物是两个连续的全零块,除非这些块内的文件数据。因此,任何天真的填充块都不会被接受。
骇客
我们可以做的是插入填充文件。在存档的开头,在添加要删除重复数据的文件(称为dup
)之前,我们添加了一个文件pad
,大小为
pad's header + pad's data + dup's header = 4096 bytes.
这样,dup
的数据就从块边界开始,可以进行重复数据删除。
然后,对于每个后续文件,我们还必须跟踪先前文件的大小,以便计算正确的填充。我们还必须预测是否需要某种标头扩展名:例如,基本的tar标头仅可容纳100个字节的文件路径,因此,较长的路径使用结构上专门命名的文件(其数据为完整的路径。通常,预测标头大小有很多潜在的复杂性- tar
文件格式受多种历史实现的影响很大。
一个小的缺点是,所有填充文件都可以共享相同的名称,因此,当我们解压缩时,最终只会得到一个单独的小于4096字节的文件。
可靠地创建归档文件的最简洁方法可能是修改GNU tar
程序。但是,如果您想快速又脏又浪费CPU和I / O时间,则可以针对每个文件执行以下操作:
#!/bin/bash
# Proof of concept and probably buggy.
# If I ever find this script in a production environment,
# I don't know whether I'll laugh or cry.
my_file="$2"
my_archive="$1"
file_size="$(wc -c <"$my_file")"
arch_size="$(tar cb 1 "$my_file" | wc -c)" # "b 1": Remember that record size I mentioned? Set it to equal the block size so we can measure usefully.
end_marker_size=1024 # End-of-archive marker: 2 blocks' worth of 0 bytes
hdr_size="$(( (arch_size - file_size - end_marker_size) % 4096 ))"
pad_size="$(( (4096 - 512 - hdr_size) % 4096 ))"
(( pad_size < 512 )) && pad_size="$(( pad_size + 4096 ))"
# Assume the pre-existing archive is already a multiple of 4096 bytes long
# (not including the end-of-archive marker), and add extra padding to the end
# so that it stays that way.
file_blocks_size="$(( ((file_size+511) / 512) * 512 ))"
end_pad_size="$(( 4096 - 512 - (file_blocks_size % 4096) ))"
(( end_pad_size < 512 )) && end_pad_size="$(( end_pad_size + 4096 ))"
head -c $pad_size /dev/zero > _PADDING_
tar rf "$my_archive" _PADDING_ "$my_file"
head -c $end_pad_size /dev/zero > _PADDING_
tar rf "$my_archive" _PADDING_