File Coverage

lib/Archive/Tar.pm
Criterion Covered Total %
statement 508 640 79.3
branch 248 426 58.2
condition 102 168 60.7
subroutine 49 56 87.5
pod 29 30 96.6
total 936 1320 70.9


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