File Coverage

lib/Archive/Extract.pm
Criterion Covered Total %
statement 377 526 71.6
branch 144 280 51.4
condition 40 67 59.7
subroutine 72 79 91.1
pod 19 24 79.1
total 652 976 66.8


line stmt bran cond sub pod time code
1             package Archive::Extract;
2 1     1   1803 use if $] > 5.017, 'deprecate';
  1         15  
  1         6  
3              
4 1     1   1320 use strict;
  1         3  
  1         25  
5              
6 1     1   5 use Cwd qw[cwd chdir];
  1         2  
  1         71  
7 1     1   6 use Carp qw[carp];
  1         2  
  1         45  
8 1     1   721 use IPC::Cmd qw[run can_run];
  1         36932  
  1         91  
9 1     1   11 use FileHandle;
  1         2  
  1         8  
10 1     1   357 use File::Path qw[mkpath];
  1         2  
  1         54  
11 1     1   5 use File::Spec;
  1         2  
  1         74  
12 1     1   7 use File::Basename qw[dirname basename];
  1         3  
  1         74  
13 1     1   6 use Params::Check qw[check];
  1         2  
  1         54  
14 1     1   7 use Module::Load::Conditional qw[can_load check_install];
  1         2  
  1         75  
15 1     1   7 use Locale::Maketext::Simple Style => 'gettext';
  1         2  
  1         9  
16              
17             ### solaris has silly /bin/tar output ###
18 1 50   1   316 use constant ON_SOLARIS => $^O eq 'solaris' ? 1 : 0;
  1         2  
  1         174  
19 1 50   1   8 use constant ON_NETBSD => $^O =~ m!^(netbsd|minix)$! ? 1 : 0;
  1         2  
  1         104  
20 1 50   1   7 use constant ON_OPENBSD => $^O =~ m!^(openbsd|bitrig)$! ? 1 : 0;
  1         2  
  1         111  
21 1 50   1   7 use constant ON_FREEBSD => $^O =~ m!^(free|midnight|dragonfly)(bsd)?$! ? 1 : 0;
  1         25  
  1         78  
22 1 50   1   7 use constant ON_LINUX => $^O eq 'linux' ? 1 : 0;
  1         2  
  1         85  
23 1 50   1   6 use constant FILE_EXISTS => sub { -e $_[0] ? 1 : 0 };
  1         2  
  1         80  
  68         9879  
24              
25             ### VMS may require quoting upper case command options
26 1 50   1   7 use constant ON_VMS => $^O eq 'VMS' ? 1 : 0;
  1         2  
  1         79  
27              
28             ### Windows needs special treatment of Tar options
29 1 50   1   7 use constant ON_WIN32 => $^O eq 'MSWin32' ? 1 : 0;
  1         1  
  1         51  
30              
31             ### we can't use this extraction method, because of missing
32             ### modules/binaries:
33 1     1   5 use constant METHOD_NA => [];
  1         1  
  1         57  
34              
35             ### If these are changed, update @TYPES and the new() POD
36 1     1   6 use constant TGZ => 'tgz';
  1         2  
  1         53  
37 1     1   6 use constant TAR => 'tar';
  1         2  
  1         52  
38 1     1   6 use constant GZ => 'gz';
  1         1  
  1         43  
39 1     1   5 use constant ZIP => 'zip';
  1         1  
  1         49  
40 1     1   6 use constant BZ2 => 'bz2';
  1         2  
  1         56  
41 1     1   6 use constant TBZ => 'tbz';
  1         1  
  1         54  
42 1     1   6 use constant Z => 'Z';
  1         1  
  1         51  
43 1     1   6 use constant LZMA => 'lzma';
  1         1  
  1         59  
44 1     1   6 use constant XZ => 'xz';
  1         2  
  1         65  
45 1     1   6 use constant TXZ => 'txz';
  1         2  
  1         58  
46              
47 1         568 use vars qw[$VERSION $PREFER_BIN $PROGRAMS $WARN $DEBUG
48             $_ALLOW_BIN $_ALLOW_PURE_PERL $_ALLOW_TAR_ITER
49 1     1   7 ];
  1         1  
