import-tars: read overlong names from pax extended header
Importing gcc tarballs[1] with import-tars script (in contrib) fails when hitting a pax extended header. Make sure we always read the extended attributes from the pax entries, and store the 'path' value if found to be used in the next ustar entry. The code to parse pax extended headers was written consulting the Pax Pax Interchange Format documentation [2]. [1] http://ftp.gnu.org/gnu/gcc/gcc-7.3.0/gcc-7.3.0.tar.xz [2] https://www.freebsd.org/cgi/man.cgi?manpath=FreeBSD+8-current&query=tar&sektion=5 Signed-off-by: Pedro Alvarez <palvarez89@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Pedro Alvarez Piedehierro committed
May 23, 2018 at 23:54 UTC
12ecea46e3a7542918efaf595fd866e74d3dba3d
1 file changed
+29
-2
contrib/fast-import/import-tars.perl
+29
-2
@@ -63,6 +63,8 @@ foreach my $tar_file (@ARGV)
63
my $have_top_dir = 1;
64
my ($top_dir, %files);
65
66
+ my $next_path = '';
67
+
68
while (read(I, $_, 512) == 512) {
69
my ($name, $mode, $uid, $gid, $size, $mtime,
70
$chksum, $typeflag, $linkname, $magic,
@@ -70,6 +72,13 @@ foreach my $tar_file (@ARGV)
72
$prefix) = unpack 'Z100 Z8 Z8 Z8 Z12 Z12
73
Z8 Z1 Z100 Z6
74
Z2 Z32 Z32 Z8 Z8 Z*', $_;
75
+
76
+ unless ($next_path eq '') {
77
+ # Recover name from previous extended header
78
+ $name = $next_path;
79
+ $next_path = '';
80
+ }
81
+
82
last unless length($name);
83
if ($name eq '././@LongLink') {
84
# GNU tar extension
@@ -90,13 +99,31 @@ foreach my $tar_file (@ARGV)
99
Z8 Z1 Z100 Z6
100
Z2 Z32 Z32 Z8 Z8 Z*', $_;
101
}
93
- next if $name =~ m{/\z};
102
$mode = oct $mode;
103
$size = oct $size;
104
$mtime = oct $mtime;
105
next if $typeflag == 5; # directory
106
99
- if ($typeflag != 1) { # handle hard links later
107
+ if ($typeflag eq 'x') { # extended header
108
+ # If extended header, check for path
109
+ my $pax_header = '';
110
+ while ($size > 0 && read(I, $_, 512) == 512) {
111
+ $pax_header = $pax_header . substr($_, 0, $size);
112
+ $size -= 512;
113
+ }
114
+
115
+ my @lines = split /\n/, $pax_header;
116
+ foreach my $line (@lines) {
117
+ my ($len, $entry) = split / /, $line;
118
+ my ($key, $value) = split /=/, $entry;
119
+ if ($key eq 'path') {
120
+ $next_path = $value;
121
+ }
122
+ }
123
+ next;
124
+ } elsif ($name =~ m{/\z}) { # directory
125
+ next;
126
+ } elsif ($typeflag != 1) { # handle hard links later
127
print FI "blob\n", "mark :$next_mark\n";
128
if ($typeflag == 2) { # symbolic link
129
print FI "data ", length($linkname), "\n",