File Coverage

lib/Archive/Tar.pm
Criterion Covered Total %
statement 525 647 81.1
branch 255 426 59.8
condition 104 168 61.9
subroutine 49 56 87.5
pod 29 30 96.6
total 962 1327 72.4


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 9     9   295922 use Cwd;
  9         65  
  9         568  
11 9     9   4162 use IO::Zlib;
  9         538009  
  9         64  
12 9     9   546 use IO::File;
  9         21  
  9         1228  
13 9     9   75 use Carp qw(carp croak);
  9         26  
  9         790  
14 9     9   54 use File::Spec ();
  9         19  
  9         170  
15 9     9   44 use File::Spec::Unix ();
  9         19  
  9         165  
16 9     9   40 use File::Path ();
  9         19  
  9         173  
17              
18 9     9   4083 use Archive::Tar::File;
  9         23  
  9         278  
19 9     9   60 use Archive::Tar::Constant;
  9         20  
  9         1593  
20              
21             require Exporter;
22              
23 9     9   67 use strict;
  9         15  
  9         400  
24 9         2104 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 9     9   57 ];
  9         26  
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.00";
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 9     9   65 use Config;
  9         32  
  9         900  
47 9     9   935 $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 9   50     35 $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 9     9   56 no strict 'refs';
  9         26  
  9         63404  
