File Coverage

lib/Archive/Tar.pm
Criterion Covered Total %
statement 502 644 77.9
branch 253 426 59.3
condition 102 168 60.7
subroutine 48 55 87.2
pod 29 30 96.6
total 934 1323 70.6


line stmt bran cond sub pod time code
1             ### the gnu tar specification:
2             ### https://www.gnu.org/software/tar/manual/tar.html
3             ###
4             ### and the pax format spec, which tar derives from:
5             ### https://www.opengroup.org/onlinepubs/007904975/utilities/pax.html
6              
7             package Archive::Tar;
8             require 5.005_03;
9              
10 17     17   2211609 use Cwd;
  17         33  
  17         1644  
11 17     17   10285 use IO::Zlib;
  17         1450285  
  17         164  
12 17     17   1260 use IO::File;
  17         53  
  17         2873  
13 17     17   132 use Carp qw(carp croak);
  17         53  
  17         1021  
14 17     17   119 use File::Spec ();
  17         37  
  17         320  
15 17     17   81 use File::Spec::Unix ();
  17         27  
  17         273  
16 17     17   89 use File::Path ();
  17         30  
  17         450  
17              
18 17     17   10831 use Archive::Tar::File;
  17         64  
  17         736  
19 17     17   121 use Archive::Tar::Constant;
  17         36  
  17         4089  
20              
21             require Exporter;
22              
23 17     17   121 use strict;
  17         44  
  17         1056  
24 17         4602 use vars qw[$DEBUG $error $VERSION $WARN $FOLLOW_SYMLINK $CHOWN $CHMOD
25             $DO_NOT_USE_PREFIX $HAS_PERLIO $HAS_IO_STRING $SAME_PERMISSIONS
26             $INSECURE_EXTRACT_MODE $ZERO_PAD_NUMBERS @ISA @EXPORT $RESOLVE_SYMLINK
27             $EXTRACT_BLOCK_SIZE
28 17     17   136 ];
  17         73  
