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   304642 use Cwd;
  9         68  
  9         631  
11 9     9   4914 use IO::Zlib;
  9         547433  
  9         59  
12 9     9   505 use IO::File;
  9         19  
  9         1198  
13 9     9   64 use Carp qw(carp croak);
  9         18  
  9         399  
14 9     9   53 use File::Spec ();
  9         20  
  9         168  
15 9     9   46 use File::Spec::Unix ();
  9         14  
  9         154  
16 9     9   44 use File::Path ();
  9         23  
  9         171  
17              
18 9     9   3940 use Archive::Tar::File;
  9         24  
  9         292  
19 9     9   59 use Archive::Tar::Constant;
  9         14  
  9         1822  
20              
21             require Exporter;
22              
23 9     9   63 use strict;
  9         16  
  9         415  
24 9         2173 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   64 ];
  9         15  
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.02";
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   69 use Config;
  9         14  
  9         812  
47 9     9   943 $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     42 $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   68 no strict 'refs';
  9         30  
  9         64983  
115             *{__PACKAGE__."::$key"} = sub {
116 763     763   2155 my $self = shift;
117 763 100       1884 $self->{$key} = $_[0] if @_;
118 763         3320 return $self->{$key};
119             }
120             }
121              
122             sub new {
123 82     80 1 214990 my $class = shift;
124 80 50       322 $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         602 my $obj = bless { _data => [ ], _file => 'Unknown', _error => '' }, $class;
129              
130 80 100       277 if (@_) {
131 25 50       76 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         2596 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 3475 my $self = shift;
207 59         132 my $file = shift;
208 59   100     346 my $gzip = shift || 0;
209 59   100     243 my $opts = shift || {};
210              
211 59 100       147 unless( defined $file ) {
212 2         11 $self->_error( qq[No file to read from!] );
213 2         12 return;
214             } else {
215 57         247 $self->_file( $file );
216             }
217              
218 57 50       373 my $handle = $self->_get_handle($file, $gzip, READ_ONLY->( ZLIB ) )
219             or return;
220              
221 58 100       254 my $data = $self->_read_tar( $handle, $opts ) or return;
222              
223 56         209 $self->_data( $data );
224              
225 56 100       712 return wantarray ? @$data : scalar @$data;
226             }
227              
228             sub _get_handle {
229 100     99   224 my $self = shift;
230 100 50       158 my $file = shift; return unless defined $file;
  100         223  
231 99   100     461 my $compress = shift || 0;
232 99   33     244 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       208 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         5 $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         122 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         135 my $magic = '';
  99         231  
247 99 100       276 if( MODE_READ->($mode) ) {
248 69 50       4098 open my $tmp, $file or do {
249 0         0 $self->_error( qq[Could not open '$file' for reading: $!] );
250 1         8 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         1008 sysread( $tmp, $magic, 6 );
256 69         902 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     815 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       68 if( MODE_READ->($mode) ) {
294 12 50       142 $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       256 $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         687 $fh = IO::Zlib->new;
318              
319 67 50       3839 unless( $fh->open( $file, $mode ) ) {
320 1         34 $self->_error(qq[Could not create filehandle for '$file': $!]);
321 0         0 return;
322             }
323              
324             ### is it plain tar?
325             } else {
326 13         86 $fh = IO::File->new;
327              
328 14 50       619 unless( $fh->open( $file, $mode ) ) {
329 1         13 $self->_error(qq[Could not create filehandle for '$file': $!]);
330 0         0 return;
331             }
332              
333             ### enable bin mode on tar archives
334 13         1517 binmode $fh;
335             }
336             }
337              
338 99         156603 return $fh;
339             }
340              
341              
342             sub _read_tar {
343 84     84   170 my $self = shift;
344 84 50       227 my $handle = shift or return;
345 84   50     209 my $opts = shift || {};
346              
347 84   100     396 my $count = $opts->{limit} || 0;
348 84         133 my $filter = $opts->{filter};
349 84   50     373 my $md5 = $opts->{md5} || 0; # cdrake
350 84         119 my $filter_cb = $opts->{filter_cb};
351 84   100     348 my $extract = $opts->{extract} || 0;
352              
353             ### set a cap on the amount of files to extract ###
354 84         142 my $limit = 0;
355 84 100       190 $limit = 1 if $count > 0;
356              
357 84         126 my $tarfile = [ ];
358 84         100 my $chunk;
359 84         99 my $read = 0;
360 84         103 my $real_name; # to set the name of a file when
361             # we're encountering @longlink
362             my $data;
363              
364             LOOP:
365 84         641 while( $handle->read( $chunk, HEAD ) ) {
366             ### IO::Zlib doesn't support this yet
367 723         104989 my $offset;
368 723 100       1504 if ( ref($handle) ne 'IO::Zlib' ) {
369 105         138 local $@;
370 105   50     167 $offset = eval { tell $handle } || 'unknown';
371 105         1266 $@ = '';
372             }
373             else {
374 618         847 $offset = 'unknown';
375             }
376              
377 723 100       1218 unless( $read++ ) {
378 80         162 my $gzip = GZIP_MAGIC_NUM;
379 80 50       750 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       244 if (length $chunk != HEAD) {
387 2         13 $self->_error( qq[Cannot read enough bytes from the tarfile] );
388 2         22 return;
389             }
390             }
391              
392             ### if we can't read in all bytes... ###
393 721 100       1203 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       1331 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         394 { my $nulls = join '', "\0" x 12;
  292         393  
406 292 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 292         364 my $entry;
416 292         668 { my %extra_args = ();
  292         397  
417 292 100       575 $extra_args{'name'} = $$real_name if defined $real_name;
418              
419 292 50       1334 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       645 next if $entry->is_label;
430              
431 292 100 66     551 if( length $entry->type and ($entry->is_file || $entry->is_longlink) ) {
      33        
432              
433 214 50 33     398 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         510 my $block = BLOCK_SIZE->( $entry->size );
446              
447 214         442 $data = $entry->get_content_by_ref;
448              
449 214         279 my $skip = 0;
450 214         255 my $ctx; # cdrake
451             ### skip this entry if we're filtering
452              
453 214 50 100     923 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         39 $skip = 1;
459              
460             } elsif ($filter_cb && ! $filter_cb->($entry)) {
461 22         85 $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         19 $skip = 3;
468             }
469              
470 214 100       438 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         59 my $amt = $block;
478 45         86 my $fsz=$entry->size; # cdrake
479 45         103 while ($amt > 0) {
480 45         93 $$data = '';
481 45         54 my $this = 64 * BLOCK;
482 45 50       88 $this = $amt if $this > $amt;
483 45 50       221 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         6288 $amt -= $this;
489 45         52 $fsz -= $this; # cdrake
490 45 50       97 substr ($$data, $fsz) = "" if ($fsz<0); # remove external junk prior to md5 # cdrake
491 45 50       122 $ctx->add($$data) if($skip==5); # cdrake
492             }
493 45 0 33     110 $$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       768 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       26370 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       569 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         176 my $nulls = $$data =~ tr/\0/\0/;
524              
525             ### cut data + size by that many bytes
526 63         156 $entry->size( $entry->size - $nulls );
527 63         155 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       595 if( $entry->is_longlink ) {
    100          
540 63         103 $real_name = $data;
541 63         289 next LOOP;
542             } elsif ( defined $real_name ) {
543 63         166 $entry->name( $$real_name );
544 63         162 $entry->prefix('');
545 63         108 undef $real_name;
546             }
547              
548 229 100 100     864 if ($filter && $entry->name !~ $filter) {
    100 100        
    100 66        
549 20         79 next LOOP;
550              
551             } elsif ($filter_cb && ! $filter_cb->($entry)) {
552 20         81 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         10 next LOOP;
559             }
560              
561 188 50 66     498 if ( $extract && !$entry->is_longlink
      66        
      33        
562             && !$entry->is_unknown
563             && !$entry->is_label ) {
564 9 50       34 $self->_extract_file( $entry ) or return;
565             }
566              
567             ### Guard against tarfiles with garbage at the end
568 188 50       508 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       502 push @$tarfile, ($extract ? $entry->name : $entry);
573              
574 188 100       898 if( $limit ) {
575 18 100 66     45 $count-- unless $entry->is_longlink || $entry->is_dir;
576 18 100       73 last LOOP unless $count;
577             }
578             } continue {
579 706         3158 undef $data;
580             }
581              
582 82         18280 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 6 my $self = shift;
599 2         4 my $full = shift;
600              
601 2 50       8 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         5 local $WARN = 0;
606 2 100       10 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 19721 my $self = shift;
630 32         129 my @args = @_;
631 32         61 my @files;
632             my $hashmap;
633              
634             # use the speed optimization for all extracted files
635 32 50       104741 local($self->{cwd}) = cwd() unless $self->{cwd};
636              
637             ### you requested the extraction of only certain files
638 32 100       672 if( @args ) {
639 2         47 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         10 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     46 map { $_->full_path, $_ } @{$self->_data}
652             };
653              
654 1 50       17 if (exists $hashmap->{$file}) {
655             ### we found the file you're looking for
656 1         18 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         589 @files = $self->get_files;
667             }
668              
669             ### nothing found? that's an error
670 32 50       177 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         201 for my $entry ( @files ) {
677 111 100       588 unless( $self->_extract_file( $entry ) ) {
678 3         10 $self->_error(q[Could not extract ']. $entry->full_path .q['] );
679 3         28 return;
680             }
681             }
682              
683 29         770 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 1431 my $self = shift;
704 165 50       285 my $file = shift; return unless defined $file;
  165         359  
705 165         597 my $alt = shift;
706              
707 165 50       1182 my $entry = $self->_find_entry( $file )
708             or $self->_error( qq[Could not find an entry for '$file'] ), return;
709              
710 165         669 return $self->_extract_file( $entry, $alt );
711             }
712              
713             sub _extract_file {
714 287     287   495 my $self = shift;
715 287 50       649 my $entry = shift or return;
716 287         447 my $alt = shift;
717              
718             ### you wanted an alternate extraction location ###
719 287 100       1613 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 287         493 my ($vol,$dirs,$file);
724 287 100       594 if ( defined $alt ) { # It's a local-OS path
725 161         390 ($vol,$dirs,$file) = File::Spec->splitpath( $alt,
726             $entry->is_dir );
727             } else {
728 126         546 ($vol,$dirs,$file) = File::Spec::Unix->splitpath( $name,
729             $entry->is_dir );
730             }
731              
732 287         652 my $dir;
733             ### is $name an absolute path? ###
734 287 100 66     4054 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     230 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         422 $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 207 100 100     316544 : cwd();
754              
755 207 100       5092 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 207 100 100     1146 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 120 100       395 if( grep { $_ eq '..' } @dirs ) {
  121         453  
767              
768 1         111 $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 119         343 my $full_path = $cwd;
782 119         414 for my $d ( @dirs ) {
783 117         800 $full_path = File::Spec->catdir( $full_path, $d );
784              
785             ### we've already checked this one, and it's safe. Move on.
786 117 100 100     722 next if ref $self and $self->{_link_cache}->{$full_path};
787              
788 23 100       560 if( -l $full_path ) {
789 2         39 my $to = readlink $full_path;
790 2         24 my $diag = "symlinked directory ($full_path => $to)";
791              
792 2         15 $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         9 return;
799             }
800              
801             ### XXX keep a cache if possible, so the stats become cheaper:
802 21 100       153 $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 204         340 map { length() ? VMS::Filespec::vmsify($_.'/') : $_ } @dirs if ON_VMS;
811              
812 204         7678 my ($cwd_vol,$cwd_dir,$cwd_file)
813             = File::Spec->splitpath( $cwd );
814 204         1868 my @cwd = File::Spec->splitdir( $cwd_dir );
815 204 50       878 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 204         4135 $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 204 50       937 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 284 50 66     7364 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 284 100       860 unless ( -d _ ) {
847 12         38 eval { File::Path::mkpath( $dir, 0, 0777 ) };
  12         3764  
848 12 100       62 if( $@ ) {
849 1         19 my $fp = $entry->full_path;
850 1         19 $self->_error(qq[Could not create directory '$dir' for '$fp': $@]);
851 1         7 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 283 100       2777 return 1 if $entry->is_dir;
868              
869 265         3089 my $full = File::Spec->catfile( $dir, $file );
870              
871 265 50       899 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 265 100 66     4898 if (-l $full || -e _) {
885 9 50       720 if (!unlink $full) {
886 0         0 $self->_error( qq[Could not remove old file '$full': $!] );
887 0         0 return;
888             }
889             }
890 265 100 66     952 if( length $entry->type && $entry->is_file ) {
891 259         3920 my $fh = IO::File->new;
892 259 50       19254 $fh->open( $full, '>' ) or (
893             $self->_error( qq[Could not open file '$full': $!] ),
894             return
895             );
896              
897 259 100       32573 if( $entry->size ) {
898 233         710 binmode $fh;
899 233         653 my $offset = 0;
900 233         1119 my $content = $entry->get_content_by_ref();
901 233         510 while ($offset < $entry->size) {
902 16826         175971 my $written
903             = syswrite $fh, $$content, $EXTRACT_BLOCK_SIZE, $offset;
904 16826 50       37397 if (defined $written) {
905 16826         44454 $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 259 50       4047 close $fh or (
914             $self->_error( qq[Could not close file '$full'] ),
915             return
916             );
917              
918             } else {
919 6 50       79 $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 265 100       4315 if( not -l $full ) {
926 259 50       1014 utime time, $entry->mtime - TIME_OFFSET, $full or
927             $self->_error( qq[Could not update timestamp] );
928             }
929              
930 265 100 33     2649 if( $CHOWN && CAN_CHOWN->() and not -l $full ) {
      66        
931 259 50       1032 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 265 100 66     4493 if( $CHMOD and not -l $full ) {
938 259         1498 my $mode = $entry->mode;
939 259 50       559 unless ($SAME_PERMISSIONS) {
940 0         0 $mode &= ~(oct(7000) | umask);
941             }
942 259 50       4313 CORE::chmod( $mode, $full ) or
943             $self->_error( qq[Could not chown '$full' to ] . $entry->mode );
944             }
945              
946 265         4361 return 1;
947             }
948              
949             sub _make_special_file {
950 6     6   21 my $self = shift;
951 6 50       23 my $entry = shift or return;
952 6 50       12 my $file = shift; return unless defined $file;
  6         14  
953              
954 6         17 my $err;
955              
956 6 50 0     43 if( $entry->is_symlink ) {
    0          
    0          
    0          
    0          
957 6         12 my $fail;
958 6         7 if( ON_UNIX ) {
959 6 50       28 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       32 $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       23 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 48     48 1 469 my $self = shift;
1050 48   50     472 my $aref = shift || [ ];
1051              
1052 48 50       214 unless( $self->_data ) {
1053 0 0       0 $self->read() or return;
1054             }
1055              
1056 48 50 0     260 if( @$aref == 0 or ( @$aref == 1 and $aref->[0] eq 'name' ) ) {
      33        
1057 48         83 return map { $_->full_path } @{$self->_data};
  179         339  
  48         96  
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   8722 my $self = shift;
1076 218         689 my $file = shift;
1077              
1078 218 50       722 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       2226 return $file if UNIVERSAL::isa( $file, 'Archive::Tar::File' );
1085              
1086             seach_entry:
1087 202 50       941 if($self->_data){
1088 202         290 for my $entry ( @{$self->_data} ) {
  202         325  
1089 510         1064 my $path = $entry->full_path;
1090 510 100       1563 return $entry if $path eq $file;
1091             }
1092             }
1093              
1094 3 50       14 if($Archive::Tar::RESOLVE_SYMLINK!~/none/){
1095 3 50       8 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         14 $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 113     113 1 6821 my $self = shift;
1144              
1145 113 100       520 return @{ $self->_data } unless @_;
  109         615  
1146              
1147 4         7 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         25 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 3124 my $self = shift;
1163 11 50       24 my $entry = $self->_find_entry( shift ) or return;
1164              
1165 11         21 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         3 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 292 my $self = shift;
1194 2 50       4 my $file = shift; return unless defined $file;
  2         7  
1195 2 50       4 my $new = shift; return unless defined $new;
  2         5  
1196              
1197 2 50       7 my $entry = $self->_find_entry( $file ) or return;
1198              
1199 2         7 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         3  
1213 1 50 33     2 my $mode = shift; return unless defined $mode && $mode =~ /^[0-7]{1,4}$/;
  1         19  
1214 1         4 my @args = ("$mode");
1215              
1216 1 50       4 my $entry = $self->_find_entry( $file ) or return;
1217 1         3 my $x = $entry->chmod( @args );
1218 1         6 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 3 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         3  
1233 2         4 my @args = ($uname);
1234 2         2 push(@args, shift);
1235              
1236 2 50       5 my $entry = $self->_find_entry( $file ) or return;
1237 2         16 my $x = $entry->chown( @args );
1238 2         8 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 425 my $self = shift;
1251 1         4 my @list = @_;
1252              
1253 1         2 my %seen = map { $_->full_path => $_ } @{$self->_data};
  5         10  
  1         18  
1254 1         8 delete $seen{ $_ } for @list;
1255              
1256 1         7 $self->_data( [values %seen] );
1257              
1258 1         6 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 343 my $self = shift or return;
1271              
1272 3         284 $self->_data( [] );
1273 3         74 $self->_file( '' );
1274              
1275 3         30 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 8358 my $self = shift;
1318 34 100       172 my $file = shift; $file = '' unless defined $file;
  34         275  
1319 34   100     263 my $gzip = shift || 0;
1320 34 50       108 my $ext_prefix = shift; $ext_prefix = '' unless defined $ext_prefix;
  33         174  
1321 33         132 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   14 : $HAS_PERLIO ? do { open my $h, '>', \$dummy; $h }
  2 50       6  
  2 100       18  
  34         368  
  4         117  
  4         1199  
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         221 local $\;
1335              
1336 34         64 for my $entry ( @{$self->_data} ) {
  34         91  
1337             ### entries to be written to the tarfile ###
1338 89         2215 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         345 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       22 $clone->name( length $ext_prefix
1353             ? File::Spec::Unix->catdir( $ext_prefix,
1354             $clone->full_path)
1355             : $clone->full_path );
1356 5         23 $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         231 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       235 $prefix = File::Spec::Unix->catdir( $ext_prefix, $prefix )
1368             if length $ext_prefix;
1369              
1370 86         279 $clone->prefix( $prefix );
1371 85         169 $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     181 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       211 if( $make_longlink ) {
1382 15         45 my $longlink = Archive::Tar::File->new(
1383             data => LONGLINK_NAME,
1384             $clone->full_path,
1385             { type => LONGLINK }
1386             );
1387              
1388 15 50       52 unless( $longlink ) {
1389 1         3 $self->_error( qq[Could not create 'LongLink' entry for ] .
1390             qq[oversize file '] . $clone->full_path ."'" );
1391 1         3 return;
1392             };
1393              
1394 16         51 push @write_me, $longlink;
1395             }
1396              
1397 90         138 push @write_me, $clone;
1398              
1399             ### write the one, optionally 2 a::t::file objects to the handle
1400 90         185 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     1078 my $link_ok = $clone->is_symlink && $Archive::Tar::FOLLOW_SYMLINK;
1408 105   100     209 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       220 $clone->_downgrade_to_plainfile if $link_ok;
1413              
1414             ### get the header for this block
1415 104         217 my $header = $self->_format_tar_entry( $clone );
1416 105 50       256 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       732 unless( print $handle $header ) {
1423 1         6 $self->_error(q[Could not write header for: ] .
1424             $clone->full_path);
1425 0         0 return;
1426             }
1427              
1428 104 100 66     8527 if( $link_ok or $data_ok ) {
1429 81 50       223 unless( print $handle $clone->data ) {
1430 1         7 $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       8064 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       1970 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       1956 : do { seek $handle, 0, 0; local $/; <$handle> };
  1 100       4  
  1         42  
  0         0  
1450              
1451             ### make sure to close the handle if we created it
1452 33 50       104 if ( $file ne $handle ) {
1453 34 50       1053 unless( close $handle ) {
1454 1         2 $self->_error( qq[Could not write tar] );
1455 1         3 return;
1456             }
1457             }
1458              
1459 34         24116 return $rv;
1460             }
1461              
1462             sub _format_tar_entry {
1463 105     105   126 my $self = shift;
1464 105 50       210 my $entry = shift or return;
1465 105 50       129 my $ext_prefix = shift; $ext_prefix = '' unless defined $ext_prefix;
  105         280  
1466 105   50     382 my $no_prefix = shift || 0;
1467              
1468 105         219 my $file = $entry->name;
1469 105 50       206 my $prefix = $entry->prefix; $prefix = '' unless defined $prefix;
  105         204  
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       172 $prefix = File::Spec::Unix->catdir($ext_prefix, $prefix)
1481             if length $ext_prefix;
1482              
1483             ### not sure why this is... ###
1484 105         131 my $l = PREFIX_LENGTH; # is ambiguous otherwise...
1485 105 100       223 substr ($prefix, 0, -$l) = "" if length $prefix >= PREFIX_LENGTH;
1486              
1487 107 50       173 my $f1 = "%06o"; my $f2 = $ZERO_PAD_NUMBERS ? "%011o" : "%11o";
  106         273  
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         702 (map { sprintf( $f1, $entry->$_() ) } qw[mode uid gid]),
1495 210         472 (map { sprintf( $f2, $entry->$_() ) } qw[size mtime]),
1496              
1497             "", # checksum field - space padded a bit down
1498              
1499 313         693 (map { $entry->$_() } qw[type linkname magic]),
1500              
1501             $entry->version || TAR_VERSION,
1502              
1503 209         446 (map { $entry->$_() } qw[uname gname]),
1504 107 50 50     210 (map { sprintf( $f1, $entry->$_() ) } qw[devmajor devminor]),
  209         473  
1505              
1506             ($no_prefix ? '' : $prefix)
1507             );
1508              
1509             ### add the checksum ###
1510 105 50       398 my $checksum_fmt = $ZERO_PAD_NUMBERS ? "%06o\0" : "%06o\0";
1511 105         677 substr($tar,148,7) = sprintf("%6o\0", unpack("%16C*",$tar));
1512              
1513 105         279 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 2824 my $self = shift;
1540 25 50       213 my @files = @_ or return;
1541              
1542 24         48 my @rv;
1543 24         103 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       203 if( UNIVERSAL::isa( $file,'Archive::Tar::File' ) ) {
1549 29         63 push @rv, $file->clone;
1550 28         57 next;
1551             }
1552              
1553 16         122 eval {
1554 15 50       70 if( utf8::is_utf8( $file )) {
1555 0         0 utf8::encode( $file );
1556             }
1557             };
1558              
1559 16 50 33     253 unless( -e $file || -l $file ) {
1560 1         3 $self->_error( qq[No such file: '$file'] );
1561 0         0 next;
1562             }
1563              
1564 15         137 my $obj = Archive::Tar::File->new( file => $file );
1565 16 50       47 unless( $obj ) {
1566 1         3 $self->_error( qq[Unable to add file: '$file'] );
1567 1         6 next;
1568             }
1569              
1570 16         49 push @rv, $obj;
1571             }
1572              
1573 24         36 push @{$self->{_data}}, @rv;
  24         65  
1574              
1575 24         69 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 5813 my $self = shift;
1633 15         34 my ($file, $data, $opt) = @_;
1634              
1635 15         67 my $obj = Archive::Tar::File->new( data => $file, $data, $opt );
1636 15 100       34 unless( $obj ) {
1637 1         9 $self->_error( qq[Unable to add file: '$file'] );
1638 1         3 return;
1639             }
1640              
1641 14         20 push @{$self->{_data}}, $obj;
  14         33  
1642              
1643 14         48 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   26 my $self = shift;
1664 15         52 my $msg = $error = shift;
1665 15         2015 $longmess = Carp::longmess($error);
1666 15 50       2500 if (ref $self) {
1667 15         52 $self->{_error} = $error;
1668 15         55 $self->{_longmess} = $longmess;
1669             }
1670              
1671             ### set Archive::Tar::WARN to 0 to disable printing
1672             ### of errors
1673 15 100       38 if( $WARN ) {
1674 6 50       644 carp $DEBUG ? $longmess : $msg;
1675             }
1676              
1677 15         259 return;
1678             }
1679              
1680             sub error {
1681 22     22 1 2821 my $self = shift;
1682 22 100       67 if (ref $self) {
1683 20 50       191 return shift() ? $self->{_longmess} : $self->{_error};
1684             } else {
1685 2 50       9 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 80 my $class = shift;
1773              
1774 9 50       23 my $file = shift; return unless defined $file;
  9         41  
1775 9   100     53 my $gzip = shift || 0;
1776 9         58 my @files = @_;
1777              
1778 9 50       42 unless( @files ) {
1779 0         0 return $class->_error( qq[Cowardly refusing to create empty archive!] );
1780             }
1781              
1782 9         35 my $tar = $class->new;
1783 9         101 $tar->add_files( @files );
1784 9         94 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 20666 my $class = shift;
1815 12         35 my $filename = shift;
1816 12 50       44 return unless defined $filename;
1817 12   100     58 my $compressed = shift || 0;
1818 12   100     50 my $opts = shift || {};
1819              
1820             ### get a handle to read from.
1821 12 50       57 my $handle = $class->_get_handle(
1822             $filename,
1823             $compressed,
1824             READ_ONLY->( ZLIB )
1825             ) or return;
1826              
1827 12         26 my @data;
1828 12         29 my $CONSTRUCT_ARGS = [ $filename, $compressed, $opts ];
1829             return sub {
1830 29 100   29   8008 return shift(@data) if @data; # more than one file returned?
1831 27 50       84 return unless $handle; # handle exhausted?
1832              
1833             ### read data, should only return file
1834 27         221 my $tarfile = $class->_read_tar($handle, { %$opts, limit => 1 });
1835 27 50 33     199 @data = @$tarfile if ref $tarfile && ref $tarfile eq 'ARRAY';
1836 27 50       89 if($Archive::Tar::RESOLVE_SYMLINK!~/none/){
1837 27         62 foreach(@data){
1838             #may refine this heuristic for ON_UNIX?
1839 17 100       40 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       109 return shift(@data) if @data;
1848              
1849             ### data is exhausted, free the filehandle
1850 12         146 undef $handle;
1851 12 50       1795 if(@$CONSTRUCT_ARGS == 4){
1852             #free archive in memory
1853 0         0 undef $CONSTRUCT_ARGS->[-1];
1854             }
1855 12         42 return;
1856 12         84 };
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 1563 my $class = shift;
1881 3 50       5 my $file = shift; return unless defined $file;
  3         9  
1882 3   50     18 my $gzip = shift || 0;
1883              
1884 3         10 my $tar = $class->new($file, $gzip);
1885 3 50       8 return unless $tar;
1886              
1887 3         8 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 42 my $class = shift;
1906 9 50       13 my $file = shift; return unless defined $file;
  9         35  
1907 9   100     48 my $gzip = shift || 0;
1908              
1909 9 50       32 my $tar = $class->new( ) or return;
1910              
1911 9         81 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 1001 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 24 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__