115             *{__PACKAGE__."::$key"} = sub {
116 818     818   2216 my $self = shift;
117 818 100       2029 $self->{$key} = $_[0] if @_;
118 818         3555 return $self->{$key};
119             }
120             }
121              
122             sub new {
123 82     80 1 195205 my $class = shift;
124 80 50       346 $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 80         695 my $obj = bless { _data => [ ], _file => 'Unknown', _error => '' }, $class;
129              
130 80 100       290 if (@_) {
131 25 50       85 unless ( $obj->read( @_ ) ) {
132 0         0 $obj->_error(qq[No data could be read from file]);
133 0         0 return;
134             }
135             }
136              
137 80         2765 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 59     60 1 3492 my $self = shift;
207 59         147 my $file = shift;
208 59   100     314 my $gzip = shift || 0;
209 59   100     269 my $opts = shift || {};
210              
211 59 100       164 unless( defined $file ) {
212 2         9 $self->_error( qq[No file to read from!] );
213 2         8 return;
214             } else {
215 57         234 $self->_file( $file );
216             }
217              
218 57 50       419 my $handle = $self->_get_handle($file, $gzip, READ_ONLY->( ZLIB ) )
219             or return;
220              
221 58 100       288 my $data = $self->_read_tar( $handle, $opts ) or return;
222              
223 56         264 $self->_data( $data );
224              
225 56 100       634 return wantarray ? @$data : scalar @$data;
226             }
227              
228             sub _get_handle {
229 100     99   243 my $self = shift;
230 100 50       175 my $file = shift; return unless defined $file;
  100         241  
231 99   100     423 my $compress = shift || 0;
232 99   33     245 my $mode = shift || READ_ONLY->( ZLIB ); # default to read only
233              
234             ### Check if file is a file handle or IO glob
235 99 50       247 if ( ref $file ) {
236 0 0       0 return $file if eval{ *$file{IO} };
  0         0  
237 1 0       3 return $file if eval{ $file->isa(q{IO::Handle}) };
  1         2  
238 1         2 $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 100         141 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 99         142 my $magic = '';
  99         209  
247 99 100       325 if( MODE_READ->($mode) ) {
248 69 50       3549 open my $tmp, $file or do {
249 0         0 $self->_error( qq[Could not open '$file' for reading: $!] );
250 1         6 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 69         1040 sysread( $tmp, $magic, 6 );
256 69         912 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 99 100 100     839 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 20 100       75 if( MODE_READ->($mode) ) {
294 12 50       136 $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 8 50       214 $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 66         708 $fh = IO::Zlib->new;
318              
319 67 50       3882 unless( $fh->open( $file, $mode ) ) {
320 1         33 $self->_error(qq[Could not create filehandle for '$file': $!]);
321 0         0 return;
322             }
323              
324             ### is it plain tar?
325             } else {
326 13         96 $fh = IO::File->new;
327              
328 14 50       680 unless( $fh->open( $file, $mode ) ) {
329 1         5 $self->_error(qq[Could not create filehandle for '$file': $!]);
330 0         0 return;
331             }
332              
333             ### enable bin mode on tar archives
334 13         1562 binmode $fh;
335             }
336             }
337              
338 99         155244 return $fh;
339             }
340              
341              
342             sub _read_tar {
343 84     84   166 my $self = shift;
344 84 50       231 my $handle = shift or return;
345 84   50     185 my $opts = shift || {};
346              
347 84   100     429 my $count = $opts->{limit} || 0;
348 84         158 my $filter = $opts->{filter};
349 84   50     334 my $md5 = $opts->{md5} || 0; # cdrake
350 84         127 my $filter_cb = $opts->{filter_cb};
351 84   100     372 my $extract = $opts->{extract} || 0;
352              
353             ### set a cap on the amount of files to extract ###
354 84         115 my $limit = 0;
355 84 100       214 $limit = 1 if $count > 0;
356              
357 84         134 my $tarfile = [ ];
358 84         112 my $chunk;
359 84         114 my $read = 0;
360 84         124 my $real_name; # to set the name of a file when
361             # we're encountering @longlink
362             my $data;
363              
364             LOOP:
365 84         617 while( $handle->read( $chunk, HEAD ) ) {
366             ### IO::Zlib doesn't support this yet
367 723         103563 my $offset;
368 723 100       1430 if ( ref($handle) ne 'IO::Zlib' ) {
369 105         123 local $@;
370 105   50     144 $offset = eval { tell $handle } || 'unknown';
371 105         1239 $@ = '';
372             }
373             else {
374 618         844 $offset = 'unknown';
375             }
376              
377 723 100       1260 unless( $read++ ) {
378 80         184 my $gzip = GZIP_MAGIC_NUM;
379 80 50       745 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 80 100       246 if (length $chunk != HEAD) {
387 2         12 $self->_error( qq[Cannot read enough bytes from the tarfile] );
388 2         25 return;
389             }
390             }
391              
392             ### if we can't read in all bytes... ###
393 721 100       1219 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 718 100       1317 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 292         301 { my $nulls = join '', "\0" x 12;
  292         382  
406 292 50       601 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 292         327 my $entry;
416 292         286 { my %extra_args = ();
  292         412  
417 292 100       539 $extra_args{'name'} = $$real_name if defined $real_name;
418              
419 292 50       1309 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 292 50       635 next if $entry->is_label;
430              
431 292 100 66     532 if( length $entry->type and ($entry->is_file || $entry->is_longlink) ) {
      33        
432              
433 214 50 33     407 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 214         492 my $block = BLOCK_SIZE->( $entry->size );
446              
447 214         434 $data = $entry->get_content_by_ref;
448              
449 214         259 my $skip = 0;
450 214         268 my $ctx; # cdrake
451             ### skip this entry if we're filtering
452              
453 214 50 100     908 if($md5) { # cdrake
    100 100        
    100 66        
    100          
454 0         0 $ctx = Digest::MD5->new; # cdrake
455 0         0 $skip=5; # cdrake
456              
457             } elsif ($filter && $entry->name !~ $filter) {
458 22         34 $skip = 1;
459              
460             } elsif ($filter_cb && ! $filter_cb->($entry)) {
461 22         33 $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 1         18 $skip = 3;
468             }
469              
470 214 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 45         57 my $amt = $block;
478 45         83 my $fsz=$entry->size; # cdrake
479 45         107 while ($amt > 0) {
480 45         57 $$data = '';
481 45         50 my $this = 64 * BLOCK;
482 45 50       91 $this = $amt if $this > $amt;
483 45 50       197 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 45         5994 $amt -= $this;
489 45         65 $fsz -= $this; # cdrake
490 45 50       83 substr ($$data, $fsz) = "" if ($fsz<0); # remove external junk prior to md5 # cdrake
491 45 50       117 $ctx->add($$data) if($skip==5); # cdrake
492             }
493 45 0 33     101 $$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 169 50       790 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 169 50       25499 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 214 100       587 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 63         162 my $nulls = $$data =~ tr/\0/\0/;
524              
525             ### cut data + size by that many bytes
526 63         171 $entry->size( $entry->size - $nulls );
527 63         149 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 292 100       577 if( $entry->is_longlink ) {
    100          
540 63         82 $real_name = $data;
541 63         318 next LOOP;
542             } elsif ( defined $real_name ) {
543 63         158 $entry->name( $$real_name );
544 63         147 $entry->prefix('');
545 63         109 undef $real_name;
546             }
547              
548 229 100 100     915 if ($filter && $entry->name !~ $filter) {
    100 100        
    100 66        
549 20         77 next LOOP;
550              
551             } elsif ($filter_cb && ! $filter_cb->($entry)) {
552 20         83 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 1         6 next LOOP;
559             }
560              
561 188 50 66     507 if ( $extract && !$entry->is_longlink
      66        
      33        
562             && !$entry->is_unknown
563             && !$entry->is_label ) {
564 9 50       44 $self->_extract_file( $entry ) or return;
565             }
566              
567             ### Guard against tarfiles with garbage at the end
568 188 50       484 last LOOP if $entry->name eq '';
569              
570             ### push only the name on the rv if we're extracting
571             ### -- for extract_archive
572 188 100       479 push @$tarfile, ($extract ? $entry->name : $entry);
573              
574 188 100       869 if( $limit ) {
575 18 100 66     39 $count-- unless $entry->is_longlink || $entry->is_dir;
576 18 100       60 last LOOP unless $count;
577             }
578             } continue {
579 706         2993 undef $data;
580             }
581              
582 82         17454 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         7 my $full = shift;
600              
601 2 50       12 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       11 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 35     35 1 22964 my $self = shift;
630 35         90 my @args = @_;
631 35         58 my @files;
632             my $hashmap;
633              
634             # use the speed optimization for all extracted files
635 35 50       115033 local($self->{cwd}) = cwd() unless $self->{cwd};
636              
637             ### you requested the extraction of only certain files
638 35 100       738 if( @args ) {
639 2         30 for my $file ( @args ) {
640              
641             ### it's already an object?
642 2 100       60 if( UNIVERSAL::isa( $file, 'Archive::Tar::File' ) ) {
643 1         17 push @files, $file;
644 1         12 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     44 map { $_->full_path, $_ } @{$self->_data}
652             };
653              
654 1 50       11 if (exists $hashmap->{$file}) {
655             ### we found the file you're looking for
656 1         16 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 33         637 @files = $self->get_files;
667             }
668              
669             ### nothing found? that's an error
670 35 50       222 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 35         317 for my $entry ( @files ) {
677 123 100       673 unless( $self->_extract_file( $entry ) ) {
678 3         12 $self->_error(q[Could not extract ']. $entry->full_path .q['] );
679 3         10 return;
680             }
681             }
682              
683 32         810 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 185     185 1 1391 my $self = shift;
704 185 50       477 my $file = shift; return unless defined $file;
  185         452  
705 185         301 my $alt = shift;
706              
707 185 50       1280 my $entry = $self->_find_entry( $file )
708             or $self->_error( qq[Could not find an entry for '$file'] ), return;
709              
710 185         804 return $self->_extract_file( $entry, $alt );
711             }
712              
713             sub _extract_file {
714 319     319   552 my $self = shift;
715 319 50       737 my $entry = shift or return;
716 319         518 my $alt = shift;
717              
718             ### you wanted an alternate extraction location ###
719 319 100       1469 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 319         550 my ($vol,$dirs,$file);
724 319 100       695 if ( defined $alt ) { # It's a local-OS path
725 181         440 ($vol,$dirs,$file) = File::Spec->splitpath( $alt,
726             $entry->is_dir );
727             } else {
728 138         664 ($vol,$dirs,$file) = File::Spec::Unix->splitpath( $name,
729             $entry->is_dir );
730             }
731              
732 319         694 my $dir;
733             ### is $name an absolute path? ###
734 319 100 66     4665 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 90 0 33     288 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 90         525 $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 229 100 100     346494 : cwd();
754              
755 229 100       5284 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 229 100 100     1318 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 132 100       458 if( grep { $_ eq '..' } @dirs ) {
  133         493  
767              
768 1         106 $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         24 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 131         384 my $full_path = $cwd;
782 131         463 for my $d ( @dirs ) {
783 129         801 $full_path = File::Spec->catdir( $full_path, $d );
784              
785             ### we've already checked this one, and it's safe. Move on.
786 129 100 100     798 next if ref $self and $self->{_link_cache}->{$full_path};
787              
788 23 100       519 if( -l $full_path ) {
789 2         38 my $to = readlink $full_path;
790 2         8 my $diag = "symlinked directory ($full_path => $to)";
791              
792 2         18 $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         10 return;
799             }
800              
801             ### XXX keep a cache if possible, so the stats become cheaper:
802 21 100       150 $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 226         334 map { length() ? VMS::Filespec::vmsify($_.'/') : $_ } @dirs if ON_VMS;
811              
812 226         8017 my ($cwd_vol,$cwd_dir,$cwd_file)
813             = File::Spec->splitpath( $cwd );
814 226         2123 my @cwd = File::Spec->splitdir( $cwd_dir );
815 226 50       963 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 226         4849 $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 226 50       1061 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 316 50 66     7767 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 316 100       891 unless ( -d _ ) {
847 12         31 eval { File::Path::mkpath( $dir, 0, 0777 ) };
  12         3570  
848 12 100       61 if( $@ ) {
849 1         20 my $fp = $entry->full_path;
850 1         20 $self->_error(qq[Could not create directory '$dir' for '$fp': $@]);
851 1         11 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 315 100       3095 return 1 if $entry->is_dir;
868              
869 295         2981 my $full = File::Spec->catfile( $dir, $file );
870              
871 295 50       1449 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 295 100 66     5465 if (-l $full || -e _) {
885 9 50       817 if (!unlink $full) {
886 0         0 $self->_error( qq[Could not remove old file '$full': $!] );
887 0         0 return;
888             }
889             }
890 295 100 66     1107 if( length $entry->type && $entry->is_file ) {
891 289         4241 my $fh = IO::File->new;
892 289 50       20476 $fh->open( $full, '>' ) or (
893             $self->_error( qq[Could not open file '$full': $!] ),
894             return
895             );
896              
897 289 100       36735 if( $entry->size ) {
898 260         1129 binmode $fh;
899 260         870 my $offset = 0;
900 260         1225 my $content = $entry->get_content_by_ref();
901 260         589 while ($offset < $entry->size) {
902 16853         176206 my $written
903             = syswrite $fh, $$content, $EXTRACT_BLOCK_SIZE, $offset;
904 16853 50       37556 if (defined $written) {
905 16853         45053 $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 289 50       4404 close $fh or (
914             $self->_error( qq[Could not close file '$full'] ),
915             return
916             );
917              
918             } else {
919 6 50       68 $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 295 100       4785 if( not -l $full ) {
926 289 50       1735 utime time, $entry->mtime - TIME_OFFSET, $full or
927             $self->_error( qq[Could not update timestamp] );
928             }
929              
930 295 100 33     2638 if( $CHOWN && CAN_CHOWN->() and not -l $full ) {
      66        
931 289 50       1117 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 295 100 66     5011 if( $CHMOD and not -l $full ) {
938 289         1543 my $mode = $entry->mode;
939 289 50       608 unless ($SAME_PERMISSIONS) {
940 0         0 $mode &= ~(oct(7000) | umask);
941             }
942 289 50       4637 CORE::chmod( $mode, $full ) or
943             $self->_error( qq[Could not chown '$full' to ] . $entry->mode );
944             }
945              
946 295         4467 return 1;
947             }
948              
949             sub _make_special_file {
950 6     6   23 my $self = shift;
951 6 50       18 my $entry = shift or return;
952 6 50       8 my $file = shift; return unless defined $file;
  6         16  
953              
954 6         7 my $err;
955              
956 6 50 0     26 if( $entry->is_symlink ) {
    0          
    0          
    0          
    0          
957 6         12 my $fail;
958 6         11 if( ON_UNIX ) {
959 6 50       24 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       31 $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       32 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 51     51 1 603 my $self = shift;
1050 51   50     697 my $aref = shift || [ ];
1051              
1052 51 50       163 unless( $self->_data ) {
1053 0 0       0 $self->read() or return;
1054             }
1055              
1056 51 50 0     217 if( @$aref == 0 or ( @$aref == 1 and $aref->[0] eq 'name' ) ) {
      33        
1057 51         75 return map { $_->full_path } @{$self->_data};
  191         356  
  51         91  
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 238     238   8113 my $self = shift;
1076 238         774 my $file = shift;
1077              
1078 238 50       877 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 238 100       2559 return $file if UNIVERSAL::isa( $file, 'Archive::Tar::File' );
1085              
1086             seach_entry:
1087 222 50       1375 if($self->_data){
1088 222         288 for my $entry ( @{$self->_data} ) {
  222         398  
1089 562         1294 my $path = $entry->full_path;
1090 562 100       2276 return $entry if $path eq $file;
1091             }
1092             }
1093              
1094 3 50       18 if($Archive::Tar::RESOLVE_SYMLINK!~/none/){
1095 3 50       10 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         13 $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 122     122 1 7259 my $self = shift;
1144              
1145 122 100       593 return @{ $self->_data } unless @_;
  118         631  
1146              
1147 4         6 my @list;
1148 4         12 for my $file ( @_ ) {
1149 4         12 push @list, grep { defined } $self->_find_entry( $file );
  2         8  
1150             }
1151              
1152 4         29 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 3172 my $self = shift;
1163 11 50       23 my $entry = $self->_find_entry( shift ) or return;
1164              
1165 11         23 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         5 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 294 my $self = shift;
1194 2 50       4 my $file = shift; return unless defined $file;
  2         10  
1195 2 50       4 my $new = shift; return unless defined $new;
  2         6  
1196              
1197 2 50       7 my $entry = $self->_find_entry( $file ) or return;
1198              
1199 2         9 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 2 my $self = shift;
1212 1 50       2 my $file = shift; return unless defined $file;
  1         14  
1213 1 50 33     3 my $mode = shift; return unless defined $mode && $mode =~ /^[0-7]{1,4}$/;
  1         10  
1214 1         4 my @args = ("$mode");
1215              
1216 1 50       4 my $entry = $self->_find_entry( $file ) or return;
1217 1         4 my $x = $entry->chmod( @args );
1218 1         16 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       3 my $file = shift; return unless defined $file;
  2         5  
1232 2 50       3 my $uname = shift; return unless defined $uname;
  2         4  
1233 2         4 my @args = ($uname);
1234 2         3 push(@args, shift);
1235              
1236 2 50       4 my $entry = $self->_find_entry( $file ) or return;
1237 2         17 my $x = $entry->chown( @args );
1238 2         15 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 408 my $self = shift;
1251 1         4 my @list = @_;
1252              
1253 1         2 my %seen = map { $_->full_path => $_ } @{$self->_data};
  5         12  
  1         17  
1254 1         8 delete $seen{ $_ } for @list;
1255              
1256 1         7 $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   3 1 342 my $self = shift or return;
1271              
1272 3         269 $self->_data( [] );
1273 3         72 $self->_file( '' );
1274              
1275 3         31 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 34     34 1 8714 my $self = shift;
1318 34 100       132 my $file = shift; $file = '' unless defined $file;
  34         244  
1319 34   100     369 my $gzip = shift || 0;
1320 34 50       90 my $ext_prefix = shift; $ext_prefix = '' unless defined $ext_prefix;
  33         189  
1321 33         159 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 2 0 50 2   19 : $HAS_PERLIO ? do { open my $h, '>', \$dummy; $h }
  2 50       6  
  2 100       19  
  34         354  
  4         115  
  4         1215  
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 34         242 local $\;
1335              
1336 34         76 for my $entry ( @{$self->_data} ) {
  34         112  
1337             ### entries to be written to the tarfile ###
1338 89         2002 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 89         322 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 90 100       238 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 5 50       24 $clone->name( length $ext_prefix
1353             ? File::Spec::Unix->catdir( $ext_prefix,
1354             $clone->full_path)
1355             : $clone->full_path );
1356 5         21 $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 86         214 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 86 50       217 $prefix = File::Spec::Unix->catdir( $ext_prefix, $prefix )
1368             if length $ext_prefix;
1369              
1370 86         300 $clone->prefix( $prefix );
1371 85         203 $clone->name( $name );
1372             }
1373              
1374             ### names are too long, and will get truncated if we don't add a
1375             ### '@LongLink' file...
1376 89   100     168 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 89 100       236 if( $make_longlink ) {
1382 15         56 my $longlink = Archive::Tar::File->new(
1383             data => LONGLINK_NAME,
1384             $clone->full_path,
1385             { type => LONGLINK }
1386             );
1387              
1388 15 50       54 unless( $longlink ) {
1389 1         12 $self->_error( qq[Could not create 'LongLink' entry for ] .
1390             qq[oversize file '] . $clone->full_path ."'" );
1391 1         3 return;
1392             };
1393              
1394 16         40 push @write_me, $longlink;
1395             }
1396              
1397 90         209 push @write_me, $clone;
1398              
1399             ### write the one, optionally 2 a::t::file objects to the handle
1400 90         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 105   66     1070 my $link_ok = $clone->is_symlink && $Archive::Tar::FOLLOW_SYMLINK;
1408 105   100     227 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 104 50       225 $clone->_downgrade_to_plainfile if $link_ok;
1413              
1414             ### get the header for this block
1415 104         243 my $header = $self->_format_tar_entry( $clone );
1416 105 50       261 unless( $header ) {
1417 0         0 $self->_error(q[Could not format header for: ] .
1418             $clone->full_path );
1419 0         0 return;
1420             }
1421              
1422 105 50       635 unless( print $handle $header ) {
1423 1         5 $self->_error(q[Could not write header for: ] .
1424             $clone->full_path);
1425 0         0 return;
1426             }
1427              
1428 104 100 66     8247 if( $link_ok or $data_ok ) {
1429 81 50       240 unless( print $handle $clone->data ) {
1430 1         5 $self->_error(q[Could not write data for: ] .
1431             $clone->full_path);
1432 1         4 return;
1433             }
1434              
1435             ### pad the end of the clone if required ###
1436 80 50       7536 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       1936 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       1869 : do { seek $handle, 0, 0; local $/; <$handle> };
  1 100       4  
  1         39  
  0         0  
1450              
1451             ### make sure to close the handle if we created it
1452 33 50       133 if ( $file ne $handle ) {
1453 34 50       1148 unless( close $handle ) {
1454 1         3 $self->_error( qq[Could not write tar] );
1455 1         3 return;
1456             }
1457             }
1458              
1459 34         24107 return $rv;
1460             }
1461              
1462             sub _format_tar_entry {
1463 105     105   161 my $self = shift;
1464 105 50       207 my $entry = shift or return;
1465 105 50       132 my $ext_prefix = shift; $ext_prefix = '' unless defined $ext_prefix;
  105         262  
1466 105   50     477 my $no_prefix = shift || 0;
1467              
1468 105         213 my $file = $entry->name;
1469 105 50       213 my $prefix = $entry->prefix; $prefix = '' unless defined $prefix;
  105         226  
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 105 50       184 $prefix = File::Spec::Unix->catdir($ext_prefix, $prefix)
1481             if length $ext_prefix;
1482              
1483             ### not sure why this is... ###
1484 105         137 my $l = PREFIX_LENGTH; # is ambiguous otherwise...
1485 105 100       258 substr ($prefix, 0, -$l) = "" if length $prefix >= PREFIX_LENGTH;
1486              
1487 107 50       184 my $f1 = "%06o"; my $f2 = $ZERO_PAD_NUMBERS ? "%011o" : "%11o";
  106         285  
1488              
1489             ### this might be optimizable with a 'changed' flag in the file objects ###
1490             my $tar = pack (
1491             PACK,
1492             $file,
1493              
1494 314         792 (map { sprintf( $f1, $entry->$_() ) } qw[mode uid gid]),
1495 210         441 (map { sprintf( $f2, $entry->$_() ) } qw[size mtime]),
1496              
1497             "", # checksum field - space padded a bit down
1498              
1499 313         654 (map { $entry->$_() } qw[type linkname magic]),
1500              
1501             $entry->version || TAR_VERSION,
1502              
1503 209         497 (map { $entry->$_() } qw[uname gname]),
1504 107 50 50     207 (map { sprintf( $f1, $entry->$_() ) } qw[devmajor devminor]),
  209         491  
1505              
1506             ($no_prefix ? '' : $prefix)
1507             );
1508              
1509             ### add the checksum ###
1510 105 50       424 my $checksum_fmt = $ZERO_PAD_NUMBERS ? "%06o\0" : "%06o\0";
1511 105         614 substr($tar,148,7) = sprintf("%6o\0", unpack("%16C*",$tar));
1512              
1513 105         310 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     24 1 2939 my $self = shift;
1540 25 50       171 my @files = @_ or return;
1541              
1542 24         79 my @rv;
1543 24         115 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 44 100       218 if( UNIVERSAL::isa( $file,'Archive::Tar::File' ) ) {
1549 29         65 push @rv, $file->clone;
1550 28         53 next;
1551             }
1552              
1553 16         53 eval {
1554 15 50       60 if( utf8::is_utf8( $file )) {
1555 0         0 utf8::encode( $file );
1556             }
1557             };
1558              
1559 16 50 33     293 unless( -e $file || -l $file ) {
1560 1         5 $self->_error( qq[No such file: '$file'] );
1561 0         0 next;
1562             }
1563              
1564 15         184 my $obj = Archive::Tar::File->new( file => $file );
1565 16 50       69 unless( $obj ) {
1566 1         2 $self->_error( qq[Unable to add file: '$file'] );
1567 1         6 next;
1568             }
1569              
1570 16         91 push @rv, $obj;
1571             }
1572              
1573 24         44 push @{$self->{_data}}, @rv;
  24         76  
1574              
1575 24         82 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 15     15 1 5843 my $self = shift;
1633 15         41 my ($file, $data, $opt) = @_;
1634              
1635 15         107 my $obj = Archive::Tar::File->new( data => $file, $data, $opt );
1636 15 100       33 unless( $obj ) {
1637 1         5 $self->_error( qq[Unable to add file: '$file'] );
1638 1         3 return;
1639             }
1640              
1641 14         19 push @{$self->{_data}}, $obj;
  14         37  
1642              
1643 14         56 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   27 my $self = shift;
1664 15         52 my $msg = $error = shift;
1665 15         2160 $longmess = Carp::longmess($error);
1666 15 50       2635 if (ref $self) {
1667 15         55 $self->{_error} = $error;
1668 15         64 $self->{_longmess} = $longmess;
1669             }
1670              
1671             ### set Archive::Tar::WARN to 0 to disable printing
1672             ### of errors
1673 15 100       43 if( $WARN ) {
1674 6 50       614 carp $DEBUG ? $longmess : $msg;
1675             }
1676              
1677 15         257 return;
1678             }
1679              
1680             sub error {
1681 22     22 1 2980 my $self = shift;
1682 22 100       74 if (ref $self) {
1683 20 50       183 return shift() ? $self->{_longmess} : $self->{_error};
1684             } else {
1685 2 50       10 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 76 my $class = shift;
1773              
1774 9 50       31 my $file = shift; return unless defined $file;
  9         44  
1775 9   100     45 my $gzip = shift || 0;
1776 9         40 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         52 my $tar = $class->new;
1783 9         73 $tar->add_files( @files );
1784 9         134 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 12     12 1 19143 my $class = shift;
1815 12         16 my $filename = shift;
1816 12 50       32 return unless defined $filename;
1817 12   100     45 my $compressed = shift || 0;
1818 12   100     34 my $opts = shift || {};
1819              
1820             ### get a handle to read from.
1821 12 50       44 my $handle = $class->_get_handle(
1822             $filename,
1823             $compressed,
1824             READ_ONLY->( ZLIB )
1825             ) or return;
1826              
1827 12         23 my @data;
1828 12         22 my $CONSTRUCT_ARGS = [ $filename, $compressed, $opts ];
1829             return sub {
1830 29 100   29   7572 return shift(@data) if @data; # more than one file returned?
1831 27 50       63 return unless $handle; # handle exhausted?
1832              
1833             ### read data, should only return file
1834 27         179 my $tarfile = $class->_read_tar($handle, { %$opts, limit => 1 });
1835 27 50 33     173 @data = @$tarfile if ref $tarfile && ref $tarfile eq 'ARRAY';
1836 27 50       80 if($Archive::Tar::RESOLVE_SYMLINK!~/none/){
1837 27         49 foreach(@data){
1838             #may refine this heuristic for ON_UNIX?
1839 17 100       38 if($_->linkname){
1840             #is there a better slot to store/share it ?
1841 1         3 $_->{'_archive'} = $CONSTRUCT_ARGS;
1842             }
1843             }
1844             }
1845              
1846             ### return one piece of data
1847 27 100       73 return shift(@data) if @data;
1848              
1849             ### data is exhausted, free the filehandle
1850 12         97 undef $handle;
1851 12 50       1297 if(@$CONSTRUCT_ARGS == 4){
1852             #free archive in memory
1853 0         0 undef $CONSTRUCT_ARGS->[-1];
1854             }
1855 12         34 return;
1856 12         82 };
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 1585 my $class = shift;
1881 3 50       5 my $file = shift; return unless defined $file;
  3         10  
1882 3   50     19 my $gzip = shift || 0;
1883              
1884 3         11 my $tar = $class->new($file, $gzip);
1885 3 50       8 return unless $tar;
1886              
1887 3         12 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 29 my $class = shift;
1906 9 50       26 my $file = shift; return unless defined $file;
  9         56  
1907 9   100     55 my $gzip = shift || 0;
1908              
1909 9 50       36 my $tar = $class->new( ) or return;
1910              
1911 9         85 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 995 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 28 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 20 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__