29              
30             @ISA = qw[Exporter];
31             @EXPORT = qw[ COMPRESS_GZIP COMPRESS_BZIP COMPRESS_XZ ];
32             $DEBUG = 0;
33             $WARN = 1;
34             $FOLLOW_SYMLINK = 0;
35             $VERSION = "3.04";
36             $CHOWN = 1;
37             $CHMOD = 1;
38             $SAME_PERMISSIONS = $> == 0 ? 1 : 0;
39             $DO_NOT_USE_PREFIX = 0;
40             $INSECURE_EXTRACT_MODE = 0;
41             $ZERO_PAD_NUMBERS = 0;
42             $RESOLVE_SYMLINK = $ENV{'PERL5_AT_RESOLVE_SYMLINK'} || 'speed';
43             $EXTRACT_BLOCK_SIZE = 1024 * 1024 * 1024;
44              
45             BEGIN {
46 17     17   141 use Config;
  17         70  
  17         1661  
47 17     17   1859 $HAS_PERLIO = $Config::Config{useperlio};
48              
49             ### try and load IO::String anyway, so you can dynamically
50             ### switch between perlio and IO::String
51 17   50     82 $HAS_IO_STRING = eval {
52             require IO::String;
53             IO::String->import;
54             1;
55             } || 0;
56             }
57              
58             =head1 NAME
59              
60             Archive::Tar - module for manipulations of tar archives
61              
62             =head1 SYNOPSIS
63              
64             use Archive::Tar;
65             my $tar = Archive::Tar->new;
66              
67             $tar->read('origin.tgz');
68             $tar->extract();
69              
70             $tar->add_files('file/foo.pl', 'docs/README');
71             $tar->add_data('file/baz.txt', 'This is the contents now');
72              
73             $tar->rename('oldname', 'new/file/name');
74             $tar->chown('/', 'root');
75             $tar->chown('/', 'root:root');
76             $tar->chmod('/tmp', '1777');
77              
78             $tar->write('files.tar'); # plain tar
79             $tar->write('files.tgz', COMPRESS_GZIP); # gzip compressed
80             $tar->write('files.tbz', COMPRESS_BZIP); # bzip2 compressed
81             $tar->write('files.txz', COMPRESS_XZ); # xz compressed
82              
83             =head1 DESCRIPTION
84              
85             Archive::Tar provides an object oriented mechanism for handling tar
86             files. It provides class methods for quick and easy files handling
87             while also allowing for the creation of tar file objects for custom
88             manipulation. If you have the IO::Zlib module installed,
89             Archive::Tar will also support compressed or gzipped tar files.
90              
91             An object of class Archive::Tar represents a .tar(.gz) archive full
92             of files and things.
93              
94             =head1 Object Methods
95              
96             =head2 Archive::Tar->new( [$file, $compressed] )
97              
98             Returns a new Tar object. If given any arguments, C calls the
99             C method automatically, passing on the arguments provided to
100             the C method.
101              
102             If C is invoked with arguments and the C method fails
103             for any reason, C returns undef.
104              
105             =cut
106              
107             my $tmpl = {
108             _data => [ ],
109             _file => 'Unknown',
110             };
111              
112             ### install get/set accessors for this object.
113             for my $key ( keys %$tmpl ) {
114 17     17   190 no strict 'refs';
  17         38  
  17         169001  
115             *{__PACKAGE__."::$key"} = sub {
116 719     719   1988 my $self = shift;
117 719 100       2862 $self->{$key} = $_[0] if @_;
118 719         3623 return $self->{$key};
119             }
120             }
121              
122             sub new {
123 77     77 1 875441 my $class = shift;
124 77 50       410 $class = ref $class if ref $class;
125              
126             ### copying $tmpl here since a shallow copy makes it use the
127             ### same aref, causing for files to remain in memory always.
128 77         676 my $obj = bless { _data => [ ], _file => 'Unknown', _error => '' }, $class;
129              
130 77 100       369 if (@_) {
131 14 50       55 unless ( $obj->read( @_ ) ) {
132 0         0 $obj->_error(qq[No data could be read from file]);
133 0         0 return;
134             }
135             }
136              
137 77         1820 return $obj;
138             }
139              
140             =head2 $tar->read ( $filename|$handle, [$compressed, {opt => 'val'}] )
141              
142             Read the given tar file into memory.
143             The first argument can either be the name of a file or a reference to
144             an already open filehandle (or an IO::Zlib object if it's compressed)
145              
146             The C will I any previous content in C<$tar>!
147              
148             The second argument may be considered optional, but remains for
149             backwards compatibility. Archive::Tar now looks at the file
150             magic to determine what class should be used to open the file
151             and will transparently Do The Right Thing.
152              
153             Archive::Tar will warn if you try to pass a bzip2 / xz compressed file and the
154             IO::Uncompress::Bunzip2 / IO::Uncompress::UnXz are not available and simply return.
155              
156             Note that you can currently B pass a C compressed
157             filehandle, which is not opened with C, a C compressed
158             filehandle, which is not opened with C, a C compressed
159             filehandle, which is not opened with C, nor a string
160             containing the full archive information (either compressed or
161             uncompressed). These are worth while features, but not currently
162             implemented. See the C section.
163              
164             The third argument can be a hash reference with options. Note that
165             all options are case-sensitive.
166              
167             =over 4
168              
169             =item limit
170              
171             Do not read more than C files. This is useful if you have
172             very big archives, and are only interested in the first few files.
173              
174             =item filter
175              
176             Can be set to a regular expression. Only files with names that match
177             the expression will be read.
178              
179             =item md5
180              
181             Set to 1 and the md5sum of files will be returned (instead of file data)
182             my $iter = Archive::Tar->iter( $file, 1, {md5 => 1} );
183             while( my $f = $iter->() ) {
184             print $f->data . "\t" . $f->full_path . $/;
185             }
186              
187             =item extract
188              
189             If set to true, immediately extract entries when reading them. This
190             gives you the same memory break as the C function.
191             Note however that entries will not be read into memory, but written
192             straight to disk. This means no C objects are
193             created for you to inspect.
194              
195             =back
196              
197             All files are stored internally as C objects.
198             Please consult the L documentation for details.
199              
200             Returns the number of files read in scalar context, and a list of
201             C objects in list context.
202              
203             =cut
204              
205             sub read {
206 50     50 1 4022 my $self = shift;
207 50         114 my $file = shift;
208 50   100     431 my $gzip = shift || 0;
209 50   100     238 my $opts = shift || {};
210              
211 50 100       162 unless( defined $file ) {
212 2         11 $self->_error( qq[No file to read from!] );
213 2         13 return;
214             } else {
215 48         229 $self->_file( $file );
216             }
217              
218 48 50       380 my $handle = $self->_get_handle($file, $gzip, READ_ONLY->( ZLIB ) )
219             or return;
220              
221 48 100       391 my $data = $self->_read_tar( $handle, $opts ) or return;
222              
223 46         311 $self->_data( $data );
224              
225 46 100       604 return wantarray ? @$data : scalar @$data;
226             }
227              
228             sub _get_handle {
229 93     93   216 my $self = shift;
230 93 50       196 my $file = shift; return unless defined $file;
  93         374  
231 93   100     472 my $compress = shift || 0;
232 93   33     301 my $mode = shift || READ_ONLY->( ZLIB ); # default to read only
233              
234             ### Check if file is a file handle or IO glob
235 93 50       323 if ( ref $file ) {
236 0 0       0 return $file if eval{ *$file{IO} };
  0         0  
237 0 0       0 return $file if eval{ $file->isa(q{IO::Handle}) };
  0         0  
238 0         0 $file = q{}.$file;
239             }
240              
241             ### get a FH opened to the right class, so we can use it transparently
242             ### throughout the program
243 93         189 my $fh;
244             { ### reading magic only makes sense if we're opening a file for
245             ### reading. otherwise, just use what the user requested.
246 93         166 my $magic = '';
  93         207  
247 93 100       461 if( MODE_READ->($mode) ) {
248 63 50       4460 open my $tmp, $file or do {
249 0         0 $self->_error( qq[Could not open '$file' for reading: $!] );
250 0         0 return;
251             };
252              
253             ### read the first 6 bytes of the file to figure out which class to
254             ### use to open the file.
255 63         1021 sysread( $tmp, $magic, 6 );
256 63         918 close $tmp;
257             }
258              
259             ### is it xz?
260             ### if you asked specifically for xz compression, or if we're in
261             ### read mode and the magic numbers add up, use xz
262 93 100 100     749 if( XZ and (
    100 66        
263             ($compress eq COMPRESS_XZ) or
264             ( MODE_READ->($mode) and $magic =~ XZ_MAGIC_NUM )
265             )
266             ) {
267             if( MODE_READ->($mode) ) {
268             $fh = IO::Uncompress::UnXz->new( $file ) or do {
269             $self->_error( qq[Could not read '$file': ] .
270             $IO::Uncompress::UnXz::UnXzError
271             );
272             return;
273             };
274             } else {
275             $fh = IO::Compress::Xz->new( $file ) or do {
276             $self->_error( qq[Could not write to '$file': ] .
277             $IO::Compress::Xz::XzError
278             );
279             return;
280             };
281             }
282              
283             ### is it bzip?
284             ### if you asked specifically for bzip compression, or if we're in
285             ### read mode and the magic numbers add up, use bzip
286 0 100 100     0 } elsif( BZIP and (
287             ($compress eq COMPRESS_BZIP) or
288             ( MODE_READ->($mode) and $magic =~ BZIP_MAGIC_NUM )
289             )
290             ) {
291              
292             ### different reader/writer modules, different error vars... sigh
293 17 100       60 if( MODE_READ->($mode) ) {
294 10 50       132 $fh = IO::Uncompress::Bunzip2->new( $file, MultiStream => 1 ) or do {
295 0         0 $self->_error( qq[Could not read '$file': ] .
296             $IO::Uncompress::Bunzip2::Bunzip2Error
297             );
298 0         0 return;
299             };
300              
301             } else {
302 7 50       172 $fh = IO::Compress::Bzip2->new( $file ) or do {
303 0         0 $self->_error( qq[Could not write to '$file': ] .
304             $IO::Compress::Bzip2::Bzip2Error
305             );
306 0         0 return;
307             };
308             }
309              
310             ### is it gzip?
311             ### if you asked for compression, if you wanted to read or the gzip
312             ### magic number is present (redundant with read)
313             } elsif( ZLIB and (
314             $compress or MODE_READ->($mode) or $magic =~ GZIP_MAGIC_NUM
315             )
316             ) {
317 61         755 $fh = IO::Zlib->new;
318              
319 61 50       4042 unless( $fh->open( $file, $mode ) ) {
320 0         0 $self->_error(qq[Could not create filehandle for '$file': $!]);
321 0         0 return;
322             }
323              
324             ### is it plain tar?
325             } else {
326 15         132 $fh = IO::File->new;
327              
328 15 50       621 unless( $fh->open( $file, $mode ) ) {
329 0         0 $self->_error(qq[Could not create filehandle for '$file': $!]);
330 0         0 return;
331             }
332              
333             ### enable bin mode on tar archives
334 15         5638 binmode $fh;
335             }
336             }
337              
338 93         163481 return $fh;
339             }
340              
341              
342             sub _read_tar {
343 81     81   170 my $self = shift;
344 81 50       237 my $handle = shift or return;
345 81   50     226 my $opts = shift || {};
346              
347 81   100     434 my $count = $opts->{limit} || 0;
348 81         199 my $filter = $opts->{filter};
349 81   50     377 my $md5 = $opts->{md5} || 0; # cdrake
350 81         164 my $filter_cb = $opts->{filter_cb};
351 81   100     328 my $extract = $opts->{extract} || 0;
352              
353             ### set a cap on the amount of files to extract ###
354 81         143 my $limit = 0;
355 81 100       236 $limit = 1 if $count > 0;
356              
357 81         157 my $tarfile = [ ];
358 81         153 my $chunk;
359 81         125 my $read = 0;
360 81         223 my $real_name; # to set the name of a file when
361             # we're encountering @longlink
362             my $data;
363              
364             LOOP:
365 81         783 while( $handle->read( $chunk, HEAD ) ) {
366             ### IO::Zlib doesn't support this yet
367 616         103146 my $offset;
368 616 100       1547 if ( ref($handle) ne 'IO::Zlib' ) {
369 81         73 local $@;
370 81   50     89 $offset = eval { tell $handle } || 'unknown';
371 81         801 $@ = '';
372             }
373             else {
374 535         891 $offset = 'unknown';
375             }
376              
377 616 100       1204 unless( $read++ ) {
378 77         223 my $gzip = GZIP_MAGIC_NUM;
379 77 50       805 if( $chunk =~ /$gzip/ ) {
380 0         0 $self->_error( qq[Cannot read compressed format in tar-mode] );
381 0         0 return;
382             }
383              
384             ### size is < HEAD, which means a corrupted file, as the minimum
385             ### length is _at least_ HEAD
386 77 100       271 if (length $chunk != HEAD) {
387 2         19 $self->_error( qq[Cannot read enough bytes from the tarfile] );
388 2         36 return;
389             }
390             }
391              
392             ### if we can't read in all bytes... ###
393 614 100       1272 last if length $chunk != HEAD;
394              
395             ### Apparently this should really be two blocks of 512 zeroes,
396             ### but GNU tar sometimes gets it wrong. See comment in the
397             ### source code (tar.c) to GNU cpio.
398 612 100       1437 next if $chunk eq TAR_END;
399              
400             ### according to the posix spec, the last 12 bytes of the header are
401             ### null bytes, to pad it to a 512 byte block. That means if these
402             ### bytes are NOT null bytes, it's a corrupt header. See:
403             ### www.koders.com/c/fidCE473AD3D9F835D690259D60AD5654591D91D5BA.aspx
404             ### line 111
405 242         317 { my $nulls = join '', "\0" x 12;
  242         422  
406 242 50       619 unless( $nulls eq substr( $chunk, 500, 12 ) ) {
407 0         0 $self->_error( qq[Invalid header block at offset $offset] );
408 0         0 next LOOP;
409             }
410             }
411              
412             ### pass the realname, so we can set it 'proper' right away
413             ### some of the heuristics are done on the name, so important
414             ### to set it ASAP
415 242         304 my $entry;
416 242         303 { my %extra_args = ();
  242         534  
417 242 100       541 $extra_args{'name'} = $$real_name if defined $real_name;
418              
419 242 50       1278 unless( $entry = Archive::Tar::File->new( chunk => $chunk,
420             %extra_args )
421             ) {
422 0         0 $self->_error( qq[Couldn't read chunk at offset $offset] );
423 0         0 next LOOP;
424             }
425             }
426              
427             ### ignore labels:
428             ### https://www.gnu.org/software/tar/manual/html_chapter/Media.html#SEC159
429 242 50       1766 next if $entry->is_label;
430              
431 242 100 66     457 if( length $entry->type and ($entry->is_file || $entry->is_longlink) ) {
      33        
432              
433 184 50 33     351 if ( $entry->is_file && !$entry->validate ) {
434             ### sometimes the chunk is rather fux0r3d and a whole 512
435             ### bytes ends up in the ->name area.
436             ### clean it up, if need be
437 0         0 my $name = $entry->name;
438 0 0       0 $name = substr($name, 0, 100) if length $name > 100;
439 0         0 $name =~ s/\n/ /g;
440              
441 0         0 $self->_error( $name . qq[: checksum error] );
442 0         0 next LOOP;
443             }
444              
445 184         477 my $block = BLOCK_SIZE->( $entry->size );
446              
447 184         473 $data = $entry->get_content_by_ref;
448              
449 184         317 my $skip = 0;
450 184         274 my $ctx; # cdrake
451             ### skip this entry if we're filtering
452              
453 184 50 100     943 if($md5) { # cdrake
    100 100        
    100 33        
    50          
454 0         0 $ctx = Digest::MD5->new; # cdrake
455 0         0 $skip=5; # cdrake
456              
457             } elsif ($filter && $entry->name !~ $filter) {
458 22         44 $skip = 1;
459              
460             } elsif ($filter_cb && ! $filter_cb->($entry)) {
461 22         39 $skip = 2;
462              
463             ### skip this entry if it's a pax header. This is a special file added
464             ### by, among others, git-generated tarballs. It holds comments and is
465             ### not meant for extracting. See #38932: pax_global_header extracted
466             } elsif ( $entry->name eq PAX_HEADER or $entry->type =~ /^(x|g)$/ ) {
467 0         0 $skip = 3;
468             }
469              
470 184 100       416 if ($skip) {
471             #
472             # Since we're skipping, do not allocate memory for the
473             # whole file. Read it 64 BLOCKS at a time. Do not
474             # complete the skip yet because maybe what we read is a
475             # longlink and it won't get skipped after all
476             #
477 44         79 my $amt = $block;
478 44         134 my $fsz=$entry->size; # cdrake
479 44         124 while ($amt > 0) {
480 44         78 $$data = '';
481 44         74 my $this = 64 * BLOCK;
482 44 50       93 $this = $amt if $this > $amt;
483 44 50       331 if( $handle->read( $$data, $this ) < $this ) {
484 0         0 $self->_error( qq[Read error on tarfile (missing data) '].
485             $entry->full_path ."' at offset $offset" );
486 0         0 next LOOP;
487             }
488 44         8183 $amt -= $this;
489 44         86 $fsz -= $this; # cdrake
490 44 50       142 substr ($$data, $fsz) = "" if ($fsz<0); # remove external junk prior to md5 # cdrake
491 44 50       136 $ctx->add($$data) if($skip==5); # cdrake
492             }
493 44 0 33     116 $$data = $ctx->hexdigest if($skip==5 && !$entry->is_longlink && !$entry->is_unknown && !$entry->is_label ) ; # cdrake
      33        
      0        
494             } else {
495              
496             ### just read everything into memory
497             ### can't do lazy loading since IO::Zlib doesn't support 'seek'
498             ### this is because Compress::Zlib doesn't support it =/
499             ### this reads in the whole data in one read() call.
500 140 50       766 if ( $handle->read( $$data, $block ) < $block ) {
501 0         0 $self->_error( qq[Read error on tarfile (missing data) '].
502             $entry->full_path ."' at offset $offset" );
503 0         0 next LOOP;
504             }
505             ### throw away trailing garbage ###
506 140 50       26673 substr ($$data, $entry->size) = "" if defined $$data;
507             }
508              
509             ### part II of the @LongLink munging -- need to do /after/
510             ### the checksum check.
511 184 100       492 if( $entry->is_longlink ) {
512             ### weird thing in tarfiles -- if the file is actually a
513             ### @LongLink, the data part seems to have a trailing ^@
514             ### (unprintable) char. to display, pipe output through less.
515             ### but that doesn't *always* happen.. so check if the last
516             ### character is a control character, and if so remove it
517             ### at any rate, we better remove that character here, or tests
518             ### like 'eq' and hash lookups based on names will SO not work
519             ### remove it by calculating the proper size, and then
520             ### tossing out everything that's longer than that size.
521              
522             ### count number of nulls
523 51         144 my $nulls = $$data =~ tr/\0/\0/;
524              
525             ### cut data + size by that many bytes
526 51         123 $entry->size( $entry->size - $nulls );
527 51         141 substr ($$data, $entry->size) = "";
528             }
529             }
530              
531             ### clean up of the entries.. posix tar /apparently/ has some
532             ### weird 'feature' that allows for filenames > 255 characters
533             ### they'll put a header in with as name '././@LongLink' and the
534             ### contents will be the name of the /next/ file in the archive
535             ### pretty crappy and kludgy if you ask me
536              
537             ### set the name for the next entry if this is a @LongLink;
538             ### this is one ugly hack =/ but needed for direct extraction
539 242 100       567 if( $entry->is_longlink ) {
    100          
540 51         104 $real_name = $data;
541 51         365 next LOOP;
542             } elsif ( defined $real_name ) {
543 51         157 $entry->name( $$real_name );
544 51         132 $entry->prefix('');
545 51         89 undef $real_name;
546             }
547              
548 191 100 100     880 if ($filter && $entry->name !~ $filter) {
    100 100        
    50 33        
549 20         132 next LOOP;
550              
551             } elsif ($filter_cb && ! $filter_cb->($entry)) {
552 20         132 next LOOP;
553              
554             ### skip this entry if it's a pax header. This is a special file added
555             ### by, among others, git-generated tarballs. It holds comments and is
556             ### not meant for extracting. See #38932: pax_global_header extracted
557             } elsif ( $entry->name eq PAX_HEADER or $entry->type =~ /^(x|g)$/ ) {
558 0         0 next LOOP;
559             }
560              
561 151 50 66     561 if ( $extract && !$entry->is_longlink
      66        
      33        
562             && !$entry->is_unknown
563             && !$entry->is_label ) {
564 9 50       45 $self->_extract_file( $entry ) or return;
565             }
566              
567             ### Guard against tarfiles with garbage at the end
568 151 50       574 last LOOP if $entry->name eq '';
569              
570             ### push only the name on the rv if we're extracting
571             ### -- for extract_archive
572 151 100       478 push @$tarfile, ($extract ? $entry->name : $entry);
573              
574 151 100       1087 if( $limit ) {
575 21 100 66     61 $count-- unless $entry->is_longlink || $entry->is_dir;
576 21 100       97 last LOOP unless $count;
577             }
578             } continue {
579 597         3275 undef $data;
580             }
581              
582 79         19860 return $tarfile;
583             }
584              
585             =head2 $tar->contains_file( $filename )
586              
587             Check if the archive contains a certain file.
588             It will return true if the file is in the archive, false otherwise.
589              
590             Note however, that this function does an exact match using C
591             on the full path. So it cannot compensate for case-insensitive file-
592             systems or compare 2 paths to see if they would point to the same
593             underlying file.
594              
595             =cut
596              
597             sub contains_file {
598 2     2 1 4 my $self = shift;
599 2         47 my $full = shift;
600              
601 2 50       7 return unless defined $full;
602              
603             ### don't warn if the entry isn't there.. that's what this function
604             ### is for after all.
605 2         4 local $WARN = 0;
606 2 100       14 return 1 if $self->_find_entry($full);
607 1         3 return;
608             }
609              
610             =head2 $tar->extract( [@filenames] )
611              
612             Write files whose names are equivalent to any of the names in
613             C<@filenames> to disk, creating subdirectories as necessary. This
614             might not work too well under VMS.
615             Under MacPerl, the file's modification time will be converted to the
616             MacOS zero of time, and appropriate conversions will be done to the
617             path. However, the length of each element of the path is not
618             inspected to see whether it's longer than MacOS currently allows (32
619             characters).
620              
621             If C is called without a list of file names, the entire
622             contents of the archive are extracted.
623              
624             Returns a list of filenames extracted.
625              
626             =cut
627              
628             sub extract {
629 32     32 1 32326 my $self = shift;
630 32         105 my @args = @_;
631 32         82 my @files;
632             my $hashmap;
633              
634             # use the speed optimization for all extracted files
635 32 50       245676 local($self->{cwd}) = cwd() unless $self->{cwd};
636              
637             ### you requested the extraction of only certain files
638 32 100       620 if( @args ) {
639 2         34 for my $file ( @args ) {
640              
641             ### it's already an object?
642 2 100       62 if( UNIVERSAL::isa( $file, 'Archive::Tar::File' ) ) {
643 1         17 push @files, $file;
644 1         8 next;
645              
646             ### go find it then
647             } else {
648              
649             # create hash-map once to speed up lookup
650             $hashmap = $hashmap || {
651 1   50     43 map { $_->full_path, $_ } @{$self->_data}
652             };
653              
654 1 50       14 if (exists $hashmap->{$file}) {
655             ### we found the file you're looking for
656 1         8 push @files, $hashmap->{$file};
657             } else {
658 0         0 return $self->_error(
659             qq[Could not find '$file' in archive] );
660             }
661             }
662             }
663              
664             ### just grab all the file items
665             } else {
666 30         673 @files = $self->get_files;
667             }
668              
669             ### nothing found? that's an error
670 32 50       369 unless( scalar @files ) {
671 0         0 $self->_error( qq[No files found for ] . $self->_file );
672 0         0 return;
673             }
674              
675             ### now extract them
676 32         253 for my $entry ( @files ) {
677 111 100       638 unless( $self->_extract_file( $entry ) ) {
678 3         15 $self->_error(q[Could not extract ']. $entry->full_path .q['] );
679 3         16 return;
680             }
681             }
682              
683 29         861 return @files;
684             }
685              
686             =head2 $tar->extract_file( $file, [$extract_path] )
687              
688             Write an entry, whose name is equivalent to the file name provided to
689             disk. Optionally takes a second parameter, which is the full native
690             path (including filename) the entry will be written to.
691              
692             For example:
693              
694             $tar->extract_file( 'name/in/archive', 'name/i/want/to/give/it' );
695              
696             $tar->extract_file( $at_file_object, 'name/i/want/to/give/it' );
697              
698             Returns true on success, false on failure.
699              
700             =cut
701              
702             sub extract_file {
703 165     165 1 1862 my $self = shift;
704 165 50       680 my $file = shift; return unless defined $file;
  165         614  
705 165         369 my $alt = shift;
706              
707 165 50       1498 my $entry = $self->_find_entry( $file )
708             or $self->_error( qq[Could not find an entry for '$file'] ), return;
709              
710 165         699 return $self->_extract_file( $entry, $alt );
711             }
712              
713             sub _extract_file {
714 288     288   689 my $self = shift;
715 288 50       1074 my $entry = shift or return;
716 288         539 my $alt = shift;
717              
718             ### you wanted an alternate extraction location ###
719 288 100       2307 my $name = defined $alt ? $alt : $entry->full_path;
720              
721             ### splitpath takes a bool at the end to indicate
722             ### that it's splitting a dir
723 288         820 my ($vol,$dirs,$file);
724 288 100       811 if ( defined $alt ) { # It's a local-OS path
725 161         966 ($vol,$dirs,$file) = File::Spec->splitpath( $alt,
726             $entry->is_dir );
727             } else {
728 127         726 ($vol,$dirs,$file) = File::Spec::Unix->splitpath( $name,
729             $entry->is_dir );
730             }
731              
732 288         972 my $dir;
733             ### is $name an absolute path? ###
734 288 100 66     5683 if( $vol || File::Spec->file_name_is_absolute( $dirs ) ) {
735              
736             ### absolute names are not allowed to be in tarballs under
737             ### strict mode, so only allow it if a user tells us to do it
738 80 0 33     408 if( not defined $alt and not $INSECURE_EXTRACT_MODE ) {
739 0         0 $self->_error(
740             q[Entry ']. $entry->full_path .q[' is an absolute path. ].
741             q[Not extracting absolute paths under SECURE EXTRACT MODE]
742             );
743 0         0 return;
744             }
745              
746             ### user asked us to, it's fine.
747 80         1037 $dir = File::Spec->catpath( $vol, $dirs, "" );
748              
749             ### it's a relative path ###
750             } else {
751             my $cwd = (ref $self and defined $self->{cwd})
752             ? $self->{cwd}
753 208 100 100     847540 : cwd();
754              
755 208 100       5325 my @dirs = defined $alt
756             ? File::Spec->splitdir( $dirs ) # It's a local-OS path
757             : File::Spec::Unix->splitdir( $dirs ); # it's UNIX-style, likely
758             # straight from the tarball
759              
760 208 100 100     1669 if( not defined $alt and
761             not $INSECURE_EXTRACT_MODE
762             ) {
763              
764             ### paths that leave the current directory are not allowed under
765             ### strict mode, so only allow it if a user tells us to do this.
766 121 100       542 if( grep { $_ eq '..' } @dirs ) {
  124         354  
767              
768 1         19 $self->_error(
769             q[Entry ']. $entry->full_path .q[' is attempting to leave ].
770             q[the current working directory. Not extracting under ].
771             q[SECURE EXTRACT MODE]
772             );
773 1         19 return;
774             }
775              
776             ### the archive may be asking us to extract into a symlink. This
777             ### is not sane and a possible security issue, as outlined here:
778             ### https://rt.cpan.org/Ticket/Display.html?id=30380
779             ### https://bugzilla.redhat.com/show_bug.cgi?id=295021
780             ### https://issues.rpath.com/browse/RPL-1716
781 120         449 my $full_path = $cwd;
782 120         419 for my $d ( @dirs ) {
783 120         932 $full_path = File::Spec->catdir( $full_path, $d );
784              
785             ### we've already checked this one, and it's safe. Move on.
786 120 100 100     708 next if ref $self and $self->{_link_cache}->{$full_path};
787              
788 26 100       774 if( -l $full_path ) {
789 2         81 my $to = readlink $full_path;
790 2         8 my $diag = "symlinked directory ($full_path => $to)";
791              
792 2         8 $self->_error(
793             q[Entry ']. $entry->full_path .q[' is attempting to ].
794             qq[extract to a $diag. This is considered a security ].
795             q[vulnerability and not allowed under SECURE EXTRACT ].
796             q[MODE]
797             );
798 2         13 return;
799             }
800              
801             ### XXX keep a cache if possible, so the stats become cheaper:
802 24 100       167 $self->{_link_cache}->{$full_path} = 1 if ref $self;
803             }
804             }
805              
806             ### '.' is the directory delimiter on VMS, which has to be escaped
807             ### or changed to '_' on vms. vmsify is used, because older versions
808             ### of vmspath do not handle this properly.
809             ### Must not add a '/' to an empty directory though.
810 205         571 map { length() ? VMS::Filespec::vmsify($_.'/') : $_ } @dirs if ON_VMS;
811              
812 205         8474 my ($cwd_vol,$cwd_dir,$cwd_file)
813             = File::Spec->splitpath( $cwd );
814 205         2438 my @cwd = File::Spec->splitdir( $cwd_dir );
815 205 50       1034 push @cwd, $cwd_file if length $cwd_file;
816              
817             ### We need to pass '' as the last element to catpath. Craig Berry
818             ### explains why (msgid ):
819             ### The root problem is that splitpath on UNIX always returns the
820             ### final path element as a file even if it is a directory, and of
821             ### course there is no way it can know the difference without checking
822             ### against the filesystem, which it is documented as not doing. When
823             ### you turn around and call catpath, on VMS you have to know which bits
824             ### are directory bits and which bits are file bits. In this case we
825             ### know the result should be a directory. I had thought you could omit
826             ### the file argument to catpath in such a case, but apparently on UNIX
827             ### you can't.
828 205         6357 $dir = File::Spec->catpath(
829             $cwd_vol, File::Spec->catdir( @cwd, @dirs ), ''
830             );
831              
832             ### catdir() returns undef if the path is longer than 255 chars on
833             ### older VMS systems.
834 205 50       1295 unless ( defined $dir ) {
835 0 0       0 $^W && $self->_error( qq[Could not compose a path for '$dirs'\n] );
836 0         0 return;
837             }
838              
839             }
840              
841 285 50 66     12605 if( -e $dir && !-d _ ) {
842 0 0       0 $^W && $self->_error( qq['$dir' exists, but it's not a directory!\n] );
843 0         0 return;
844             }
845              
846 285 100       1103 unless ( -d _ ) {
847 12         39 eval { File::Path::mkpath( $dir, 0, 0777 ) };
  12         5379  
848 12 100       89 if( $@ ) {
849 1         20 my $fp = $entry->full_path;
850 1         19 $self->_error(qq[Could not create directory '$dir' for '$fp': $@]);
851 1         9 return;
852             }
853              
854             ### XXX chown here? that might not be the same as in the archive
855             ### as we're only chown'ing to the owner of the file we're extracting
856             ### not to the owner of the directory itself, which may or may not
857             ### be another entry in the archive
858             ### Answer: no, gnu tar doesn't do it either, it'd be the wrong
859             ### way to go.
860             #if( $CHOWN && CAN_CHOWN ) {
861             # chown $entry->uid, $entry->gid, $dir or
862             # $self->_error( qq[Could not set uid/gid on '$dir'] );
863             #}
864             }
865              
866             ### we're done if we just needed to create a dir ###
867 284 100       3148 return 1 if $entry->is_dir;
868              
869 266         4092 my $full = File::Spec->catfile( $dir, $file );
870              
871 266 50       2820 if( $entry->is_unknown ) {
872 0         0 $self->_error( qq[Unknown file type for file '$full'] );
873 0         0 return;
874             }
875              
876             ### If a file system already contains a block device with the same name as
877             ### the being extracted regular file, we would write the file's content
878             ### to the block device. So remove the existing file (block device) now.
879             ### If an archive contains multiple same-named entries, the last one
880             ### should replace the previous ones. So remove the old file now.
881             ### If the old entry is a symlink to a file outside of the CWD, the new
882             ### entry would create a file there. This is CVE-2018-12015
883             ### .
884 266 100 66     6552 if (-l $full || -e _) {
885 9 50       3052 if (!unlink $full) {
886 0         0 $self->_error( qq[Could not remove old file '$full': $!] );
887 0         0 return;
888             }
889             }
890 266 100 66     983 if( length $entry->type && $entry->is_file ) {
891 260         5513 my $fh = IO::File->new;
892 260 50       21227 $fh->open( $full, '>' ) or (
893             $self->_error( qq[Could not open file '$full': $!] ),
894             return
895             );
896              
897 260 100       67207 if( $entry->size ) {
898 234         1302 binmode $fh;
899 234         828 my $offset = 0;
900 234         1359 my $content = $entry->get_content_by_ref();
901 234         661 while ($offset < $entry->size) {
902 16827         236399 my $written
903             = syswrite $fh, $$content, $EXTRACT_BLOCK_SIZE, $offset;
904 16827 50       34963 if (defined $written) {
905 16827         41836 $offset += $written;
906             } else {
907 0         0 $self->_error( qq[Could not write data to '$full': $!] );
908 0         0 return;
909             }
910             }
911             }
912              
913 260 50       6644 close $fh or (
914             $self->_error( qq[Could not close file '$full'] ),
915             return
916             );
917              
918             } else {
919 6 50       75 $self->_make_special_file( $entry, $full ) or return;
920             }
921              
922             ### only update the timestamp if it's not a symlink; that will change the
923             ### timestamp of the original. This addresses bug #33669: Could not update
924             ### timestamp warning on symlinks
925 266 100       6691 if( not -l $full ) {
926 260 50       2119 utime time, $entry->mtime - TIME_OFFSET, $full or
927             $self->_error( qq[Could not update timestamp] );
928             }
929              
930 266 100 33     3826 if( $CHOWN && CAN_CHOWN->() and not -l $full ) {
      66        
931 260 50       1539 CORE::chown( $entry->uid, $entry->gid, $full ) or
932             $self->_error( qq[Could not set uid/gid on '$full'] );
933             }
934              
935             ### only chmod if we're allowed to, but never chmod symlinks, since they'll
936             ### change the perms on the file they're linking too...
937 266 100 66     5377 if( $CHMOD and not -l $full ) {
938 260         1805 my $mode = $entry->mode;
939 260 50       711 unless ($SAME_PERMISSIONS) {
940 0         0 $mode &= ~(oct(7000) | umask);
941             }
942 260 50       5105 CORE::chmod( $mode, $full ) or
943             $self->_error( qq[Could not chown '$full' to ] . $entry->mode );
944             }
945              
946 266         4899 return 1;
947             }
948              
949             sub _make_special_file {
950 6     6   20 my $self = shift;
951 6 50       24 my $entry = shift or return;
952 6 50       13 my $file = shift; return unless defined $file;
  6         16  
953              
954 6         12 my $err;
955              
956 6 50 0     31 if( $entry->is_symlink ) {
    0          
    0          
    0          
    0          
957 6         11 my $fail;
958 6         16 if( ON_UNIX ) {
959 6 50       96 symlink( $entry->linkname, $file ) or $fail++;
960              
961             } else {
962             $self->_extract_special_file_as_plain_file( $entry, $file )
963             or $fail++;
964             }
965              
966 6 50       39 $err = qq[Making symbolic link '$file' to '] .
967             $entry->linkname .q[' failed] if $fail;
968              
969             } elsif ( $entry->is_hardlink ) {
970 0         0 my $fail;
971 0         0 if( ON_UNIX ) {
972 0 0       0 link( $entry->linkname, $file ) or $fail++;
973              
974             } else {
975             $self->_extract_special_file_as_plain_file( $entry, $file )
976             or $fail++;
977             }
978              
979 0 0       0 $err = qq[Making hard link from '] . $entry->linkname .
980             qq[' to '$file' failed] if $fail;
981              
982             } elsif ( $entry->is_fifo ) {
983 0 0       0 ON_UNIX && !system('mknod', $file, 'p') or
984             $err = qq[Making fifo ']. $entry->name .qq[' failed];
985              
986             } elsif ( $entry->is_blockdev or $entry->is_chardev ) {
987 0 0       0 my $mode = $entry->is_blockdev ? 'b' : 'c';
988              
989 0 0       0 ON_UNIX && !system('mknod', $file, $mode,
990             $entry->devmajor, $entry->devminor) or
991             $err = qq[Making block device ']. $entry->name .qq[' (maj=] .
992             $entry->devmajor . qq[ min=] . $entry->devminor .
993             qq[) failed.];
994              
995             } elsif ( $entry->is_socket ) {
996             ### the original doesn't do anything special for sockets.... ###
997 0         0 1;
998             }
999              
1000 6 50       48 return $err ? $self->_error( $err ) : 1;
1001             }
1002              
1003             ### don't know how to make symlinks, let's just extract the file as
1004             ### a plain file
1005             sub _extract_special_file_as_plain_file {
1006 0     0   0 my $self = shift;
1007 0 0       0 my $entry = shift or return;
1008 0 0       0 my $file = shift; return unless defined $file;
  0         0  
1009              
1010 0         0 my $err;
1011             TRY: {
1012 0         0 my $orig = $self->_find_entry( $entry->linkname, $entry );
  0         0  
1013              
1014 0 0       0 unless( $orig ) {
1015 0         0 $err = qq[Could not find file '] . $entry->linkname .
1016             qq[' in memory.];
1017 0         0 last TRY;
1018             }
1019              
1020             ### clone the entry, make it appear as a normal file ###
1021 0         0 my $clone = $orig->clone;
1022 0         0 $clone->_downgrade_to_plainfile;
1023 0 0       0 $self->_extract_file( $clone, $file ) or last TRY;
1024              
1025 0         0 return 1;
1026             }
1027              
1028 0         0 return $self->_error($err);
1029             }
1030              
1031             =head2 $tar->list_files( [\@properties] )
1032              
1033             Returns a list of the names of all the files in the archive.
1034              
1035             If C is passed an array reference as its first argument
1036             it returns a list of hash references containing the requested
1037             properties of each file. The following list of properties is
1038             supported: name, size, mtime (last modified date), mode, uid, gid,
1039             linkname, uname, gname, devmajor, devminor, prefix.
1040              
1041             Passing an array reference containing only one element, 'name', is
1042             special cased to return a list of names rather than a list of hash
1043             references, making it equivalent to calling C without
1044             arguments.
1045              
1046             =cut
1047              
1048             sub list_files {
1049 38     38 1 368 my $self = shift;
1050 38   50     515 my $aref = shift || [ ];
1051              
1052 38 50       192 unless( $self->_data ) {
1053 0 0       0 $self->read() or return;
1054             }
1055              
1056 38 50 0     178 if( @$aref == 0 or ( @$aref == 1 and $aref->[0] eq 'name' ) ) {
      33        
1057 38         72 return map { $_->full_path } @{$self->_data};
  137         357  
  38         93  
1058             } else {
1059              
1060             #my @rv;
1061             #for my $obj ( @{$self->_data} ) {
1062             # push @rv, { map { $_ => $obj->$_() } @$aref };
1063             #}
1064             #return @rv;
1065              
1066             ### this does the same as the above.. just needs a +{ }
1067             ### to make sure perl doesn't confuse it for a block
1068 0         0 return map { my $o=$_;
1069 0         0 +{ map { $_ => $o->$_() } @$aref }
  0         0  
1070 0         0 } @{$self->_data};
  0         0  
1071             }
1072             }
1073              
1074             sub _find_entry {
1075 218     218   10303 my $self = shift;
1076 218         819 my $file = shift;
1077              
1078 218 50       676 unless( defined $file ) {
1079 0         0 $self->_error( qq[No file specified] );
1080 0         0 return;
1081             }
1082              
1083             ### it's an object already
1084 218 100       3334 return $file if UNIVERSAL::isa( $file, 'Archive::Tar::File' );
1085              
1086             seach_entry:
1087 202 50       1426 if($self->_data){
1088 202         406 for my $entry ( @{$self->_data} ) {
  202         431  
1089 510         1385 my $path = $entry->full_path;
1090 510 100       2515 return $entry if $path eq $file;
1091             }
1092             }
1093              
1094 3 50       18 if($Archive::Tar::RESOLVE_SYMLINK!~/none/){
1095 3 50       13 if(my $link_entry = shift()){#fallback mode when symlinks are using relative notations ( ../a/./b/text.bin )
1096 0         0 $file = _symlinks_resolver( $link_entry->name, $file );
1097 0 0       0 goto seach_entry if $self->_data;
1098              
1099             #this will be slower than never, but won't failed!
1100              
1101 0         0 my $iterargs = $link_entry->{'_archive'};
1102 0 0 0     0 if($Archive::Tar::RESOLVE_SYMLINK=~/speed/ && @$iterargs==3){
1103             #faster but whole archive will be read in memory
1104             #read whole archive and share data
1105 0         0 my $archive = Archive::Tar->new;
1106 0         0 $archive->read( @$iterargs );
1107 0         0 push @$iterargs, $archive; #take a trace for destruction
1108 0 0       0 if($archive->_data){
1109 0         0 $self->_data( $archive->_data );
1110 0         0 goto seach_entry;
1111             }
1112             }#faster
1113              
1114             {#slower but lower memory usage
1115             # $iterargs = [$filename, $compressed, $opts];
1116 0         0 my $next = Archive::Tar->iter( @$iterargs );
  0         0  
1117 0         0 while(my $e = $next->()){
1118 0 0       0 if($e->full_path eq $file){
1119 0         0 undef $next;
1120 0         0 return $e;
1121             }
1122             }
1123             }#slower
1124             }
1125             }
1126              
1127 3         18 $self->_error( qq[No such file in archive: '$file'] );
1128 3         8 return;
1129             }
1130              
1131             =head2 $tar->get_files( [@filenames] )
1132              
1133             Returns the C objects matching the filenames
1134             provided. If no filename list was passed, all C
1135             objects in the current Tar object are returned.
1136              
1137             Please refer to the C documentation on how to
1138             handle these objects.
1139              
1140             =cut
1141              
1142             sub get_files {
1143 109     109 1 11103 my $self = shift;
1144              
1145 109 100       1445 return @{ $self->_data } unless @_;
  105         859  
1146              
1147 4         6 my @list;
1148 4         21 for my $file ( @_ ) {
1149 4         16 push @list, grep { defined } $self->_find_entry( $file );
  2         10  
1150             }
1151              
1152 4         45 return @list;
1153             }
1154              
1155             =head2 $tar->get_content( $file )
1156              
1157             Return the content of the named file.
1158              
1159             =cut
1160              
1161             sub get_content {
1162 11     11 1 3295 my $self = shift;
1163 11 50       34 my $entry = $self->_find_entry( shift ) or return;
1164              
1165 11         42 return $entry->data;
1166             }
1167              
1168             =head2 $tar->replace_content( $file, $content )
1169              
1170             Make the string $content be the content for the file named $file.
1171              
1172             =cut
1173              
1174             sub replace_content {
1175 1     1 1 3 my $self = shift;
1176 1 50       4 my $entry = $self->_find_entry( shift ) or return;
1177              
1178 1         6 return $entry->replace_content( shift );
1179             }
1180              
1181             =head2 $tar->rename( $file, $new_name )
1182              
1183             Rename the file of the in-memory archive to $new_name.
1184              
1185             Note that you must specify a Unix path for $new_name, since per tar
1186             standard, all files in the archive must be Unix paths.
1187              
1188             Returns true on success and false on failure.
1189              
1190             =cut
1191              
1192             sub rename {
1193 2     2 1 410 my $self = shift;
1194 2 50       5 my $file = shift; return unless defined $file;
  2         9  
1195 2 50       6 my $new = shift; return unless defined $new;
  2         7  
1196              
1197 2 50       9 my $entry = $self->_find_entry( $file ) or return;
1198              
1199 2         11 return $entry->rename( $new );
1200             }
1201              
1202             =head2 $tar->chmod( $file, $mode )
1203              
1204             Change mode of $file to $mode.
1205              
1206             Returns true on success and false on failure.
1207              
1208             =cut
1209              
1210             sub chmod {
1211 1     1 1 3 my $self = shift;
1212 1 50       2 my $file = shift; return unless defined $file;
  1         5  
1213 1 50 33     3 my $mode = shift; return unless defined $mode && $mode =~ /^[0-7]{1,4}$/;
  1         12  
1214 1         4 my @args = ("$mode");
1215              
1216 1 50       5 my $entry = $self->_find_entry( $file ) or return;
1217 1         4 my $x = $entry->chmod( @args );
1218 1         7 return $x;
1219             }
1220              
1221             =head2 $tar->chown( $file, $uname [, $gname] )
1222              
1223             Change owner $file to $uname and $gname.
1224              
1225             Returns true on success and false on failure.
1226              
1227             =cut
1228              
1229             sub chown {
1230 2     2 1 5 my $self = shift;
1231 2 50       4 my $file = shift; return unless defined $file;
  2         7  
1232 2 50       5 my $uname = shift; return unless defined $uname;
  2         6  
1233 2         4 my @args = ($uname);
1234 2         5 push(@args, shift);
1235              
1236 2 50       5 my $entry = $self->_find_entry( $file ) or return;
1237 2         24 my $x = $entry->chown( @args );
1238 2         12 return $x;
1239             }
1240              
1241             =head2 $tar->remove (@filenamelist)
1242              
1243             Removes any entries with names matching any of the given filenames
1244             from the in-memory archive. Returns a list of C
1245             objects that remain.
1246              
1247             =cut
1248              
1249             sub remove {
1250 1     1 1 647 my $self = shift;
1251 1         4 my @list = @_;
1252              
1253 1         2 my %seen = map { $_->full_path => $_ } @{$self->_data};
  5         8  
  1         3  
1254 1         5 delete $seen{ $_ } for @list;
1255              
1256 1         3 $self->_data( [values %seen] );
1257              
1258 1         7 return values %seen;
1259             }
1260              
1261             =head2 $tar->clear
1262              
1263             C clears the current in-memory archive. This effectively gives
1264             you a 'blank' object, ready to be filled again. Note that C
1265             only has effect on the object, not the underlying tarfile.
1266              
1267             =cut
1268              
1269             sub clear {
1270 2 50   2 1 580 my $self = shift or return;
1271              
1272 2         26 $self->_data( [] );
1273 2         13 $self->_file( '' );
1274              
1275 2         16 return 1;
1276             }
1277              
1278              
1279             =head2 $tar->write ( [$file, $compressed, $prefix] )
1280              
1281             Write the in-memory archive to disk. The first argument can either
1282             be the name of a file or a reference to an already open filehandle (a
1283             GLOB reference).
1284              
1285             The second argument is used to indicate compression. You can
1286             compress using C, C or C. If you pass a digit, it's assumed
1287             to be the C compression level (between 1 and 9), but the use of
1288             constants is preferred:
1289              
1290             # write a gzip compressed file
1291             $tar->write( 'out.tgz', COMPRESS_GZIP );
1292              
1293             # write a bzip compressed file
1294             $tar->write( 'out.tbz', COMPRESS_BZIP );
1295              
1296             # write a xz compressed file
1297             $tar->write( 'out.txz', COMPRESS_XZ );
1298              
1299             Note that when you pass in a filehandle, the compression argument
1300             is ignored, as all files are printed verbatim to your filehandle.
1301             If you wish to enable compression with filehandles, use an
1302             C, C or C filehandle instead.
1303              
1304             The third argument is an optional prefix. All files will be tucked
1305             away in the directory you specify as prefix. So if you have files
1306             'a' and 'b' in your archive, and you specify 'foo' as prefix, they
1307             will be written to the archive as 'foo/a' and 'foo/b'.
1308              
1309             If no arguments are given, C returns the entire formatted
1310             archive as a string, which could be useful if you'd like to stuff the
1311             archive into a socket or a pipe to gzip or something.
1312              
1313              
1314             =cut
1315              
1316             sub write {
1317 33     33 1 7242 my $self = shift;
1318 33 100       136 my $file = shift; $file = '' unless defined $file;
  33         309  
1319 33   100     250 my $gzip = shift || 0;
1320 33 50       63 my $ext_prefix = shift; $ext_prefix = '' unless defined $ext_prefix;
  33         155  
1321 33         130 my $dummy = '';
1322              
1323             ### only need a handle if we have a file to print to ###
1324             my $handle = length($file)
1325             ? ( $self->_get_handle($file, $gzip, WRITE_ONLY->($gzip) )
1326             or return )
1327 33 0 50     326 : $HAS_PERLIO ? do { open my $h, '>', \$dummy; $h }
  3 50       60  
  3 100       10  
1328             : $HAS_IO_STRING ? IO::String->new
1329             : __PACKAGE__->no_string_support();
1330              
1331             ### Addresses: #41798: Nonempty $\ when writing a TAR file produces a
1332             ### corrupt TAR file. Must clear out $\ to make sure no garbage is
1333             ### printed to the archive
1334 33         183 local $\;
1335              
1336 33         131 for my $entry ( @{$self->_data} ) {
  33         139  
1337             ### entries to be written to the tarfile ###
1338 74         1644 my @write_me;
1339              
1340             ### only now will we change the object to reflect the current state
1341             ### of the name and prefix fields -- this needs to be limited to
1342             ### write() only!
1343 74         372 my $clone = $entry->clone;
1344              
1345              
1346             ### so, if you don't want use to use the prefix, we'll stuff
1347             ### everything in the name field instead
1348 74 100       314 if( $DO_NOT_USE_PREFIX ) {
1349              
1350             ### you might have an extended prefix, if so, set it in the clone
1351             ### XXX is ::Unix right?
1352 4 50       24 $clone->name( length $ext_prefix
1353             ? File::Spec::Unix->catdir( $ext_prefix,
1354             $clone->full_path)
1355             : $clone->full_path );
1356 4         17 $clone->prefix( '' );
1357              
1358             ### otherwise, we'll have to set it properly -- prefix part in the
1359             ### prefix and name part in the name field.
1360             } else {
1361              
1362             ### split them here, not before!
1363 70         244 my ($prefix,$name) = $clone->_prefix_and_file( $clone->full_path );
1364              
1365             ### you might have an extended prefix, if so, set it in the clone
1366             ### XXX is ::Unix right?
1367 70 50       253 $prefix = File::Spec::Unix->catdir( $ext_prefix, $prefix )
1368             if length $ext_prefix;
1369              
1370 70         192 $clone->prefix( $prefix );
1371 70         136 $clone->name( $name );
1372             }
1373              
1374             ### names are too long, and will get truncated if we don't add a
1375             ### '@LongLink' file...
1376 74   100     153 my $make_longlink = ( length($clone->name) > NAME_LENGTH or
1377             length($clone->prefix) > PREFIX_LENGTH
1378             ) || 0;
1379              
1380             ### perhaps we need to make a longlink file?
1381 74 100       290 if( $make_longlink ) {
1382 9         83 my $longlink = Archive::Tar::File->new(
1383             data => LONGLINK_NAME,
1384             $clone->full_path,
1385             { type => LONGLINK }
1386             );
1387              
1388 9 50       29 unless( $longlink ) {
1389 0         0 $self->_error( qq[Could not create 'LongLink' entry for ] .
1390             qq[oversize file '] . $clone->full_path ."'" );
1391 0         0 return;
1392             };
1393              
1394 9         14 push @write_me, $longlink;
1395             }
1396              
1397 74         142 push @write_me, $clone;
1398              
1399             ### write the one, optionally 2 a::t::file objects to the handle
1400 74         177 for my $clone (@write_me) {
1401              
1402             ### if the file is a symlink, there are 2 options:
1403             ### either we leave the symlink intact, but then we don't write any
1404             ### data OR we follow the symlink, which means we actually make a
1405             ### copy. if we do the latter, we have to change the TYPE of the
1406             ### clone to 'FILE'
1407 83   66     624 my $link_ok = $clone->is_symlink && $Archive::Tar::FOLLOW_SYMLINK;
1408 83   100     228 my $data_ok = !$clone->is_symlink && $clone->has_content;
1409              
1410             ### downgrade to a 'normal' file if it's a symlink we're going to
1411             ### treat as a regular file
1412 83 50       197 $clone->_downgrade_to_plainfile if $link_ok;
1413              
1414             ### get the header for this block
1415 83         312 my $header = $self->_format_tar_entry( $clone );
1416 83 50       207 unless( $header ) {
1417 0         0 $self->_error(q[Could not format header for: ] .
1418             $clone->full_path );
1419 0         0 return;
1420             }
1421              
1422 83 50       731 unless( print $handle $header ) {
1423 0         0 $self->_error(q[Could not write header for: ] .
1424             $clone->full_path);
1425 0         0 return;
1426             }
1427              
1428 83 100 66     8633 if( $link_ok or $data_ok ) {
1429 70 50       222 unless( print $handle $clone->data ) {
1430 0         0 $self->_error(q[Could not write data for: ] .
1431             $clone->full_path);
1432 0         0 return;
1433             }
1434              
1435             ### pad the end of the clone if required ###
1436 70 50       7424 print $handle TAR_PAD->( $clone->size ) if $clone->size % BLOCK
1437             }
1438              
1439             } ### done writing these entries
1440             }
1441              
1442             ### write the end markers ###
1443 33 50       1847 print $handle TAR_END x 2 or
1444             return $self->_error( qq[Could not write tar end markers] );
1445              
1446             ### did you want it written to a file, or returned as a string? ###
1447             my $rv = length($file) ? 1
1448             : $HAS_PERLIO ? $dummy
1449 33 50       1733 : do { seek $handle, 0, 0; local $/; <$handle> };
  0 100       0  
  0         0  
  0         0  
1450              
1451             ### make sure to close the handle if we created it
1452 33 50       166 if ( $file ne $handle ) {
1453 33 50       2312 unless( close $handle ) {
1454 0         0 $self->_error( qq[Could not write tar] );
1455 0         0 return;
1456             }
1457             }
1458              
1459 33         28168 return $rv;
1460             }
1461              
1462             sub _format_tar_entry {
1463 83     83   198 my $self = shift;
1464 83 50       195 my $entry = shift or return;
1465 83 50       151 my $ext_prefix = shift; $ext_prefix = '' unless defined $ext_prefix;
  83         253  
1466 83   50     387 my $no_prefix = shift || 0;
1467              
1468 83         173 my $file = $entry->name;
1469 83 50       225 my $prefix = $entry->prefix; $prefix = '' unless defined $prefix;
  83         170  
1470              
1471             ### remove the prefix from the file name
1472             ### not sure if this is still needed --kane
1473             ### no it's not -- Archive::Tar::File->_new_from_file will take care of
1474             ### this for us. Even worse, this would break if we tried to add a file
1475             ### like x/x.
1476             #if( length $prefix ) {
1477             # $file =~ s/^$match//;
1478             #}
1479              
1480 83 50       166 $prefix = File::Spec::Unix->catdir($ext_prefix, $prefix)
1481             if length $ext_prefix;
1482              
1483             ### not sure why this is... ###
1484 83         133 my $l = PREFIX_LENGTH; # is ambiguous otherwise...
1485 83 100       182 substr ($prefix, 0, -$l) = "" if length $prefix >= PREFIX_LENGTH;
1486              
1487 83 50       185 my $f1 = "%06o"; my $f2 = $ZERO_PAD_NUMBERS ? "%011o" : "%11o";
  83         195  
1488              
1489             ### this might be optimizable with a 'changed' flag in the file objects ###
1490             my $tar = pack (
1491             PACK,
1492             $file,
1493              
1494 249         665 (map { sprintf( $f1, $entry->$_() ) } qw[mode uid gid]),
1495 166         392 (map { sprintf( $f2, $entry->$_() ) } qw[size mtime]),
1496              
1497             "", # checksum field - space padded a bit down
1498              
1499 249         668 (map { $entry->$_() } qw[type linkname magic]),
1500              
1501             $entry->version || TAR_VERSION,
1502              
1503 166         395 (map { $entry->$_() } qw[uname gname]),
1504 83 50 50     190 (map { sprintf( $f1, $entry->$_() ) } qw[devmajor devminor]),
  166         381  
1505              
1506             ($no_prefix ? '' : $prefix)
1507             );
1508              
1509             ### add the checksum ###
1510 83 50       276 my $checksum_fmt = $ZERO_PAD_NUMBERS ? "%06o\0" : "%06o\0";
1511 83         570 substr($tar,148,7) = sprintf("%6o\0", unpack("%16C*",$tar));
1512              
1513 83         226 return $tar;
1514             }
1515              
1516             =head2 $tar->add_files( @filenamelist )
1517              
1518             Takes a list of filenames and adds them to the in-memory archive.
1519              
1520             The path to the file is automatically converted to a Unix like
1521             equivalent for use in the archive, and, if on MacOS, the file's
1522             modification time is converted from the MacOS epoch to the Unix epoch.
1523             So tar archives created on MacOS with B can be read
1524             both with I on Unix and applications like I or
1525             I on MacOS.
1526              
1527             Be aware that the file's type/creator and resource fork will be lost,
1528             which is usually what you want in cross-platform archives.
1529              
1530             Instead of a filename, you can also pass it an existing C
1531             object from, for example, another archive. The object will be clone, and
1532             effectively be a copy of the original, not an alias.
1533              
1534             Returns a list of C objects that were just added.
1535              
1536             =cut
1537              
1538             sub add_files {
1539 25     25 1 5899 my $self = shift;
1540 25 50       189 my @files = @_ or return;
1541              
1542 25         73 my @rv;
1543 25         123 for my $file ( @files ) {
1544              
1545             ### you passed an Archive::Tar::File object
1546             ### clone it so we don't accidentally have a reference to
1547             ### an object from another archive
1548 29 100       351 if( UNIVERSAL::isa( $file,'Archive::Tar::File' ) ) {
1549 7         19 push @rv, $file->clone;
1550 7         11 next;
1551             }
1552              
1553 22         56 eval {
1554 22 50       121 if( utf8::is_utf8( $file )) {
1555 0         0 utf8::encode( $file );
1556             }
1557             };
1558              
1559 22 50 33     623 unless( -e $file || -l $file ) {
1560 0         0 $self->_error( qq[No such file: '$file'] );
1561 0         0 next;
1562             }
1563              
1564 22         237 my $obj = Archive::Tar::File->new( file => $file );
1565 22 50       82 unless( $obj ) {
1566 0         0 $self->_error( qq[Unable to add file: '$file'] );
1567 0         0 next;
1568             }
1569              
1570 22         97 push @rv, $obj;
1571             }
1572              
1573 25         43 push @{$self->{_data}}, @rv;
  25         108  
1574              
1575 25         92 return @rv;
1576             }
1577              
1578             =head2 $tar->add_data ( $filename, $data, [$opthashref] )
1579              
1580             Takes a filename, a scalar full of data and optionally a reference to
1581             a hash with specific options.
1582              
1583             Will add a file to the in-memory archive, with name C<$filename> and
1584             content C<$data>. Specific properties can be set using C<$opthashref>.
1585             The following list of properties is supported: name, size, mtime
1586             (last modified date), mode, uid, gid, linkname, uname, gname,
1587             devmajor, devminor, prefix, type. (On MacOS, the file's path and
1588             modification times are converted to Unix equivalents.)
1589              
1590             Valid values for the file type are the following constants defined by
1591             Archive::Tar::Constant:
1592              
1593             =over 4
1594              
1595             =item FILE
1596              
1597             Regular file.
1598              
1599             =item HARDLINK
1600              
1601             =item SYMLINK
1602              
1603             Hard and symbolic ("soft") links; linkname should specify target.
1604              
1605             =item CHARDEV
1606              
1607             =item BLOCKDEV
1608              
1609             Character and block devices. devmajor and devminor should specify the major
1610             and minor device numbers.
1611              
1612             =item DIR
1613              
1614             Directory.
1615              
1616             =item FIFO
1617              
1618             FIFO (named pipe).
1619              
1620             =item SOCKET
1621              
1622             Socket.
1623              
1624             =back
1625              
1626             Returns the C object that was just added, or
1627             C on failure.
1628              
1629             =cut
1630              
1631             sub add_data {
1632 14     14 1 9453 my $self = shift;
1633 14         46 my ($file, $data, $opt) = @_;
1634              
1635 14         104 my $obj = Archive::Tar::File->new( data => $file, $data, $opt );
1636 14 100       36 unless( $obj ) {
1637 1         4 $self->_error( qq[Unable to add file: '$file'] );
1638 1         2 return;
1639             }
1640              
1641 13         21 push @{$self->{_data}}, $obj;
  13         45  
1642              
1643 13         53 return $obj;
1644             }
1645              
1646             =head2 $tar->error( [$BOOL] )
1647              
1648             Returns the current error string (usually, the last error reported).
1649             If a true value was specified, it will give the C
1650             equivalent of the error, in effect giving you a stacktrace.
1651              
1652             For backwards compatibility, this error is also available as
1653             C<$Archive::Tar::error> although it is much recommended you use the
1654             method call instead.
1655              
1656             =cut
1657              
1658             {
1659             $error = '';
1660             my $longmess;
1661              
1662             sub _error {
1663 15     15   34 my $self = shift;
1664 15         47 my $msg = $error = shift;
1665 15         4661 $longmess = Carp::longmess($error);
1666 15 50       86 if (ref $self) {
1667 15         61 $self->{_error} = $error;
1668 15         80 $self->{_longmess} = $longmess;
1669             }
1670              
1671             ### set Archive::Tar::WARN to 0 to disable printing
1672             ### of errors
1673 15 100       53 if( $WARN ) {
1674 6 50       1039 carp $DEBUG ? $longmess : $msg;
1675             }
1676              
1677 15         87 return;
1678             }
1679              
1680             sub error {
1681 22     22 1 3645 my $self = shift;
1682 22 100       68 if (ref $self) {
1683 20 50       187 return shift() ? $self->{_longmess} : $self->{_error};
1684             } else {
1685 2 50       14 return shift() ? $longmess : $error;
1686             }
1687             }
1688             }
1689              
1690             =head2 $tar->setcwd( $cwd );
1691              
1692             C needs to know the current directory, and it will run
1693             C I time it extracts a I entry from the
1694             tarfile and saves it in the file system. (As of version 1.30, however,
1695             C will use the speed optimization described below
1696             automatically, so it's only relevant if you're using C).
1697              
1698             Since C doesn't change the current directory internally
1699             while it is extracting the items in a tarball, all calls to C
1700             can be avoided if we can guarantee that the current directory doesn't
1701             get changed externally.
1702              
1703             To use this performance boost, set the current directory via
1704              
1705             use Cwd;
1706             $tar->setcwd( cwd() );
1707              
1708             once before calling a function like C and
1709             C will use the current directory setting from then on
1710             and won't call C internally.
1711              
1712             To switch back to the default behaviour, use
1713              
1714             $tar->setcwd( undef );
1715              
1716             and C will call C internally again.
1717              
1718             If you're using C's C method, C will
1719             be called for you.
1720              
1721             =cut
1722              
1723             sub setcwd {
1724 0     0 1 0 my $self = shift;
1725 0         0 my $cwd = shift;
1726              
1727 0         0 $self->{cwd} = $cwd;
1728             }
1729              
1730             =head1 Class Methods
1731              
1732             =head2 Archive::Tar->create_archive($file, $compressed, @filelist)
1733              
1734             Creates a tar file from the list of files provided. The first
1735             argument can either be the name of the tar file to create or a
1736             reference to an open file handle (e.g. a GLOB reference).
1737              
1738             The second argument is used to indicate compression. You can
1739             compress using C, C or C. If you pass a digit, it's assumed
1740             to be the C compression level (between 1 and 9), but the use of
1741             constants is preferred:
1742              
1743             # write a gzip compressed file
1744             Archive::Tar->create_archive( 'out.tgz', COMPRESS_GZIP, @filelist );
1745              
1746             # write a bzip compressed file
1747             Archive::Tar->create_archive( 'out.tbz', COMPRESS_BZIP, @filelist );
1748              
1749             # write a xz compressed file
1750             Archive::Tar->create_archive( 'out.txz', COMPRESS_XZ, @filelist );
1751              
1752             Note that when you pass in a filehandle, the compression argument
1753             is ignored, as all files are printed verbatim to your filehandle.
1754             If you wish to enable compression with filehandles, use an
1755             C, C or C filehandle instead.
1756              
1757             The remaining arguments list the files to be included in the tar file.
1758             These files must all exist. Any files which don't exist or can't be
1759             read are silently ignored.
1760              
1761             If the archive creation fails for any reason, C will
1762             return false. Please use the C method to find the cause of the
1763             failure.
1764              
1765             Note that this method does not write C as it were; it
1766             still reads all the files into memory before writing out the archive.
1767             Consult the FAQ below if this is a problem.
1768              
1769             =cut
1770              
1771             sub create_archive {
1772 9     9 1 50 my $class = shift;
1773              
1774 9 50       28 my $file = shift; return unless defined $file;
  9         65  
1775 9   100     56 my $gzip = shift || 0;
1776 9         48 my @files = @_;
1777              
1778 9 50       30 unless( @files ) {
1779 0         0 return $class->_error( qq[Cowardly refusing to create empty archive!] );
1780             }
1781              
1782 9         85 my $tar = $class->new;
1783 9         126 $tar->add_files( @files );
1784 9         107 return $tar->write( $file, $gzip );
1785             }
1786              
1787             =head2 Archive::Tar->iter( $filename, [ $compressed, {opt => $val} ] )
1788              
1789             Returns an iterator function that reads the tar file without loading
1790             it all in memory. Each time the function is called it will return the
1791             next file in the tarball. The files are returned as
1792             C objects. The iterator function returns the
1793             empty list once it has exhausted the files contained.
1794              
1795             The second argument can be a hash reference with options, which are
1796             identical to the arguments passed to C.
1797              
1798             Example usage:
1799              
1800             my $next = Archive::Tar->iter( "example.tar.gz", 1, {filter => qr/\.pm$/} );
1801              
1802             while( my $f = $next->() ) {
1803             print $f->name, "\n";
1804              
1805             $f->extract or warn "Extraction failed";
1806              
1807             # ....
1808             }
1809              
1810             =cut
1811              
1812              
1813             sub iter {
1814 15     15 1 30557 my $class = shift;
1815 15         41 my $filename = shift;
1816 15 50       58 return unless defined $filename;
1817 15   100     82 my $compressed = shift || 0;
1818 15   100     62 my $opts = shift || {};
1819              
1820             ### get a handle to read from.
1821 15 50       111 my $handle = $class->_get_handle(
1822             $filename,
1823             $compressed,
1824             READ_ONLY->( ZLIB )
1825             ) or return;
1826              
1827 15         37 my @data;
1828 15         43 my $CONSTRUCT_ARGS = [ $filename, $compressed, $opts ];
1829             return sub {
1830 35 100   35   12010 return shift(@data) if @data; # more than one file returned?
1831 33 50       93 return unless $handle; # handle exhausted?
1832              
1833             ### read data, should only return file
1834 33         329 my $tarfile = $class->_read_tar($handle, { %$opts, limit => 1 });
1835 33 50 33     313 @data = @$tarfile if ref $tarfile && ref $tarfile eq 'ARRAY';
1836 33 50       135 if($Archive::Tar::RESOLVE_SYMLINK!~/none/){
1837 33         102 foreach(@data){
1838             #may refine this heuristic for ON_UNIX?
1839 20 100       77 if($_->linkname){
1840             #is there a better slot to store/share it ?
1841 1         8 $_->{'_archive'} = $CONSTRUCT_ARGS;
1842             }
1843             }
1844             }
1845              
1846             ### return one piece of data
1847 33 100       148 return shift(@data) if @data;
1848              
1849             ### data is exhausted, free the filehandle
1850 15         214 undef $handle;
1851 15 50       2481 if(@$CONSTRUCT_ARGS == 4){
1852             #free archive in memory
1853 0         0 undef $CONSTRUCT_ARGS->[-1];
1854             }
1855 15         62 return;
1856 15         136 };
1857             }
1858              
1859             =head2 Archive::Tar->list_archive($file, $compressed, [\@properties])
1860              
1861             Returns a list of the names of all the files in the archive. The
1862             first argument can either be the name of the tar file to list or a
1863             reference to an open file handle (e.g. a GLOB reference).
1864              
1865             If C is passed an array reference as its third
1866             argument it returns a list of hash references containing the requested
1867             properties of each file. The following list of properties is
1868             supported: full_path, name, size, mtime (last modified date), mode,
1869             uid, gid, linkname, uname, gname, devmajor, devminor, prefix, type.
1870              
1871             See C for details about supported properties.
1872              
1873             Passing an array reference containing only one element, 'name', is
1874             special cased to return a list of names rather than a list of hash
1875             references.
1876              
1877             =cut
1878              
1879             sub list_archive {
1880 3     3 1 1600 my $class = shift;
1881 3 50       7 my $file = shift; return unless defined $file;
  3         12  
1882 3   50     20 my $gzip = shift || 0;
1883              
1884 3         15 my $tar = $class->new($file, $gzip);
1885 3 50       11 return unless $tar;
1886              
1887 3         17 return $tar->list_files( @_ );
1888             }
1889              
1890             =head2 Archive::Tar->extract_archive($file, $compressed)
1891              
1892             Extracts the contents of the tar file. The first argument can either
1893             be the name of the tar file to create or a reference to an open file
1894             handle (e.g. a GLOB reference). All relative paths in the tar file will
1895             be created underneath the current working directory.
1896              
1897             C will return a list of files it extracted.
1898             If the archive extraction fails for any reason, C
1899             will return false. Please use the C method to find the cause
1900             of the failure.
1901              
1902             =cut
1903              
1904             sub extract_archive {
1905 9     9 1 28 my $class = shift;
1906 9 50       92 my $file = shift; return unless defined $file;
  9         39  
1907 9   100     74 my $gzip = shift || 0;
1908              
1909 9 50       47 my $tar = $class->new( ) or return;
1910              
1911 9         50 return $tar->read( $file, $gzip, { extract => 1 } );
1912             }
1913              
1914             =head2 $bool = Archive::Tar->has_io_string
1915              
1916             Returns true if we currently have C support loaded.
1917              
1918             Either C or C support is needed to support writing
1919             stringified archives. Currently, C is the preferred method, if
1920             available.
1921              
1922             See the C section to see how to change this preference.
1923              
1924             =cut
1925              
1926 0     0 1 0 sub has_io_string { return $HAS_IO_STRING; }
1927              
1928             =head2 $bool = Archive::Tar->has_perlio
1929              
1930             Returns true if we currently have C support loaded.
1931              
1932             This requires C or higher, compiled with C
1933              
1934             Either C or C support is needed to support writing
1935             stringified archives. Currently, C is the preferred method, if
1936             available.
1937              
1938             See the C section to see how to change this preference.
1939              
1940             =cut
1941              
1942 0     0 1 0 sub has_perlio { return $HAS_PERLIO; }
1943              
1944             =head2 $bool = Archive::Tar->has_zlib_support
1945              
1946             Returns true if C can extract C compressed archives
1947              
1948             =cut
1949              
1950 6     6 1 328895 sub has_zlib_support { return ZLIB }
1951              
1952             =head2 $bool = Archive::Tar->has_bzip2_support
1953              
1954             Returns true if C can extract C compressed archives
1955              
1956             =cut
1957              
1958 6     6 1 27 sub has_bzip2_support { return BZIP }
1959              
1960             =head2 $bool = Archive::Tar->has_xz_support
1961              
1962             Returns true if C can extract C compressed archives
1963              
1964             =cut
1965              
1966 5     5 1 42 sub has_xz_support { return XZ }
1967              
1968             =head2 Archive::Tar->can_handle_compressed_files
1969              
1970             A simple checking routine, which will return true if C
1971             is able to uncompress compressed archives on the fly with C,
1972             C and C or false if not both are installed.
1973              
1974             You can use this as a shortcut to determine whether C
1975             will do what you think before passing compressed archives to its
1976             C method.
1977              
1978             =cut
1979              
1980 0     0 1   sub can_handle_compressed_files { return ZLIB && BZIP ? 1 : 0 }
1981              
1982             sub no_string_support {
1983 0     0 0   croak("You have to install IO::String to support writing archives to strings");
1984             }
1985              
1986             sub _symlinks_resolver{
1987 0     0     my ($src, $trg) = @_;
1988 0           my @src = split /[\/\\]/, $src;
1989 0           my @trg = split /[\/\\]/, $trg;
1990 0           pop @src; #strip out current object name
1991 0 0 0       if(@trg and $trg[0] eq ''){
1992 0           shift @trg;
1993             #restart path from scratch
1994 0           @src = ( );
1995             }
1996 0           foreach my $part ( @trg ){
1997 0 0         next if $part eq '.'; #ignore current
1998 0 0         if($part eq '..'){
1999             #got to parent
2000 0           pop @src;
2001             }
2002             else{
2003             #append it
2004 0           push @src, $part;
2005             }
2006             }
2007 0           my $path = join('/', @src);
2008 0 0         warn "_symlinks_resolver('$src','$trg') = $path" if $DEBUG;
2009 0           return $path;
2010             }
2011              
2012             1;
2013              
2014             __END__