Restore deterministic tar with pax and xattr support

- all creating and extraction of tarballs respects extended attributes
 - extended attributes require pax format, so explicitly request the
   format
 - to make pax bit-by-bit reproducible, ctime, atime and PID have to be
   removed from the headers with:
   --pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime
 - always pass --numeric-owner to tar
 - always pass --xattrs when creating a tar
 - always pass --xattrs --xattrs-include=* when extracting a tar
This commit is contained in:
Johannes 'josch' Schauer 2020-01-21 13:24:49 +01:00
parent a1df1a9730
commit 64fedc530e
Signed by: josch
GPG key ID: F2CBA5C78FBD83E1
2 changed files with 30 additions and 14 deletions

View file

@ -1585,9 +1585,9 @@ echo copy-in-customize > /tmp/copy-in-customize
echo tar-in-setup > /tmp/tar-in-setup echo tar-in-setup > /tmp/tar-in-setup
echo tar-in-essential > /tmp/tar-in-essential echo tar-in-essential > /tmp/tar-in-essential
echo tar-in-customize > /tmp/tar-in-customize echo tar-in-customize > /tmp/tar-in-customize
tar -C /tmp -cf /tmp/tar-in-setup.tar tar-in-setup tar --numeric-owner --format=pax --pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime -C /tmp -cf /tmp/tar-in-setup.tar tar-in-setup
tar -C /tmp -cf /tmp/tar-in-essential.tar tar-in-essential tar --numeric-owner --format=pax --pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime -C /tmp -cf /tmp/tar-in-essential.tar tar-in-essential
tar -C /tmp -cf /tmp/tar-in-customize.tar tar-in-customize tar --numeric-owner --format=pax --pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime -C /tmp -cf /tmp/tar-in-customize.tar tar-in-customize
rm /tmp/tar-in-setup rm /tmp/tar-in-setup
rm /tmp/tar-in-essential rm /tmp/tar-in-essential
rm /tmp/tar-in-customize rm /tmp/tar-in-customize

View file

@ -2369,7 +2369,11 @@ sub hookhelper {
# path that is valid on the outside -- fakechroot and proot have their # path that is valid on the outside -- fakechroot and proot have their
# own reasons, see below # own reasons, see below
my @cmdprefix = (); my @cmdprefix = ();
my @tarcmd = ('tar'); my @tarcmd = (
'tar', '--numeric-owner', '--xattrs', '--format=pax',
'--pax-option=exthdr.name=%d/PaxHeaders/%f,'
. 'delete=atime,delete=ctime'
);
if ($hook eq 'setup') { if ($hook eq 'setup') {
if ($mode eq 'proot') { if ($mode eq 'proot') {
# since we cannot run tar inside the chroot under proot during # since we cannot run tar inside the chroot under proot during
@ -2378,7 +2382,7 @@ sub hookhelper {
# by the user running mmdebstrap. To let the ownership # by the user running mmdebstrap. To let the ownership
# information not be completely off, we force all files be # information not be completely off, we force all files be
# owned by the root user. # owned by the root user.
push @tarcmd, '--owner=root', '--group=root'; push @tarcmd, '--owner=0', '--group=0';
} }
} elsif (any { $_ eq $hook } ('essential', 'customize')) { } elsif (any { $_ eq $hook } ('essential', 'customize')) {
if ($mode eq 'fakechroot') { if ($mode eq 'fakechroot') {
@ -2440,8 +2444,8 @@ sub hookhelper {
# open a tar process that extracts the tarfile that we # open a tar process that extracts the tarfile that we
# supply it with on stdin to the output directory inside # supply it with on stdin to the output directory inside
# the chroot # the chroot
open $fh, '|-', @cmdprefix, @tarcmd, '--directory', open $fh, '|-', @cmdprefix, @tarcmd, '--xattrs-include=*',
$directory, '--extract', '--file', '--directory', $directory, '--extract', '--file',
'-' // error "failed to fork(): $!"; '-' // error "failed to fork(): $!";
} else { } else {
error "unknown command: $command"; error "unknown command: $command";
@ -3571,10 +3575,16 @@ sub main() {
my $exitstatus = 0; my $exitstatus = 0;
my @taropts = ( my @taropts = (
'--sort=name', "--mtime=\@$mtime", '--sort=name',
'--clamp-mtime', '--numeric-owner', "--mtime=\@$mtime",
'--one-file-system', '--xattrs', '--clamp-mtime',
'-c', '--exclude=./dev' '--numeric-owner',
'--one-file-system',
'--xattrs',
'--format=pax',
'--pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime',
'-c',
'--exclude=./dev'
); );
# disable signals so that we can fork and change behaviour of the signal # disable signals so that we can fork and change behaviour of the signal
@ -3925,7 +3935,11 @@ sub main() {
# Open a tar process creating a tarfile of the instructed # Open a tar process creating a tarfile of the instructed
# path. To emulate the behaviour of cp, change to the # path. To emulate the behaviour of cp, change to the
# dirname of the requested path first. # dirname of the requested path first.
open my $fh, '-|', 'tar', '--directory', open my $fh, '-|', 'tar', '--numeric-owner', '--xattrs',
'--format=pax',
'--pax-option=exthdr.name=%d/PaxHeaders/%f,'
. 'delete=atime,delete=ctime',
'--directory',
$msg eq 'mktar' ? dirname($indir) : $indir, $msg eq 'mktar' ? dirname($indir) : $indir,
'--create', '--file', '-', '--create', '--file', '-',
$msg eq 'mktar' ? basename($indir) : '.' $msg eq 'mktar' ? basename($indir) : '.'
@ -3994,8 +4008,10 @@ sub main() {
# now we expect one or more "write" messages containing the # now we expect one or more "write" messages containing the
# tarball to unpack # tarball to unpack
open my $fh, '|-', 'tar', '--directory', $outdir, '--extract', open my $fh, '|-', 'tar', '--numeric-owner', '--xattrs',
'--file', '-' // error "failed to fork(): $!"; '--xattrs-include=*', '--directory', $outdir,
'--extract', '--file',
'-' // error "failed to fork(): $!";
# handle "write" messages from the child process and feed # handle "write" messages from the child process and feed
# their payload into the tar process until a "close" message # their payload into the tar process until a "close" message