Commit 9ffc6b47 authored by Kevin Locke's avatar Kevin Locke
Browse files

pristine-xz: Handle pixz tar index



When compressing a tar file, unless the `-t` option is passed, `pixz`
adds a data block to the end of the xz stream which contains an index of
the tar file contents.  During decompression, `xz` assumes the data
block contains file data and appends the decompressed data to the output
file.  This confuses pristine-xz, since there is no way to compress the
data+index such that it matches the original.  To avoid this, use `pixz`
to decompress, when available.

When a pixz tar index is present (detected using `pixz -l`), skip
compression testing with `xz`, since we know it won't work.  This saves
significant time for large archives.

Fixes: #859303

Signed-off-by: Kevin Locke's avatarKevin Locke <kevin@kevinlocke.name>
parent 52154d6f
Loading
Loading
Loading
Loading
+22 −4
Original line number Diff line number Diff line
@@ -176,6 +176,17 @@ sub scan_xz_lvv_robot {
  return \%xz;
}

sub check_pixz_tar_index {
  my ($filename) = @_;
  open(my $pixz, '-|', 'pixz', '-l', $filename) or return;
  my $line = <$pixz>;
  chomp $line;
  close $pixz;
  # If the file has a tar index, pixz -l prints file names, one per line.
  # If not, pixz -l prints ("%9u / %9u", compressed, uncompressed) block sizes.
  return ($line and $line !~ /^ *[0-9]+ \/ +[0-9]+$/);
}

sub predict_xz_args {
  my ($xz, $program) = @_;
  my $presets    = undef;
@@ -267,10 +278,14 @@ sub readxz {
  # lzma2_presets_from_dict_size_of in predict_xz_args) or if --extreme
  # was used. We output possible args for each combination in this case.
  my $xz                 = scan_xz_lvv_robot($filename);
  my $has_pixz_tar_index = scalar(@{ $xz->{blocks} }) > 1
    and check_pixz_tar_index($filename);
  my $possible_args      = [];
  foreach my $program (@supported_xz_programs) {
    if (!$has_pixz_tar_index or $program eq 'pixz') {
      push @$possible_args, @{ predict_xz_args($xz, $program) };
    }
  }
  return $possible_args;
}

@@ -330,7 +345,10 @@ sub reproducexz {
  my $wd = tempdir();

  my $tmpin = "$wd/test";
  doit_redir($orig, $tmpin, "xz", "-dc");
  # When a file with a pixz tar index is decompressed by xz, the index is
  # appended to the end of the decompressed tar file.  So try pixz first.
  eval { doit_redir($orig, $tmpin, "pixz", "-d") };
  doit_redir($orig, $tmpin, "xz", "-dc") if ($@);

  # read fields from xz headers
  my $possible_args;