É possível recriar uma estrutura de diretórios que crie um fluxo de saída bsdcpio idêntico binário?

1

A criação de arquivos initramfs a partir do script resulta em arquivos cmp binários não comparáveis, embora diff -r /rootfs1/ /rootfs2/ exista com 0 , portanto diff não encontre diferenças.

As diferenças que posso encontrar são as datas Acesso e Alterar . Por exemplo:

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

Regressão

  1. Verifiquei que o comando find retorna todos os itens do diretório exatamente na mesma ordem, OK.

  2. Eu tentei toque em cada entrada nas estruturas de diretório para um arquivo de origem idêntico . Ainda sem sorte para criar um fluxo de bytes idêntico.

  3. As imagens initramfs lz4 -l bsdcpio resultantes já diferem no byte 5:

    $ cmp /tmp/1.img /tmp/2.img e /tmp/rootfs1/initramfs.img /tmp/rootfs2/initramfs.img differ: char 5, line 1

  4. mount -o remount,noatime /tmp ainda atualiza " tempo da última alteração de status " de acordo com stat %z

O código de script bsdcpio é como:

pushd "$BUILDROOT" >/dev/null
find -mindepth 1 -printf '%P
# 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: -
' | LANG=C bsdcpio -0 -o -H newc | lz4 -l > "$out"

Existe alguma chance de ter um fluxo de bytes de saída idêntico para execuções consecutivas de scripts, em que $ BUILDROOT é uma nova pasta temporária em cada execução?

    
por Pro Backup 12.12.2017 / 02:20

1 resposta

1

O tempo de acesso e a hora da alteração não são armazenados na estrutura do cpio newc. O que é, no entanto, é o número do inode e o número do dispositivo do sistema de arquivos.

           struct cpio_newc_header {
                   char    c_magic[6];
                   char    c_ino[8];
                   char    c_mode[8];
                   char    c_uid[8];
                   char    c_gid[8];
                   char    c_nlink[8];
                   char    c_mtime[8];
                   char    c_filesize[8];
                   char    c_devmajor[8];
                   char    c_devminor[8];
                   char    c_rdevmajor[8];
                   char    c_rdevminor[8];
                   char    c_namesize[8];
                   char    c_check[8];
           };

Você pode replicar números de inode consistentemente extraindo os arquivos em um novo sistema de arquivos a cada vez, mas você não poderá ter duas estruturas de diretório separadas que existam no mesmo ponto no tempo produzindo o mesmo arquivo cpio que a combinação de dev + ino é por design exclusivo em um determinado sistema.

Para produzir um arquivo cpio consistente, você precisaria criar um novo sistema de arquivos a cada vez, e garantir que ele recebesse o mesmo número de dispositivo, e garantir que cada arquivo recebesse o mesmo número de inode a cada vez.

Ou, como alternativa, você poderia pós-processar o arquivo cpio resultante para substituir os números de dispositivo e inode. Algo como:

printf '%s
           struct cpio_newc_header {
                   char    c_magic[6];
                   char    c_ino[8];
                   char    c_mode[8];
                   char    c_uid[8];
                   char    c_gid[8];
                   char    c_nlink[8];
                   char    c_mtime[8];
                   char    c_filesize[8];
                   char    c_devmajor[8];
                   char    c_devminor[8];
                   char    c_rdevmajor[8];
                   char    c_rdevminor[8];
                   char    c_namesize[8];
                   char    c_check[8];
           };
' **/*(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, "") }'

Onde o dev é codificado como 1 e inode é incrementado de 1 para cada entrada (mas ainda é igual para hardlinks).

Usando zsh ' **/*(D) para obter uma lista classificada de caminhos de arquivo em vez de find , cuja ordem não é garantida como consistente.

    
por 12.12.2017 / 13:50