50              
51             $VERSION = '0.88';
52             $PREFER_BIN = 0;
53             $WARN = 1;
54             $DEBUG = 0;
55             $_ALLOW_PURE_PERL = 1; # allow pure perl extractors
56             $_ALLOW_BIN = 1; # allow binary extractors
57             $_ALLOW_TAR_ITER = 1; # try to use Archive::Tar->iter if available
58              
59             # same as all constants
60             my @Types = ( TGZ, TAR, GZ, ZIP, BZ2, TBZ, Z, LZMA, XZ, TXZ );
61              
62             local $Params::Check::VERBOSE = $Params::Check::VERBOSE = 1;
63             local $Module::Load::Conditional::FORCE_SAFE_INC = 1;
64              
65             =pod
66              
67             =head1 NAME
68              
69             Archive::Extract - A generic archive extracting mechanism
70              
71             =head1 SYNOPSIS
72              
73             use Archive::Extract;
74              
75             ### build an Archive::Extract object ###
76             my $ae = Archive::Extract->new( archive => 'foo.tgz' );
77              
78             ### extract to cwd() ###
79             my $ok = $ae->extract;
80              
81             ### extract to /tmp ###
82             my $ok = $ae->extract( to => '/tmp' );
83              
84             ### what if something went wrong?
85             my $ok = $ae->extract or die $ae->error;
86              
87             ### files from the archive ###
88             my $files = $ae->files;
89              
90             ### dir that was extracted to ###
91             my $outdir = $ae->extract_path;
92              
93              
94             ### quick check methods ###
95             $ae->is_tar # is it a .tar file?
96             $ae->is_tgz # is it a .tar.gz or .tgz file?
97             $ae->is_gz; # is it a .gz file?
98             $ae->is_zip; # is it a .zip file?
99             $ae->is_bz2; # is it a .bz2 file?
100             $ae->is_tbz; # is it a .tar.bz2 or .tbz file?
101             $ae->is_lzma; # is it a .lzma file?
102             $ae->is_xz; # is it a .xz file?
103             $ae->is_txz; # is it a .tar.xz or .txz file?
104              
105             ### absolute path to the archive you provided ###
106             $ae->archive;
107              
108             ### commandline tools, if found ###
109             $ae->bin_tar # path to /bin/tar, if found
110             $ae->bin_gzip # path to /bin/gzip, if found
111             $ae->bin_unzip # path to /bin/unzip, if found
112             $ae->bin_bunzip2 # path to /bin/bunzip2 if found
113             $ae->bin_unlzma # path to /bin/unlzma if found
114             $ae->bin_unxz # path to /bin/unxz if found
115              
116             =head1 DESCRIPTION
117              
118             Archive::Extract is a generic archive extraction mechanism.
119              
120             It allows you to extract any archive file of the type .tar, .tar.gz,
121             .gz, .Z, tar.bz2, .tbz, .bz2, .zip, .xz,, .txz, .tar.xz or .lzma
122             without having to worry how it
123             does so, or use different interfaces for each type by using either
124             perl modules, or commandline tools on your system.
125              
126             See the C section further down for details.
127              
128             =cut
129              
130              
131             ### see what /bin/programs are available ###
132             $PROGRAMS = {};
133             CMD: for my $pgm (qw[tar unzip gzip bunzip2 uncompress unlzma unxz]) {
134             if ( $pgm eq 'unzip' and ON_FREEBSD and my $unzip = can_run('info-unzip') ) {
135             $PROGRAMS->{$pgm} = $unzip;
136             next CMD;
137             }
138             if ( $pgm eq 'unzip' and ( ON_FREEBSD || ON_LINUX ) ) {
139             local $IPC::Cmd::INSTANCES = 1;
140             ($PROGRAMS->{$pgm}) = grep { _is_infozip_esque($_) } can_run($pgm);
141             next CMD;
142             }
143             if ( $pgm eq 'unzip' and ON_NETBSD ) {
144             local $IPC::Cmd::INSTANCES = 1;
145             ($PROGRAMS->{$pgm}) = grep { m!/usr/pkg/! } can_run($pgm);
146             next CMD;
147             }
148             if ( $pgm eq 'tar' and ( ON_OPENBSD || ON_SOLARIS || ON_NETBSD ) ) {
149             # try gtar first
150             next CMD if $PROGRAMS->{$pgm} = can_run('gtar');
151             }
152             $PROGRAMS->{$pgm} = can_run($pgm);
153             }
154              
155             ### mapping from types to extractor methods ###
156             my $Mapping = { # binary program # pure perl module
157             is_tgz => { bin => '_untar_bin', pp => '_untar_at' },
158             is_tar => { bin => '_untar_bin', pp => '_untar_at' },
159             is_gz => { bin => '_gunzip_bin', pp => '_gunzip_cz' },
160             is_zip => { bin => '_unzip_bin', pp => '_unzip_az' },
161             is_tbz => { bin => '_untar_bin', pp => '_untar_at' },
162             is_bz2 => { bin => '_bunzip2_bin', pp => '_bunzip2_bz2'},
163             is_Z => { bin => '_uncompress_bin', pp => '_gunzip_cz' },
164             is_lzma => { bin => '_unlzma_bin', pp => '_unlzma_cz' },
165             is_xz => { bin => '_unxz_bin', pp => '_unxz_cz' },
166             is_txz => { bin => '_untar_bin', pp => '_untar_at' },
167             };
168              
169             { ### use subs so we re-generate array refs etc for the no-override flags
170             ### if we don't, then we reuse the same arrayref, meaning objects store
171             ### previous errors
172             my $tmpl = {
173             archive => sub { { required => 1, allow => FILE_EXISTS } },
174             type => sub { { default => '', allow => [ @Types ] } },
175             _error_msg => sub { { no_override => 1, default => [] } },
176             _error_msg_long => sub { { no_override => 1, default => [] } },
177             };
178              
179             ### build accessors ###
180             for my $method( keys %$tmpl,
181             qw[_extractor _gunzip_to files extract_path],
182             ) {
183 1     1   9 no strict 'refs';
  1         2  
  1         3120  
184             *$method = sub {
185 4237     4237   488202 my $self = shift;
186 4237 100       12452 $self->{$method} = $_[0] if @_;
187 4237         63780 return $self->{$method};
188             }
189             }
190              
191             sub type_for {
192 77     77 1 10957 local $_ = shift;
193 77 100       5178 return /.+?\.(?:tar\.gz|tgz)$/i ? TGZ :
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
194             /.+?\.gz$/i ? GZ :
195             /.+?\.tar$/i ? TAR :
196             /.+?\.(zip|jar|ear|war|par)$/i ? ZIP :
197             /.+?\.(?:tbz2?|tar\.bz2?)$/i ? TBZ :
198             /.+?\.bz2$/i ? BZ2 :
199             /.+?\.Z$/ ? Z :
200             /.+?\.lzma$/ ? LZMA :
201             /.+?\.(?:txz|tar\.xz)$/i ? TXZ :
202             /.+?\.xz$/ ? XZ :
203             '';
204             }
205              
206             =head1 METHODS
207              
208             =head2 $ae = Archive::Extract->new(archive => '/path/to/archive',[type => TYPE])
209              
210             Creates a new C object based on the archive file you
211             passed it. Automatically determines the type of archive based on the
212             extension, but you can override that by explicitly providing the
213             C argument, potentially by calling C.
214              
215             Valid values for C are:
216              
217             =over 4
218              
219             =item tar
220              
221             Standard tar files, as produced by, for example, C.
222             Corresponds to a C<.tar> suffix.
223              
224             =item tgz
225              
226             Gzip compressed tar files, as produced by, for example C.
227             Corresponds to a C<.tgz> or C<.tar.gz> suffix.
228              
229             =item gz
230              
231             Gzip compressed file, as produced by, for example C.
232             Corresponds to a C<.gz> suffix.
233              
234             =item Z
235              
236             Lempel-Ziv compressed file, as produced by, for example C.
237             Corresponds to a C<.Z> suffix.
238              
239             =item zip
240              
241             Zip compressed file, as produced by, for example C.
242             Corresponds to a C<.zip>, C<.jar> or C<.par> suffix.
243              
244             =item bz2
245              
246             Bzip2 compressed file, as produced by, for example, C.
247             Corresponds to a C<.bz2> suffix.
248              
249             =item tbz
250              
251             Bzip2 compressed tar file, as produced by, for example C.
252             Corresponds to a C<.tbz> or C<.tar.bz2> suffix.
253              
254             =item lzma
255              
256             Lzma compressed file, as produced by C.
257             Corresponds to a C<.lzma> suffix.
258              
259             =item xz
260              
261             Xz compressed file, as produced by C.
262             Corresponds to a C<.xz> suffix.
263              
264             =item txz
265              
266             Xz compressed tar file, as produced by, for example C.
267             Corresponds to a C<.txz> or C<.tar.xz> suffix.
268              
269             =back
270              
271             Returns a C object on success, or false on failure.
272              
273             =cut
274              
275             ### constructor ###
276             sub new {
277 68     68 1 124679 my $class = shift;
278 68         417 my %hash = @_;
279              
280             ### see above why we use subs here and generate the template;
281             ### it's basically to not re-use arrayrefs
282 68         462 my %utmpl = map { $_ => $tmpl->{$_}->() } keys %$tmpl;
  272         915  
283              
284 68 50       709 my $parsed = check( \%utmpl, \%hash ) or return;
285              
286             ### make sure we have an absolute path ###
287 68         3895 my $ar = $parsed->{archive} = File::Spec->rel2abs( $parsed->{archive} );
288              
289             ### figure out the type, if it wasn't already specified ###
290 68   100     594 $parsed->{type} ||= type_for $ar;
291              
292 68         175 bless $parsed, $class;
293              
294             ### don't know what type of file it is
295             ### XXX this *has* to be an object call, not a package call
296             return $parsed->_error(loc("Cannot determine file type for '%1'",
297 68 100       242 $parsed->{archive} )) unless $parsed->{type};
298 67         436 return $parsed;
299             }
300             }
301              
302             =head2 $ae->extract( [to => '/output/path'] )
303              
304             Extracts the archive represented by the C object to
305             the path of your choice as specified by the C argument. Defaults to
306             C.
307              
308             Since C<.gz> files never hold a directory, but only a single file; if
309             the C argument is an existing directory, the file is extracted
310             there, with its C<.gz> suffix stripped.
311             If the C argument is not an existing directory, the C argument
312             is understood to be a filename, if the archive type is C.
313             In the case that you did not specify a C argument, the output
314             file will be the name of the archive file, stripped from its C<.gz>
315             suffix, in the current working directory.
316              
317             C will try a pure perl solution first, and then fall back to
318             commandline tools if they are available. See the C
319             section below on how to alter this behaviour.
320              
321             It will return true on success, and false on failure.
322              
323             On success, it will also set the follow attributes in the object:
324              
325             =over 4
326              
327             =item $ae->extract_path
328              
329             This is the directory that the files where extracted to.
330              
331             =item $ae->files
332              
333             This is an array ref with the paths of all the files in the archive,
334             relative to the C argument you specified.
335             To get the full path to an extracted file, you would use:
336              
337             File::Spec->catfile( $to, $ae->files->[0] );
338              
339             Note that all files from a tar archive will be in unix format, as per
340             the tar specification.
341              
342             =back
343              
344             =cut
345              
346             sub extract {
347 97     97 1 28515 my $self = shift;
348 97         385 my %hash = @_;
349              
350             ### reset error messages
351 97         424 $self->_error_msg( [] );
352 97         911 $self->_error_msg_long( [] );
353              
354 97         164 my $to;
355 97         492 my $tmpl = {
356             to => { default => '.', store => \$to }
357             };
358              
359 97 100       424 check( $tmpl, \%hash ) or return;
360              
361             ### so 'to' could be a file or a dir, depending on whether it's a .gz
362             ### file, or basically anything else.
363             ### so, check that, then act accordingly.
364             ### set an accessor specifically so _gunzip can know what file to extract
365             ### to.
366 96         8684 my $dir;
367             { ### a foo.gz file
368 96 100 100     366 if( $self->is_gz or $self->is_bz2 or $self->is_Z or $self->is_lzma or $self->is_xz ) {
  96   100     679  
      100        
      100        
369              
370 16         86 my $cp = $self->archive; $cp =~ s/\.(?:gz|bz2?|Z|lzma|xz)$//i;
  16         273  
371              
372             ### to is a dir?
373 16 50       335 if ( -d $to ) {
374 0         0 $dir = $to;
375 0         0 $self->_gunzip_to( basename($cp) );
376              
377             ### then it's a filename
378             } else {
379 16         1725 $dir = dirname($to);
380 16         634 $self->_gunzip_to( basename($to) );
381             }
382              
383             ### not a foo.gz file
384             } else {
385 80         167 $dir = $to;
386             }
387             }
388              
389             ### make the dir if it doesn't exist ###
390 96 100       2094 unless( -d $dir ) {
391 38         116 eval { mkpath( $dir ) };
  38         12228  
392              
393 38 50       242 return $self->_error(loc("Could not create path '%1': %2", $dir, $@))
394             if $@;
395             }
396              
397             ### get the current dir, to restore later ###
398 96         368878 my $cwd = cwd();
399              
400 96         1349 my $ok = 1;
401             EXTRACT: {
402              
403             ### chdir to the target dir ###
404 96 50       200 unless( chdir $dir ) {
  96         13304  
405 0         0 $self->_error(loc("Could not chdir to '%1': %2", $dir, $!));
406 0         0 $ok = 0; last EXTRACT;
  0         0  
407             }
408              
409             ### set files to an empty array ref, so there's always an array
410             ### ref IN the accessor, to avoid errors like:
411             ### Can't use an undefined value as an ARRAY reference at
412             ### ../lib/Archive/Extract.pm line 742. (rt #19815)
413 96         2429 $self->files( [] );
414              
415             ### find out the dispatch methods needed for this type of
416             ### archive. Do a $self->is_XXX to figure out the type, then
417             ### get the hashref with bin + pure perl dispatchers.
418 96         3340 my ($map) = map { $Mapping->{$_} } grep { $self->$_ } keys %$Mapping;
  96         365  
  960         5092  
419              
420             ### add pure perl extractor if allowed & add bin extractor if allowed
421 96         253 my @methods;
422 96 100       695 push @methods, $map->{'pp'} if $_ALLOW_PURE_PERL;
423 96 100       740 push @methods, $map->{'bin'} if $_ALLOW_BIN;
424              
425             ### reverse it if we prefer bin extractors
426 96 50       332 @methods = reverse @methods if $PREFER_BIN;
427              
428 96         218 my($na, $fail);
429 96         655 for my $method (@methods) {
430 96         1599 $self->debug( "# Extracting with ->$method\n" );
431              
432 96         1297 my $rv = $self->$method;
433              
434             ### a positive extraction
435 96 50 33     7839 if( $rv and $rv ne METHOD_NA ) {
    0 0        
436 96         1585 $self->debug( "# Extraction succeeded\n" );
437 96         1146 $self->_extractor($method);
438 96         675 last;
439              
440             ### method is not available
441             } elsif ( $rv and $rv eq METHOD_NA ) {
442 0         0 $self->debug( "# Extraction method not available\n" );
443 0         0 $na++;
444             } else {
445 0         0 $self->debug( "# Extraction method failed\n" );
446 0         0 $fail++;
447             }
448             }
449              
450             ### warn something went wrong if we didn't get an extractor
451 96 50       709 unless( $self->_extractor ) {
452 0 0       0 my $diag = $fail ? loc("Extract failed due to errors") :
    0          
453             $na ? loc("Extract failed; no extractors available") :
454             '';
455              
456 0         0 $self->_error($diag);
457 0         0 $ok = 0;
458             }
459             }
460              
461             ### and chdir back ###
462 96 50       7608 unless( chdir $cwd ) {
463 0         0 $self->_error(loc("Could not chdir back to start dir '%1': %2'",
464             $cwd, $!));
465             }
466              
467 96         3602 return $ok;
468             }
469              
470             =pod
471              
472             =head1 ACCESSORS
473              
474             =head2 $ae->error([BOOL])
475              
476             Returns the last encountered error as string.
477             Pass it a true value to get the C output instead.
478              
479             =head2 $ae->extract_path
480              
481             This is the directory the archive got extracted to.
482             See C for details.
483              
484             =head2 $ae->files
485              
486             This is an array ref holding all the paths from the archive.
487             See C for details.
488              
489             =head2 $ae->archive
490              
491             This is the full path to the archive file represented by this
492             C object.
493              
494             =head2 $ae->type
495              
496             This is the type of archive represented by this C
497             object. See accessors below for an easier way to use this.
498             See the C method for details.
499              
500             =head2 $ae->types
501              
502             Returns a list of all known C for C's
503             C method.
504              
505             =cut
506              
507 1     1 1 1336 sub types { return @Types }
508              
509             =head2 $ae->is_tgz
510              
511             Returns true if the file is of type C<.tar.gz>.
512             See the C method for details.
513              
514             =head2 $ae->is_tar
515              
516             Returns true if the file is of type C<.tar>.
517             See the C method for details.
518              
519             =head2 $ae->is_gz
520              
521             Returns true if the file is of type C<.gz>.
522             See the C method for details.
523              
524             =head2 $ae->is_Z
525              
526             Returns true if the file is of type C<.Z>.
527             See the C method for details.
528              
529             =head2 $ae->is_zip
530              
531             Returns true if the file is of type C<.zip>.
532             See the C method for details.
533              
534             =head2 $ae->is_lzma
535              
536             Returns true if the file is of type C<.lzma>.
537             See the C method for details.
538              
539             =head2 $ae->is_xz
540              
541             Returns true if the file is of type C<.xz>.
542             See the C method for details.
543              
544             =cut
545              
546             ### quick check methods ###
547 376     376 1 12770 sub is_tgz { return $_[0]->type eq TGZ }
548 160     160 1 6801 sub is_tar { return $_[0]->type eq TAR }
549 274     274 1 1928 sub is_gz { return $_[0]->type eq GZ }
550 118     118 1 10640 sub is_zip { return $_[0]->type eq ZIP }
551 288     288 0 8467 sub is_tbz { return $_[0]->type eq TBZ }
552 268     268 0 2465 sub is_bz2 { return $_[0]->type eq BZ2 }
553 262     262 1 2648 sub is_Z { return $_[0]->type eq Z }
554 256     256 1 2346 sub is_lzma { return $_[0]->type eq LZMA }
555 252     252 1 1662 sub is_xz { return $_[0]->type eq XZ }
556 272     272 0 27497 sub is_txz { return $_[0]->type eq TXZ }
557              
558             =pod
559              
560             =head2 $ae->bin_tar
561              
562             Returns the full path to your tar binary, if found.
563              
564             =head2 $ae->bin_gzip
565              
566             Returns the full path to your gzip binary, if found
567              
568             =head2 $ae->bin_unzip
569              
570             Returns the full path to your unzip binary, if found
571              
572             =head2 $ae->bin_unlzma
573              
574             Returns the full path to your unlzma binary, if found
575              
576             =head2 $ae->bin_unxz
577              
578             Returns the full path to your unxz binary, if found
579              
580             =cut
581              
582             ### paths to commandline tools ###
583 52 50   52 1 493 sub bin_gzip { return $PROGRAMS->{'gzip'} if $PROGRAMS->{'gzip'} }
584 0 0   0 1 0 sub bin_unzip { return $PROGRAMS->{'unzip'} if $PROGRAMS->{'unzip'} }
585 144 50   144 1 1780 sub bin_tar { return $PROGRAMS->{'tar'} if $PROGRAMS->{'tar'} }
586 34 50   34 0 472 sub bin_bunzip2 { return $PROGRAMS->{'bunzip2'} if $PROGRAMS->{'bunzip2'} }
587             sub bin_uncompress { return $PROGRAMS->{'uncompress'}
588 4 50   4 0 68 if $PROGRAMS->{'uncompress'} }
589 4 50   4 1 54 sub bin_unlzma { return $PROGRAMS->{'unlzma'} if $PROGRAMS->{'unlzma'} }
590 52 50   52 1 545 sub bin_unxz { return $PROGRAMS->{'unxz'} if $PROGRAMS->{'unxz'} }
591              
592             =head2 $bool = $ae->have_old_bunzip2
593              
594             Older versions of C, from before the C release,
595             require all archive names to end in C<.bz2> or it will not extract
596             them. This method checks if you have a recent version of C
597             that allows any extension, or an older one that doesn't.
598              
599             =cut
600              
601             sub have_old_bunzip2 {
602 3     3 1 4904 my $self = shift;
603              
604             ### no bunzip2? no old bunzip2 either :)
605 3 50       43 return unless $self->bin_bunzip2;
606              
607             ### if we can't run this, we can't be sure if it's too old or not
608             ### XXX stupid stupid stupid bunzip2 doesn't understand --version
609             ### is not a request to extract data:
610             ### $ bunzip2 --version
611             ### bzip2, a block-sorting file compressor. Version 1.0.2, 30-Dec-2001.
612             ### [...]
613             ### bunzip2: I won't read compressed data from a terminal.
614             ### bunzip2: For help, type: `bunzip2 --help'.
615             ### $ echo $?
616             ### 1
617             ### HATEFUL!
618              
619             ### double hateful: bunzip2 --version also hangs if input is a pipe
620             ### See #32370: Archive::Extract will hang if stdin is a pipe [+PATCH]
621             ### So, we have to provide *another* argument which is a fake filename,
622             ### just so it wont try to read from stdin to print its version..
623             ### *sigh*
624             ### Even if the file exists, it won't clobber or change it.
625 3         12 my $buffer;
626 3         17 scalar run(
627             command => [$self->bin_bunzip2, '--version', 'NoSuchFile'],
628             verbose => 0,
629             buffer => \$buffer
630             );
631              
632             ### no output
633 3 100       32906 return unless $buffer;
634              
635 2         54 my ($version) = $buffer =~ /version \s+ (\d+)/ix;
636              
637 2 50       24 return 1 if $version < 1;
638 2         43 return;
639             }
640              
641             #################################
642             #
643             # Untar code
644             #
645             #################################
646              
647             ### annoying issue with (gnu) tar on win32, as illustrated by this
648             ### bug: https://rt.cpan.org/Ticket/Display.html?id=40138
649             ### which shows that (gnu) tar will interpret a file name with a :
650             ### in it as a remote file name, so C:\tmp\foo.txt is interpreted
651             ### as a remote shell, and the extract fails.
652             { my @ExtraTarFlags;
653             if( ON_WIN32 and my $cmd = __PACKAGE__->bin_tar ) {
654             $cmd = $1 if $cmd =~ m{^(.+)}s; # Tainted perl #
655             ### if this is gnu tar we are running, we need to use --force-local
656             push @ExtraTarFlags, '--force-local' if `$cmd --version` =~ /gnu tar/i;
657             }
658              
659              
660             ### use /bin/tar to extract ###
661             sub _untar_bin {
662 48     48   141 my $self = shift;
663              
664             ### check for /bin/tar ###
665             ### check for /bin/gzip if we need it ###
666             ### if any of the binaries are not available, return NA
667 48 50 66     58 { my $diag = !$self->bin_tar ?
  48 50 66     143  
    50 66        
    50          
668             loc("No '%1' program found", '/bin/tar') :
669             $self->is_tgz && !$self->bin_gzip ?
670             loc("No '%1' program found", '/bin/gzip') :
671             $self->is_tbz && !$self->bin_bunzip2 ?
672             loc("No '%1' program found", '/bin/bunzip2') :
673             $self->is_txz && !$self->bin_unxz ?
674             loc("No '%1' program found", '/bin/unxz') :
675             '';
676              
677 48 50       239 if( $diag ) {
678 0         0 $self->_error( $diag );
679 0         0 return METHOD_NA;
680             }
681             }
682              
683             ### XXX figure out how to make IPC::Run do this in one call --
684             ### currently i don't know how to get output of a command after a pipe
685             ### trapped in a scalar. Mailed barries about this 5th of june 2004.
686              
687             ### see what command we should run, based on whether
688             ### it's a .tgz or .tar
689              
690             ### GNU tar can't handled VMS filespecs, but VMSTAR can handle Unix filespecs.
691 48         189 my $archive = $self->archive;
692 48         81 $archive = VMS::Filespec::unixify($archive) if ON_VMS;
693              
694             ### XXX solaris tar and bsdtar are having different outputs
695             ### depending whether you run with -x or -t
696             ### compensate for this insanity by running -t first, then -x
697 48 100       113 { my $cmd =
    100          
    100          
698             $self->is_tgz ? [$self->bin_gzip, '-c', '-d', '-f', $archive, '|',
699             $self->bin_tar, '-tf', '-'] :
700             $self->is_tbz ? [$self->bin_bunzip2, '-cd', $archive, '|',
701             $self->bin_tar, '-tf', '-'] :
702             $self->is_txz ? [$self->bin_unxz, '-cd', $archive, '|',
703             $self->bin_tar, '-tf', '-'] :
704             [$self->bin_tar, @ExtraTarFlags, '-tf', $archive];
705              
706             ### run the command
707             ### newer versions of 'tar' (1.21 and up) now print record size
708             ### to STDERR as well if v OR t is given (used to be both). This
709             ### is a 'feature' according to the changelog, so we must now only
710             ### inspect STDOUT, otherwise, failures like these occur:
711             ### http://www.cpantesters.org/cpan/report/3230366
712 48         451 my $buffer = '';
713 48         1480 my @out = run( command => $cmd,
714             buffer => \$buffer,
715             verbose => $DEBUG );
716              
717             ### command was unsuccessful
718 48 50       411055 unless( $out[0] ) {
719 0         0 return $self->_error(loc(
720             "Error listing contents of archive '%1': %2",
721             $archive, $buffer ));
722             }
723              
724             ### no buffers available?
725 48 100 66     1278 if( !IPC::Cmd->can_capture_buffer and !$buffer ) {
726 24         991 $self->_error( $self->_no_buffer_files( $archive ) );
727              
728             } else {
729             ### if we're on solaris we /might/ be using /bin/tar, which has
730             ### a weird output format... we might also be using
731             ### /usr/local/bin/tar, which is gnu tar, which is perfectly
732             ### fine... so we have to do some guessing here =/
733 38         67 my @files = map { chomp; s!\x0D!!g if ON_WIN32;
  38         46  
734 38         157 !ON_SOLARIS ? $_
735             : (m|^ x \s+ # 'xtract' -- sigh
736             (.+?), # the actual file name
737             \s+ [\d,.]+ \s bytes,
738             \s+ [\d,.]+ \s tape \s blocks
739             |x ? $1 : $_);
740              
741             ### only STDOUT, see above. Sometimes, extra whitespace
742             ### is present, so make sure we only pick lines with
743             ### a length
744 24         7626 } grep { length } map { split $/, $_ } join '', @{$out[3]};
  38         116  
  24         1090  
  24         106  
745              
746             ### store the files that are in the archive ###
747 24         471 $self->files(\@files);
748             }
749             }
750              
751             ### now actually extract it ###
752 48 100       71 { my $cmd =
  48 100       317  
  48 100       827  
753             $self->is_tgz ? [$self->bin_gzip, '-c', '-d', '-f', $archive, '|',
754             $self->bin_tar, '-xf', '-'] :
755             $self->is_tbz ? [$self->bin_bunzip2, '-cd', $archive, '|',
756             $self->bin_tar, '-xf', '-'] :
757             $self->is_txz ? [$self->bin_unxz, '-cd', $archive, '|',
758             $self->bin_tar, '-xf', '-'] :
759             [$self->bin_tar, @ExtraTarFlags, '-xf', $archive];
760              
761 48         389 my $buffer = '';
762 48 50       719 unless( scalar run( command => $cmd,
763             buffer => \$buffer,
764             verbose => $DEBUG )
765             ) {
766 0         0 return $self->_error(loc("Error extracting archive '%1': %2",
767             $archive, $buffer ));
768             }
769              
770             ### we might not have them, due to lack of buffers
771 48 50       392366 if( $self->files ) {
772             ### now that we've extracted, figure out where we extracted to
773 48         164 my $dir = $self->__get_extract_dir( $self->files );
774              
775             ### store the extraction dir ###
776 48         668 $self->extract_path( $dir );
777             }
778             }
779              
780             ### we got here, no error happened
781 48         406 return 1;
782             }
783             }
784              
785              
786             ### use archive::tar to extract ###
787             sub _untar_at {
788 32     32   263 my $self = shift;
789              
790             ### Loading Archive::Tar is going to set it to 1, so make it local
791             ### within this block, starting with its initial value. Whatever
792             ### Achive::Tar does will be undone when we return.
793             ###
794             ### Also, later, set $Archive::Tar::WARN to $Archive::Extract::WARN
795             ### so users don't have to even think about this variable. If they
796             ### do, they still get their set value outside of this call.
797 32         237 local $Archive::Tar::WARN = $Archive::Tar::WARN;
798              
799             ### we definitely need Archive::Tar, so load that first
800 32         110 { my $use_list = { 'Archive::Tar' => '0.0' };
  32         303  
801              
802 32 50       1065 unless( can_load( modules => $use_list ) ) {
803              
804 0         0 $self->_error(loc("You do not have '%1' installed - " .
805             "Please install it as soon as possible.",
806             'Archive::Tar'));
807              
808 0         0 return METHOD_NA;
809             }
810             }
811              
812             ### we might pass it a filehandle if it's a .tbz file..
813 32         133572 my $fh_to_read = $self->archive;
814              
815             ### we will need Compress::Zlib too, if it's a tgz... and IO::Zlib
816             ### if A::T's version is 0.99 or higher
817 32 100       131 if( $self->is_tgz ) {
    100          
    50          
818 16         250 my $use_list = { 'Compress::Zlib' => '0.0' };
819             {
820 16         146 local $@;
  16         99  
821             $use_list->{ 'IO::Zlib' } = '0.0'
822 16 50       106 if eval { Archive::Tar->VERSION('0.99'); 1 };
  16         697  
  16         367  
823             }
824              
825 16 50       89 unless( can_load( modules => $use_list ) ) {
826 0         0 my $which = join '/', sort keys %$use_list;
827              
828 0         0 $self->_error(loc(
829             "You do not have '%1' installed - Please ".
830             "install it as soon as possible.", $which)
831             );
832              
833 0         0 return METHOD_NA;
834             }
835              
836             } elsif ( $self->is_tbz ) {
837 8         136 my $use_list = { 'IO::Uncompress::Bunzip2' => '0.0' };
838 8 50       76 unless( can_load( modules => $use_list ) ) {
839 0         0 $self->_error(loc(
840             "You do not have '%1' installed - Please " .
841             "install it as soon as possible.",
842             'IO::Uncompress::Bunzip2')
843             );
844              
845 0         0 return METHOD_NA;
846             }
847              
848 8 50       11579 my $bz = IO::Uncompress::Bunzip2->new( $self->archive ) or
849             return $self->_error(loc("Unable to open '%1': %2",
850             $self->archive,
851             $IO::Uncompress::Bunzip2::Bunzip2Error));
852              
853 8         16957 $fh_to_read = $bz;
854             } elsif ( $self->is_txz ) {
855 0         0 my $use_list = { 'IO::Uncompress::UnXz' => '0.0' };
856 0 0       0 unless( can_load( modules => $use_list ) ) {
857 0         0 $self->_error(loc(
858             "You do not have '%1' installed - Please " .
859             "install it as soon as possible.",
860             'IO::Uncompress::UnXz')
861             );
862              
863 0         0 return METHOD_NA;
864             }
865              
866 0 0       0 my $xz = IO::Uncompress::UnXz->new( $self->archive ) or
867             return $self->_error(loc("Unable to open '%1': %2",
868             $self->archive,
869             $IO::Uncompress::UnXz::UnXzError));
870              
871 0         0 $fh_to_read = $xz;
872             }
873              
874 32         28424 my @files;
875             {
876             ### $Archive::Tar::WARN is 1 by default in Archive::Tar, but we've
877             ### localized $Archive::Tar::WARN already.
878 32         137 $Archive::Tar::WARN = $Archive::Extract::WARN;
  32         315  
879              
880             ### only tell it it's compressed if it's a .tgz, as we give it a file
881             ### handle if it's a .tbz
882 32 100       382 my @read = ( $fh_to_read, ( $self->is_tgz ? 1 : 0 ) );
883              
884             ### for version of Archive::Tar > 1.04
885 32         228 local $Archive::Tar::CHOWN = 0;
886              
887             ### use the iterator if we can. it's a feature of A::T 1.40 and up
888 32 100 66     1142 if ( $_ALLOW_TAR_ITER && Archive::Tar->can( 'iter' ) ) {
889              
890 16         46 my $next;
891 16 50       250 unless ( $next = Archive::Tar->iter( @read ) ) {
892 0         0 return $self->_error(loc(
893             "Unable to read '%1': %2", $self->archive,
894             $Archive::Tar::error));
895             }
896              
897 16         41382 while ( my $file = $next->() ) {
898 26         71523 push @files, $file->full_path;
899              
900 26 50       1022 $file->extract or return $self->_error(loc(
901             "Unable to read '%1': %2",
902             $self->archive,
903             $Archive::Tar::error));
904             }
905              
906             ### older version, read the archive into memory
907             } else {
908              
909 16         366 my $tar = Archive::Tar->new();
910              
911 16 50       678 unless( $tar->read( @read ) ) {
912 0         0 return $self->_error(loc("Unable to read '%1': %2",
913             $self->archive, $Archive::Tar::error));
914             }
915              
916             ### workaround to prevent Archive::Tar from setting uid, which
917             ### is a potential security hole. -autrijus
918             ### have to do it here, since A::T needs to be /loaded/ first ###
919 1     1   16 { no strict 'refs'; local $^W;
  1         2  
  1         3661  
  16         68  
920              
921             ### older versions of archive::tar <= 0.23
922 16     0   769 *Archive::Tar::chown = sub {};
923             }
924              
925 16         105147 { local $^W; # quell 'splice() offset past end of array' warnings
  16         52  
  16         45  
926             # on older versions of A::T
927              
928             ### older archive::tar always returns $self, return value
929             ### slightly fux0r3d because of it.
930 16 50       155 $tar->extract or return $self->_error(loc(
931             "Unable to extract '%1': %2",
932             $self->archive, $Archive::Tar::error ));
933             }
934              
935 16         92503 @files = $tar->list_files;
936             }
937             }
938              
939 32         135785 my $dir = $self->__get_extract_dir( \@files );
940              
941             ### store the files that are in the archive ###
942 32         785 $self->files(\@files);
943              
944             ### store the extraction dir ###
945 32         528 $self->extract_path( $dir );
946              
947             ### check if the dir actually appeared ###
948 32 50       145 return 1 if -d $self->extract_path;
949              
950             ### no dir, we failed ###
951 0         0 return $self->_error(loc("Unable to extract '%1': %2",
952             $self->archive, $Archive::Tar::error ));
953             }
954              
955             #################################
956             #
957             # Gunzip code
958             #
959             #################################
960              
961             sub _gunzip_bin {
962 2     2   25 my $self = shift;
963              
964             ### check for /bin/gzip -- we need it ###
965 2 50       26 unless( $self->bin_gzip ) {
966 0         0 $self->_error(loc("No '%1' program found", '/bin/gzip'));
967 0         0 return METHOD_NA;
968             }
969              
970 2 50       42 my $fh = FileHandle->new('>'. $self->_gunzip_to) or
971             return $self->_error(loc("Could not open '%1' for writing: %2",
972             $self->_gunzip_to, $! ));
973              
974 2         517 my $cmd = [ $self->bin_gzip, '-c', '-d', '-f', $self->archive ];
975              
976 2         7 my $buffer;
977 2 50       50 unless( scalar run( command => $cmd,
978             verbose => $DEBUG,
979             buffer => \$buffer )
980             ) {
981 0         0 return $self->_error(loc("Unable to gunzip '%1': %2",
982             $self->archive, $buffer));
983             }
984              
985             ### no buffers available?
986 2 50 66     10041 if( !IPC::Cmd->can_capture_buffer and !$buffer ) {
987 1         69 $self->_error( $self->_no_buffer_content( $self->archive ) );
988             }
989              
990 2 50       387 $self->_print($fh, $buffer) if defined $buffer;
991              
992 2         30 close $fh;
993              
994             ### set what files where extract, and where they went ###
995 2         40 $self->files( [$self->_gunzip_to] );
996 2         6869 $self->extract_path( File::Spec->rel2abs(cwd()) );
997              
998 2         106 return 1;
999             }
1000              
1001             sub _gunzip_cz {
1002 4     4   39 my $self = shift;
1003              
1004 4         85 my $use_list = { 'Compress::Zlib' => '0.0' };
1005 4 50       134 unless( can_load( modules => $use_list ) ) {
1006 0         0 $self->_error(loc("You do not have '%1' installed - Please " .
1007             "install it as soon as possible.", 'Compress::Zlib'));
1008 0         0 return METHOD_NA;
1009             }
1010              
1011 4 50       1160 my $gz = Compress::Zlib::gzopen( $self->archive, "rb" ) or
1012             return $self->_error(loc("Unable to open '%1': %2",
1013             $self->archive, $Compress::Zlib::gzerrno));
1014              
1015 4 50       12807 my $fh = FileHandle->new('>'. $self->_gunzip_to) or
1016             return $self->_error(loc("Could not open '%1' for writing: %2",
1017             $self->_gunzip_to, $! ));
1018              
1019 4         544 my $buffer;
1020 4         48 $self->_print($fh, $buffer) while $gz->gzread($buffer) > 0;
1021 4         1374 $fh->close;
1022              
1023             ### set what files where extract, and where they went ###
1024 4         321 $self->files( [$self->_gunzip_to] );
1025 4         17141 $self->extract_path( File::Spec->rel2abs(cwd()) );
1026              
1027 4         486 return 1;
1028             }
1029              
1030             #################################
1031             #
1032             # Uncompress code
1033             #
1034             #################################
1035              
1036             sub _uncompress_bin {
1037 2     2   25 my $self = shift;
1038              
1039             ### check for /bin/gzip -- we need it ###
1040 2 50       26 unless( $self->bin_uncompress ) {
1041 0         0 $self->_error(loc("No '%1' program found", '/bin/uncompress'));
1042 0         0 return METHOD_NA;
1043             }
1044              
1045 2 50       41 my $fh = FileHandle->new('>'. $self->_gunzip_to) or
1046             return $self->_error(loc("Could not open '%1' for writing: %2",
1047             $self->_gunzip_to, $! ));
1048              
1049 2         636 my $cmd = [ $self->bin_uncompress, '-c', $self->archive ];
1050              
1051 2         5 my $buffer;
1052 2 50       58 unless( scalar run( command => $cmd,
1053             verbose => $DEBUG,
1054             buffer => \$buffer )
1055             ) {
1056 0         0 return $self->_error(loc("Unable to uncompress '%1': %2",
1057             $self->archive, $buffer));
1058             }
1059              
1060             ### no buffers available?
1061 2 50 66     13441 if( !IPC::Cmd->can_capture_buffer and !$buffer ) {
1062 1         72 $self->_error( $self->_no_buffer_content( $self->archive ) );
1063             }
1064              
1065 2 100       426 $self->_print($fh, $buffer) if defined $buffer;
1066              
1067 2         80 close $fh;
1068              
1069             ### set what files where extract, and where they went ###
1070 2         46 $self->files( [$self->_gunzip_to] );
1071 2         7559 $self->extract_path( File::Spec->rel2abs(cwd()) );
1072              
1073 2         130 return 1;
1074             }
1075              
1076              
1077             #################################
1078             #
1079             # Unzip code
1080             #
1081             #################################
1082              
1083              
1084             sub _unzip_bin {
1085 0     0   0 my $self = shift;
1086              
1087             ### check for /bin/gzip if we need it ###
1088 0 0       0 unless( $self->bin_unzip ) {
1089 0         0 $self->_error(loc("No '%1' program found", '/bin/unzip'));
1090 0         0 return METHOD_NA;
1091             }
1092              
1093             ### first, get the files.. it must be 2 different commands with 'unzip' :(
1094             { ### on VMS, capital letter options have to be quoted. This is
1095             ### reported by John Malmberg on P5P Tue 21 Aug 2007 05:05:11
1096             ### Subject: [patch@31735]Archive Extract fix on VMS.
1097 0         0 my $opt = ON_VMS ? '"-Z"' : '-Z';
1098 0         0 my $cmd = [ $self->bin_unzip, $opt, '-1', $self->archive ];
1099              
1100 0         0 my $buffer = '';
1101 0 0       0 unless( scalar run( command => $cmd,
1102             verbose => $DEBUG,
1103             buffer => \$buffer )
1104             ) {
1105 0         0 return $self->_error(loc("Unable to unzip '%1': %2",
1106             $self->archive, $buffer));
1107             }
1108              
1109             ### no buffers available?
1110 0 0 0     0 if( !IPC::Cmd->can_capture_buffer and !$buffer ) {
1111 0         0 $self->_error( $self->_no_buffer_files( $self->archive ) );
1112              
1113             } else {
1114             ### Annoyingly, pesky MSWin32 can either have 'native' tools
1115             ### which have \r\n line endings or Cygwin-based tools which
1116             ### have \n line endings. Jan Dubois suggested using this fix
1117 0         0 my $split = ON_WIN32 ? qr/\r?\n/ : "\n";
1118 0         0 $self->files( [split $split, $buffer] );
1119             }
1120             }
1121              
1122             ### now, extract the archive ###
1123 0         0 { my $cmd = [ $self->bin_unzip, '-qq', '-o', $self->archive ];
  0         0  
  0         0  
1124              
1125 0         0 my $buffer;
1126 0 0       0 unless( scalar run( command => $cmd,
1127             verbose => $DEBUG,
1128             buffer => \$buffer )
1129             ) {
1130 0         0 return $self->_error(loc("Unable to unzip '%1': %2",
1131             $self->archive, $buffer));
1132             }
1133              
1134 0 0       0 if( scalar @{$self->files} ) {
  0         0  
1135 0         0 my $files = $self->files;
1136 0         0 my $dir = $self->__get_extract_dir( $files );
1137              
1138 0         0 $self->extract_path( $dir );
1139             }
1140             }
1141              
1142 0         0 return 1;
1143             }
1144              
1145             sub _unzip_az {
1146 0     0   0 my $self = shift;
1147              
1148 0         0 my $use_list = { 'Archive::Zip' => '0.0' };
1149 0 0       0 unless( can_load( modules => $use_list ) ) {
1150 0         0 $self->_error(loc("You do not have '%1' installed - Please " .
1151             "install it as soon as possible.", 'Archive::Zip'));
1152 0         0 return METHOD_NA;
1153             }
1154              
1155 0         0 my $zip = Archive::Zip->new();
1156              
1157 0 0       0 unless( $zip->read( $self->archive ) == &Archive::Zip::AZ_OK ) {
1158 0         0 return $self->_error(loc("Unable to read '%1'", $self->archive));
1159             }
1160              
1161 0         0 my @files;
1162              
1163              
1164             ### Address: #43278: Explicitly tell Archive::Zip where to put the files:
1165             ### "In my BackPAN indexing, Archive::Zip was extracting things
1166             ### in my script's directory instead of the current working directory.
1167             ### I traced this back through Archive::Zip::_asLocalName which
1168             ### eventually calls File::Spec::Win32::rel2abs which on Windows might
1169             ### call Cwd::getdcwd. getdcwd returns the wrong directory in my
1170             ### case, even though I think I'm on the same drive.
1171             ###
1172             ### To fix this, I pass the optional second argument to
1173             ### extractMember using the cwd from Archive::Extract." --bdfoy
1174              
1175             ## store cwd() before looping; calls to cwd() can be expensive, and
1176             ### it won't change during the loop
1177 0         0 my $extract_dir = cwd();
1178              
1179             ### have to extract every member individually ###
1180 0         0 for my $member ($zip->members) {
1181 0         0 push @files, $member->{fileName};
1182              
1183             ### file to extract to, to avoid the above problem
1184 0         0 my $to = File::Spec->catfile( $extract_dir, $member->{fileName} );
1185              
1186 0 0       0 unless( $zip->extractMember($member, $to) == &Archive::Zip::AZ_OK ) {
1187             return $self->_error(loc("Extraction of '%1' from '%2' failed",
1188 0         0 $member->{fileName}, $self->archive ));
1189             }
1190             }
1191              
1192 0         0 my $dir = $self->__get_extract_dir( \@files );
1193              
1194             ### set what files where extract, and where they went ###
1195 0         0 $self->files( \@files );
1196 0         0 $self->extract_path( File::Spec->rel2abs($dir) );
1197              
1198 0         0 return 1;
1199             }
1200              
1201             sub __get_extract_dir {
1202 82     82   2112 my $self = shift;
1203 82   50     1205 my $files = shift || [];
1204              
1205 82 100       847 return unless scalar @$files;
1206              
1207 58         170 my($dir1, $dir2);
1208 58         578 for my $aref ( [ \$dir1, 0 ], [ \$dir2, -1 ] ) {
1209 116         384 my($dir,$pos) = @$aref;
1210              
1211             ### add a catdir(), so that any trailing slashes get
1212             ### take care of (removed)
1213             ### also, a catdir() normalises './dir/foo' to 'dir/foo';
1214             ### which was the problem in bug #23999
1215 116 100       10783 my $res = -d $files->[$pos]
1216             ? File::Spec->catdir( $files->[$pos], '' )
1217             : File::Spec->catdir( dirname( $files->[$pos] ) );
1218              
1219 116         790 $$dir = $res;
1220             }
1221              
1222             ### if the first and last dir don't match, make sure the
1223             ### dirname is not set wrongly
1224 58         150 my $dir;
1225              
1226             ### dirs are the same, so we know for sure what the extract dir is
1227 58 50       196 if( $dir1 eq $dir2 ) {
1228 58         443 $dir = $dir1;
1229              
1230             ### dirs are different.. do they share the base dir?
1231             ### if so, use that, if not, fall back to '.'
1232             } else {
1233 0         0 my $base1 = [ File::Spec->splitdir( $dir1 ) ]->[0];
1234 0         0 my $base2 = [ File::Spec->splitdir( $dir2 ) ]->[0];
1235              
1236 0 0       0 $dir = File::Spec->rel2abs( $base1 eq $base2 ? $base1 : '.' );
1237             }
1238              
1239 58         3755 return File::Spec->rel2abs( $dir );
1240             }
1241              
1242             #################################
1243             #
1244             # Bunzip2 code
1245             #
1246             #################################
1247              
1248             sub _bunzip2_bin {
1249 2     2   27 my $self = shift;
1250              
1251             ### check for /bin/gzip -- we need it ###
1252 2 50       29 unless( $self->bin_bunzip2 ) {
1253 0         0 $self->_error(loc("No '%1' program found", '/bin/bunzip2'));
1254 0         0 return METHOD_NA;
1255             }
1256              
1257 2 50       34 my $fh = FileHandle->new('>'. $self->_gunzip_to) or
1258             return $self->_error(loc("Could not open '%1' for writing: %2",
1259             $self->_gunzip_to, $! ));
1260              
1261             ### guard against broken bunzip2. See ->have_old_bunzip2()
1262             ### for details
1263 2 50 33     555 if( $self->have_old_bunzip2 and $self->archive !~ /\.bz2$/i ) {
1264 0         0 return $self->_error(loc("Your bunzip2 version is too old and ".
1265             "can only extract files ending in '%1'",
1266             '.bz2'));
1267             }
1268              
1269 2         46 my $cmd = [ $self->bin_bunzip2, '-cd', $self->archive ];
1270              
1271 2         11 my $buffer;
1272 2 50       28 unless( scalar run( command => $cmd,
1273             verbose => $DEBUG,
1274             buffer => \$buffer )
1275             ) {
1276 0         0 return $self->_error(loc("Unable to bunzip2 '%1': %2",
1277             $self->archive, $buffer));
1278             }
1279              
1280             ### no buffers available?
1281 2 50 66     7719 if( !IPC::Cmd->can_capture_buffer and !$buffer ) {
1282 1         69 $self->_error( $self->_no_buffer_content( $self->archive ) );
1283             }
1284              
1285 2 50       284 $self->_print($fh, $buffer) if defined $buffer;
1286              
1287 2         29 close $fh;
1288              
1289             ### set what files where extract, and where they went ###
1290 2         38 $self->files( [$self->_gunzip_to] );
1291 2         4296 $self->extract_path( File::Spec->rel2abs(cwd()) );
1292              
1293 2         92 return 1;
1294             }
1295              
1296             ### using cz2, the compact versions... this we use mainly in archive::tar
1297             ### extractor..
1298             # sub _bunzip2_cz1 {
1299             # my $self = shift;
1300             #
1301             # my $use_list = { 'IO::Uncompress::Bunzip2' => '0.0' };
1302             # unless( can_load( modules => $use_list ) ) {
1303             # return $self->_error(loc("You do not have '%1' installed - Please " .
1304             # "install it as soon as possible.",
1305             # 'IO::Uncompress::Bunzip2'));
1306             # }
1307             #
1308             # my $bz = IO::Uncompress::Bunzip2->new( $self->archive ) or
1309             # return $self->_error(loc("Unable to open '%1': %2",
1310             # $self->archive,
1311             # $IO::Uncompress::Bunzip2::Bunzip2Error));
1312             #
1313             # my $fh = FileHandle->new('>'. $self->_gunzip_to) or
1314             # return $self->_error(loc("Could not open '%1' for writing: %2",
1315             # $self->_gunzip_to, $! ));
1316             #
1317             # my $buffer;
1318             # $fh->print($buffer) while $bz->read($buffer) > 0;
1319             # $fh->close;
1320             #
1321             # ### set what files where extract, and where they went ###
1322             # $self->files( [$self->_gunzip_to] );
1323             # $self->extract_path( File::Spec->rel2abs(cwd()) );
1324             #
1325             # return 1;
1326             # }
1327              
1328             sub _bunzip2_bz2 {
1329 2     2   34 my $self = shift;
1330              
1331 2         48 my $use_list = { 'IO::Uncompress::Bunzip2' => '0.0' };
1332 2 50       79 unless( can_load( modules => $use_list ) ) {
1333 0         0 $self->_error(loc("You do not have '%1' installed - Please " .
1334             "install it as soon as possible.",
1335             'IO::Uncompress::Bunzip2'));
1336 0         0 return METHOD_NA;
1337             }
1338              
1339 2 50       628 IO::Uncompress::Bunzip2::bunzip2($self->archive => $self->_gunzip_to)
1340             or return $self->_error(loc("Unable to uncompress '%1': %2",
1341             $self->archive,
1342             $IO::Uncompress::Bunzip2::Bunzip2Error));
1343              
1344             ### set what files where extract, and where they went ###
1345 2         7006 $self->files( [$self->_gunzip_to] );
1346 2         12759 $self->extract_path( File::Spec->rel2abs(cwd()) );
1347              
1348 2         67 return 1;
1349             }
1350              
1351             #################################
1352             #
1353             # UnXz code
1354             #
1355             #################################
1356              
1357             sub _unxz_bin {
1358 2     2   21 my $self = shift;
1359              
1360             ### check for /bin/unxz -- we need it ###
1361 2 50       22 unless( $self->bin_unxz ) {
1362 0         0 $self->_error(loc("No '%1' program found", '/bin/unxz'));
1363 0         0 return METHOD_NA;
1364             }
1365              
1366 2 50       34 my $fh = FileHandle->new('>'. $self->_gunzip_to) or
1367             return $self->_error(loc("Could not open '%1' for writing: %2",
1368             $self->_gunzip_to, $! ));
1369              
1370 2         520 my $cmd = [ $self->bin_unxz, '-c', '-d', '-f', $self->archive ];
1371              
1372 2         8 my $buffer;
1373 2 50       49 unless( scalar run( command => $cmd,
1374             verbose => $DEBUG,
1375             buffer => \$buffer )
1376             ) {
1377 0         0 return $self->_error(loc("Unable to unxz '%1': %2",
1378             $self->archive, $buffer));
1379             }
1380              
1381             ### no buffers available?
1382 2 50 66     8758 if( !IPC::Cmd->can_capture_buffer and !$buffer ) {
1383 1         52 $self->_error( $self->_no_buffer_content( $self->archive ) );
1384             }
1385              
1386 2 50       244 $self->_print($fh, $buffer) if defined $buffer;
1387              
1388 2         26 close $fh;
1389              
1390             ### set what files where extract, and where they went ###
1391 2         35 $self->files( [$self->_gunzip_to] );
1392 2         4693 $self->extract_path( File::Spec->rel2abs(cwd()) );
1393              
1394 2         85 return 1;
1395             }
1396              
1397             sub _unxz_cz {
1398 0     0   0 my $self = shift;
1399              
1400 0         0 my $use_list = { 'IO::Uncompress::UnXz' => '0.0' };
1401 0 0       0 unless( can_load( modules => $use_list ) ) {
1402 0         0 $self->_error(loc("You do not have '%1' installed - Please " .
1403             "install it as soon as possible.",
1404             'IO::Uncompress::UnXz'));
1405 0         0 return METHOD_NA;
1406             }
1407              
1408 0 0       0 IO::Uncompress::UnXz::unxz($self->archive => $self->_gunzip_to)
1409             or return $self->_error(loc("Unable to uncompress '%1': %2",
1410             $self->archive,
1411             $IO::Uncompress::UnXz::UnXzError));
1412              
1413             ### set what files where extract, and where they went ###
1414 0         0 $self->files( [$self->_gunzip_to] );
1415 0         0 $self->extract_path( File::Spec->rel2abs(cwd()) );
1416              
1417 0         0 return 1;
1418             }
1419              
1420              
1421             #################################
1422             #
1423             # unlzma code
1424             #
1425             #################################
1426              
1427             sub _unlzma_bin {
1428 2     2   18 my $self = shift;
1429              
1430             ### check for /bin/unlzma -- we need it ###
1431 2 50       35 unless( $self->bin_unlzma ) {
1432 0         0 $self->_error(loc("No '%1' program found", '/bin/unlzma'));
1433 0         0 return METHOD_NA;
1434             }
1435              
1436 2 50       35 my $fh = FileHandle->new('>'. $self->_gunzip_to) or
1437             return $self->_error(loc("Could not open '%1' for writing: %2",
1438             $self->_gunzip_to, $! ));
1439              
1440 2         587 my $cmd = [ $self->bin_unlzma, '-c', $self->archive ];
1441              
1442 2         17 my $buffer;
1443 2 50       53 unless( scalar run( command => $cmd,
1444             verbose => $DEBUG,
1445             buffer => \$buffer )
1446             ) {
1447 0         0 return $self->_error(loc("Unable to unlzma '%1': %2",
1448             $self->archive, $buffer));
1449             }
1450              
1451             ### no buffers available?
1452 2 50 66     11713 if( !IPC::Cmd->can_capture_buffer and !$buffer ) {
1453 1         74 $self->_error( $self->_no_buffer_content( $self->archive ) );
1454             }
1455              
1456 2 50       272 $self->_print($fh, $buffer) if defined $buffer;
1457              
1458 2         41 close $fh;
1459              
1460             ### set what files where extract, and where they went ###
1461 2         48 $self->files( [$self->_gunzip_to] );
1462 2         5640 $self->extract_path( File::Spec->rel2abs(cwd()) );
1463              
1464 2         129 return 1;
1465             }
1466              
1467             sub _unlzma_cz {
1468 0     0   0 my $self = shift;
1469              
1470 0         0 my $use_list1 = { 'IO::Uncompress::UnLzma' => '0.0' };
1471 0         0 my $use_list2 = { 'Compress::unLZMA' => '0.0' };
1472              
1473 0 0       0 if (can_load( modules => $use_list1 ) ) {
    0          
1474 0 0       0 IO::Uncompress::UnLzma::unlzma($self->archive => $self->_gunzip_to)
1475             or return $self->_error(loc("Unable to uncompress '%1': %2",
1476             $self->archive,
1477             $IO::Uncompress::UnLzma::UnLzmaError));
1478             }
1479             elsif (can_load( modules => $use_list2 ) ) {
1480              
1481 0 0       0 my $fh = FileHandle->new('>'. $self->_gunzip_to) or
1482             return $self->_error(loc("Could not open '%1' for writing: %2",
1483             $self->_gunzip_to, $! ));
1484              
1485 0         0 my $buffer;
1486 0         0 $buffer = Compress::unLZMA::uncompressfile( $self->archive );
1487 0 0       0 unless ( defined $buffer ) {
1488 0         0 return $self->_error(loc("Could not unlzma '%1': %2",
1489             $self->archive, $@));
1490             }
1491              
1492 0 0       0 $self->_print($fh, $buffer) if defined $buffer;
1493              
1494 0         0 close $fh;
1495             }
1496             else {
1497 0         0 $self->_error(loc("You do not have '%1' or '%2' installed - Please " .
1498             "install it as soon as possible.", 'Compress::unLZMA', 'IO::Uncompress::UnLzma'));
1499 0         0 return METHOD_NA;
1500             }
1501              
1502             ### set what files where extract, and where they went ###
1503 0         0 $self->files( [$self->_gunzip_to] );
1504 0         0 $self->extract_path( File::Spec->rel2abs(cwd()) );
1505              
1506 0         0 return 1;
1507             }
1508              
1509             #####################################
1510             #
1511             # unzip heuristics for FreeBSD-alikes
1512             #
1513             #####################################
1514              
1515             sub _is_infozip_esque {
1516 0     0   0 my $unzip = shift;
1517              
1518 0         0 my @strings;
1519 0         0 my $buf = '';
1520              
1521             {
1522 0 0       0 open my $file, '<', $unzip or die "$!\n";
  0         0  
1523 0         0 binmode $file;
1524 0         0 local $/ = \1;
1525 0         0 local $_;
1526 0         0 while(<$file>) {
1527 0 0       0 if ( m![[:print:]]! ) {
1528 0         0 $buf .= $_;
1529 0         0 next;
1530             }
1531 0 0 0     0 if ( $buf and m![^[:print:]]! ) {
1532 0 0       0 push @strings, $buf if length $buf >= 4;
1533 0         0 $buf = '';
1534 0         0 next;
1535             }
1536             }
1537             }
1538 0 0       0 push @strings, $buf if $buf;
1539 0         0 foreach my $part ( @strings ) {
1540 0 0 0     0 if ( $part =~ m!ZIPINFO! or $part =~ m!usage:.+?Z1! ) {
1541 0         0 return $unzip;
1542             }
1543             }
1544 0         0 return;
1545             }
1546              
1547             #################################
1548             #
1549             # Error code
1550             #
1551             #################################
1552              
1553             # For printing binaries that avoids interfering globals
1554             sub _print {
1555 3     3   1040 my $self = shift;
1556 3         24 my $fh = shift;
1557              
1558 3         103 local( $\, $", $, ) = ( undef, ' ', '' );
1559 3         71 return print $fh @_;
1560             }
1561              
1562             sub _error {
1563 35     35   2437 my $self = shift;
1564 35         89 my $error = shift;
1565 35         10386 my $lerror = Carp::longmess($error);
1566              
1567 35         8550 push @{$self->_error_msg}, $error;
  35         531  
1568 35         67 push @{$self->_error_msg_long}, $lerror;
  35         256  
1569              
1570             ### set $Archive::Extract::WARN to 0 to disable printing
1571             ### of errors
1572 35 100       113 if( $WARN ) {
1573 1 50       226 carp $DEBUG ? $lerror : $error;
1574             }
1575              
1576 35         224 return;
1577             }
1578              
1579             sub error {
1580 110     110 1 7681 my $self = shift;
1581              
1582             ### make sure we have a fallback aref
1583 110   100     601 my $aref = do {
1584             shift()
1585             ? $self->_error_msg_long
1586             : $self->_error_msg
1587             } || [];
1588              
1589 110         751 return join $/, @$aref;
1590             }
1591              
1592             =head2 debug( MESSAGE )
1593              
1594             This method outputs MESSAGE to the default filehandle if C<$DEBUG> is
1595             true. It's a small method, but it's here if you'd like to subclass it
1596             so you can so something else with any debugging output.
1597              
1598             =cut
1599              
1600             ### this is really a stub for subclassing
1601             sub debug {
1602 192 50   192 1 1161 return unless $DEBUG;
1603              
1604 0         0 print $_[1];
1605             }
1606              
1607             sub _no_buffer_files {
1608 24     24   116 my $self = shift;
1609 24 50       131 my $file = shift or return;
1610 24         506 return loc("No buffer captured, unable to tell ".
1611             "extracted files or extraction dir for '%1'", $file);
1612             }
1613              
1614             sub _no_buffer_content {
1615 5     5   21 my $self = shift;
1616 5 50       22 my $file = shift or return;
1617 5         114 return loc("No buffer captured, unable to get content for '%1'", $file);
1618             }
1619             1;
1620              
1621             =pod
1622              
1623             =head1 UTILITY FUNCTION
1624              
1625             =head2 type_for($archive)
1626              
1627             Given an archive file name, it determins the type by parsing the file
1628             name extension. Used by C when the C parameter is not passed.
1629             Also useful when the archive file does not include a suffix but the file
1630             name is otherwise known, such as when a file is uploaded to a web server
1631             and stored with a temporary name that differs from the original name, and
1632             you want to use the same detection pattern as Archive::Extract. Example:
1633              
1634             my $ae = Archive::Extract->new(
1635             archive => '/tmp/02af6s',
1636             type => Archive::Extract::type_for('archive.zip'),
1637             );
1638              
1639             =head1 HOW IT WORKS
1640              
1641             C tries first to determine what type of archive you
1642             are passing it, by inspecting its suffix. It does not do this by using
1643             Mime magic, or something related. See C below.
1644              
1645             Once it has determined the file type, it knows which extraction methods
1646             it can use on the archive. It will try a perl solution first, then fall
1647             back to a commandline tool if that fails. If that also fails, it will
1648             return false, indicating it was unable to extract the archive.
1649             See the section on C to see how to alter this order.
1650              
1651             =head1 CAVEATS
1652              
1653             =head2 File Extensions
1654              
1655             C trusts on the extension of the archive to determine
1656             what type it is, and what extractor methods therefore can be used. If
1657             your archives do not have any of the extensions as described in the
1658             C method, you will have to specify the type explicitly, or
1659             C will not be able to extract the archive for you.
1660              
1661             =head2 Supporting Very Large Files
1662              
1663             C can use either pure perl modules or command line
1664             programs under the hood. Some of the pure perl modules (like
1665             C and Compress::unLZMA) take the entire contents of the archive into memory,
1666             which may not be feasible on your system. Consider setting the global
1667             variable C<$Archive::Extract::PREFER_BIN> to C<1>, which will prefer
1668             the use of command line programs and won't consume so much memory.
1669              
1670             See the C section below for details.
1671              
1672             =head2 Bunzip2 support of arbitrary extensions.
1673              
1674             Older versions of C do not support arbitrary file
1675             extensions and insist on a C<.bz2> suffix. Although we do our best
1676             to guard against this, if you experience a bunzip2 error, it may
1677             be related to this. For details, please see the C
1678             method.
1679              
1680             =head1 GLOBAL VARIABLES
1681              
1682             =head2 $Archive::Extract::DEBUG
1683              
1684             Set this variable to C to have all calls to command line tools
1685             be printed out, including all their output.
1686             This also enables C errors, instead of the regular
1687             C errors.
1688              
1689             Good for tracking down why things don't work with your particular
1690             setup.
1691              
1692             Defaults to C.
1693              
1694             =head2 $Archive::Extract::WARN
1695              
1696             This variable controls whether errors encountered internally by
1697             C should be C'd or not.
1698              
1699             Set to false to silence warnings. Inspect the output of the C
1700             method manually to see what went wrong.
1701              
1702             Defaults to C.
1703              
1704             =head2 $Archive::Extract::PREFER_BIN
1705              
1706             This variables controls whether C should prefer the
1707             use of perl modules, or commandline tools to extract archives.
1708              
1709             Set to C to have C prefer commandline tools.
1710              
1711             Defaults to C.
1712              
1713             =head1 TODO / CAVEATS
1714              
1715             =over 4
1716              
1717             =item Mime magic support
1718              
1719             Maybe this module should use something like C to determine
1720             the type, rather than blindly trust the suffix.
1721              
1722             =item Thread safety
1723              
1724             Currently, C does a C to the extraction dir before
1725             extraction, and a C back again after. This is not necessarily
1726             thread safe. See C bug C<#45671> for details.
1727              
1728             =back
1729              
1730             =head1 BUG REPORTS
1731              
1732             Please report bugs or other issues to Ebug-archive-extract@rt.cpan.orgE.
1733              
1734             =head1 AUTHOR
1735              
1736             This module by Jos Boumans Ekane@cpan.orgE.
1737              
1738             =head1 COPYRIGHT
1739              
1740             This library is free software; you may redistribute and/or modify it
1741             under the same terms as Perl itself.
1742              
1743             =cut
1744              
1745             # Local variables:
1746             # c-indentation-style: bsd
1747             # c-basic-offset: 4
1748             # indent-tabs-mode: nil
1749             # End:
1750             # vim: expandtab shiftwidth=4:
1751