从脚本构建 initramfs 文件会产生二进制不可比较的cmp
文件,即使diff -r /rootfs1/ /rootfs2/
退出0
也diff
不会发现任何差异。
我发现的差异是使用权和改变日期。例如:
# stat /rootfs1/config
File: /rootfs1/config
Size: 275 Blocks: 8 IO Block: 4096 regular file
Device: 28h/40d Inode: 119120 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2017-12-12 01:31:03.800453381 +0100
Modify: 2017-12-05 20:11:38.000000000 +0100
Change: 2017-12-12 01:02:38.607238288 +0100
Birth: -
# stat /rootfs2/config
File: /rootfs2/config
Size: 275 Blocks: 8 IO Block: 4096 regular file
Device: 28h/40d Inode: 119881 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2017-12-12 01:28:02.913799257 +0100
Modify: 2017-12-05 20:11:38.000000000 +0100
Change: 2017-12-12 01:20:44.920496295 +0100
Birth: -
回归
我已经检查过该
find
命令以完全相同的顺序返回所有目录项,好的。我尝试过了touch 将目录结构中的每个条目引用到相同的源文件。仍然没有运气创建相同的字节流。
生成的 initramfs映像
lz4 -l
bsdcpio
在字节 5 处已经不同:$ cmp /tmp/1.img /tmp/2.img
/tmp/rootfs1/initramfs.img /tmp/rootfs2/initramfs.img differ: char 5, line 1
mount -o remount,noatime /tmp
仍然更新”最后一次状态改变的时间“ 根据stat %z
bsdcpio 脚本代码如下:
pushd "$BUILDROOT" >/dev/null
find -mindepth 1 -printf '%P\0' | LANG=C bsdcpio -0 -o -H newc | lz4 -l > "$out"
是否有可能为连续脚本运行提供相同的输出字节流,其中 $BUILDROOT 是每次运行时的新临时文件夹?
答案1
访问时间和更改时间不存储在 cpio newc 结构中。但实际上是索引节点号和文件系统的设备号。
结构 cpio_newc_header { char c_magic[6]; 字符 c_ino[8]; 字符 c_mode[8]; char c_uid[8]; 字符c_gid[8]; 字符c_nlink[8]; char c_mtime[8]; char c_filesize[8]; 字符 c_devmajor[8]; 字符 c_devminor[8]; char c_rdevmajor[8]; 字符 c_rdevminor[8]; char c_namesize[8]; 字符c_check[8]; };
您可以通过每次提取新文件系统中的文件来一致地复制 inode 编号,但您将无法让同一时间点存在的两个单独的目录结构生成与 dev+ 组合相同的 cpio 存档ino 在设计上在给定系统上是唯一的。
要生成一致的 cpio 存档,您需要每次创建一个新的文件系统,并确保为其分配相同的设备编号,并确保每次为每个文件分配相同的 inode 编号。
或者,您可以对生成的 cpio 存档进行后处理以替换设备和 inode 编号。就像是:
printf '%s\0' **/*(D) | bsdcpio -0 -o -H newc | perl -0777 -pe '
$dev = sprintf("%016x", 1);
while (substr($_, 0, 6) eq "070701") {
($inode, $size, $nsize) = map hex, unpack("x6a8x40a8x32a8", $_);
$nsize += (2-$nsize) % 4; $size += (-$size) % 4;
$inode{$inode} ||= ++$n;
substr($_, 6, 8) = sprintf("%08x", $inode{$inode});
substr($_, 62, 16) = $dev;
print substr($_, 0, 110+$size+$nsize, "")
}'
哪里的开发者是硬编码的1
,每个条目的 inode 从 1 开始递增(但硬链接仍然相等)。
使用zsh
'**/*(D)
来获取文件路径的排序列表,而不是find
' ,其顺序不能保证一致。