是否可以重新创建一个目录结构来创建二进制相同的 bsdcpio 输出流?

是否可以重新创建一个目录结构来创建二进制相同的 bsdcpio 输出流?

从脚本构建 initramfs 文件会产生二进制不可比较的cmp文件,即使diff -r /rootfs1/ /rootfs2/退出0diff不会发现任何差异。

我发现的差异是使用权改变日期。例如:

# 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: -

回归

  1. 我已经检查过该find命令以完全相同的顺序返回所有目录项,好的。

  2. 我尝试过了touch 将目录结构中的每个条目引用到相同的源文件。仍然没有运气创建相同的字节流。

  3. 生成的 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

  4. 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' ,其顺序不能保证一致。

相关内容