diff options
author | Matthew Vernon <matthew@debian.org> | 2022-11-08 10:11:17 +0000 |
---|---|---|
committer | Matthew Vernon <matthew@debian.org> | 2022-11-08 10:11:17 +0000 |
commit | cdc511a457e03d84e297b66fd491ee7bccd7ad04 (patch) | |
tree | e148697f319a5a516176f7fc6243313e9197fc12 /pristine-tar | |
parent | 9401d7c09f575173d84727cae58674dbcc20106e (diff) | |
parent | 1b9f8be97b47d5fe4934073a55b725b29c12c435 (diff) |
Merge branch 'matthew_fix_manifest' into 'master'HEADdebian/1.50archive/debian/1.50master
quote manifests, fix unquoting of paths, use tar --null (closes: #1010024, #784635, #736201, #719078)
See merge request debian/pristine-tar!9
Diffstat (limited to 'pristine-tar')
-rwxr-xr-x | pristine-tar | 112 |
1 files changed, 78 insertions, 34 deletions
diff --git a/pristine-tar b/pristine-tar index 081dca1..7ec8d3e 100755 --- a/pristine-tar +++ b/pristine-tar @@ -362,6 +362,28 @@ Options: sub unquote_filename { my $filename = shift; + my %tar_escapes = ( + 'a' => "\a", + 'b' => "\b", + 'f' => "\f", + 'n' => "\n", + 'r' => "\r", + 't' => "\t", + 'v' => "\x11", + '\\' => '\\', + ); + $filename =~ s/\\([abfnrtv\\]|[0-9]{3})/$tar_escapes{$1} or chr(oct($1))/ge; + + return $filename; +} + +#This is unquote_filename from pristine-tar 1.49; it isn't correct. +#But we need to be able to identically mis-unquote paths in order to +#generate identical tarballs to those buggy versions to apply deltas +#against. +sub buggy_unquote_filename { + my $filename = shift; + $filename =~ s/\\a/\a/g; $filename =~ s/\\b/\b/g; $filename =~ s/\\f/\f/g; @@ -430,7 +452,12 @@ sub recreatetarball { # in the tarball, since it can easily vary. my $full_sweep = 0; foreach my $file (@manifest) { - my $unquoted_file = unquote_filename($file); + my $unquoted_file; + if ($options{buggy_unquote}) { + $unquoted_file = buggy_unquote_filename($file); + } else { + $unquoted_file = unquote_filename($file); + } if (-l "$tempdir/workdir/$unquoted_file") { # Can't set timestamp of a symlink, so @@ -464,7 +491,12 @@ sub recreatetarball { # Set file times only after modifying of the directory content is # done. foreach my $file (@manifest) { - my $unquoted_file = unquote_filename($file); + my $unquoted_file; + if ($options{buggy_unquote}) { + $unquoted_file = buggy_unquote_filename($file); + } else { + $unquoted_file = unquote_filename($file); + } if (-e "$tempdir/workdir/$unquoted_file") { utime(0, 0, "$tempdir/workdir/$unquoted_file") || die "utime: $file: $!"; } @@ -508,6 +540,26 @@ sub recreatetarball_helper { my %options = @_; my $tempdir = $recreatetarball_tempdir; + # Most manifests are quoted; we want to unquote and null-separate them + # to pass to tar --null --files-from. Unfortunately, some versions of + # pristine-tar wrote unquoted manifests; for many of these, unquoting + # is a no-op. + # So we try unquote-and-null-separate; if that fails, try just + # null-separate (there should be no unquoted manifests with paths with + # newlines in). + open(IN, "<", "$tempdir/manifest") || die "$tempdir/manifest: $!"; + open(OUT, ">", "$tempdir/nulledmanifest") || die "$!"; + while (<IN>) { + chomp; + if ($options{buggy_unquote}) { + print OUT buggy_unquote_filename($_) . "\0" if length $_; + } else { + print OUT unquote_filename($_) . "\0" if length $_; + } + } + close IN; + close OUT; + my $ret = "$tempdir/recreatetarball"; my @cmd = ( $tar_program, "cf", @@ -516,14 +568,26 @@ sub recreatetarball_helper { 0, "--numeric-owner", "-C", "$tempdir/workdir", "--no-recursion", "--mode", - "0644", "--verbatim-files-from", - "--files-from", "$tempdir/manifest" + "0644", "--null", + "--files-from", "$tempdir/nulledmanifest" ); if (exists $options{tar_format}) { push @cmd, ("-H", $options{tar_format}); } - doit(@cmd); + if (try_doit(@cmd) != 0) { + debug "tar failed with unquoted manifest, retrying without unquoting"; + open(IN, "<", "$tempdir/manifest") || die "$tempdir/manifest: $!"; + open(OUT, ">", "$tempdir/nulledmanifest") || die "$!"; + while (<IN>) { + chomp; + print OUT "$_\0" if length $_; + } + close IN; + close OUT; + doit(@cmd); + } +# unlink("$tempdir/nulledmanifest") || die "unlink $tempdir/nulledmanifest: $!"; return $ret; } @@ -560,33 +624,6 @@ sub recreatetarball_broken_numeric_owner { return recreatetarball_helper(); } -sub recreatetarball_broken_verbatim { - # To fix #851286, the option --verbatim-files-from was added by - # default. But now some older older stored tarballs won't reproduce - # (#933031). Try again *without* that option to tar. - my %options = @_; - my $tempdir = $recreatetarball_tempdir; - - my $ret = "$tempdir/recreatetarball"; - my @cmd = ( - $tar_program, "cf", - $ret, "--owner", - 0, "--group", - 0, "--numeric-owner", - "-C", "$tempdir/workdir", - "--no-recursion", "--mode", - "0644", - "--files-from", "$tempdir/manifest" - ); - if (exists $options{tar_format}) { - push @cmd, ("-H", $options{tar_format}); - } - - doit(@cmd); - - return $ret; -} - sub gentar { my $deltafile = shift; my $tarball = shift; @@ -624,6 +661,14 @@ sub gentar { %opts ); }; + push @try, sub { + recreatetarball( + $delta->{manifest}, getcwd, + clobber_source => 0, + buggy_unquote => 1, + %opts + ); + }; push @try, \&recreatetarball_longlink_100; push @try, sub { recreatetarball( @@ -641,7 +686,6 @@ sub gentar { %opts ); }; - push @try, \&recreatetarball_broken_verbatim; push @try, \&recreatetarball_broken_numeric_owner; my $ok; @@ -692,7 +736,7 @@ sub genmanifest { chomp; # ./ or / in the manifest just confuses tar s/^\.?\/+//; - print OUT unquote_filename($_) . "\n" if length $_; + print OUT "$_\n" if length $_; } close IN; close OUT; |