1BEGIN { chdir 't' if -d 't' }
2
3use Test::More      'no_plan';
4use File::Basename  'basename';
5use strict;
6use lib '../lib';
7
8my $NO_UNLINK   = @ARGV ? 1 : 0;
9
10my $Class       = 'Archive::Tar';
11my $FileClass   = $Class . '::File';
12
13use_ok( $Class );
14use_ok( $FileClass );
15
16### bug #13636
17### tests for @longlink behaviour on files that have a / at the end
18### of their shortened path, making them appear to be directories
19{   ok( 1,                      "Testing bug 13636" );
20
21    ### dont use the prefix, otherwise A::T will not use @longlink
22    ### encoding style
23    local $Archive::Tar::DO_NOT_USE_PREFIX = 1;
24    local $Archive::Tar::DO_NOT_USE_PREFIX = 1;
25
26    my $dir =   'Catalyst-Helper-Controller-Scaffold-HTML-Template-0_03/' .
27                'lib/Catalyst/Helper/Controller/Scaffold/HTML/';
28    my $file =  'Template.pm';
29    my $out =   $$ . '.tar';
30
31    ### first create the file
32    {   my $tar = $Class->new;
33
34        isa_ok( $tar, $Class,   "   Object" );
35        ok( $tar->add_data( $dir.$file => $$ ),
36                                "       Added long file" );
37
38        ok( $tar->write($out),  "       File written to $out" );
39    }
40
41    ### then read it back in
42    {   my $tar = $Class->new;
43        isa_ok( $tar, $Class,   "   Object" );
44        ok( $tar->read( $out ), "       Read in $out again" );
45
46        my @files = $tar->get_files;
47        is( scalar(@files), 1,  "       Only 1 entry found" );
48
49        my $entry = shift @files;
50        ok( $entry->is_file,    "       Entry is a file" );
51        is( $entry->name, $dir.$file,
52                                "       With the proper name" );
53    }
54
55    ### remove the file
56    unless( $NO_UNLINK ) { 1 while unlink $out }
57}
58
59### bug #14922
60### There's a bug in Archive::Tar that causes a file like: foo/foo.txt
61### to be stored in the tar file as: foo/.txt
62### XXX could not be reproduced in 1.26 -- leave test to be sure
63{   ok( 1,                      "Testing bug 14922" );
64
65    my $dir     = $$ . '/';
66    my $file    = $$ . '.txt';
67    my $out     = $$ . '.tar';
68
69    ### first create the file
70    {   my $tar = $Class->new;
71
72        isa_ok( $tar, $Class,   "   Object" );
73        ok( $tar->add_data( $dir.$file => $$ ),
74                                "       Added long file" );
75
76        ok( $tar->write($out),  "       File written to $out" );
77    }
78
79    ### then read it back in
80    {   my $tar = $Class->new;
81        isa_ok( $tar, $Class,   "   Object" );
82        ok( $tar->read( $out ), "       Read in $out again" );
83
84        my @files = $tar->get_files;
85        is( scalar(@files), 1,  "       Only 1 entry found" );
86
87        my $entry = shift @files;
88        ok( $entry->is_file,    "       Entry is a file" );
89        is( $entry->full_path, $dir.$file,
90                                "       With the proper name" );
91    }
92
93    ### remove the file
94    unless( $NO_UNLINK ) { 1 while unlink $out }
95}
96
97### bug #30380: directory traversal vulnerability in Archive-Tar
98### Archive::Tar allowed files to be extracted to a dir outside
99### it's cwd(), effectively allowing you to overwrite any files
100### on the system, given the right permissions.
101{   ok( 1,                      "Testing bug 30880" );
102
103    my $tar = $Class->new;
104    isa_ok( $tar, $Class,       "   Object" );
105
106    ### absolute paths are already taken care of. Only relative paths
107    ### matter
108    my $in_file     = basename($0);
109    my $out_file    = '../' . $in_file . "_$$";
110
111    ok( $tar->add_files( $in_file ),
112                                "       Added '$in_file'" );
113
114    ok( $tar->chmod( $in_file, '1777'),
115                                "       chmod 177 $in_file" );
116
117    ok( $tar->chown( $in_file, 'root' ),
118                                "       chown to root" );
119
120    ok( $tar->chown( $in_file, 'root', 'root' ),
121                                "       chown to root:root" );
122
123    ok( $tar->rename( $in_file, $out_file ),
124                                "       Renamed to '$out_file'" );
125
126    ### first, test with strict extract permissions on
127    {   local $Archive::Tar::INSECURE_EXTRACT_MODE = 0;
128
129        ### we quell the error on STDERR
130        local $Archive::Tar::WARN = 0;
131        local $Archive::Tar::WARN = 0;
132
133        ok( 1,                  "   Extracting in secure mode" );
134
135        ok( ! $tar->extract_file( $out_file ),
136                                "       File not extracted" );
137        ok( ! -e $out_file,     "       File '$out_file' does not exist" );
138
139        ok( $tar->error,        "       Error message stored" );
140        like( $tar->error, qr/attempting to leave/,
141                                "           Proper violation detected" );
142    }
143
144    ### now disable those
145    {   local $Archive::Tar::INSECURE_EXTRACT_MODE = 1;
146        ok( 1,                  "   Extracting in insecure mode" );
147
148        ok( $tar->extract_file( $out_file ),
149                                "       File extracted" );
150        ok( -e $out_file,       "       File '$out_file' exists" );
151
152        ### and clean up
153        unless( $NO_UNLINK ) { 1 while unlink $out_file };
154    }
155}
156
157### bug #43513: [PATCH] Accept wrong checksums from SunOS and HP-UX tar
158### like GNU tar does. See here for details:
159### http://www.gnu.org/software/tar/manual/tar.html#SEC139
160SKIP: {
161    skip "File contains an alien character set", 5 if ord "A" != 65;
162
163    ok( 1,                      "Testing bug 43513" );
164
165    my $src = File::Spec->catfile( qw[src header signed.tar] );
166    my $tar = $Class->new;
167
168    isa_ok( $tar, $Class,       "   Object" );
169    ok( $tar->read( $src ),     "   Read non-Posix file with signed Checksum" );
170
171    for my $file ( $tar->get_files ) {
172        ok( $file,              "       File object retrieved" );
173        ok( $file->validate,    "           File validates" );
174    }
175}
176
177### return error properly on corrupted archives
178### Addresses RT #44680: Improve error reporting on short corrupted archives
179{   ok( 1,                      "Testing bug 44680" );
180
181    {   ### XXX whitebox test -- resetting the error string
182        no warnings 'once';
183        $Archive::Tar::error = "";
184    }
185
186    my $src = File::Spec->catfile( qw[src short b] );
187    my $tar = $Class->new;
188
189    isa_ok( $tar, $Class,       "   Object" );
190
191
192    ### we quell the error on STDERR
193    local $Archive::Tar::WARN = 0;
194
195    ok( !$tar->read( $src ),    "   No files in the corrupted archive" );
196    like( $tar->error, qr/enough bytes/,
197                                "       Expected error reported" );
198}
199
200### bug #78030
201### tests for symlinks with relative paths
202### seen on MSWin32
203if ($^O ne 'msys') # symlink tests fail on Windows/msys2
204{   ok( 1,                      "Testing bug 78030" );
205		my $archname = 'tmp-symlink.tar.gz';
206		{	#build archive
207			unlink $archname if -e $archname;
208			local $Archive::Tar::DO_NOT_USE_PREFIX = 1;
209			my $t=Archive::Tar->new;
210			my $f = $t->add_data( 'tmp/a/b/link.txt', '',
211				{
212					linkname => '../c/ori.txt',
213					type     => 2,
214				} );
215			#why doesn't it keep my wish?
216			$f->{name}   = 'tmp/a/b/link.txt';
217			$f->{prefix} = '';
218			$t->add_data( 'tmp/a/c/ori.txt', 'test case' );
219			$t->write( $archname, 1 );
220		}
221
222    { #use case 1 - in memory extraction
223			my $t=Archive::Tar->new;
224			$t->read( $archname );
225			my $r = eval{ $t->extract };
226			ok( $r && !$@,            "   In memory extraction/symlinks" );
227			ok((stat 'tmp/a/b/link.txt')[7] == 9,
228			                          "       Linked content" ) unless $r;
229			clean_78030();
230		}
231
232		{ #use case 2 - iter extraction
233		  #$DB::single = 2;
234			my $next=Archive::Tar->iter( $archname, 1 );
235			my $failed = 0;
236			#use Data::Dumper;
237			while(my $f = $next->() ){
238			#  print "\$f = ", Dumper( $f ), $/;
239				eval{ $f->extract } or $failed++;
240			}
241			ok( !$failed,             "   From disk extraction/symlinks" );
242			ok((stat 'tmp/a/b/link.txt')[7] == 9,
243			                          "       Linked content" ) unless $failed;
244		}
245
246    #remove tmp files
247		sub clean_78030{
248			unlink for ('tmp/a/c/ori.txt', 'tmp/a/b/link.txt');
249			rmdir for ('tmp/a/c', 'tmp/a/b', 'tmp/a', 'tmp');
250		}
251		clean_78030();
252		unlink $archname;
253}
254
255### bug 97748
256### retain leading '/' for absolute pathnames.
257{   ok( 1,                      "Testing bug 97748" );
258	my $path= '/absolute/path';
259	my $tar = $Class->new;
260	isa_ok( $tar, $Class,       "   Object" );
261	my $file;
262
263	ok( $file = $tar->add_data( $path, '' ),
264		"       Added $path" );
265
266	ok( $file->full_path eq $path,
267		"	Paths mismatch <" . $file->full_path . "> ne <$path>" );
268}
269
270### bug 103279
271### retain trailing whitespace on filename
272{
273  ok( 1,                      "Testing bug 103279" );
274	my $tar = $Class->new;
275	isa_ok( $tar, $Class,       "   Object" );
276	ok( $tar->add_data( 'white_space   ', '' ),
277				    "   Add file <white_space   > containing filename with trailing whitespace");
278	ok( $tar->extract(),        "	Extract filename with trailing whitespace" );
279  SKIP: {
280    skip "Windows tries to be clever", 1 if $^O eq 'MSWin32';
281	  ok( ! -e 'white_space',     "	<white_space> should not exist" );
282  }
283	ok( -e 'white_space   ',    "	<white_space   > should exist" );
284	unlink foreach ('white_space   ', 'white_space');
285}
286