dpkg (1.18.25) stretch; urgency=medium
[dpkg] / lib / dpkg / t / t-tarextract.t
CommitLineData
1479465f
GJ
1#!/usr/bin/perl
2#
3# Copyright © 2014 Guillem Jover <guillem@debian.org>
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program. If not, see <https://www.gnu.org/licenses/>.
17
18use Test::More;
19use Cwd;
20use File::Path qw(make_path remove_tree);
21use File::Temp qw(tempdir);
22use File::Spec;
23use File::Find;
24use POSIX qw(mkfifo);
25
26use Dpkg ();
27use Dpkg::IPC;
28
29use strict;
30use warnings;
31use version;
32
33my $srcdir = $ENV{srcdir} || '.';
34my $builddir = $ENV{builddir} || '.';
35my $tmpdir = 't.tmp/t-tarextract';
36
37# We require GNU tar >= 1.27 for --owner=NAME:ID and --group=NAME:ID.
38my $tar_version = qx($Dpkg::PROGTAR --version 2>/dev/null);
39if ($tar_version and $tar_version =~ m/^tar \(GNU tar\) (\d+\.\d+)/ and
40 qv("v$1") >= qv('v1.27'))
41{
42 plan tests => 12;
43} else {
44 plan skip_all => 'needs GNU tar >= 1.27';
45}
46
47# Set a known umask.
48umask 0022;
49
50sub create {
51 my ($pathname) = @_;
52
53 open my $fh, '>>', $pathname or die "cannot touch $pathname: $!";
54 close $fh;
55}
56
57sub tar_create_tree {
58 my $type = shift;
59
60 my $long_a = 'a' x 29;
61 my $long_b = 'b' x 29;
62 my $long_c = 'c' x 29;
63 my $long_d = 'd' x 29;
64 my $long_e = 'e' x 29;
65 my $long_f = 'f' x 22;
66
67 # Populate tar hierarchy
68 create('file');
69 link 'file', 'hardlink';
70
71 make_path("$long_a/$long_b/$long_c/$long_d/$long_e/");
72 make_path("$long_a/$long_b/$long_c/$long_d/$long_e/$long_f/");
73 create("$long_a/$long_b/$long_c/$long_d/$long_e/$long_f/long");
74
75 # POSIX specifies that symlinks have undefined permissions in their
76 # mode, so their handling is system dependent. Linux does not honor
77 # the umask for symlinks, other systems like GNU/Hurd or kFreeBSD do,
78 # which means we get different results due to this.
79 my $umask = umask 0;
80
81 symlink "$long_a/$long_b/$long_c/$long_d/$long_e/$long_f/long",
82 'symlink-long';
83 symlink 'file', 'symlink-a';
84 symlink 'hardlink', 'symlink-b';
85 symlink 'dangling', 'symlink-c';
86
87 umask $umask;
88
89 mkdir 'directory';
90 mkfifo('fifo', 0770);
91
92 # FIXME: Need root.
93 # system 'mknod', 'chardev', 'c', '1', '3';
94 # system 'mknod', 'blockdev', 'b', '0', '0';
95}
96
97sub test_tar_extractor {
98 my $stdout;
99 my $stderr;
100
101 my $expected_tar = <<'TAR';
102. mode=40755 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=dir
103./fifo mode=10750 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=fifo
104./file mode=100644 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=file size=0
105./hardlink mode=100644 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=hardlink linkto=./file size=0
106./aaaaaaaaaaaaaaaaaaaaaaaaaaaaa mode=40755 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=dir
107./aaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbb mode=40755 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=dir
108./aaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ccccccccccccccccccccccccccccc mode=40755 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=dir
109./aaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ccccccccccccccccccccccccccccc/ddddddddddddddddddddddddddddd mode=40755 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=dir
110./aaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ccccccccccccccccccccccccccccc/ddddddddddddddddddddddddddddd/eeeeeeeeeeeeeeeeeeeeeeeeeeeee mode=40755 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=dir
111./aaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ccccccccccccccccccccccccccccc/ddddddddddddddddddddddddddddd/eeeeeeeeeeeeeeeeeeeeeeeeeeeee/ffffffffffffffffffffff mode=40755 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=dir
112./aaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ccccccccccccccccccccccccccccc/ddddddddddddddddddddddddddddd/eeeeeeeeeeeeeeeeeeeeeeeeeeeee/ffffffffffffffffffffff/long mode=100644 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=file size=0
113./directory mode=40755 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=dir
114./symlink-a mode=120777 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=symlink linkto=file size=0
115./symlink-b mode=120777 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=symlink linkto=hardlink size=0
116./symlink-c mode=120777 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=symlink linkto=dangling size=0
117./symlink-long mode=120777 time=100000000.000000000 uid=100 gid=200 uname=user gname=group type=symlink linkto=aaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ccccccccccccccccccccccccccccc/ddddddddddddddddddddddddddddd/eeeeeeeeeeeeeeeeeeeeeeeeeeeee/ffffffffffffffffffffff/long size=0
118TAR
119
120 make_path($tmpdir);
121
122 my $cwd = cwd();
123
124 # Check generated tarballs.
125 foreach my $type (qw(v7 ustar oldgnu gnu)) {
126 my $dirtree = "$tmpdir/$type";
127 my @paths;
128
129 mkdir $dirtree;
130 chdir $dirtree;
131 tar_create_tree($type);
132 find({ no_chdir => 1, wanted => sub {
133 return if $type eq 'v7' and length > 99;
134 return if $type eq 'v7' and -l and length readlink > 99;
135 return if $type eq 'v7' and not (-f or -l or -d);
136 return if $type eq 'ustar' and length > 256;
137 return if $type eq 'ustar' and -l and length readlink > 100;
138 push @paths, $_;
139 },
140 preprocess => sub { my (@files) = sort @_; @files } }, '.');
141 chdir $cwd;
142
143 my $paths_list = join "\0", @paths;
144 spawn(exec => [ $Dpkg::PROGTAR, '-cf', "$dirtree.tar",
145 '--format', $type,
146 '-C', $dirtree, '--mtime=@100000000',
147 '--owner=user:100', '--group=group:200',
148 '--null', '--no-unquote', '--no-recursion', '-T-' ],
149 wait_child => 1, from_string => \$paths_list);
150
151 my $expected = $expected_tar;
152 $expected =~ s/[ug]name=[^ ]+ //g if $type eq 'v7';
153 $expected =~ s/\n^.*fifo.*$//mg if $type eq 'v7';
154 $expected =~ s/\n^.*dddd.*$//mg if $type eq 'v7';
155 $expected =~ s/\n^.*symlink-long.*$//mg if $type eq 'ustar';
156
157 spawn(exec => [ './c-tarextract', "$dirtree.tar" ],
158 nocheck => 1, to_string => \$stdout, to_error => \$stderr);
159 ok($? == 0, "tar extractor $type should succeed");
160 is($stderr, undef, "tar extractor $type stderr is empty");
161 is($stdout, $expected, "tar extractor $type is ok");
162 }
163}
164
165test_tar_extractor();