Bump version of deployable
[deployable.git] / bundle / deployable
blob85df9558e259db5217819064c0352540ce82702a
1 #!/usr/bin/env perl
2 use strict;
3 use warnings;
4 use Carp;
5 use version; our $VERSION = qv('0.1.2');
6 use Fatal qw( close );
7 use Pod::Usage qw( pod2usage );
8 use Getopt::Long qw( :config gnu_getopt );
9 use English qw( -no_match_vars );
10 use File::Basename qw( basename dirname );
11 use File::Spec::Functions qw( file_name_is_absolute catfile );
12 use File::Temp qw( tempfile );
13 use POSIX qw( strftime );
14 use Cwd qw( cwd realpath );
15 use Data::Dumper;
16 use Encode;
18 # __MOBUNDLE_INCLUSION__
19 BEGIN {
20 my %file_for = (
21 # __MOBUNDLE_FILES__
24 # __MOBUNDLE_FILE__
26 'Archive/Tar.pm' => <<'END_OF_FILE',
27 ### the gnu tar specification:
28 ### http://www.gnu.org/software/tar/manual/tar.html
29 ###
30 ### and the pax format spec, which tar derives from:
31 ### http://www.opengroup.org/onlinepubs/007904975/utilities/pax.html
33 package Archive::Tar;
34 require 5.005_03;
36 use Cwd;
37 use IO::Zlib;
38 use IO::File;
39 use Carp qw(carp croak);
40 use File::Spec ();
41 use File::Spec::Unix ();
42 use File::Path ();
44 use Archive::Tar::File;
45 use Archive::Tar::Constant;
47 require Exporter;
49 use strict;
50 use vars qw[$DEBUG $error $VERSION $WARN $FOLLOW_SYMLINK $CHOWN $CHMOD
51 $DO_NOT_USE_PREFIX $HAS_PERLIO $HAS_IO_STRING $SAME_PERMISSIONS
52 $INSECURE_EXTRACT_MODE $ZERO_PAD_NUMBERS @ISA @EXPORT $RESOLVE_SYMLINK
55 @ISA = qw[Exporter];
56 @EXPORT = qw[ COMPRESS_GZIP COMPRESS_BZIP ];
57 $DEBUG = 0;
58 $WARN = 1;
59 $FOLLOW_SYMLINK = 0;
60 $VERSION = "2.04_01";
61 $CHOWN = 1;
62 $CHMOD = 1;
63 $SAME_PERMISSIONS = $> == 0 ? 1 : 0;
64 $DO_NOT_USE_PREFIX = 0;
65 $INSECURE_EXTRACT_MODE = 0;
66 $ZERO_PAD_NUMBERS = 0;
67 $RESOLVE_SYMLINK = $ENV{'PERL5_AT_RESOLVE_SYMLINK'} || 'speed';
69 BEGIN {
70 use Config;
71 $HAS_PERLIO = $Config::Config{useperlio};
73 ### try and load IO::String anyway, so you can dynamically
74 ### switch between perlio and IO::String
75 $HAS_IO_STRING = eval {
76 require IO::String;
77 import IO::String;
79 } || 0;
82 =head1 NAME
84 Archive::Tar - module for manipulations of tar archives
86 =head1 SYNOPSIS
88 use Archive::Tar;
89 my $tar = Archive::Tar->new;
91 $tar->read('origin.tgz');
92 $tar->extract();
94 $tar->add_files('file/foo.pl', 'docs/README');
95 $tar->add_data('file/baz.txt', 'This is the contents now');
97 $tar->rename('oldname', 'new/file/name');
98 $tar->chown('/', 'root');
99 $tar->chown('/', 'root:root');
100 $tar->chmod('/tmp', '1777');
102 $tar->write('files.tar'); # plain tar
103 $tar->write('files.tgz', COMPRESS_GZIP); # gzip compressed
104 $tar->write('files.tbz', COMPRESS_BZIP); # bzip2 compressed
106 =head1 DESCRIPTION
108 Archive::Tar provides an object oriented mechanism for handling tar
109 files. It provides class methods for quick and easy files handling
110 while also allowing for the creation of tar file objects for custom
111 manipulation. If you have the IO::Zlib module installed,
112 Archive::Tar will also support compressed or gzipped tar files.
114 An object of class Archive::Tar represents a .tar(.gz) archive full
115 of files and things.
117 =head1 Object Methods
119 =head2 Archive::Tar->new( [$file, $compressed] )
121 Returns a new Tar object. If given any arguments, C<new()> calls the
122 C<read()> method automatically, passing on the arguments provided to
123 the C<read()> method.
125 If C<new()> is invoked with arguments and the C<read()> method fails
126 for any reason, C<new()> returns undef.
128 =cut
130 my $tmpl = {
131 _data => [ ],
132 _file => 'Unknown',
135 ### install get/set accessors for this object.
136 for my $key ( keys %$tmpl ) {
137 no strict 'refs';
138 *{__PACKAGE__."::$key"} = sub {
139 my $self = shift;
140 $self->{$key} = $_[0] if @_;
141 return $self->{$key};
145 sub new {
146 my $class = shift;
147 $class = ref $class if ref $class;
149 ### copying $tmpl here since a shallow copy makes it use the
150 ### same aref, causing for files to remain in memory always.
151 my $obj = bless { _data => [ ], _file => 'Unknown', _error => '' }, $class;
153 if (@_) {
154 unless ( $obj->read( @_ ) ) {
155 $obj->_error(qq[No data could be read from file]);
156 return;
160 return $obj;
163 =head2 $tar->read ( $filename|$handle, [$compressed, {opt => 'val'}] )
165 Read the given tar file into memory.
166 The first argument can either be the name of a file or a reference to
167 an already open filehandle (or an IO::Zlib object if it's compressed)
169 The C<read> will I<replace> any previous content in C<$tar>!
171 The second argument may be considered optional, but remains for
172 backwards compatibility. Archive::Tar now looks at the file
173 magic to determine what class should be used to open the file
174 and will transparently Do The Right Thing.
176 Archive::Tar will warn if you try to pass a bzip2 compressed file and the
177 IO::Zlib / IO::Uncompress::Bunzip2 modules are not available and simply return.
179 Note that you can currently B<not> pass a C<gzip> compressed
180 filehandle, which is not opened with C<IO::Zlib>, a C<bzip2> compressed
181 filehandle, which is not opened with C<IO::Uncompress::Bunzip2>, nor a string
182 containing the full archive information (either compressed or
183 uncompressed). These are worth while features, but not currently
184 implemented. See the C<TODO> section.
186 The third argument can be a hash reference with options. Note that
187 all options are case-sensitive.
189 =over 4
191 =item limit
193 Do not read more than C<limit> files. This is useful if you have
194 very big archives, and are only interested in the first few files.
196 =item filter
198 Can be set to a regular expression. Only files with names that match
199 the expression will be read.
201 =item md5
203 Set to 1 and the md5sum of files will be returned (instead of file data)
204 my $iter = Archive::Tar->iter( $file, 1, {md5 => 1} );
205 while( my $f = $iter->() ) {
206 print $f->data . "\t" . $f->full_path . $/;
209 =item extract
211 If set to true, immediately extract entries when reading them. This
212 gives you the same memory break as the C<extract_archive> function.
213 Note however that entries will not be read into memory, but written
214 straight to disk. This means no C<Archive::Tar::File> objects are
215 created for you to inspect.
217 =back
219 All files are stored internally as C<Archive::Tar::File> objects.
220 Please consult the L<Archive::Tar::File> documentation for details.
222 Returns the number of files read in scalar context, and a list of
223 C<Archive::Tar::File> objects in list context.
225 =cut
227 sub read {
228 my $self = shift;
229 my $file = shift;
230 my $gzip = shift || 0;
231 my $opts = shift || {};
233 unless( defined $file ) {
234 $self->_error( qq[No file to read from!] );
235 return;
236 } else {
237 $self->_file( $file );
240 my $handle = $self->_get_handle($file, $gzip, READ_ONLY->( ZLIB ) )
241 or return;
243 my $data = $self->_read_tar( $handle, $opts ) or return;
245 $self->_data( $data );
247 return wantarray ? @$data : scalar @$data;
250 sub _get_handle {
251 my $self = shift;
252 my $file = shift; return unless defined $file;
253 my $compress = shift || 0;
254 my $mode = shift || READ_ONLY->( ZLIB ); # default to read only
256 ### Check if file is a file handle or IO glob
257 if ( ref $file ) {
258 return $file if eval{ *$file{IO} };
259 return $file if eval{ $file->isa(q{IO::Handle}) };
260 $file = q{}.$file;
263 ### get a FH opened to the right class, so we can use it transparently
264 ### throughout the program
265 my $fh;
266 { ### reading magic only makes sense if we're opening a file for
267 ### reading. otherwise, just use what the user requested.
268 my $magic = '';
269 if( MODE_READ->($mode) ) {
270 open my $tmp, $file or do {
271 $self->_error( qq[Could not open '$file' for reading: $!] );
272 return;
275 ### read the first 4 bites of the file to figure out which class to
276 ### use to open the file.
277 sysread( $tmp, $magic, 4 );
278 close $tmp;
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 if( BZIP and (
285 ($compress eq COMPRESS_BZIP) or
286 ( MODE_READ->($mode) and $magic =~ BZIP_MAGIC_NUM )
290 ### different reader/writer modules, different error vars... sigh
291 if( MODE_READ->($mode) ) {
292 $fh = IO::Uncompress::Bunzip2->new( $file ) or do {
293 $self->_error( qq[Could not read '$file': ] .
294 $IO::Uncompress::Bunzip2::Bunzip2Error
296 return;
299 } else {
300 $fh = IO::Compress::Bzip2->new( $file ) or do {
301 $self->_error( qq[Could not write to '$file': ] .
302 $IO::Compress::Bzip2::Bzip2Error
304 return;
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
315 $fh = IO::Zlib->new;
317 unless( $fh->open( $file, $mode ) ) {
318 $self->_error(qq[Could not create filehandle for '$file': $!]);
319 return;
322 ### is it plain tar?
323 } else {
324 $fh = IO::File->new;
326 unless( $fh->open( $file, $mode ) ) {
327 $self->_error(qq[Could not create filehandle for '$file': $!]);
328 return;
331 ### enable bin mode on tar archives
332 binmode $fh;
336 return $fh;
340 sub _read_tar {
341 my $self = shift;
342 my $handle = shift or return;
343 my $opts = shift || {};
345 my $count = $opts->{limit} || 0;
346 my $filter = $opts->{filter};
347 my $md5 = $opts->{md5} || 0; # cdrake
348 my $filter_cb = $opts->{filter_cb};
349 my $extract = $opts->{extract} || 0;
351 ### set a cap on the amount of files to extract ###
352 my $limit = 0;
353 $limit = 1 if $count > 0;
355 my $tarfile = [ ];
356 my $chunk;
357 my $read = 0;
358 my $real_name; # to set the name of a file when
359 # we're encountering @longlink
360 my $data;
362 LOOP:
363 while( $handle->read( $chunk, HEAD ) ) {
364 ### IO::Zlib doesn't support this yet
365 my $offset;
366 if ( ref($handle) ne 'IO::Zlib' ) {
367 local $@;
368 $offset = eval { tell $handle } || 'unknown';
369 $@ = '';
371 else {
372 $offset = 'unknown';
375 unless( $read++ ) {
376 my $gzip = GZIP_MAGIC_NUM;
377 if( $chunk =~ /$gzip/ ) {
378 $self->_error( qq[Cannot read compressed format in tar-mode] );
379 return;
382 ### size is < HEAD, which means a corrupted file, as the minimum
383 ### length is _at least_ HEAD
384 if (length $chunk != HEAD) {
385 $self->_error( qq[Cannot read enough bytes from the tarfile] );
386 return;
390 ### if we can't read in all bytes... ###
391 last if length $chunk != HEAD;
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 next if $chunk eq TAR_END;
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 { my $nulls = join '', "\0" x 12;
404 unless( $nulls eq substr( $chunk, 500, 12 ) ) {
405 $self->_error( qq[Invalid header block at offset $offset] );
406 next LOOP;
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 my $entry;
414 { my %extra_args = ();
415 $extra_args{'name'} = $$real_name if defined $real_name;
417 unless( $entry = Archive::Tar::File->new( chunk => $chunk,
418 %extra_args )
420 $self->_error( qq[Couldn't read chunk at offset $offset] );
421 next LOOP;
425 ### ignore labels:
426 ### http://www.gnu.org/software/tar/manual/html_chapter/Media.html#SEC159
427 next if $entry->is_label;
429 if( length $entry->type and ($entry->is_file || $entry->is_longlink) ) {
431 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 my $name = $entry->name;
436 $name = substr($name, 0, 100) if length $name > 100;
437 $name =~ s/\n/ /g;
439 $self->_error( $name . qq[: checksum error] );
440 next LOOP;
443 my $block = BLOCK_SIZE->( $entry->size );
445 $data = $entry->get_content_by_ref;
447 my $skip = 0;
448 my $ctx; # cdrake
449 ### skip this entry if we're filtering
451 if($md5) { # cdrake
452 $ctx = Digest::MD5->new; # cdrake
453 $skip=5; # cdrake
455 } elsif ($filter && $entry->name !~ $filter) {
456 $skip = 1;
458 } elsif ($filter_cb && ! $filter_cb->($entry)) {
459 $skip = 2;
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 $skip = 3;
468 if ($skip) {
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
475 my $amt = $block;
476 my $fsz=$entry->size; # cdrake
477 while ($amt > 0) {
478 $$data = '';
479 my $this = 64 * BLOCK;
480 $this = $amt if $this > $amt;
481 if( $handle->read( $$data, $this ) < $this ) {
482 $self->_error( qq[Read error on tarfile (missing data) '].
483 $entry->full_path ."' at offset $offset" );
484 next LOOP;
486 $amt -= $this;
487 $fsz -= $this; # cdrake
488 substr ($$data, $fsz) = "" if ($fsz<0); # remove external junk prior to md5 # cdrake
489 $ctx->add($$data) if($skip==5); # cdrake
491 $$data = $ctx->hexdigest if($skip==5 && !$entry->is_longlink && !$entry->is_unknown && !$entry->is_label ) ; # cdrake
492 } else {
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 if ( $handle->read( $$data, $block ) < $block ) {
499 $self->_error( qq[Read error on tarfile (missing data) '].
500 $entry->full_path ."' at offset $offset" );
501 next LOOP;
503 ### throw away trailing garbage ###
504 substr ($$data, $entry->size) = "" if defined $$data;
507 ### part II of the @LongLink munging -- need to do /after/
508 ### the checksum check.
509 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.
520 ### count number of nulls
521 my $nulls = $$data =~ tr/\0/\0/;
523 ### cut data + size by that many bytes
524 $entry->size( $entry->size - $nulls );
525 substr ($$data, $entry->size) = "";
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
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 if( $entry->is_longlink ) {
538 $real_name = $data;
539 next LOOP;
540 } elsif ( defined $real_name ) {
541 $entry->name( $$real_name );
542 $entry->prefix('');
543 undef $real_name;
546 if ($filter && $entry->name !~ $filter) {
547 next LOOP;
549 } elsif ($filter_cb && ! $filter_cb->($entry)) {
550 next LOOP;
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 next LOOP;
559 if ( $extract && !$entry->is_longlink
560 && !$entry->is_unknown
561 && !$entry->is_label ) {
562 $self->_extract_file( $entry ) or return;
565 ### Guard against tarfiles with garbage at the end
566 last LOOP if $entry->name eq '';
568 ### push only the name on the rv if we're extracting
569 ### -- for extract_archive
570 push @$tarfile, ($extract ? $entry->name : $entry);
572 if( $limit ) {
573 $count-- unless $entry->is_longlink || $entry->is_dir;
574 last LOOP unless $count;
576 } continue {
577 undef $data;
580 return $tarfile;
583 =head2 $tar->contains_file( $filename )
585 Check if the archive contains a certain file.
586 It will return true if the file is in the archive, false otherwise.
588 Note however, that this function does an exact match using C<eq>
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.
593 =cut
595 sub contains_file {
596 my $self = shift;
597 my $full = shift;
599 return unless defined $full;
601 ### don't warn if the entry isn't there.. that's what this function
602 ### is for after all.
603 local $WARN = 0;
604 return 1 if $self->_find_entry($full);
605 return;
608 =head2 $tar->extract( [@filenames] )
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).
619 If C<extract> is called without a list of file names, the entire
620 contents of the archive are extracted.
622 Returns a list of filenames extracted.
624 =cut
626 sub extract {
627 my $self = shift;
628 my @args = @_;
629 my @files;
631 # use the speed optimization for all extracted files
632 local($self->{cwd}) = cwd() unless $self->{cwd};
634 ### you requested the extraction of only certain files
635 if( @args ) {
636 for my $file ( @args ) {
638 ### it's already an object?
639 if( UNIVERSAL::isa( $file, 'Archive::Tar::File' ) ) {
640 push @files, $file;
641 next;
643 ### go find it then
644 } else {
646 my $found;
647 for my $entry ( @{$self->_data} ) {
648 next unless $file eq $entry->full_path;
650 ### we found the file you're looking for
651 push @files, $entry;
652 $found++;
655 unless( $found ) {
656 return $self->_error(
657 qq[Could not find '$file' in archive] );
662 ### just grab all the file items
663 } else {
664 @files = $self->get_files;
667 ### nothing found? that's an error
668 unless( scalar @files ) {
669 $self->_error( qq[No files found for ] . $self->_file );
670 return;
673 ### now extract them
674 for my $entry ( @files ) {
675 unless( $self->_extract_file( $entry ) ) {
676 $self->_error(q[Could not extract ']. $entry->full_path .q['] );
677 return;
681 return @files;
684 =head2 $tar->extract_file( $file, [$extract_path] )
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.
690 For example:
692 $tar->extract_file( 'name/in/archive', 'name/i/want/to/give/it' );
694 $tar->extract_file( $at_file_object, 'name/i/want/to/give/it' );
696 Returns true on success, false on failure.
698 =cut
700 sub extract_file {
701 my $self = shift;
702 my $file = shift; return unless defined $file;
703 my $alt = shift;
705 my $entry = $self->_find_entry( $file )
706 or $self->_error( qq[Could not find an entry for '$file'] ), return;
708 return $self->_extract_file( $entry, $alt );
711 sub _extract_file {
712 my $self = shift;
713 my $entry = shift or return;
714 my $alt = shift;
716 ### you wanted an alternate extraction location ###
717 my $name = defined $alt ? $alt : $entry->full_path;
719 ### splitpath takes a bool at the end to indicate
720 ### that it's splitting a dir
721 my ($vol,$dirs,$file);
722 if ( defined $alt ) { # It's a local-OS path
723 ($vol,$dirs,$file) = File::Spec->splitpath( $alt,
724 $entry->is_dir );
725 } else {
726 ($vol,$dirs,$file) = File::Spec::Unix->splitpath( $name,
727 $entry->is_dir );
730 my $dir;
731 ### is $name an absolute path? ###
732 if( $vol || File::Spec->file_name_is_absolute( $dirs ) ) {
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 if( not defined $alt and not $INSECURE_EXTRACT_MODE ) {
737 $self->_error(
738 q[Entry ']. $entry->full_path .q[' is an absolute path. ].
739 q[Not extracting absolute paths under SECURE EXTRACT MODE]
741 return;
744 ### user asked us to, it's fine.
745 $dir = File::Spec->catpath( $vol, $dirs, "" );
747 ### it's a relative path ###
748 } else {
749 my $cwd = (ref $self and defined $self->{cwd})
750 ? $self->{cwd}
751 : cwd();
753 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
758 if( not defined $alt and
759 not $INSECURE_EXTRACT_MODE
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 if( grep { $_ eq '..' } @dirs ) {
766 $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]
771 return;
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 my $full_path = $cwd;
780 for my $d ( @dirs ) {
781 $full_path = File::Spec->catdir( $full_path, $d );
783 ### we've already checked this one, and it's safe. Move on.
784 next if ref $self and $self->{_link_cache}->{$full_path};
786 if( -l $full_path ) {
787 my $to = readlink $full_path;
788 my $diag = "symlinked directory ($full_path => $to)";
790 $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]
796 return;
799 ### XXX keep a cache if possible, so the stats become cheaper:
800 $self->{_link_cache}->{$full_path} = 1 if ref $self;
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 map { length() ? VMS::Filespec::vmsify($_.'/') : $_ } @dirs if ON_VMS;
810 my ($cwd_vol,$cwd_dir,$cwd_file)
811 = File::Spec->splitpath( $cwd );
812 my @cwd = File::Spec->splitdir( $cwd_dir );
813 push @cwd, $cwd_file if length $cwd_file;
815 ### We need to pass '' as the last element to catpath. Craig Berry
816 ### explains why (msgid <p0624083dc311ae541393@[172.16.52.1]>):
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 $dir = File::Spec->catpath(
827 $cwd_vol, File::Spec->catdir( @cwd, @dirs ), ''
830 ### catdir() returns undef if the path is longer than 255 chars on
831 ### older VMS systems.
832 unless ( defined $dir ) {
833 $^W && $self->_error( qq[Could not compose a path for '$dirs'\n] );
834 return;
839 if( -e $dir && !-d _ ) {
840 $^W && $self->_error( qq['$dir' exists, but it's not a directory!\n] );
841 return;
844 unless ( -d _ ) {
845 eval { File::Path::mkpath( $dir, 0, 0777 ) };
846 if( $@ ) {
847 my $fp = $entry->full_path;
848 $self->_error(qq[Could not create directory '$dir' for '$fp': $@]);
849 return;
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'] );
864 ### we're done if we just needed to create a dir ###
865 return 1 if $entry->is_dir;
867 my $full = File::Spec->catfile( $dir, $file );
869 if( $entry->is_unknown ) {
870 $self->_error( qq[Unknown file type for file '$full'] );
871 return;
874 if( length $entry->type && $entry->is_file ) {
875 my $fh = IO::File->new;
876 $fh->open( '>' . $full ) or (
877 $self->_error( qq[Could not open file '$full': $!] ),
878 return
881 if( $entry->size ) {
882 binmode $fh;
883 syswrite $fh, $entry->data or (
884 $self->_error( qq[Could not write data to '$full'] ),
885 return
889 close $fh or (
890 $self->_error( qq[Could not close file '$full'] ),
891 return
894 } else {
895 $self->_make_special_file( $entry, $full ) or return;
898 ### only update the timestamp if it's not a symlink; that will change the
899 ### timestamp of the original. This addresses bug #33669: Could not update
900 ### timestamp warning on symlinks
901 if( not -l $full ) {
902 utime time, $entry->mtime - TIME_OFFSET, $full or
903 $self->_error( qq[Could not update timestamp] );
906 if( $CHOWN && CAN_CHOWN->() and not -l $full ) {
907 chown $entry->uid, $entry->gid, $full or
908 $self->_error( qq[Could not set uid/gid on '$full'] );
911 ### only chmod if we're allowed to, but never chmod symlinks, since they'll
912 ### change the perms on the file they're linking too...
913 if( $CHMOD and not -l $full ) {
914 my $mode = $entry->mode;
915 unless ($SAME_PERMISSIONS) {
916 $mode &= ~(oct(7000) | umask);
918 chmod $mode, $full or
919 $self->_error( qq[Could not chown '$full' to ] . $entry->mode );
922 return 1;
925 sub _make_special_file {
926 my $self = shift;
927 my $entry = shift or return;
928 my $file = shift; return unless defined $file;
930 my $err;
932 if( $entry->is_symlink ) {
933 my $fail;
934 if( ON_UNIX ) {
935 symlink( $entry->linkname, $file ) or $fail++;
937 } else {
938 $self->_extract_special_file_as_plain_file( $entry, $file )
939 or $fail++;
942 $err = qq[Making symbolic link '$file' to '] .
943 $entry->linkname .q[' failed] if $fail;
945 } elsif ( $entry->is_hardlink ) {
946 my $fail;
947 if( ON_UNIX ) {
948 link( $entry->linkname, $file ) or $fail++;
950 } else {
951 $self->_extract_special_file_as_plain_file( $entry, $file )
952 or $fail++;
955 $err = qq[Making hard link from '] . $entry->linkname .
956 qq[' to '$file' failed] if $fail;
958 } elsif ( $entry->is_fifo ) {
959 ON_UNIX && !system('mknod', $file, 'p') or
960 $err = qq[Making fifo ']. $entry->name .qq[' failed];
962 } elsif ( $entry->is_blockdev or $entry->is_chardev ) {
963 my $mode = $entry->is_blockdev ? 'b' : 'c';
965 ON_UNIX && !system('mknod', $file, $mode,
966 $entry->devmajor, $entry->devminor) or
967 $err = qq[Making block device ']. $entry->name .qq[' (maj=] .
968 $entry->devmajor . qq[ min=] . $entry->devminor .
969 qq[) failed.];
971 } elsif ( $entry->is_socket ) {
972 ### the original doesn't do anything special for sockets.... ###
976 return $err ? $self->_error( $err ) : 1;
979 ### don't know how to make symlinks, let's just extract the file as
980 ### a plain file
981 sub _extract_special_file_as_plain_file {
982 my $self = shift;
983 my $entry = shift or return;
984 my $file = shift; return unless defined $file;
986 my $err;
987 TRY: {
988 my $orig = $self->_find_entry( $entry->linkname, $entry );
990 unless( $orig ) {
991 $err = qq[Could not find file '] . $entry->linkname .
992 qq[' in memory.];
993 last TRY;
996 ### clone the entry, make it appear as a normal file ###
997 my $clone = $orig->clone;
998 $clone->_downgrade_to_plainfile;
999 $self->_extract_file( $clone, $file ) or last TRY;
1001 return 1;
1004 return $self->_error($err);
1007 =head2 $tar->list_files( [\@properties] )
1009 Returns a list of the names of all the files in the archive.
1011 If C<list_files()> is passed an array reference as its first argument
1012 it returns a list of hash references containing the requested
1013 properties of each file. The following list of properties is
1014 supported: name, size, mtime (last modified date), mode, uid, gid,
1015 linkname, uname, gname, devmajor, devminor, prefix.
1017 Passing an array reference containing only one element, 'name', is
1018 special cased to return a list of names rather than a list of hash
1019 references, making it equivalent to calling C<list_files> without
1020 arguments.
1022 =cut
1024 sub list_files {
1025 my $self = shift;
1026 my $aref = shift || [ ];
1028 unless( $self->_data ) {
1029 $self->read() or return;
1032 if( @$aref == 0 or ( @$aref == 1 and $aref->[0] eq 'name' ) ) {
1033 return map { $_->full_path } @{$self->_data};
1034 } else {
1036 #my @rv;
1037 #for my $obj ( @{$self->_data} ) {
1038 # push @rv, { map { $_ => $obj->$_() } @$aref };
1040 #return @rv;
1042 ### this does the same as the above.. just needs a +{ }
1043 ### to make sure perl doesn't confuse it for a block
1044 return map { my $o=$_;
1045 +{ map { $_ => $o->$_() } @$aref }
1046 } @{$self->_data};
1050 sub _find_entry {
1051 my $self = shift;
1052 my $file = shift;
1054 unless( defined $file ) {
1055 $self->_error( qq[No file specified] );
1056 return;
1059 ### it's an object already
1060 return $file if UNIVERSAL::isa( $file, 'Archive::Tar::File' );
1062 seach_entry:
1063 if($self->_data){
1064 for my $entry ( @{$self->_data} ) {
1065 my $path = $entry->full_path;
1066 return $entry if $path eq $file;
1070 if($Archive::Tar::RESOLVE_SYMLINK!~/none/){
1071 if(my $link_entry = shift()){#fallback mode when symlinks are using relative notations ( ../a/./b/text.bin )
1072 $file = _symlinks_resolver( $link_entry->name, $file );
1073 goto seach_entry if $self->_data;
1075 #this will be slower than never, but won't failed!
1077 my $iterargs = $link_entry->{'_archive'};
1078 if($Archive::Tar::RESOLVE_SYMLINK=~/speed/ && @$iterargs==3){
1079 #faster but whole archive will be read in memory
1080 #read whole archive and share data
1081 my $archive = Archive::Tar->new;
1082 $archive->read( @$iterargs );
1083 push @$iterargs, $archive; #take a trace for destruction
1084 if($archive->_data){
1085 $self->_data( $archive->_data );
1086 goto seach_entry;
1088 }#faster
1090 {#slower but lower memory usage
1091 # $iterargs = [$filename, $compressed, $opts];
1092 my $next = Archive::Tar->iter( @$iterargs );
1093 while(my $e = $next->()){
1094 if($e->full_path eq $file){
1095 undef $next;
1096 return $e;
1099 }#slower
1103 $self->_error( qq[No such file in archive: '$file'] );
1104 return;
1107 =head2 $tar->get_files( [@filenames] )
1109 Returns the C<Archive::Tar::File> objects matching the filenames
1110 provided. If no filename list was passed, all C<Archive::Tar::File>
1111 objects in the current Tar object are returned.
1113 Please refer to the C<Archive::Tar::File> documentation on how to
1114 handle these objects.
1116 =cut
1118 sub get_files {
1119 my $self = shift;
1121 return @{ $self->_data } unless @_;
1123 my @list;
1124 for my $file ( @_ ) {
1125 push @list, grep { defined } $self->_find_entry( $file );
1128 return @list;
1131 =head2 $tar->get_content( $file )
1133 Return the content of the named file.
1135 =cut
1137 sub get_content {
1138 my $self = shift;
1139 my $entry = $self->_find_entry( shift ) or return;
1141 return $entry->data;
1144 =head2 $tar->replace_content( $file, $content )
1146 Make the string $content be the content for the file named $file.
1148 =cut
1150 sub replace_content {
1151 my $self = shift;
1152 my $entry = $self->_find_entry( shift ) or return;
1154 return $entry->replace_content( shift );
1157 =head2 $tar->rename( $file, $new_name )
1159 Rename the file of the in-memory archive to $new_name.
1161 Note that you must specify a Unix path for $new_name, since per tar
1162 standard, all files in the archive must be Unix paths.
1164 Returns true on success and false on failure.
1166 =cut
1168 sub rename {
1169 my $self = shift;
1170 my $file = shift; return unless defined $file;
1171 my $new = shift; return unless defined $new;
1173 my $entry = $self->_find_entry( $file ) or return;
1175 return $entry->rename( $new );
1178 =head2 $tar->chmod( $file, $mode )
1180 Change mode of $file to $mode.
1182 Returns true on success and false on failure.
1184 =cut
1186 sub chmod {
1187 my $self = shift;
1188 my $file = shift; return unless defined $file;
1189 my $mode = shift; return unless defined $mode && $mode =~ /^[0-7]{1,4}$/;
1190 my @args = ("$mode");
1192 my $entry = $self->_find_entry( $file ) or return;
1193 my $x = $entry->chmod( @args );
1194 return $x;
1197 =head2 $tar->chown( $file, $uname [, $gname] )
1199 Change owner $file to $uname and $gname.
1201 Returns true on success and false on failure.
1203 =cut
1205 sub chown {
1206 my $self = shift;
1207 my $file = shift; return unless defined $file;
1208 my $uname = shift; return unless defined $uname;
1209 my @args = ($uname);
1210 push(@args, shift);
1212 my $entry = $self->_find_entry( $file ) or return;
1213 my $x = $entry->chown( @args );
1214 return $x;
1217 =head2 $tar->remove (@filenamelist)
1219 Removes any entries with names matching any of the given filenames
1220 from the in-memory archive. Returns a list of C<Archive::Tar::File>
1221 objects that remain.
1223 =cut
1225 sub remove {
1226 my $self = shift;
1227 my @list = @_;
1229 my %seen = map { $_->full_path => $_ } @{$self->_data};
1230 delete $seen{ $_ } for @list;
1232 $self->_data( [values %seen] );
1234 return values %seen;
1237 =head2 $tar->clear
1239 C<clear> clears the current in-memory archive. This effectively gives
1240 you a 'blank' object, ready to be filled again. Note that C<clear>
1241 only has effect on the object, not the underlying tarfile.
1243 =cut
1245 sub clear {
1246 my $self = shift or return;
1248 $self->_data( [] );
1249 $self->_file( '' );
1251 return 1;
1255 =head2 $tar->write ( [$file, $compressed, $prefix] )
1257 Write the in-memory archive to disk. The first argument can either
1258 be the name of a file or a reference to an already open filehandle (a
1259 GLOB reference).
1261 The second argument is used to indicate compression. You can either
1262 compress using C<gzip> or C<bzip2>. If you pass a digit, it's assumed
1263 to be the C<gzip> compression level (between 1 and 9), but the use of
1264 constants is preferred:
1266 # write a gzip compressed file
1267 $tar->write( 'out.tgz', COMPRESS_GZIP );
1269 # write a bzip compressed file
1270 $tar->write( 'out.tbz', COMPRESS_BZIP );
1272 Note that when you pass in a filehandle, the compression argument
1273 is ignored, as all files are printed verbatim to your filehandle.
1274 If you wish to enable compression with filehandles, use an
1275 C<IO::Zlib> or C<IO::Compress::Bzip2> filehandle instead.
1277 The third argument is an optional prefix. All files will be tucked
1278 away in the directory you specify as prefix. So if you have files
1279 'a' and 'b' in your archive, and you specify 'foo' as prefix, they
1280 will be written to the archive as 'foo/a' and 'foo/b'.
1282 If no arguments are given, C<write> returns the entire formatted
1283 archive as a string, which could be useful if you'd like to stuff the
1284 archive into a socket or a pipe to gzip or something.
1287 =cut
1289 sub write {
1290 my $self = shift;
1291 my $file = shift; $file = '' unless defined $file;
1292 my $gzip = shift || 0;
1293 my $ext_prefix = shift; $ext_prefix = '' unless defined $ext_prefix;
1294 my $dummy = '';
1296 ### only need a handle if we have a file to print to ###
1297 my $handle = length($file)
1298 ? ( $self->_get_handle($file, $gzip, WRITE_ONLY->($gzip) )
1299 or return )
1300 : $HAS_PERLIO ? do { open my $h, '>', \$dummy; $h }
1301 : $HAS_IO_STRING ? IO::String->new
1302 : __PACKAGE__->no_string_support();
1304 ### Addresses: #41798: Nonempty $\ when writing a TAR file produces a
1305 ### corrupt TAR file. Must clear out $\ to make sure no garbage is
1306 ### printed to the archive
1307 local $\;
1309 for my $entry ( @{$self->_data} ) {
1310 ### entries to be written to the tarfile ###
1311 my @write_me;
1313 ### only now will we change the object to reflect the current state
1314 ### of the name and prefix fields -- this needs to be limited to
1315 ### write() only!
1316 my $clone = $entry->clone;
1319 ### so, if you don't want use to use the prefix, we'll stuff
1320 ### everything in the name field instead
1321 if( $DO_NOT_USE_PREFIX ) {
1323 ### you might have an extended prefix, if so, set it in the clone
1324 ### XXX is ::Unix right?
1325 $clone->name( length $ext_prefix
1326 ? File::Spec::Unix->catdir( $ext_prefix,
1327 $clone->full_path)
1328 : $clone->full_path );
1329 $clone->prefix( '' );
1331 ### otherwise, we'll have to set it properly -- prefix part in the
1332 ### prefix and name part in the name field.
1333 } else {
1335 ### split them here, not before!
1336 my ($prefix,$name) = $clone->_prefix_and_file( $clone->full_path );
1338 ### you might have an extended prefix, if so, set it in the clone
1339 ### XXX is ::Unix right?
1340 $prefix = File::Spec::Unix->catdir( $ext_prefix, $prefix )
1341 if length $ext_prefix;
1343 $clone->prefix( $prefix );
1344 $clone->name( $name );
1347 ### names are too long, and will get truncated if we don't add a
1348 ### '@LongLink' file...
1349 my $make_longlink = ( length($clone->name) > NAME_LENGTH or
1350 length($clone->prefix) > PREFIX_LENGTH
1351 ) || 0;
1353 ### perhaps we need to make a longlink file?
1354 if( $make_longlink ) {
1355 my $longlink = Archive::Tar::File->new(
1356 data => LONGLINK_NAME,
1357 $clone->full_path,
1358 { type => LONGLINK }
1361 unless( $longlink ) {
1362 $self->_error( qq[Could not create 'LongLink' entry for ] .
1363 qq[oversize file '] . $clone->full_path ."'" );
1364 return;
1367 push @write_me, $longlink;
1370 push @write_me, $clone;
1372 ### write the one, optionally 2 a::t::file objects to the handle
1373 for my $clone (@write_me) {
1375 ### if the file is a symlink, there are 2 options:
1376 ### either we leave the symlink intact, but then we don't write any
1377 ### data OR we follow the symlink, which means we actually make a
1378 ### copy. if we do the latter, we have to change the TYPE of the
1379 ### clone to 'FILE'
1380 my $link_ok = $clone->is_symlink && $Archive::Tar::FOLLOW_SYMLINK;
1381 my $data_ok = !$clone->is_symlink && $clone->has_content;
1383 ### downgrade to a 'normal' file if it's a symlink we're going to
1384 ### treat as a regular file
1385 $clone->_downgrade_to_plainfile if $link_ok;
1387 ### get the header for this block
1388 my $header = $self->_format_tar_entry( $clone );
1389 unless( $header ) {
1390 $self->_error(q[Could not format header for: ] .
1391 $clone->full_path );
1392 return;
1395 unless( print $handle $header ) {
1396 $self->_error(q[Could not write header for: ] .
1397 $clone->full_path);
1398 return;
1401 if( $link_ok or $data_ok ) {
1402 unless( print $handle $clone->data ) {
1403 $self->_error(q[Could not write data for: ] .
1404 $clone->full_path);
1405 return;
1408 ### pad the end of the clone if required ###
1409 print $handle TAR_PAD->( $clone->size ) if $clone->size % BLOCK
1412 } ### done writing these entries
1415 ### write the end markers ###
1416 print $handle TAR_END x 2 or
1417 return $self->_error( qq[Could not write tar end markers] );
1419 ### did you want it written to a file, or returned as a string? ###
1420 my $rv = length($file) ? 1
1421 : $HAS_PERLIO ? $dummy
1422 : do { seek $handle, 0, 0; local $/; <$handle> };
1424 ### make sure to close the handle if we created it
1425 if ( $file ne $handle ) {
1426 unless( close $handle ) {
1427 $self->_error( qq[Could not write tar] );
1428 return;
1432 return $rv;
1435 sub _format_tar_entry {
1436 my $self = shift;
1437 my $entry = shift or return;
1438 my $ext_prefix = shift; $ext_prefix = '' unless defined $ext_prefix;
1439 my $no_prefix = shift || 0;
1441 my $file = $entry->name;
1442 my $prefix = $entry->prefix; $prefix = '' unless defined $prefix;
1444 ### remove the prefix from the file name
1445 ### not sure if this is still needed --kane
1446 ### no it's not -- Archive::Tar::File->_new_from_file will take care of
1447 ### this for us. Even worse, this would break if we tried to add a file
1448 ### like x/x.
1449 #if( length $prefix ) {
1450 # $file =~ s/^$match//;
1453 $prefix = File::Spec::Unix->catdir($ext_prefix, $prefix)
1454 if length $ext_prefix;
1456 ### not sure why this is... ###
1457 my $l = PREFIX_LENGTH; # is ambiguous otherwise...
1458 substr ($prefix, 0, -$l) = "" if length $prefix >= PREFIX_LENGTH;
1460 my $f1 = "%06o"; my $f2 = $ZERO_PAD_NUMBERS ? "%011o" : "%11o";
1462 ### this might be optimizable with a 'changed' flag in the file objects ###
1463 my $tar = pack (
1464 PACK,
1465 $file,
1467 (map { sprintf( $f1, $entry->$_() ) } qw[mode uid gid]),
1468 (map { sprintf( $f2, $entry->$_() ) } qw[size mtime]),
1470 "", # checksum field - space padded a bit down
1472 (map { $entry->$_() } qw[type linkname magic]),
1474 $entry->version || TAR_VERSION,
1476 (map { $entry->$_() } qw[uname gname]),
1477 (map { sprintf( $f1, $entry->$_() ) } qw[devmajor devminor]),
1479 ($no_prefix ? '' : $prefix)
1482 ### add the checksum ###
1483 my $checksum_fmt = $ZERO_PAD_NUMBERS ? "%06o\0" : "%06o\0";
1484 substr($tar,148,7) = sprintf("%6o\0", unpack("%16C*",$tar));
1486 return $tar;
1489 =head2 $tar->add_files( @filenamelist )
1491 Takes a list of filenames and adds them to the in-memory archive.
1493 The path to the file is automatically converted to a Unix like
1494 equivalent for use in the archive, and, if on MacOS, the file's
1495 modification time is converted from the MacOS epoch to the Unix epoch.
1496 So tar archives created on MacOS with B<Archive::Tar> can be read
1497 both with I<tar> on Unix and applications like I<suntar> or
1498 I<Stuffit Expander> on MacOS.
1500 Be aware that the file's type/creator and resource fork will be lost,
1501 which is usually what you want in cross-platform archives.
1503 Instead of a filename, you can also pass it an existing C<Archive::Tar::File>
1504 object from, for example, another archive. The object will be clone, and
1505 effectively be a copy of the original, not an alias.
1507 Returns a list of C<Archive::Tar::File> objects that were just added.
1509 =cut
1511 sub add_files {
1512 my $self = shift;
1513 my @files = @_ or return;
1515 my @rv;
1516 for my $file ( @files ) {
1518 ### you passed an Archive::Tar::File object
1519 ### clone it so we don't accidentally have a reference to
1520 ### an object from another archive
1521 if( UNIVERSAL::isa( $file,'Archive::Tar::File' ) ) {
1522 push @rv, $file->clone;
1523 next;
1526 eval {
1527 if( utf8::is_utf8( $file )) {
1528 utf8::encode( $file );
1532 unless( -e $file || -l $file ) {
1533 $self->_error( qq[No such file: '$file'] );
1534 next;
1537 my $obj = Archive::Tar::File->new( file => $file );
1538 unless( $obj ) {
1539 $self->_error( qq[Unable to add file: '$file'] );
1540 next;
1543 push @rv, $obj;
1546 push @{$self->{_data}}, @rv;
1548 return @rv;
1551 =head2 $tar->add_data ( $filename, $data, [$opthashref] )
1553 Takes a filename, a scalar full of data and optionally a reference to
1554 a hash with specific options.
1556 Will add a file to the in-memory archive, with name C<$filename> and
1557 content C<$data>. Specific properties can be set using C<$opthashref>.
1558 The following list of properties is supported: name, size, mtime
1559 (last modified date), mode, uid, gid, linkname, uname, gname,
1560 devmajor, devminor, prefix, type. (On MacOS, the file's path and
1561 modification times are converted to Unix equivalents.)
1563 Valid values for the file type are the following constants defined by
1564 Archive::Tar::Constant:
1566 =over 4
1568 =item FILE
1570 Regular file.
1572 =item HARDLINK
1574 =item SYMLINK
1576 Hard and symbolic ("soft") links; linkname should specify target.
1578 =item CHARDEV
1580 =item BLOCKDEV
1582 Character and block devices. devmajor and devminor should specify the major
1583 and minor device numbers.
1585 =item DIR
1587 Directory.
1589 =item FIFO
1591 FIFO (named pipe).
1593 =item SOCKET
1595 Socket.
1597 =back
1599 Returns the C<Archive::Tar::File> object that was just added, or
1600 C<undef> on failure.
1602 =cut
1604 sub add_data {
1605 my $self = shift;
1606 my ($file, $data, $opt) = @_;
1608 my $obj = Archive::Tar::File->new( data => $file, $data, $opt );
1609 unless( $obj ) {
1610 $self->_error( qq[Unable to add file: '$file'] );
1611 return;
1614 push @{$self->{_data}}, $obj;
1616 return $obj;
1619 =head2 $tar->error( [$BOOL] )
1621 Returns the current error string (usually, the last error reported).
1622 If a true value was specified, it will give the C<Carp::longmess>
1623 equivalent of the error, in effect giving you a stacktrace.
1625 For backwards compatibility, this error is also available as
1626 C<$Archive::Tar::error> although it is much recommended you use the
1627 method call instead.
1629 =cut
1632 $error = '';
1633 my $longmess;
1635 sub _error {
1636 my $self = shift;
1637 my $msg = $error = shift;
1638 $longmess = Carp::longmess($error);
1639 if (ref $self) {
1640 $self->{_error} = $error;
1641 $self->{_longmess} = $longmess;
1644 ### set Archive::Tar::WARN to 0 to disable printing
1645 ### of errors
1646 if( $WARN ) {
1647 carp $DEBUG ? $longmess : $msg;
1650 return;
1653 sub error {
1654 my $self = shift;
1655 if (ref $self) {
1656 return shift() ? $self->{_longmess} : $self->{_error};
1657 } else {
1658 return shift() ? $longmess : $error;
1663 =head2 $tar->setcwd( $cwd );
1665 C<Archive::Tar> needs to know the current directory, and it will run
1666 C<Cwd::cwd()> I<every> time it extracts a I<relative> entry from the
1667 tarfile and saves it in the file system. (As of version 1.30, however,
1668 C<Archive::Tar> will use the speed optimization described below
1669 automatically, so it's only relevant if you're using C<extract_file()>).
1671 Since C<Archive::Tar> doesn't change the current directory internally
1672 while it is extracting the items in a tarball, all calls to C<Cwd::cwd()>
1673 can be avoided if we can guarantee that the current directory doesn't
1674 get changed externally.
1676 To use this performance boost, set the current directory via
1678 use Cwd;
1679 $tar->setcwd( cwd() );
1681 once before calling a function like C<extract_file> and
1682 C<Archive::Tar> will use the current directory setting from then on
1683 and won't call C<Cwd::cwd()> internally.
1685 To switch back to the default behaviour, use
1687 $tar->setcwd( undef );
1689 and C<Archive::Tar> will call C<Cwd::cwd()> internally again.
1691 If you're using C<Archive::Tar>'s C<extract()> method, C<setcwd()> will
1692 be called for you.
1694 =cut
1696 sub setcwd {
1697 my $self = shift;
1698 my $cwd = shift;
1700 $self->{cwd} = $cwd;
1703 =head1 Class Methods
1705 =head2 Archive::Tar->create_archive($file, $compressed, @filelist)
1707 Creates a tar file from the list of files provided. The first
1708 argument can either be the name of the tar file to create or a
1709 reference to an open file handle (e.g. a GLOB reference).
1711 The second argument is used to indicate compression. You can either
1712 compress using C<gzip> or C<bzip2>. If you pass a digit, it's assumed
1713 to be the C<gzip> compression level (between 1 and 9), but the use of
1714 constants is preferred:
1716 # write a gzip compressed file
1717 Archive::Tar->create_archive( 'out.tgz', COMPRESS_GZIP, @filelist );
1719 # write a bzip compressed file
1720 Archive::Tar->create_archive( 'out.tbz', COMPRESS_BZIP, @filelist );
1722 Note that when you pass in a filehandle, the compression argument
1723 is ignored, as all files are printed verbatim to your filehandle.
1724 If you wish to enable compression with filehandles, use an
1725 C<IO::Zlib> or C<IO::Compress::Bzip2> filehandle instead.
1727 The remaining arguments list the files to be included in the tar file.
1728 These files must all exist. Any files which don't exist or can't be
1729 read are silently ignored.
1731 If the archive creation fails for any reason, C<create_archive> will
1732 return false. Please use the C<error> method to find the cause of the
1733 failure.
1735 Note that this method does not write C<on the fly> as it were; it
1736 still reads all the files into memory before writing out the archive.
1737 Consult the FAQ below if this is a problem.
1739 =cut
1741 sub create_archive {
1742 my $class = shift;
1744 my $file = shift; return unless defined $file;
1745 my $gzip = shift || 0;
1746 my @files = @_;
1748 unless( @files ) {
1749 return $class->_error( qq[Cowardly refusing to create empty archive!] );
1752 my $tar = $class->new;
1753 $tar->add_files( @files );
1754 return $tar->write( $file, $gzip );
1757 =head2 Archive::Tar->iter( $filename, [ $compressed, {opt => $val} ] )
1759 Returns an iterator function that reads the tar file without loading
1760 it all in memory. Each time the function is called it will return the
1761 next file in the tarball. The files are returned as
1762 C<Archive::Tar::File> objects. The iterator function returns the
1763 empty list once it has exhausted the files contained.
1765 The second argument can be a hash reference with options, which are
1766 identical to the arguments passed to C<read()>.
1768 Example usage:
1770 my $next = Archive::Tar->iter( "example.tar.gz", 1, {filter => qr/\.pm$/} );
1772 while( my $f = $next->() ) {
1773 print $f->name, "\n";
1775 $f->extract or warn "Extraction failed";
1777 # ....
1780 =cut
1783 sub iter {
1784 my $class = shift;
1785 my $filename = shift or return;
1786 my $compressed = shift || 0;
1787 my $opts = shift || {};
1789 ### get a handle to read from.
1790 my $handle = $class->_get_handle(
1791 $filename,
1792 $compressed,
1793 READ_ONLY->( ZLIB )
1794 ) or return;
1796 my @data;
1797 my $CONSTRUCT_ARGS = [ $filename, $compressed, $opts ];
1798 return sub {
1799 return shift(@data) if @data; # more than one file returned?
1800 return unless $handle; # handle exhausted?
1802 ### read data, should only return file
1803 my $tarfile = $class->_read_tar($handle, { %$opts, limit => 1 });
1804 @data = @$tarfile if ref $tarfile && ref $tarfile eq 'ARRAY';
1805 if($Archive::Tar::RESOLVE_SYMLINK!~/none/){
1806 foreach(@data){
1807 #may refine this heuristic for ON_UNIX?
1808 if($_->linkname){
1809 #is there a better slot to store/share it ?
1810 $_->{'_archive'} = $CONSTRUCT_ARGS;
1815 ### return one piece of data
1816 return shift(@data) if @data;
1818 ### data is exhausted, free the filehandle
1819 undef $handle;
1820 if(@$CONSTRUCT_ARGS == 4){
1821 #free archive in memory
1822 undef $CONSTRUCT_ARGS->[-1];
1824 return;
1828 =head2 Archive::Tar->list_archive($file, $compressed, [\@properties])
1830 Returns a list of the names of all the files in the archive. The
1831 first argument can either be the name of the tar file to list or a
1832 reference to an open file handle (e.g. a GLOB reference).
1834 If C<list_archive()> is passed an array reference as its third
1835 argument it returns a list of hash references containing the requested
1836 properties of each file. The following list of properties is
1837 supported: full_path, name, size, mtime (last modified date), mode,
1838 uid, gid, linkname, uname, gname, devmajor, devminor, prefix, type.
1840 See C<Archive::Tar::File> for details about supported properties.
1842 Passing an array reference containing only one element, 'name', is
1843 special cased to return a list of names rather than a list of hash
1844 references.
1846 =cut
1848 sub list_archive {
1849 my $class = shift;
1850 my $file = shift; return unless defined $file;
1851 my $gzip = shift || 0;
1853 my $tar = $class->new($file, $gzip);
1854 return unless $tar;
1856 return $tar->list_files( @_ );
1859 =head2 Archive::Tar->extract_archive($file, $compressed)
1861 Extracts the contents of the tar file. The first argument can either
1862 be the name of the tar file to create or a reference to an open file
1863 handle (e.g. a GLOB reference). All relative paths in the tar file will
1864 be created underneath the current working directory.
1866 C<extract_archive> will return a list of files it extracted.
1867 If the archive extraction fails for any reason, C<extract_archive>
1868 will return false. Please use the C<error> method to find the cause
1869 of the failure.
1871 =cut
1873 sub extract_archive {
1874 my $class = shift;
1875 my $file = shift; return unless defined $file;
1876 my $gzip = shift || 0;
1878 my $tar = $class->new( ) or return;
1880 return $tar->read( $file, $gzip, { extract => 1 } );
1883 =head2 $bool = Archive::Tar->has_io_string
1885 Returns true if we currently have C<IO::String> support loaded.
1887 Either C<IO::String> or C<perlio> support is needed to support writing
1888 stringified archives. Currently, C<perlio> is the preferred method, if
1889 available.
1891 See the C<GLOBAL VARIABLES> section to see how to change this preference.
1893 =cut
1895 sub has_io_string { return $HAS_IO_STRING; }
1897 =head2 $bool = Archive::Tar->has_perlio
1899 Returns true if we currently have C<perlio> support loaded.
1901 This requires C<perl-5.8> or higher, compiled with C<perlio>
1903 Either C<IO::String> or C<perlio> support is needed to support writing
1904 stringified archives. Currently, C<perlio> is the preferred method, if
1905 available.
1907 See the C<GLOBAL VARIABLES> section to see how to change this preference.
1909 =cut
1911 sub has_perlio { return $HAS_PERLIO; }
1913 =head2 $bool = Archive::Tar->has_zlib_support
1915 Returns true if C<Archive::Tar> can extract C<zlib> compressed archives
1917 =cut
1919 sub has_zlib_support { return ZLIB }
1921 =head2 $bool = Archive::Tar->has_bzip2_support
1923 Returns true if C<Archive::Tar> can extract C<bzip2> compressed archives
1925 =cut
1927 sub has_bzip2_support { return BZIP }
1929 =head2 Archive::Tar->can_handle_compressed_files
1931 A simple checking routine, which will return true if C<Archive::Tar>
1932 is able to uncompress compressed archives on the fly with C<IO::Zlib>
1933 and C<IO::Compress::Bzip2> or false if not both are installed.
1935 You can use this as a shortcut to determine whether C<Archive::Tar>
1936 will do what you think before passing compressed archives to its
1937 C<read> method.
1939 =cut
1941 sub can_handle_compressed_files { return ZLIB && BZIP ? 1 : 0 }
1943 sub no_string_support {
1944 croak("You have to install IO::String to support writing archives to strings");
1947 sub _symlinks_resolver{
1948 my ($src, $trg) = @_;
1949 my @src = split /[\/\\]/, $src;
1950 my @trg = split /[\/\\]/, $trg;
1951 pop @src; #strip out current object name
1952 if(@trg and $trg[0] eq ''){
1953 shift @trg;
1954 #restart path from scratch
1955 @src = ( );
1957 foreach my $part ( @trg ){
1958 next if $part eq '.'; #ignore current
1959 if($part eq '..'){
1960 #got to parent
1961 pop @src;
1963 else{
1964 #append it
1965 push @src, $part;
1968 my $path = join('/', @src);
1969 warn "_symlinks_resolver('$src','$trg') = $path" if $DEBUG;
1970 return $path;
1975 __END__
1977 =head1 GLOBAL VARIABLES
1979 =head2 $Archive::Tar::FOLLOW_SYMLINK
1981 Set this variable to C<1> to make C<Archive::Tar> effectively make a
1982 copy of the file when extracting. Default is C<0>, which
1983 means the symlink stays intact. Of course, you will have to pack the
1984 file linked to as well.
1986 This option is checked when you write out the tarfile using C<write>
1987 or C<create_archive>.
1989 This works just like C</bin/tar>'s C<-h> option.
1991 =head2 $Archive::Tar::CHOWN
1993 By default, C<Archive::Tar> will try to C<chown> your files if it is
1994 able to. In some cases, this may not be desired. In that case, set
1995 this variable to C<0> to disable C<chown>-ing, even if it were
1996 possible.
1998 The default is C<1>.
2000 =head2 $Archive::Tar::CHMOD
2002 By default, C<Archive::Tar> will try to C<chmod> your files to
2003 whatever mode was specified for the particular file in the archive.
2004 In some cases, this may not be desired. In that case, set this
2005 variable to C<0> to disable C<chmod>-ing.
2007 The default is C<1>.
2009 =head2 $Archive::Tar::SAME_PERMISSIONS
2011 When, C<$Archive::Tar::CHMOD> is enabled, this setting controls whether
2012 the permissions on files from the archive are used without modification
2013 of if they are filtered by removing any setid bits and applying the
2014 current umask.
2016 The default is C<1> for the root user and C<0> for normal users.
2018 =head2 $Archive::Tar::DO_NOT_USE_PREFIX
2020 By default, C<Archive::Tar> will try to put paths that are over
2021 100 characters in the C<prefix> field of your tar header, as
2022 defined per POSIX-standard. However, some (older) tar programs
2023 do not implement this spec. To retain compatibility with these older
2024 or non-POSIX compliant versions, you can set the C<$DO_NOT_USE_PREFIX>
2025 variable to a true value, and C<Archive::Tar> will use an alternate
2026 way of dealing with paths over 100 characters by using the
2027 C<GNU Extended Header> feature.
2029 Note that clients who do not support the C<GNU Extended Header>
2030 feature will not be able to read these archives. Such clients include
2031 tars on C<Solaris>, C<Irix> and C<AIX>.
2033 The default is C<0>.
2035 =head2 $Archive::Tar::DEBUG
2037 Set this variable to C<1> to always get the C<Carp::longmess> output
2038 of the warnings, instead of the regular C<carp>. This is the same
2039 message you would get by doing:
2041 $tar->error(1);
2043 Defaults to C<0>.
2045 =head2 $Archive::Tar::WARN
2047 Set this variable to C<0> if you do not want any warnings printed.
2048 Personally I recommend against doing this, but people asked for the
2049 option. Also, be advised that this is of course not threadsafe.
2051 Defaults to C<1>.
2053 =head2 $Archive::Tar::error
2055 Holds the last reported error. Kept for historical reasons, but its
2056 use is very much discouraged. Use the C<error()> method instead:
2058 warn $tar->error unless $tar->extract;
2060 Note that in older versions of this module, the C<error()> method
2061 would return an effectively global value even when called an instance
2062 method as above. This has since been fixed, and multiple instances of
2063 C<Archive::Tar> now have separate error strings.
2065 =head2 $Archive::Tar::INSECURE_EXTRACT_MODE
2067 This variable indicates whether C<Archive::Tar> should allow
2068 files to be extracted outside their current working directory.
2070 Allowing this could have security implications, as a malicious
2071 tar archive could alter or replace any file the extracting user
2072 has permissions to. Therefor, the default is to not allow
2073 insecure extractions.
2075 If you trust the archive, or have other reasons to allow the
2076 archive to write files outside your current working directory,
2077 set this variable to C<true>.
2079 Note that this is a backwards incompatible change from version
2080 C<1.36> and before.
2082 =head2 $Archive::Tar::HAS_PERLIO
2084 This variable holds a boolean indicating if we currently have
2085 C<perlio> support loaded. This will be enabled for any perl
2086 greater than C<5.8> compiled with C<perlio>.
2088 If you feel strongly about disabling it, set this variable to
2089 C<false>. Note that you will then need C<IO::String> installed
2090 to support writing stringified archives.
2092 Don't change this variable unless you B<really> know what you're
2093 doing.
2095 =head2 $Archive::Tar::HAS_IO_STRING
2097 This variable holds a boolean indicating if we currently have
2098 C<IO::String> support loaded. This will be enabled for any perl
2099 that has a loadable C<IO::String> module.
2101 If you feel strongly about disabling it, set this variable to
2102 C<false>. Note that you will then need C<perlio> support from
2103 your perl to be able to write stringified archives.
2105 Don't change this variable unless you B<really> know what you're
2106 doing.
2108 =head2 $Archive::Tar::ZERO_PAD_NUMBERS
2110 This variable holds a boolean indicating if we will create
2111 zero padded numbers for C<size>, C<mtime> and C<checksum>.
2112 The default is C<0>, indicating that we will create space padded
2113 numbers. Added for compatibility with C<busybox> implementations.
2115 =head2 Tuning the way RESOLVE_SYMLINK will works
2117 You can tune the behaviour by setting the $Archive::Tar::RESOLVE_SYMLINK variable,
2118 or $ENV{PERL5_AT_RESOLVE_SYMLINK} before loading the module Archive::Tar.
2120 Values can be one of the following:
2122 none
2123 Disable this mechanism and failed as it was in previous version (<1.88)
2125 speed (default)
2126 If you prefer speed
2127 this will read again the whole archive using read() so all entries
2128 will be available
2130 memory
2131 If you prefer memory
2133 Limitation
2135 It won't work for terminal, pipe or sockets or every non seekable source.
2137 =cut
2139 =head1 FAQ
2141 =over 4
2143 =item What's the minimum perl version required to run Archive::Tar?
2145 You will need perl version 5.005_03 or newer.
2147 =item Isn't Archive::Tar slow?
2149 Yes it is. It's pure perl, so it's a lot slower then your C</bin/tar>
2150 However, it's very portable. If speed is an issue, consider using
2151 C</bin/tar> instead.
2153 =item Isn't Archive::Tar heavier on memory than /bin/tar?
2155 Yes it is, see previous answer. Since C<Compress::Zlib> and therefore
2156 C<IO::Zlib> doesn't support C<seek> on their filehandles, there is little
2157 choice but to read the archive into memory.
2158 This is ok if you want to do in-memory manipulation of the archive.
2160 If you just want to extract, use the C<extract_archive> class method
2161 instead. It will optimize and write to disk immediately.
2163 Another option is to use the C<iter> class method to iterate over
2164 the files in the tarball without reading them all in memory at once.
2166 =item Can you lazy-load data instead?
2168 In some cases, yes. You can use the C<iter> class method to iterate
2169 over the files in the tarball without reading them all in memory at once.
2171 =item How much memory will an X kb tar file need?
2173 Probably more than X kb, since it will all be read into memory. If
2174 this is a problem, and you don't need to do in memory manipulation
2175 of the archive, consider using the C<iter> class method, or C</bin/tar>
2176 instead.
2178 =item What do you do with unsupported filetypes in an archive?
2180 C<Unix> has a few filetypes that aren't supported on other platforms,
2181 like C<Win32>. If we encounter a C<hardlink> or C<symlink> we'll just
2182 try to make a copy of the original file, rather than throwing an error.
2184 This does require you to read the entire archive in to memory first,
2185 since otherwise we wouldn't know what data to fill the copy with.
2186 (This means that you cannot use the class methods, including C<iter>
2187 on archives that have incompatible filetypes and still expect things
2188 to work).
2190 For other filetypes, like C<chardevs> and C<blockdevs> we'll warn that
2191 the extraction of this particular item didn't work.
2193 =item I'm using WinZip, or some other non-POSIX client, and files are not being extracted properly!
2195 By default, C<Archive::Tar> is in a completely POSIX-compatible
2196 mode, which uses the POSIX-specification of C<tar> to store files.
2197 For paths greater than 100 characters, this is done using the
2198 C<POSIX header prefix>. Non-POSIX-compatible clients may not support
2199 this part of the specification, and may only support the C<GNU Extended
2200 Header> functionality. To facilitate those clients, you can set the
2201 C<$Archive::Tar::DO_NOT_USE_PREFIX> variable to C<true>. See the
2202 C<GLOBAL VARIABLES> section for details on this variable.
2204 Note that GNU tar earlier than version 1.14 does not cope well with
2205 the C<POSIX header prefix>. If you use such a version, consider setting
2206 the C<$Archive::Tar::DO_NOT_USE_PREFIX> variable to C<true>.
2208 =item How do I extract only files that have property X from an archive?
2210 Sometimes, you might not wish to extract a complete archive, just
2211 the files that are relevant to you, based on some criteria.
2213 You can do this by filtering a list of C<Archive::Tar::File> objects
2214 based on your criteria. For example, to extract only files that have
2215 the string C<foo> in their title, you would use:
2217 $tar->extract(
2218 grep { $_->full_path =~ /foo/ } $tar->get_files
2221 This way, you can filter on any attribute of the files in the archive.
2222 Consult the C<Archive::Tar::File> documentation on how to use these
2223 objects.
2225 =item How do I access .tar.Z files?
2227 The C<Archive::Tar> module can optionally use C<Compress::Zlib> (via
2228 the C<IO::Zlib> module) to access tar files that have been compressed
2229 with C<gzip>. Unfortunately tar files compressed with the Unix C<compress>
2230 utility cannot be read by C<Compress::Zlib> and so cannot be directly
2231 accesses by C<Archive::Tar>.
2233 If the C<uncompress> or C<gunzip> programs are available, you can use
2234 one of these workarounds to read C<.tar.Z> files from C<Archive::Tar>
2236 Firstly with C<uncompress>
2238 use Archive::Tar;
2240 open F, "uncompress -c $filename |";
2241 my $tar = Archive::Tar->new(*F);
2244 and this with C<gunzip>
2246 use Archive::Tar;
2248 open F, "gunzip -c $filename |";
2249 my $tar = Archive::Tar->new(*F);
2252 Similarly, if the C<compress> program is available, you can use this to
2253 write a C<.tar.Z> file
2255 use Archive::Tar;
2256 use IO::File;
2258 my $fh = new IO::File "| compress -c >$filename";
2259 my $tar = Archive::Tar->new();
2261 $tar->write($fh);
2262 $fh->close ;
2264 =item How do I handle Unicode strings?
2266 C<Archive::Tar> uses byte semantics for any files it reads from or writes
2267 to disk. This is not a problem if you only deal with files and never
2268 look at their content or work solely with byte strings. But if you use
2269 Unicode strings with character semantics, some additional steps need
2270 to be taken.
2272 For example, if you add a Unicode string like
2274 # Problem
2275 $tar->add_data('file.txt', "Euro: \x{20AC}");
2277 then there will be a problem later when the tarfile gets written out
2278 to disk via C<$tar->write()>:
2280 Wide character in print at .../Archive/Tar.pm line 1014.
2282 The data was added as a Unicode string and when writing it out to disk,
2283 the C<:utf8> line discipline wasn't set by C<Archive::Tar>, so Perl
2284 tried to convert the string to ISO-8859 and failed. The written file
2285 now contains garbage.
2287 For this reason, Unicode strings need to be converted to UTF-8-encoded
2288 bytestrings before they are handed off to C<add_data()>:
2290 use Encode;
2291 my $data = "Accented character: \x{20AC}";
2292 $data = encode('utf8', $data);
2294 $tar->add_data('file.txt', $data);
2296 A opposite problem occurs if you extract a UTF8-encoded file from a
2297 tarball. Using C<get_content()> on the C<Archive::Tar::File> object
2298 will return its content as a bytestring, not as a Unicode string.
2300 If you want it to be a Unicode string (because you want character
2301 semantics with operations like regular expression matching), you need
2302 to decode the UTF8-encoded content and have Perl convert it into
2303 a Unicode string:
2305 use Encode;
2306 my $data = $tar->get_content();
2308 # Make it a Unicode string
2309 $data = decode('utf8', $data);
2311 There is no easy way to provide this functionality in C<Archive::Tar>,
2312 because a tarball can contain many files, and each of which could be
2313 encoded in a different way.
2315 =back
2317 =head1 CAVEATS
2319 The AIX tar does not fill all unused space in the tar archive with 0x00.
2320 This sometimes leads to warning messages from C<Archive::Tar>.
2322 Invalid header block at offset nnn
2324 A fix for that problem is scheduled to be released in the following levels
2325 of AIX, all of which should be coming out in the 4th quarter of 2009:
2327 AIX 5.3 TL7 SP10
2328 AIX 5.3 TL8 SP8
2329 AIX 5.3 TL9 SP5
2330 AIX 5.3 TL10 SP2
2332 AIX 6.1 TL0 SP11
2333 AIX 6.1 TL1 SP7
2334 AIX 6.1 TL2 SP6
2335 AIX 6.1 TL3 SP3
2337 The IBM APAR number for this problem is IZ50240 (Reported component ID:
2338 5765G0300 / AIX 5.3). It is possible to get an ifix for that problem.
2339 If you need an ifix please contact your local IBM AIX support.
2341 =head1 TODO
2343 =over 4
2345 =item Check if passed in handles are open for read/write
2347 Currently I don't know of any portable pure perl way to do this.
2348 Suggestions welcome.
2350 =item Allow archives to be passed in as string
2352 Currently, we only allow opened filehandles or filenames, but
2353 not strings. The internals would need some reworking to facilitate
2354 stringified archives.
2356 =item Facilitate processing an opened filehandle of a compressed archive
2358 Currently, we only support this if the filehandle is an IO::Zlib object.
2359 Environments, like apache, will present you with an opened filehandle
2360 to an uploaded file, which might be a compressed archive.
2362 =back
2364 =head1 SEE ALSO
2366 =over 4
2368 =item The GNU tar specification
2370 C<http://www.gnu.org/software/tar/manual/tar.html>
2372 =item The PAX format specification
2374 The specification which tar derives from; C< http://www.opengroup.org/onlinepubs/007904975/utilities/pax.html>
2376 =item A comparison of GNU and POSIX tar standards; C<http://www.delorie.com/gnu/docs/tar/tar_114.html>
2378 =item GNU tar intends to switch to POSIX compatibility
2380 GNU Tar authors have expressed their intention to become completely
2381 POSIX-compatible; C<http://www.gnu.org/software/tar/manual/html_node/Formats.html>
2383 =item A Comparison between various tar implementations
2385 Lists known issues and incompatibilities; C<http://gd.tuwien.ac.at/utils/archivers/star/README.otherbugs>
2387 =back
2389 =head1 AUTHOR
2391 This module by Jos Boumans E<lt>kane@cpan.orgE<gt>.
2393 Please reports bugs to E<lt>bug-archive-tar@rt.cpan.orgE<gt>.
2395 =head1 ACKNOWLEDGEMENTS
2397 Thanks to Sean Burke, Chris Nandor, Chip Salzenberg, Tim Heaney, Gisle Aas,
2398 Rainer Tammer and especially Andrew Savige for their help and suggestions.
2400 =head1 COPYRIGHT
2402 This module is copyright (c) 2002 - 2009 Jos Boumans
2403 E<lt>kane@cpan.orgE<gt>. All rights reserved.
2405 This library is free software; you may redistribute and/or modify
2406 it under the same terms as Perl itself.
2408 =cut
2410 END_OF_FILE
2413 # __MOBUNDLE_FILE__
2415 'Archive/Tar/Constant.pm' => <<'END_OF_FILE',
2416 package Archive::Tar::Constant;
2418 BEGIN {
2419 require Exporter;
2421 $VERSION = '2.04_01';
2422 @ISA = qw[Exporter];
2424 require Time::Local if $^O eq "MacOS";
2427 @EXPORT = Archive::Tar::Constant->_list_consts( __PACKAGE__ );
2429 use constant FILE => 0;
2430 use constant HARDLINK => 1;
2431 use constant SYMLINK => 2;
2432 use constant CHARDEV => 3;
2433 use constant BLOCKDEV => 4;
2434 use constant DIR => 5;
2435 use constant FIFO => 6;
2436 use constant SOCKET => 8;
2437 use constant UNKNOWN => 9;
2438 use constant LONGLINK => 'L';
2439 use constant LABEL => 'V';
2441 use constant BUFFER => 4096;
2442 use constant HEAD => 512;
2443 use constant BLOCK => 512;
2445 use constant COMPRESS_GZIP => 9;
2446 use constant COMPRESS_BZIP => 'bzip2';
2448 use constant BLOCK_SIZE => sub { my $n = int($_[0]/BLOCK); $n++ if $_[0] % BLOCK; $n * BLOCK };
2449 use constant TAR_PAD => sub { my $x = shift || return; return "\0" x (BLOCK - ($x % BLOCK) ) };
2450 use constant TAR_END => "\0" x BLOCK;
2452 use constant READ_ONLY => sub { shift() ? 'rb' : 'r' };
2453 use constant WRITE_ONLY => sub { $_[0] ? 'wb' . shift : 'w' };
2454 use constant MODE_READ => sub { $_[0] =~ /^r/ ? 1 : 0 };
2456 # Pointless assignment to make -w shut up
2457 my $getpwuid; $getpwuid = 'unknown' unless eval { my $f = getpwuid (0); };
2458 my $getgrgid; $getgrgid = 'unknown' unless eval { my $f = getgrgid (0); };
2459 use constant UNAME => sub { $getpwuid || scalar getpwuid( shift() ) || '' };
2460 use constant GNAME => sub { $getgrgid || scalar getgrgid( shift() ) || '' };
2461 use constant UID => $>;
2462 use constant GID => (split ' ', $) )[0];
2464 use constant MODE => do { 0666 & (0777 & ~umask) };
2465 use constant STRIP_MODE => sub { shift() & 0777 };
2466 use constant CHECK_SUM => " ";
2468 use constant UNPACK => 'A100 A8 A8 A8 a12 A12 A8 A1 A100 A6 A2 A32 A32 A8 A8 A155 x12'; # cdrake - size must be a12 - not A12 - or else screws up huge file sizes (>8gb)
2469 use constant PACK => 'a100 a8 a8 a8 a12 a12 A8 a1 a100 a6 a2 a32 a32 a8 a8 a155 x12';
2470 use constant NAME_LENGTH => 100;
2471 use constant PREFIX_LENGTH => 155;
2473 use constant TIME_OFFSET => ($^O eq "MacOS") ? Time::Local::timelocal(0,0,0,1,0,70) : 0;
2474 use constant MAGIC => "ustar";
2475 use constant TAR_VERSION => "00";
2476 use constant LONGLINK_NAME => '././@LongLink';
2477 use constant PAX_HEADER => 'pax_global_header';
2479 ### allow ZLIB to be turned off using ENV: DEBUG only
2480 use constant ZLIB => do { !$ENV{'PERL5_AT_NO_ZLIB'} and
2481 eval { require IO::Zlib };
2482 $ENV{'PERL5_AT_NO_ZLIB'} || $@ ? 0 : 1
2485 ### allow BZIP to be turned off using ENV: DEBUG only
2486 use constant BZIP => do { !$ENV{'PERL5_AT_NO_BZIP'} and
2487 eval { require IO::Uncompress::Bunzip2;
2488 require IO::Compress::Bzip2; };
2489 $ENV{'PERL5_AT_NO_BZIP'} || $@ ? 0 : 1
2492 use constant GZIP_MAGIC_NUM => qr/^(?:\037\213|\037\235)/;
2493 use constant BZIP_MAGIC_NUM => qr/^BZh\d/;
2495 use constant CAN_CHOWN => sub { ($> == 0 and $^O ne "MacOS" and $^O ne "MSWin32") };
2496 use constant CAN_READLINK => ($^O ne 'MSWin32' and $^O !~ /RISC(?:[ _])?OS/i and $^O ne 'VMS');
2497 use constant ON_UNIX => ($^O ne 'MSWin32' and $^O ne 'MacOS' and $^O ne 'VMS');
2498 use constant ON_VMS => $^O eq 'VMS';
2500 sub _list_consts {
2501 my $class = shift;
2502 my $pkg = shift;
2503 return unless defined $pkg; # some joker might use '0' as a pkg...
2505 my @rv;
2506 { no strict 'refs';
2507 my $stash = $pkg . '::';
2509 for my $name (sort keys %$stash ) {
2511 ### is it a subentry?
2512 my $sub = $pkg->can( $name );
2513 next unless defined $sub;
2515 next unless defined prototype($sub) and
2516 not length prototype($sub);
2518 push @rv, $name;
2522 return sort @rv;
2527 END_OF_FILE
2530 # __MOBUNDLE_FILE__
2532 'Archive/Tar/File.pm' => <<'END_OF_FILE',
2533 package Archive::Tar::File;
2534 use strict;
2536 use Carp ();
2537 use IO::File;
2538 use File::Spec::Unix ();
2539 use File::Spec ();
2540 use File::Basename ();
2542 ### avoid circular use, so only require;
2543 require Archive::Tar;
2544 use Archive::Tar::Constant;
2546 use vars qw[@ISA $VERSION];
2547 #@ISA = qw[Archive::Tar];
2548 $VERSION = '2.04_01';
2550 ### set value to 1 to oct() it during the unpack ###
2552 my $tmpl = [
2553 name => 0, # string A100
2554 mode => 1, # octal A8
2555 uid => 1, # octal A8
2556 gid => 1, # octal A8
2557 size => 0, # octal # cdrake - not *always* octal.. A12
2558 mtime => 1, # octal A12
2559 chksum => 1, # octal A8
2560 type => 0, # character A1
2561 linkname => 0, # string A100
2562 magic => 0, # string A6
2563 version => 0, # 2 bytes A2
2564 uname => 0, # string A32
2565 gname => 0, # string A32
2566 devmajor => 1, # octal A8
2567 devminor => 1, # octal A8
2568 prefix => 0, # A155 x 12
2570 ### end UNPACK items ###
2571 raw => 0, # the raw data chunk
2572 data => 0, # the data associated with the file --
2573 # This might be very memory intensive
2576 ### install get/set accessors for this object.
2577 for ( my $i=0; $i<scalar @$tmpl ; $i+=2 ) {
2578 my $key = $tmpl->[$i];
2579 no strict 'refs';
2580 *{__PACKAGE__."::$key"} = sub {
2581 my $self = shift;
2582 $self->{$key} = $_[0] if @_;
2584 ### just in case the key is not there or undef or something ###
2585 { local $^W = 0;
2586 return $self->{$key};
2591 =head1 NAME
2593 Archive::Tar::File - a subclass for in-memory extracted file from Archive::Tar
2595 =head1 SYNOPSIS
2597 my @items = $tar->get_files;
2599 print $_->name, ' ', $_->size, "\n" for @items;
2601 print $object->get_content;
2602 $object->replace_content('new content');
2604 $object->rename( 'new/full/path/to/file.c' );
2606 =head1 DESCRIPTION
2608 Archive::Tar::Files provides a neat little object layer for in-memory
2609 extracted files. It's mostly used internally in Archive::Tar to tidy
2610 up the code, but there's no reason users shouldn't use this API as
2611 well.
2613 =head2 Accessors
2615 A lot of the methods in this package are accessors to the various
2616 fields in the tar header:
2618 =over 4
2620 =item name
2622 The file's name
2624 =item mode
2626 The file's mode
2628 =item uid
2630 The user id owning the file
2632 =item gid
2634 The group id owning the file
2636 =item size
2638 File size in bytes
2640 =item mtime
2642 Modification time. Adjusted to mac-time on MacOS if required
2644 =item chksum
2646 Checksum field for the tar header
2648 =item type
2650 File type -- numeric, but comparable to exported constants -- see
2651 Archive::Tar's documentation
2653 =item linkname
2655 If the file is a symlink, the file it's pointing to
2657 =item magic
2659 Tar magic string -- not useful for most users
2661 =item version
2663 Tar version string -- not useful for most users
2665 =item uname
2667 The user name that owns the file
2669 =item gname
2671 The group name that owns the file
2673 =item devmajor
2675 Device major number in case of a special file
2677 =item devminor
2679 Device minor number in case of a special file
2681 =item prefix
2683 Any directory to prefix to the extraction path, if any
2685 =item raw
2687 Raw tar header -- not useful for most users
2689 =back
2691 =head1 Methods
2693 =head2 Archive::Tar::File->new( file => $path )
2695 Returns a new Archive::Tar::File object from an existing file.
2697 Returns undef on failure.
2699 =head2 Archive::Tar::File->new( data => $path, $data, $opt )
2701 Returns a new Archive::Tar::File object from data.
2703 C<$path> defines the file name (which need not exist), C<$data> the
2704 file contents, and C<$opt> is a reference to a hash of attributes
2705 which may be used to override the default attributes (fields in the
2706 tar header), which are described above in the Accessors section.
2708 Returns undef on failure.
2710 =head2 Archive::Tar::File->new( chunk => $chunk )
2712 Returns a new Archive::Tar::File object from a raw 512-byte tar
2713 archive chunk.
2715 Returns undef on failure.
2717 =cut
2719 sub new {
2720 my $class = shift;
2721 my $what = shift;
2723 my $obj = ($what eq 'chunk') ? __PACKAGE__->_new_from_chunk( @_ ) :
2724 ($what eq 'file' ) ? __PACKAGE__->_new_from_file( @_ ) :
2725 ($what eq 'data' ) ? __PACKAGE__->_new_from_data( @_ ) :
2726 undef;
2728 return $obj;
2731 ### copies the data, creates a clone ###
2732 sub clone {
2733 my $self = shift;
2734 return bless { %$self }, ref $self;
2737 sub _new_from_chunk {
2738 my $class = shift;
2739 my $chunk = shift or return; # 512 bytes of tar header
2740 my %hash = @_;
2742 ### filter any arguments on defined-ness of values.
2743 ### this allows overriding from what the tar-header is saying
2744 ### about this tar-entry. Particularly useful for @LongLink files
2745 my %args = map { $_ => $hash{$_} } grep { defined $hash{$_} } keys %hash;
2747 ### makes it start at 0 actually... :) ###
2748 my $i = -1;
2749 my %entry = map {
2750 my ($s,$v)=($tmpl->[++$i],$tmpl->[++$i]); # cdrake
2751 ($_)=($_=~/^([^\0]*)/) unless($s eq 'size'); # cdrake
2752 $s=> $v ? oct $_ : $_ # cdrake
2753 # $tmpl->[++$i] => $tmpl->[++$i] ? oct $_ : $_ # removed by cdrake - mucks up binary sizes >8gb
2754 } unpack( UNPACK, $chunk ); # cdrake
2755 # } map { /^([^\0]*)/ } unpack( UNPACK, $chunk ); # old - replaced now by cdrake
2758 if(substr($entry{'size'}, 0, 1) eq "\x80") { # binary size extension for files >8gigs (> octal 77777777777777) # cdrake
2759 my @sz=unpack("aCSNN",$entry{'size'}); $entry{'size'}=$sz[4]+(2**32)*$sz[3]+$sz[2]*(2**64); # Use the low 80 bits (should use the upper 15 as well, but as at year 2011, that seems unlikely to ever be needed - the numbers are just too big...) # cdrake
2760 } else { # cdrake
2761 ($entry{'size'})=($entry{'size'}=~/^([^\0]*)/); $entry{'size'}=oct $entry{'size'}; # cdrake
2762 } # cdrake
2765 my $obj = bless { %entry, %args }, $class;
2767 ### magic is a filetype string.. it should have something like 'ustar' or
2768 ### something similar... if the chunk is garbage, skip it
2769 return unless $obj->magic !~ /\W/;
2771 ### store the original chunk ###
2772 $obj->raw( $chunk );
2774 $obj->type(FILE) if ( (!length $obj->type) or ($obj->type =~ /\W/) );
2775 $obj->type(DIR) if ( ($obj->is_file) && ($obj->name =~ m|/$|) );
2778 return $obj;
2782 sub _new_from_file {
2783 my $class = shift;
2784 my $path = shift;
2786 ### path has to at least exist
2787 return unless defined $path;
2789 my $type = __PACKAGE__->_filetype($path);
2790 my $data = '';
2792 READ: {
2793 unless ($type == DIR ) {
2794 my $fh = IO::File->new;
2796 unless( $fh->open($path) ) {
2797 ### dangling symlinks are fine, stop reading but continue
2798 ### creating the object
2799 last READ if $type == SYMLINK;
2801 ### otherwise, return from this function --
2802 ### anything that's *not* a symlink should be
2803 ### resolvable
2804 return;
2807 ### binmode needed to read files properly on win32 ###
2808 binmode $fh;
2809 $data = do { local $/; <$fh> };
2810 close $fh;
2814 my @items = qw[mode uid gid size mtime];
2815 my %hash = map { shift(@items), $_ } (lstat $path)[2,4,5,7,9];
2817 if (ON_VMS) {
2818 ### VMS has two UID modes, traditional and POSIX. Normally POSIX is
2819 ### not used. We currently do not have an easy way to see if we are in
2820 ### POSIX mode. In traditional mode, the UID is actually the VMS UIC.
2821 ### The VMS UIC has the upper 16 bits is the GID, which in many cases
2822 ### the VMS UIC will be larger than 209715, the largest that TAR can
2823 ### handle. So for now, assume it is traditional if the UID is larger
2824 ### than 0x10000.
2826 if ($hash{uid} > 0x10000) {
2827 $hash{uid} = $hash{uid} & 0xFFFF;
2830 ### The file length from stat() is the physical length of the file
2831 ### However the amount of data read in may be more for some file types.
2832 ### Fixed length files are read past the logical EOF to end of the block
2833 ### containing. Other file types get expanded on read because record
2834 ### delimiters are added.
2836 my $data_len = length $data;
2837 $hash{size} = $data_len if $hash{size} < $data_len;
2840 ### you *must* set size == 0 on symlinks, or the next entry will be
2841 ### though of as the contents of the symlink, which is wrong.
2842 ### this fixes bug #7937
2843 $hash{size} = 0 if ($type == DIR or $type == SYMLINK);
2844 $hash{mtime} -= TIME_OFFSET;
2846 ### strip the high bits off the mode, which we don't need to store
2847 $hash{mode} = STRIP_MODE->( $hash{mode} );
2850 ### probably requires some file path munging here ... ###
2851 ### name and prefix are set later
2852 my $obj = {
2853 %hash,
2854 name => '',
2855 chksum => CHECK_SUM,
2856 type => $type,
2857 linkname => ($type == SYMLINK and CAN_READLINK)
2858 ? readlink $path
2859 : '',
2860 magic => MAGIC,
2861 version => TAR_VERSION,
2862 uname => UNAME->( $hash{uid} ),
2863 gname => GNAME->( $hash{gid} ),
2864 devmajor => 0, # not handled
2865 devminor => 0, # not handled
2866 prefix => '',
2867 data => $data,
2870 bless $obj, $class;
2872 ### fix up the prefix and file from the path
2873 my($prefix,$file) = $obj->_prefix_and_file( $path );
2874 $obj->prefix( $prefix );
2875 $obj->name( $file );
2877 return $obj;
2880 sub _new_from_data {
2881 my $class = shift;
2882 my $path = shift; return unless defined $path;
2883 my $data = shift; return unless defined $data;
2884 my $opt = shift;
2886 my $obj = {
2887 data => $data,
2888 name => '',
2889 mode => MODE,
2890 uid => UID,
2891 gid => GID,
2892 size => length $data,
2893 mtime => time - TIME_OFFSET,
2894 chksum => CHECK_SUM,
2895 type => FILE,
2896 linkname => '',
2897 magic => MAGIC,
2898 version => TAR_VERSION,
2899 uname => UNAME->( UID ),
2900 gname => GNAME->( GID ),
2901 devminor => 0,
2902 devmajor => 0,
2903 prefix => '',
2906 ### overwrite with user options, if provided ###
2907 if( $opt and ref $opt eq 'HASH' ) {
2908 for my $key ( keys %$opt ) {
2910 ### don't write bogus options ###
2911 next unless exists $obj->{$key};
2912 $obj->{$key} = $opt->{$key};
2916 bless $obj, $class;
2918 ### fix up the prefix and file from the path
2919 my($prefix,$file) = $obj->_prefix_and_file( $path );
2920 $obj->prefix( $prefix );
2921 $obj->name( $file );
2923 return $obj;
2926 sub _prefix_and_file {
2927 my $self = shift;
2928 my $path = shift;
2930 my ($vol, $dirs, $file) = File::Spec->splitpath( $path, $self->is_dir );
2931 my @dirs = File::Spec->splitdir( $dirs );
2933 ### so sometimes the last element is '' -- probably when trailing
2934 ### dir slashes are encountered... this is of course pointless,
2935 ### so remove it
2936 pop @dirs while @dirs and not length $dirs[-1];
2938 ### if it's a directory, then $file might be empty
2939 $file = pop @dirs if $self->is_dir and not length $file;
2941 ### splitting ../ gives you the relative path in native syntax
2942 map { $_ = '..' if $_ eq '-' } @dirs if ON_VMS;
2944 my $prefix = File::Spec::Unix->catdir(
2945 grep { length } $vol, @dirs
2947 return( $prefix, $file );
2950 sub _filetype {
2951 my $self = shift;
2952 my $file = shift;
2954 return unless defined $file;
2956 return SYMLINK if (-l $file); # Symlink
2958 return FILE if (-f _); # Plain file
2960 return DIR if (-d _); # Directory
2962 return FIFO if (-p _); # Named pipe
2964 return SOCKET if (-S _); # Socket
2966 return BLOCKDEV if (-b _); # Block special
2968 return CHARDEV if (-c _); # Character special
2970 ### shouldn't happen, this is when making archives, not reading ###
2971 return LONGLINK if ( $file eq LONGLINK_NAME );
2973 return UNKNOWN; # Something else (like what?)
2977 ### this method 'downgrades' a file to plain file -- this is used for
2978 ### symlinks when FOLLOW_SYMLINKS is true.
2979 sub _downgrade_to_plainfile {
2980 my $entry = shift;
2981 $entry->type( FILE );
2982 $entry->mode( MODE );
2983 $entry->linkname('');
2985 return 1;
2988 =head2 $bool = $file->extract( [ $alternative_name ] )
2990 Extract this object, optionally to an alternative name.
2992 See C<< Archive::Tar->extract_file >> for details.
2994 Returns true on success and false on failure.
2996 =cut
2998 sub extract {
2999 my $self = shift;
3001 local $Carp::CarpLevel += 1;
3003 return Archive::Tar->_extract_file( $self, @_ );
3006 =head2 $path = $file->full_path
3008 Returns the full path from the tar header; this is basically a
3009 concatenation of the C<prefix> and C<name> fields.
3011 =cut
3013 sub full_path {
3014 my $self = shift;
3016 ### if prefix field is empty
3017 return $self->name unless defined $self->prefix and length $self->prefix;
3019 ### or otherwise, catfile'd
3020 return File::Spec::Unix->catfile( $self->prefix, $self->name );
3024 =head2 $bool = $file->validate
3026 Done by Archive::Tar internally when reading the tar file:
3027 validate the header against the checksum to ensure integer tar file.
3029 Returns true on success, false on failure
3031 =cut
3033 sub validate {
3034 my $self = shift;
3036 my $raw = $self->raw;
3038 ### don't know why this one is different from the one we /write/ ###
3039 substr ($raw, 148, 8) = " ";
3041 ### bug #43513: [PATCH] Accept wrong checksums from SunOS and HP-UX tar
3042 ### like GNU tar does. See here for details:
3043 ### http://www.gnu.org/software/tar/manual/tar.html#SEC139
3044 ### so we do both a signed AND unsigned validate. if one succeeds, that's
3045 ### good enough
3046 return ( (unpack ("%16C*", $raw) == $self->chksum)
3047 or (unpack ("%16c*", $raw) == $self->chksum)) ? 1 : 0;
3050 =head2 $bool = $file->has_content
3052 Returns a boolean to indicate whether the current object has content.
3053 Some special files like directories and so on never will have any
3054 content. This method is mainly to make sure you don't get warnings
3055 for using uninitialized values when looking at an object's content.
3057 =cut
3059 sub has_content {
3060 my $self = shift;
3061 return defined $self->data() && length $self->data() ? 1 : 0;
3064 =head2 $content = $file->get_content
3066 Returns the current content for the in-memory file
3068 =cut
3070 sub get_content {
3071 my $self = shift;
3072 $self->data( );
3075 =head2 $cref = $file->get_content_by_ref
3077 Returns the current content for the in-memory file as a scalar
3078 reference. Normal users won't need this, but it will save memory if
3079 you are dealing with very large data files in your tar archive, since
3080 it will pass the contents by reference, rather than make a copy of it
3081 first.
3083 =cut
3085 sub get_content_by_ref {
3086 my $self = shift;
3088 return \$self->{data};
3091 =head2 $bool = $file->replace_content( $content )
3093 Replace the current content of the file with the new content. This
3094 only affects the in-memory archive, not the on-disk version until
3095 you write it.
3097 Returns true on success, false on failure.
3099 =cut
3101 sub replace_content {
3102 my $self = shift;
3103 my $data = shift || '';
3105 $self->data( $data );
3106 $self->size( length $data );
3107 return 1;
3110 =head2 $bool = $file->rename( $new_name )
3112 Rename the current file to $new_name.
3114 Note that you must specify a Unix path for $new_name, since per tar
3115 standard, all files in the archive must be Unix paths.
3117 Returns true on success and false on failure.
3119 =cut
3121 sub rename {
3122 my $self = shift;
3123 my $path = shift;
3125 return unless defined $path;
3127 my ($prefix,$file) = $self->_prefix_and_file( $path );
3129 $self->name( $file );
3130 $self->prefix( $prefix );
3132 return 1;
3135 =head2 $bool = $file->chmod $mode)
3137 Change mode of $file to $mode. The mode can be a string or a number
3138 which is interpreted as octal whether or not a leading 0 is given.
3140 Returns true on success and false on failure.
3142 =cut
3144 sub chmod {
3145 my $self = shift;
3146 my $mode = shift; return unless defined $mode && $mode =~ /^[0-7]{1,4}$/;
3147 $self->{mode} = oct($mode);
3148 return 1;
3151 =head2 $bool = $file->chown( $user [, $group])
3153 Change owner of $file to $user. If a $group is given that is changed
3154 as well. You can also pass a single parameter with a colon separating the
3155 use and group as in 'root:wheel'.
3157 Returns true on success and false on failure.
3159 =cut
3161 sub chown {
3162 my $self = shift;
3163 my $uname = shift;
3164 return unless defined $uname;
3165 my $gname;
3166 if (-1 != index($uname, ':')) {
3167 ($uname, $gname) = split(/:/, $uname);
3168 } else {
3169 $gname = shift if @_ > 0;
3172 $self->uname( $uname );
3173 $self->gname( $gname ) if $gname;
3174 return 1;
3177 =head1 Convenience methods
3179 To quickly check the type of a C<Archive::Tar::File> object, you can
3180 use the following methods:
3182 =over 4
3184 =item $file->is_file
3186 Returns true if the file is of type C<file>
3188 =item $file->is_dir
3190 Returns true if the file is of type C<dir>
3192 =item $file->is_hardlink
3194 Returns true if the file is of type C<hardlink>
3196 =item $file->is_symlink
3198 Returns true if the file is of type C<symlink>
3200 =item $file->is_chardev
3202 Returns true if the file is of type C<chardev>
3204 =item $file->is_blockdev
3206 Returns true if the file is of type C<blockdev>
3208 =item $file->is_fifo
3210 Returns true if the file is of type C<fifo>
3212 =item $file->is_socket
3214 Returns true if the file is of type C<socket>
3216 =item $file->is_longlink
3218 Returns true if the file is of type C<LongLink>.
3219 Should not happen after a successful C<read>.
3221 =item $file->is_label
3223 Returns true if the file is of type C<Label>.
3224 Should not happen after a successful C<read>.
3226 =item $file->is_unknown
3228 Returns true if the file type is C<unknown>
3230 =back
3232 =cut
3234 #stupid perl5.5.3 needs to warn if it's not numeric
3235 sub is_file { local $^W; FILE == $_[0]->type }
3236 sub is_dir { local $^W; DIR == $_[0]->type }
3237 sub is_hardlink { local $^W; HARDLINK == $_[0]->type }
3238 sub is_symlink { local $^W; SYMLINK == $_[0]->type }
3239 sub is_chardev { local $^W; CHARDEV == $_[0]->type }
3240 sub is_blockdev { local $^W; BLOCKDEV == $_[0]->type }
3241 sub is_fifo { local $^W; FIFO == $_[0]->type }
3242 sub is_socket { local $^W; SOCKET == $_[0]->type }
3243 sub is_unknown { local $^W; UNKNOWN == $_[0]->type }
3244 sub is_longlink { local $^W; LONGLINK eq $_[0]->type }
3245 sub is_label { local $^W; LABEL eq $_[0]->type }
3249 END_OF_FILE
3252 # __MOBUNDLE_FILE__
3254 'File/Find/Rule.pm' => <<'END_OF_FILE',
3255 # $Id$
3257 package File::Find::Rule;
3258 use strict;
3259 use File::Spec;
3260 use Text::Glob 'glob_to_regex';
3261 use Number::Compare;
3262 use Carp qw/croak/;
3263 use File::Find (); # we're only wrapping for now
3265 our $VERSION = '0.34';
3267 # we'd just inherit from Exporter, but I want the colon
3268 sub import {
3269 my $pkg = shift;
3270 my $to = caller;
3271 for my $sym ( qw( find rule ) ) {
3272 no strict 'refs';
3273 *{"$to\::$sym"} = \&{$sym};
3275 for (grep /^:/, @_) {
3276 my ($extension) = /^:(.*)/;
3277 eval "require File::Find::Rule::$extension";
3278 croak "couldn't bootstrap File::Find::Rule::$extension: $@" if $@;
3282 =head1 NAME
3284 File::Find::Rule - Alternative interface to File::Find
3286 =head1 SYNOPSIS
3288 use File::Find::Rule;
3289 # find all the subdirectories of a given directory
3290 my @subdirs = File::Find::Rule->directory->in( $directory );
3292 # find all the .pm files in @INC
3293 my @files = File::Find::Rule->file()
3294 ->name( '*.pm' )
3295 ->in( @INC );
3297 # as above, but without method chaining
3298 my $rule = File::Find::Rule->new;
3299 $rule->file;
3300 $rule->name( '*.pm' );
3301 my @files = $rule->in( @INC );
3303 =head1 DESCRIPTION
3305 File::Find::Rule is a friendlier interface to File::Find. It allows
3306 you to build rules which specify the desired files and directories.
3308 =cut
3310 # the procedural shim
3312 *rule = \&find;
3313 sub find {
3314 my $object = __PACKAGE__->new();
3315 my $not = 0;
3317 while (@_) {
3318 my $method = shift;
3319 my @args;
3321 if ($method =~ s/^\!//) {
3322 # jinkies, we're really negating this
3323 unshift @_, $method;
3324 $not = 1;
3325 next;
3327 unless (defined prototype $method) {
3328 my $args = shift;
3329 @args = ref $args eq 'ARRAY' ? @$args : $args;
3331 if ($not) {
3332 $not = 0;
3333 @args = $object->new->$method(@args);
3334 $method = "not";
3337 my @return = $object->$method(@args);
3338 return @return if $method eq 'in';
3340 $object;
3344 =head1 METHODS
3346 =over
3348 =item C<new>
3350 A constructor. You need not invoke C<new> manually unless you wish
3351 to, as each of the rule-making methods will auto-create a suitable
3352 object if called as class methods.
3354 =cut
3356 sub new {
3357 my $referent = shift;
3358 my $class = ref $referent || $referent;
3359 bless {
3360 rules => [],
3361 subs => {},
3362 iterator => [],
3363 extras => {},
3364 maxdepth => undef,
3365 mindepth => undef,
3366 }, $class;
3369 sub _force_object {
3370 my $object = shift;
3371 $object = $object->new()
3372 unless ref $object;
3373 $object;
3376 =back
3378 =head2 Matching Rules
3380 =over
3382 =item C<name( @patterns )>
3384 Specifies names that should match. May be globs or regular
3385 expressions.
3387 $set->name( '*.mp3', '*.ogg' ); # mp3s or oggs
3388 $set->name( qr/\.(mp3|ogg)$/ ); # the same as a regex
3389 $set->name( 'foo.bar' ); # just things named foo.bar
3391 =cut
3393 sub _flatten {
3394 my @flat;
3395 while (@_) {
3396 my $item = shift;
3397 ref $item eq 'ARRAY' ? push @_, @{ $item } : push @flat, $item;
3399 return @flat;
3402 sub name {
3403 my $self = _force_object shift;
3404 my @names = map { ref $_ eq "Regexp" ? $_ : glob_to_regex $_ } _flatten( @_ );
3406 push @{ $self->{rules} }, {
3407 rule => 'name',
3408 code => join( ' || ', map { "m{$_}" } @names ),
3409 args => \@_,
3412 $self;
3415 =item -X tests
3417 Synonyms are provided for each of the -X tests. See L<perlfunc/-X> for
3418 details. None of these methods take arguments.
3420 Test | Method Test | Method
3421 ------|------------- ------|----------------
3422 -r | readable -R | r_readable
3423 -w | writeable -W | r_writeable
3424 -w | writable -W | r_writable
3425 -x | executable -X | r_executable
3426 -o | owned -O | r_owned
3428 -e | exists -f | file
3429 -z | empty -d | directory
3430 -s | nonempty -l | symlink
3431 | -p | fifo
3432 -u | setuid -S | socket
3433 -g | setgid -b | block
3434 -k | sticky -c | character
3435 | -t | tty
3436 -M | modified |
3437 -A | accessed -T | ascii
3438 -C | changed -B | binary
3440 Though some tests are fairly meaningless as binary flags (C<modified>,
3441 C<accessed>, C<changed>), they have been included for completeness.
3443 # find nonempty files
3444 $rule->file,
3445 ->nonempty;
3447 =cut
3449 use vars qw( %X_tests );
3450 %X_tests = (
3451 -r => readable => -R => r_readable =>
3452 -w => writeable => -W => r_writeable =>
3453 -w => writable => -W => r_writable =>
3454 -x => executable => -X => r_executable =>
3455 -o => owned => -O => r_owned =>
3457 -e => exists => -f => file =>
3458 -z => empty => -d => directory =>
3459 -s => nonempty => -l => symlink =>
3460 => -p => fifo =>
3461 -u => setuid => -S => socket =>
3462 -g => setgid => -b => block =>
3463 -k => sticky => -c => character =>
3464 => -t => tty =>
3465 -M => modified =>
3466 -A => accessed => -T => ascii =>
3467 -C => changed => -B => binary =>
3470 for my $test (keys %X_tests) {
3471 my $sub = eval 'sub () {
3472 my $self = _force_object shift;
3473 push @{ $self->{rules} }, {
3474 code => "' . $test . ' \$_",
3475 rule => "'.$X_tests{$test}.'",
3477 $self;
3478 } ';
3479 no strict 'refs';
3480 *{ $X_tests{$test} } = $sub;
3484 =item stat tests
3486 The following C<stat> based methods are provided: C<dev>, C<ino>,
3487 C<mode>, C<nlink>, C<uid>, C<gid>, C<rdev>, C<size>, C<atime>,
3488 C<mtime>, C<ctime>, C<blksize>, and C<blocks>. See L<perlfunc/stat>
3489 for details.
3491 Each of these can take a number of targets, which will follow
3492 L<Number::Compare> semantics.
3494 $rule->size( 7 ); # exactly 7
3495 $rule->size( ">7Ki" ); # larger than 7 * 1024 * 1024 bytes
3496 $rule->size( ">=7" )
3497 ->size( "<=90" ); # between 7 and 90, inclusive
3498 $rule->size( 7, 9, 42 ); # 7, 9 or 42
3500 =cut
3502 use vars qw( @stat_tests );
3503 @stat_tests = qw( dev ino mode nlink uid gid rdev
3504 size atime mtime ctime blksize blocks );
3506 my $i = 0;
3507 for my $test (@stat_tests) {
3508 my $index = $i++; # to close over
3509 my $sub = sub {
3510 my $self = _force_object shift;
3512 my @tests = map { Number::Compare->parse_to_perl($_) } @_;
3514 push @{ $self->{rules} }, {
3515 rule => $test,
3516 args => \@_,
3517 code => 'do { my $val = (stat $_)['.$index.'] || 0;'.
3518 join ('||', map { "(\$val $_)" } @tests ).' }',
3520 $self;
3522 no strict 'refs';
3523 *$test = $sub;
3527 =item C<any( @rules )>
3529 =item C<or( @rules )>
3531 Allows shortcircuiting boolean evaluation as an alternative to the
3532 default and-like nature of combined rules. C<any> and C<or> are
3533 interchangeable.
3535 # find avis, movs, things over 200M and empty files
3536 $rule->any( File::Find::Rule->name( '*.avi', '*.mov' ),
3537 File::Find::Rule->size( '>200M' ),
3538 File::Find::Rule->file->empty,
3541 =cut
3543 sub any {
3544 my $self = _force_object shift;
3545 # compile all the subrules to code fragments
3546 push @{ $self->{rules} }, {
3547 rule => "any",
3548 code => '(' . join( ' || ', map '( ' . $_->_compile . ' )', @_ ). ')',
3549 args => \@_,
3552 # merge all the subs hashes of the kids into ourself
3553 %{ $self->{subs} } = map { %{ $_->{subs} } } $self, @_;
3554 $self;
3557 *or = \&any;
3559 =item C<none( @rules )>
3561 =item C<not( @rules )>
3563 Negates a rule. (The inverse of C<any>.) C<none> and C<not> are
3564 interchangeable.
3566 # files that aren't 8.3 safe
3567 $rule->file
3568 ->not( $rule->new->name( qr/^[^.]{1,8}(\.[^.]{0,3})?$/ ) );
3570 =cut
3572 sub not {
3573 my $self = _force_object shift;
3575 push @{ $self->{rules} }, {
3576 rule => 'not',
3577 args => \@_,
3578 code => '(' . join ( ' && ', map { "!(". $_->_compile . ")" } @_ ) . ")",
3581 # merge all the subs hashes into us
3582 %{ $self->{subs} } = map { %{ $_->{subs} } } $self, @_;
3583 $self;
3586 *none = \&not;
3588 =item C<prune>
3590 Traverse no further. This rule always matches.
3592 =cut
3594 sub prune () {
3595 my $self = _force_object shift;
3597 push @{ $self->{rules} },
3599 rule => 'prune',
3600 code => '$File::Find::prune = 1'
3602 $self;
3605 =item C<discard>
3607 Don't keep this file. This rule always matches.
3609 =cut
3611 sub discard () {
3612 my $self = _force_object shift;
3614 push @{ $self->{rules} }, {
3615 rule => 'discard',
3616 code => '$discarded = 1',
3618 $self;
3621 =item C<exec( \&subroutine( $shortname, $path, $fullname ) )>
3623 Allows user-defined rules. Your subroutine will be invoked with C<$_>
3624 set to the current short name, and with parameters of the name, the
3625 path you're in, and the full relative filename.
3627 Return a true value if your rule matched.
3629 # get things with long names
3630 $rules->exec( sub { length > 20 } );
3632 =cut
3634 sub exec {
3635 my $self = _force_object shift;
3636 my $code = shift;
3638 push @{ $self->{rules} }, {
3639 rule => 'exec',
3640 code => $code,
3642 $self;
3645 =item C<grep( @specifiers )>
3647 Opens a file and tests it each line at a time.
3649 For each line it evaluates each of the specifiers, stopping at the
3650 first successful match. A specifier may be a regular expression or a
3651 subroutine. The subroutine will be invoked with the same parameters
3652 as an ->exec subroutine.
3654 It is possible to provide a set of negative specifiers by enclosing
3655 them in anonymous arrays. Should a negative specifier match the
3656 iteration is aborted and the clause is failed. For example:
3658 $rule->grep( qr/^#!.*\bperl/, [ sub { 1 } ] );
3660 Is a passing clause if the first line of a file looks like a perl
3661 shebang line.
3663 =cut
3665 sub grep {
3666 my $self = _force_object shift;
3667 my @pattern = map {
3668 ref $_
3669 ? ref $_ eq 'ARRAY'
3670 ? map { [ ( ref $_ ? $_ : qr/$_/ ) => 0 ] } @$_
3671 : [ $_ => 1 ]
3672 : [ qr/$_/ => 1 ]
3673 } @_;
3675 $self->exec( sub {
3676 local *FILE;
3677 open FILE, $_ or return;
3678 local ($_, $.);
3679 while (<FILE>) {
3680 for my $p (@pattern) {
3681 my ($rule, $ret) = @$p;
3682 return $ret
3683 if ref $rule eq 'Regexp'
3684 ? /$rule/
3685 : $rule->(@_);
3688 return;
3689 } );
3692 =item C<maxdepth( $level )>
3694 Descend at most C<$level> (a non-negative integer) levels of directories
3695 below the starting point.
3697 May be invoked many times per rule, but only the most recent value is
3698 used.
3700 =item C<mindepth( $level )>
3702 Do not apply any tests at levels less than C<$level> (a non-negative
3703 integer).
3705 =item C<extras( \%extras )>
3707 Specifies extra values to pass through to C<File::File::find> as part
3708 of the options hash.
3710 For example this allows you to specify following of symlinks like so:
3712 my $rule = File::Find::Rule->extras({ follow => 1 });
3714 May be invoked many times per rule, but only the most recent value is
3715 used.
3717 =cut
3719 for my $setter (qw( maxdepth mindepth extras )) {
3720 my $sub = sub {
3721 my $self = _force_object shift;
3722 $self->{$setter} = shift;
3723 $self;
3725 no strict 'refs';
3726 *$setter = $sub;
3730 =item C<relative>
3732 Trim the leading portion of any path found
3734 =cut
3736 sub relative () {
3737 my $self = _force_object shift;
3738 $self->{relative} = 1;
3739 $self;
3742 =item C<canonpath>
3744 Normalize paths found using C<File::Spec->canonpath>. This will return paths
3745 with a file-seperator that is native to your OS (as determined by L<File::Spec>),
3746 instead of the default C</>.
3748 For example, this will return C<tmp/foobar> on Unix-ish OSes
3749 and C<tmp\foobar> on Win32.
3751 =cut
3753 sub canonpath () {
3754 my $self = _force_object shift;
3755 $self->{canonpath} = 1;
3756 $self;
3759 =item C<not_*>
3761 Negated version of the rule. An effective shortand related to ! in
3762 the procedural interface.
3764 $foo->not_name('*.pl');
3766 $foo->not( $foo->new->name('*.pl' ) );
3768 =cut
3770 sub DESTROY {}
3771 sub AUTOLOAD {
3772 our $AUTOLOAD;
3773 $AUTOLOAD =~ /::not_([^:]*)$/
3774 or croak "Can't locate method $AUTOLOAD";
3775 my $method = $1;
3777 my $sub = sub {
3778 my $self = _force_object shift;
3779 $self->not( $self->new->$method(@_) );
3782 no strict 'refs';
3783 *$AUTOLOAD = $sub;
3785 &$sub;
3788 =back
3790 =head2 Query Methods
3792 =over
3794 =item C<in( @directories )>
3796 Evaluates the rule, returns a list of paths to matching files and
3797 directories.
3799 =cut
3801 sub in {
3802 my $self = _force_object shift;
3804 my @found;
3805 my $fragment = $self->_compile;
3806 my %subs = %{ $self->{subs} };
3808 warn "relative mode handed multiple paths - that's a bit silly\n"
3809 if $self->{relative} && @_ > 1;
3811 my $topdir;
3812 my $code = 'sub {
3813 (my $path = $File::Find::name) =~ s#^(?:\./+)+##;
3814 my @args = ($_, $File::Find::dir, $path);
3815 my $maxdepth = $self->{maxdepth};
3816 my $mindepth = $self->{mindepth};
3817 my $relative = $self->{relative};
3818 my $canonpath = $self->{canonpath};
3820 # figure out the relative path and depth
3821 my $relpath = $File::Find::name;
3822 $relpath =~ s{^\Q$topdir\E/?}{};
3823 my $depth = scalar File::Spec->splitdir($relpath);
3824 #print "name: \'$File::Find::name\' ";
3825 #print "relpath: \'$relpath\' depth: $depth relative: $relative\n";
3827 defined $maxdepth && $depth >= $maxdepth
3828 and $File::Find::prune = 1;
3830 defined $mindepth && $depth < $mindepth
3831 and return;
3833 #print "Testing \'$_\'\n";
3835 my $discarded;
3836 return unless ' . $fragment . ';
3837 return if $discarded;
3838 if ($relative) {
3839 if ($relpath ne "") {
3840 push @found, $canonpath ? File::Spec->canonpath($relpath) : $relpath;
3843 else {
3844 push @found, $canonpath ? File::Spec->canonpath($path) : $path;
3848 #use Data::Dumper;
3849 #print Dumper \%subs;
3850 #warn "Compiled sub: '$code'\n";
3852 my $sub = eval "$code" or die "compile error '$code' $@";
3853 for my $path (@_) {
3854 # $topdir is used for relative and maxdepth
3855 $topdir = $path;
3856 # slice off the trailing slash if there is one (the
3857 # maxdepth/mindepth code is fussy)
3858 $topdir =~ s{/?$}{}
3859 unless $topdir eq '/';
3860 $self->_call_find( { %{ $self->{extras} }, wanted => $sub }, $path );
3863 return @found;
3866 sub _call_find {
3867 my $self = shift;
3868 File::Find::find( @_ );
3871 sub _compile {
3872 my $self = shift;
3874 return '1' unless @{ $self->{rules} };
3875 my $code = join " && ", map {
3876 if (ref $_->{code}) {
3877 my $key = "$_->{code}";
3878 $self->{subs}{$key} = $_->{code};
3879 "\$subs{'$key'}->(\@args) # $_->{rule}\n";
3881 else {
3882 "( $_->{code} ) # $_->{rule}\n";
3884 } @{ $self->{rules} };
3886 #warn $code;
3887 return $code;
3890 =item C<start( @directories )>
3892 Starts a find across the specified directories. Matching items may
3893 then be queried using L</match>. This allows you to use a rule as an
3894 iterator.
3896 my $rule = File::Find::Rule->file->name("*.jpeg")->start( "/web" );
3897 while ( defined ( my $image = $rule->match ) ) {
3901 =cut
3903 sub start {
3904 my $self = _force_object shift;
3906 $self->{iterator} = [ $self->in( @_ ) ];
3907 $self;
3910 =item C<match>
3912 Returns the next file which matches, false if there are no more.
3914 =cut
3916 sub match {
3917 my $self = _force_object shift;
3919 return shift @{ $self->{iterator} };
3924 __END__
3926 =back
3928 =head2 Extensions
3930 Extension modules are available from CPAN in the File::Find::Rule
3931 namespace. In order to use these extensions either use them directly:
3933 use File::Find::Rule::ImageSize;
3934 use File::Find::Rule::MMagic;
3936 # now your rules can use the clauses supplied by the ImageSize and
3937 # MMagic extension
3939 or, specify that File::Find::Rule should load them for you:
3941 use File::Find::Rule qw( :ImageSize :MMagic );
3943 For notes on implementing your own extensions, consult
3944 L<File::Find::Rule::Extending>
3946 =head2 Further examples
3948 =over
3950 =item Finding perl scripts
3952 my $finder = File::Find::Rule->or
3954 File::Find::Rule->name( '*.pl' ),
3955 File::Find::Rule->exec(
3956 sub {
3957 if (open my $fh, $_) {
3958 my $shebang = <$fh>;
3959 close $fh;
3960 return $shebang =~ /^#!.*\bperl/;
3962 return 0;
3963 } ),
3966 Based upon this message http://use.perl.org/comments.pl?sid=7052&cid=10842
3968 =item ignore CVS directories
3970 my $rule = File::Find::Rule->new;
3971 $rule->or($rule->new
3972 ->directory
3973 ->name('CVS')
3974 ->prune
3975 ->discard,
3976 $rule->new);
3978 Note here the use of a null rule. Null rules match anything they see,
3979 so the effect is to match (and discard) directories called 'CVS' or to
3980 match anything.
3982 =back
3984 =head1 TWO FOR THE PRICE OF ONE
3986 File::Find::Rule also gives you a procedural interface. This is
3987 documented in L<File::Find::Rule::Procedural>
3989 =head1 EXPORTS
3991 L</find>, L</rule>
3993 =head1 TAINT MODE INTERACTION
3995 As of 0.32 File::Find::Rule doesn't capture the current working directory in
3996 a taint-unsafe manner. File::Find itself still does operations that the taint
3997 system will flag as insecure but you can use the L</extras> feature to ask
3998 L<File::Find> to internally C<untaint> file paths with a regex like so:
4000 my $rule = File::Find::Rule->extras({ untaint => 1 });
4002 Please consult L<File::Find>'s documentation for C<untaint>,
4003 C<untaint_pattern>, and C<untaint_skip> for more information.
4005 =head1 BUGS
4007 The code makes use of the C<our> keyword and as such requires perl version
4008 5.6.0 or newer.
4010 Currently it isn't possible to remove a clause from a rule object. If
4011 this becomes a significant issue it will be addressed.
4013 =head1 AUTHOR
4015 Richard Clamp <richardc@unixbeard.net> with input gained from this
4016 use.perl discussion: http://use.perl.org/~richardc/journal/6467
4018 Additional proofreading and input provided by Kake, Greg McCarroll,
4019 and Andy Lester andy@petdance.com.
4021 =head1 COPYRIGHT
4023 Copyright (C) 2002, 2003, 2004, 2006, 2009, 2011 Richard Clamp. All Rights Reserved.
4025 This module is free software; you can redistribute it and/or modify it
4026 under the same terms as Perl itself.
4028 =head1 SEE ALSO
4030 L<File::Find>, L<Text::Glob>, L<Number::Compare>, find(1)
4032 If you want to know about the procedural interface, see
4033 L<File::Find::Rule::Procedural>, and if you have an idea for a neat
4034 extension L<File::Find::Rule::Extending>
4036 =cut
4038 Implementation notes:
4040 $self->rules is an array of hashrefs. it may be a code fragment or a call
4041 to a subroutine.
4043 Anonymous subroutines are stored in the $self->subs hashref keyed on the
4044 stringfied version of the coderef.
4046 When one File::Find::Rule object is combined with another, such as in the any
4047 and not operations, this entire hash is merged.
4049 The _compile method walks the rules element and simply glues the code
4050 fragments together so they can be compiled into an anyonymous File::Find
4051 match sub for speed
4054 [*] There's probably a win to be made with the current model in making
4055 stat calls use C<_>. For
4057 find( file => size => "> 20M" => size => "< 400M" );
4059 up to 3 stats will happen for each candidate. Adding a priming _
4060 would be a bit blind if the first operation was C< name => 'foo' >,
4061 since that can be tested by a single regex. Simply checking what the
4062 next type of operation doesn't work since any arbritary exec sub may
4063 or may not stat. Potentially worse, they could stat something else
4064 like so:
4066 # extract from the worlds stupidest make(1)
4067 find( exec => sub { my $f = $_; $f =~ s/\.c$/.o/ && !-e $f } );
4069 Maybe the best way is to treat C<_> as invalid after calling an exec,
4070 and doc that C<_> will only be meaningful after stat and -X tests if
4071 they're wanted in exec blocks.
4073 END_OF_FILE
4076 # __MOBUNDLE_FILE__
4078 'Number/Compare.pm' => <<'END_OF_FILE',
4079 package Number::Compare;
4080 use strict;
4081 use Carp qw(croak);
4082 use vars qw/$VERSION/;
4083 $VERSION = '0.03';
4085 sub new {
4086 my $referent = shift;
4087 my $class = ref $referent || $referent;
4088 my $expr = $class->parse_to_perl( shift );
4090 bless eval "sub { \$_[0] $expr }", $class;
4093 sub parse_to_perl {
4094 shift;
4095 my $test = shift;
4097 $test =~ m{^
4098 ([<>]=?)? # comparison
4099 (.*?) # value
4100 ([kmg]i?)? # magnitude
4101 $}ix
4102 or croak "don't understand '$test' as a test";
4104 my $comparison = $1 || '==';
4105 my $target = $2;
4106 my $magnitude = $3 || '';
4107 $target *= 1000 if lc $magnitude eq 'k';
4108 $target *= 1024 if lc $magnitude eq 'ki';
4109 $target *= 1000000 if lc $magnitude eq 'm';
4110 $target *= 1024*1024 if lc $magnitude eq 'mi';
4111 $target *= 1000000000 if lc $magnitude eq 'g';
4112 $target *= 1024*1024*1024 if lc $magnitude eq 'gi';
4114 return "$comparison $target";
4117 sub test { $_[0]->( $_[1] ) }
4121 __END__
4123 =head1 NAME
4125 Number::Compare - numeric comparisons
4127 =head1 SYNOPSIS
4129 Number::Compare->new(">1Ki")->test(1025); # is 1025 > 1024
4131 my $c = Number::Compare->new(">1M");
4132 $c->(1_200_000); # slightly terser invocation
4134 =head1 DESCRIPTION
4136 Number::Compare compiles a simple comparison to an anonymous
4137 subroutine, which you can call with a value to be tested again.
4139 Now this would be very pointless, if Number::Compare didn't understand
4140 magnitudes.
4142 The target value may use magnitudes of kilobytes (C<k>, C<ki>),
4143 megabytes (C<m>, C<mi>), or gigabytes (C<g>, C<gi>). Those suffixed
4144 with an C<i> use the appropriate 2**n version in accordance with the
4145 IEC standard: http://physics.nist.gov/cuu/Units/binary.html
4147 =head1 METHODS
4149 =head2 ->new( $test )
4151 Returns a new object that compares the specified test.
4153 =head2 ->test( $value )
4155 A longhanded version of $compare->( $value ). Predates blessed
4156 subroutine reference implementation.
4158 =head2 ->parse_to_perl( $test )
4160 Returns a perl code fragment equivalent to the test.
4162 =head1 AUTHOR
4164 Richard Clamp <richardc@unixbeard.net>
4166 =head1 COPYRIGHT
4168 Copyright (C) 2002,2011 Richard Clamp. All Rights Reserved.
4170 This module is free software; you can redistribute it and/or modify it
4171 under the same terms as Perl itself.
4173 =head1 SEE ALSO
4175 http://physics.nist.gov/cuu/Units/binary.html
4177 =cut
4179 END_OF_FILE
4182 # __MOBUNDLE_FILE__
4184 'Text/Glob.pm' => <<'END_OF_FILE',
4185 package Text::Glob;
4186 use strict;
4187 use Exporter;
4188 use vars qw/$VERSION @ISA @EXPORT_OK
4189 $strict_leading_dot $strict_wildcard_slash/;
4190 $VERSION = '0.11';
4191 @ISA = 'Exporter';
4192 @EXPORT_OK = qw( glob_to_regex glob_to_regex_string match_glob );
4194 $strict_leading_dot = 1;
4195 $strict_wildcard_slash = 1;
4197 use constant debug => 0;
4199 sub glob_to_regex {
4200 my $glob = shift;
4201 my $regex = glob_to_regex_string($glob);
4202 return qr/^$regex$/;
4205 sub glob_to_regex_string
4207 my $glob = shift;
4209 my $seperator = $Text::Glob::seperator;
4210 $seperator = "/" unless defined $seperator;
4211 $seperator = quotemeta($seperator);
4213 my ($regex, $in_curlies, $escaping);
4214 local $_;
4215 my $first_byte = 1;
4216 for ($glob =~ m/(.)/gs) {
4217 if ($first_byte) {
4218 if ($strict_leading_dot) {
4219 $regex .= '(?=[^\.])' unless $_ eq '.';
4221 $first_byte = 0;
4223 if ($_ eq '/') {
4224 $first_byte = 1;
4226 if ($_ eq '.' || $_ eq '(' || $_ eq ')' || $_ eq '|' ||
4227 $_ eq '+' || $_ eq '^' || $_ eq '$' || $_ eq '@' || $_ eq '%' ) {
4228 $regex .= "\\$_";
4230 elsif ($_ eq '*') {
4231 $regex .= $escaping ? "\\*" :
4232 $strict_wildcard_slash ? "(?:(?!$seperator).)*" : ".*";
4234 elsif ($_ eq '?') {
4235 $regex .= $escaping ? "\\?" :
4236 $strict_wildcard_slash ? "(?!$seperator)." : ".";
4238 elsif ($_ eq '{') {
4239 $regex .= $escaping ? "\\{" : "(";
4240 ++$in_curlies unless $escaping;
4242 elsif ($_ eq '}' && $in_curlies) {
4243 $regex .= $escaping ? "}" : ")";
4244 --$in_curlies unless $escaping;
4246 elsif ($_ eq ',' && $in_curlies) {
4247 $regex .= $escaping ? "," : "|";
4249 elsif ($_ eq "\\") {
4250 if ($escaping) {
4251 $regex .= "\\\\";
4252 $escaping = 0;
4254 else {
4255 $escaping = 1;
4257 next;
4259 else {
4260 $regex .= $_;
4261 $escaping = 0;
4263 $escaping = 0;
4265 print "# $glob $regex\n" if debug;
4267 return $regex;
4270 sub match_glob {
4271 print "# ", join(', ', map { "'$_'" } @_), "\n" if debug;
4272 my $glob = shift;
4273 my $regex = glob_to_regex $glob;
4274 local $_;
4275 grep { $_ =~ $regex } @_;
4279 __END__
4281 =head1 NAME
4283 Text::Glob - match globbing patterns against text
4285 =head1 SYNOPSIS
4287 use Text::Glob qw( match_glob glob_to_regex );
4289 print "matched\n" if match_glob( "foo.*", "foo.bar" );
4291 # prints foo.bar and foo.baz
4292 my $regex = glob_to_regex( "foo.*" );
4293 for ( qw( foo.bar foo.baz foo bar ) ) {
4294 print "matched: $_\n" if /$regex/;
4297 =head1 DESCRIPTION
4299 Text::Glob implements glob(3) style matching that can be used to match
4300 against text, rather than fetching names from a filesystem. If you
4301 want to do full file globbing use the File::Glob module instead.
4303 =head2 Routines
4305 =over
4307 =item match_glob( $glob, @things_to_test )
4309 Returns the list of things which match the glob from the source list.
4311 =item glob_to_regex( $glob )
4313 Returns a compiled regex which is the equivalent of the globbing
4314 pattern.
4316 =item glob_to_regex_string( $glob )
4318 Returns a regex string which is the equivalent of the globbing
4319 pattern.
4321 =back
4323 =head1 SYNTAX
4325 The following metacharacters and rules are respected.
4327 =over
4329 =item C<*> - match zero or more characters
4331 C<a*> matches C<a>, C<aa>, C<aaaa> and many many more.
4333 =item C<?> - match exactly one character
4335 C<a?> matches C<aa>, but not C<a>, or C<aaa>
4337 =item Character sets/ranges
4339 C<example.[ch]> matches C<example.c> and C<example.h>
4341 C<demo.[a-c]> matches C<demo.a>, C<demo.b>, and C<demo.c>
4343 =item alternation
4345 C<example.{foo,bar,baz}> matches C<example.foo>, C<example.bar>, and
4346 C<example.baz>
4348 =item leading . must be explicitly matched
4350 C<*.foo> does not match C<.bar.foo>. For this you must either specify
4351 the leading . in the glob pattern (C<.*.foo>), or set
4352 C<$Text::Glob::strict_leading_dot> to a false value while compiling
4353 the regex.
4355 =item C<*> and C<?> do not match the seperator (i.e. do not match C</>)
4357 C<*.foo> does not match C<bar/baz.foo>. For this you must either
4358 explicitly match the / in the glob (C<*/*.foo>), or set
4359 C<$Text::Glob::strict_wildcard_slash> to a false value while compiling
4360 the regex, or change the seperator that Text::Glob uses by setting
4361 C<$Text::Glob::seperator> to an alternative value while compiling the
4362 the regex.
4364 =back
4366 =head1 BUGS
4368 The code uses qr// to produce compiled regexes, therefore this module
4369 requires perl version 5.005_03 or newer.
4371 =head1 AUTHOR
4373 Richard Clamp <richardc@unixbeard.net>
4375 =head1 COPYRIGHT
4377 Copyright (C) 2002, 2003, 2006, 2007 Richard Clamp. All Rights Reserved.
4379 This module is free software; you can redistribute it and/or modify it
4380 under the same terms as Perl itself.
4382 =head1 SEE ALSO
4384 L<File::Glob>, glob(3)
4386 =cut
4388 END_OF_FILE
4391 # __MOBUNDLE_FILE__
4394 unshift @INC, sub {
4395 my ($me, $packfile) = @_;
4396 return unless exists $file_for{$packfile};
4397 (my $text = $file_for{$packfile}) =~ s/^\ //gmxs;
4398 chop($text); # added \n at the end
4399 open my $fh, '<', \$text or die "open(): $!\n";
4400 return $fh;
4402 } ## end BEGIN
4403 # __MOBUNDLE_INCLUSION__
4405 use File::Find::Rule;
4406 use Archive::Tar;
4408 my %config = (
4409 output => '-',
4410 remote => catfile(dirname(realpath(__FILE__)), 'remote'),
4411 heredir => [],
4412 herefile => [],
4413 rootdir => [],
4414 root => [],
4415 rootfile => [],
4416 tarfile => [],
4417 deploy => [],
4418 xform => [],
4419 passthrough => 0,
4421 GetOptions(
4422 \%config,
4424 usage! help! man! version!
4426 bundle|all-exec|X!
4427 bzip2|bz2|j!
4428 cleanup|c!
4429 deploy|exec|d=s@
4430 gzip|gz|z!
4431 heredir|H=s@
4432 include-archive-tar|T!
4433 no-tar!
4434 output|o=s
4435 passthrough|P!
4436 root|r=s@
4437 rootdir|in-root|R=s@
4438 tar|t=s
4439 tarfile|F=s@
4440 tempdir-mode|m=s
4441 xform|x=s@
4442 workdir|work-directory|deploy-directory|w=s
4444 ) or pod2usage(message => "invalid command line", -verbose => 99, -sections => ' ', -noperldoc => 1);
4445 pod2usage(message => "$0 $VERSION", -verbose => 99, -sections => ' ', -noperldoc => 1)
4446 if $config{version};
4447 pod2usage(-verbose => 99, -sections => 'USAGE', -noperldoc => 1) if $config{usage};
4448 pod2usage(-verbose => 99, -sections => 'USAGE|EXAMPLES|OPTIONS', -noperldoc => 1)
4449 if $config{help};
4450 pod2usage(-verbose => 2, -noperldoc => 1) if $config{man};
4452 pod2usage(
4453 message => 'working directory must be an absolute path',
4454 -verbose => 99,
4455 -sections => '',
4456 -noperldoc => 1
4457 ) if exists $config{workdir} && !file_name_is_absolute($config{workdir});
4459 if (@{$config{xform}}) {
4460 $config{'no-tar'} = 1; # force internal stuff
4461 for my $xform (@{$config{xform}}) {
4462 my ($src, $filename) =
4463 $xform =~ m{\A((?:[^\\:]|\\.)*) : (.*)}mxs;
4464 s{\\(.)}{$1}gmxs for $src, $filename;
4465 my $array_name = file_name_is_absolute($filename) ? 'rootfile'
4466 : 'herefile';
4467 push @{$config{$array_name}}, [$src, $filename];
4471 if ($config{'include-archive-tar'}) {
4472 $config{remote} = catfile(dirname(realpath(__FILE__)), 'remote-at');
4473 if (!-e $config{remote}) { # "make" it
4474 print {*STDERR} "### Making remote-at...\n";
4475 my $startdir = cwd();
4476 chdir dirname realpath __FILE__;
4477 system {'make'} qw( make remote-at );
4478 chdir $startdir;
4479 } ## end if (!-e $config{remote...})
4480 } ## end if ($config{'include-archive-tar'...})
4482 # Establish output channel
4483 my $out_fh = \*STDOUT;
4484 if ($config{output} ne '-') {
4485 open my $fh, '>', $config{output} ## no critic
4486 or croak "open('$config{output}'): $OS_ERROR";
4487 $out_fh = $fh;
4489 binmode $out_fh;
4491 # Emit script code to be executed remotely. It is guaranteed to end
4492 # with __END__, so that all what comes next is data
4493 print {$out_fh} get_remote_script();
4495 # Where all the data will be kept
4496 print_configuration($out_fh, \%config);
4498 print_here_stuff($out_fh, \%config, @ARGV);
4499 print_root_stuff($out_fh, \%config);
4501 close $out_fh;
4503 # Set as executable
4504 if ($config{output} ne '-') {
4505 chmod oct(755), $config{output}
4506 or carp "chmod(0755, '$config{output}'): $OS_ERROR";
4509 sub header {
4510 my %params = @_;
4511 my $namesize = length $params{name};
4512 return "$namesize $params{size}\n$params{name}";
4515 sub print_configuration { # FIXME
4516 my ($fh, $config) = @_;
4517 my %general_configuration;
4518 for my $name (
4519 qw( workdir cleanup bundle deploy
4520 gzip bzip2 passthrough tempdir-mode )
4523 $general_configuration{$name} = $config->{$name}
4524 if exists $config->{$name};
4525 } ## end for my $name (qw( workdir cleanup bundle deploy...))
4526 my $configuration = Dumper \%general_configuration;
4527 print {$fh} header(name => 'config.pl', size => length($configuration)),
4528 "\n", $configuration, "\n\n";
4529 } ## end sub print_configuration
4531 # Process files and directories. All these will be reported in the
4532 # extraction directory, i.e. basename() will be applied to them. For
4533 # directories, they will be re-created
4534 sub print_here_stuff {
4535 my $fh = shift;
4536 my $config = shift;
4537 my @ARGV = @_;
4539 my $ai = Deployable::Tar->new($config);
4540 $ai->add(
4541 '.' => \@ARGV,
4542 '.' => $config->{herefile},
4543 map { $_ => ['.'] } @{$config->{heredir}}
4546 print {$fh} header(name => 'here', size => $ai->size()), "\n";
4547 $ai->copy_to($fh);
4548 print {$fh} "\n\n";
4550 return;
4551 } ## end sub print_here_stuff
4553 sub print_root_stuff {
4554 my ($fh, $config) = @_;
4556 my $ai = Deployable::Tar->new($config);
4557 $ai->add(
4558 '.' => $config->{rootdir},
4559 '.' => $config->{rootfile},
4560 (undef, $config->{tarfile}),
4561 map { $_ => ['.'] } @{$config->{root}},
4564 print {$fh} header(name => 'root', size => $ai->size()), "\n";
4565 $ai->copy_to($fh);
4566 print {$fh} "\n\n";
4568 return;
4569 } ## end sub print_root_stuff
4571 sub get_remote_script {
4572 my $fh;
4573 if (-e $config{remote}) {
4574 open $fh, '<', $config{remote}
4575 or croak "open('$config{remote}'): $OS_ERROR";
4577 else {
4578 no warnings 'once';
4579 $fh = \*DATA;
4581 my @lines;
4582 while (<$fh>) {
4583 last if /\A __END__ \s*\z/mxs;
4584 push @lines, $_;
4586 close $fh;
4587 return join '', @lines, "__END__\n";
4588 } ## end sub get_remote_script
4590 package Deployable::Tar;
4592 sub new {
4593 my $package = shift;
4594 my $self = {ref $_[0] ? %{$_[0]} : @_};
4595 $package = 'Deployable::Tar::Internal';
4596 if (!$self->{'no-tar'}) {
4597 if ((exists $self->{tar}) || (open my $fh, '-|', 'tar', '--help')) {
4598 $package = 'Deployable::Tar::External';
4599 $self->{tar} ||= 'tar';
4601 } ## end if (!$self->{'no-tar'})
4602 bless $self, $package;
4603 $self->initialise();
4604 return $self;
4605 } ## end sub new
4607 package Deployable::Tar::External;
4608 use File::Temp qw( :seekable );
4609 use English qw( -no_match_vars );
4610 use Cwd ();
4611 use Carp;
4612 our @ISA = qw( Deployable::Tar );
4614 sub initialise {
4615 my $self = shift;
4616 $self->{_temp} = File::Temp->new();
4617 $self->{_filename} = Cwd::abs_path($self->{_temp}->filename());
4618 return $self;
4619 } ## end sub initialise
4621 sub add {
4622 my $self = shift;
4623 my $tar = $self->{tar};
4624 delete $self->{_compressed};
4625 while (@_) {
4626 my ($directory, $stuff) = splice @_, 0, 2;
4627 my @stuff = @$stuff;
4628 if (defined $directory) {
4629 while (@stuff) {
4630 my @chunk = splice @stuff, 0, 50;
4631 system {$tar} $tar, 'rvf', $self->{_filename},
4632 '-C', $directory, '--', @chunk;
4634 } ## end if (defined $directory)
4635 else { # it's another TAR file, concatenate
4636 while (@stuff) {
4637 my @chunk = splice @stuff, 0, 50;
4638 system {$tar} $tar, 'Avf', $self->{_filename}, '--', @chunk;
4640 } ## end else [ if (defined $directory)]
4641 } ## end while (@_)
4642 return $self;
4643 } ## end sub add
4645 sub _compress {
4646 my $self = shift;
4647 return if exists $self->{_compressed};
4649 $self->{_temp}->sysseek(0, SEEK_SET);
4650 if ($self->{bzip2}) {
4651 require IO::Compress::Bzip2;
4652 $self->{_compressed} = File::Temp->new();
4654 # double-quotes needed to force usage of filename
4655 # instead of filehandle
4656 IO::Compress::Bzip2::bzip2($self->{_temp}, "$self->{_compressed}");
4657 } ## end if ($self->{bzip2})
4658 elsif ($self->{gzip}) {
4659 require IO::Compress::Gzip;
4660 $self->{_compressed} = File::Temp->new();
4662 # double-quotes needed to force usage of filename
4663 # instead of filehandle
4664 IO::Compress::Gzip::gzip($self->{_temp}, "$self->{_compressed}");
4665 } ## end elsif ($self->{gzip})
4666 else {
4667 $self->{_compressed} = $self->{_temp};
4670 return $self;
4671 } ## end sub _compress
4673 sub size {
4674 my ($self) = @_;
4675 $self->_compress();
4676 return (stat $self->{_compressed})[7];
4679 sub copy_to {
4680 my ($self, $out_fh) = @_;
4681 $self->_compress();
4682 my $in_fh = $self->{_compressed};
4683 $in_fh->sysseek(0, SEEK_SET);
4684 while ('true') {
4685 my $nread = $in_fh->sysread(my $buffer, 4096);
4686 croak "sysread(): $OS_ERROR" unless defined $nread;
4687 last unless $nread;
4688 print {$out_fh} $buffer;
4689 } ## end while ('true')
4690 return $self;
4691 } ## end sub copy_to
4693 package Deployable::Tar::Internal;
4694 use Archive::Tar ();
4695 use Cwd ();
4696 use File::Find::Rule ();
4697 use Carp qw< croak >;
4698 our @ISA = qw( Deployable::Tar );
4700 sub initialise {
4701 my $self = shift;
4702 $self->{_tar} = Archive::Tar->new();
4703 return $self;
4706 sub add {
4707 my $self = shift;
4708 delete $self->{_string};
4709 my $tar = $self->{_tar};
4710 my $cwd = Cwd::getcwd();
4711 while (@_) {
4712 my ($directory, $stuff) = splice @_, 0, 2;
4713 if (defined $directory) {
4714 chdir $directory;
4715 for my $item (@$stuff) {
4716 if (ref $item) {
4717 my ($src, $filename) = @$item;
4718 my $src_len = length $src;
4719 for my $input (File::Find::Rule->in($src)) {
4720 my ($atf) = $tar->add_files($input);
4721 my $name = $filename . substr $input, $src_len;
4722 $atf->rename($name);
4725 else {
4726 $tar->add_files($_) for File::Find::Rule->in($item);
4729 chdir $cwd;
4730 } ## end if (defined $directory)
4731 else { # It's another TAR file to be concatenated
4732 for my $item (@$stuff) {
4733 my $iterator = Archive::Tar->iter($item);
4734 while (my $f = $iterator->()) {
4735 $tar->add_files($f);
4739 } ## end while (@_)
4740 return $self;
4741 } ## end sub add
4743 sub size {
4744 my ($self) = @_;
4745 $self->{_string} = $self->{_tar}->write()
4746 unless exists $self->{_string};
4747 return length $self->{_string};
4748 } ## end sub size
4750 sub copy_to {
4751 my ($self, $out_fh) = @_;
4752 $self->{_string} = $self->{_tar}->write()
4753 unless exists $self->{_string};
4754 print {$out_fh} $self->{_string};
4755 } ## end sub copy_to
4757 =head1 NAME
4759 deployable - create a deploy script for some files/scripts
4761 =head1 VERSION
4763 See version at beginning of script, variable $VERSION, or call
4765 shell$ deployable --version
4767 =head1 USAGE
4769 deployable [--usage] [--help] [--man] [--version]
4771 deployable [--bundle|--all-exec|-X]
4772 [--bzip2|--bz2|-j]
4773 [--cleanup|-c]
4774 [--deploy|--exec|d <program>]
4775 [--gzip|-gz|-z]
4776 [--heredir|-H <dirname>]
4777 [--include-archive-tar|-T]
4778 [--no-tar]
4779 [--output|-o <filename>]
4780 [--root|-r <dirname>]
4781 [--rootdir|--in-root|-R <dirname>]
4782 [--tar|-t <program-path>]
4783 [--tarfile|-F <filename>]
4784 [--tempdir-mode|-m <mode>]
4785 [--xform|-x src:filename]
4786 [--workdir|-w <path>]
4787 [ files or directories... ]
4789 =head1 EXAMPLES
4791 # pack some files and a deploy script together.
4792 shell$ deployable script.sh file.txt some/directory -d script.sh
4794 # Use a directory's contents as elements for the target root
4795 shell$ ls -1 /path/to/target/root
4800 # The above will be deployed as /etc, /opt, /usr and /var
4801 shell$ deployable -o dep.pl --root /path/to/target/root
4803 # Include sub-directory etc/ for inclusion and extraction
4804 # directly as /etc/
4805 shell$ deployable -o dep.pl --in-root etc/
4807 =head1 DESCRIPTION
4809 This is a meta-script to create deploy scripts. The latter ones are
4810 suitable to be distributed in order to deploy something.
4812 You basically have to provide two things: files to install and programs
4813 to be executed. Files can be put directly into the deployed script, or
4814 can be included in gzipped tar archives.
4816 When called, this script creates a deploy script for you. This script
4817 includes all the specified files, and when executed it will extract
4818 those files and execute the given programs. In this way, you can ship
4819 both files and logic needed to correctly install those files, but this
4820 is of course of of scope.
4822 All files and archives will be extracted under a configured path
4823 (see L<--workdir> below), which we'll call I<workdir> from now on. Under
4824 the I<workdir> a temporary directory will be created, and the files
4825 will be put in the temporary directory. You can specify if you want to
4826 clean up this temporary directory or keep it, at your choice. (You're able
4827 to both set a default for this cleanup when invoking deployable, or when
4828 invoking the deploy script itself). The temporary directory will be
4829 called I<tmpdir> in the following.
4831 There are several ways to embed files to be shipped:
4833 =over
4835 =item *
4837 pass the name of an already-prepared tar file via L</--tarfile>. The
4838 contents of this file will be assumed to be referred to the root
4839 directory;
4841 =item *
4843 specify the file name directly on the command line. A file given in this
4844 way will always be extracted into the I<tmpdir>, whatever its initial path
4845 was;
4847 =item *
4849 specify the name of a directory on the command line. In this case,
4850 C<tar> will be used to archive the directory, with the usual option to
4851 turn absolute paths into relative ones; this means that directories will
4852 be re-created under I<tmpdir> when extraction is performed;
4854 =item *
4856 give the name of a directory to be used as a "here directory", using
4857 the C<--heredir|-H> option. This is much the same as giving the directory
4858 name (see above), but in this case C<tar> will be told to change into the
4859 directory first, and archive '.'. This means that the contents of the
4860 "here-directory" will be extracted directly into I<tmpdir>.
4862 =back
4864 =head2 Extended Example
4866 Suppose you have a few server which have the same configuration, apart
4867 from some specific stuff (e.g. the hostname, the IP addresses, etc.).
4868 You'd like to perform changes to all with the minimum work possible...
4869 so you know you should script something.
4871 For example, suppose you want to update a few files in /etc, setting these
4872 files equal for all hosts. You would typically do the following:
4874 # In your computer
4875 shell$ mkdir -p /tmp/newfiles/etc
4876 shell$ cd /tmp/newfiles/etc
4877 # Craft the new files
4878 shell$ cd ..
4879 shell$ tar cvzf newetc.tar.gz etc
4881 # Now, for each server:
4882 shell$ scp newetc.tar.gz $server:/tmp
4883 shell$ ssh $server tar xvzf /tmp/newetc.tar.gz -C /
4886 So far, so good. But what if you need to kick in a little more logic?
4887 For example, if you update some configuration files, you'll most likey
4888 want to restart some services. So you could do the following:
4890 shell$ mkdir -p /tmp/newfiles/tmp
4891 shell$ cd /tmp/newfiles/tmp
4892 # craft a shell script to be executed remotely and set the exec bit
4893 # Suppose it's called deploy.sh
4894 shell$ cd ..
4895 shell$ tar cvzf newetc.tar.gz etc tmp
4897 # Now, for each server:
4898 shell$ scp newetc.tar.gz $server:/tmp
4899 shell$ ssh $server tar xvzf /tmp/newetc.tar.gz -C /
4900 shell$ ssh $server /tmp/deploy.sh
4902 And what if you want to install files depending on the particular machine?
4903 Or you have a bundle of stuff to deploy and a bunch of scripts to execute?
4904 You can use deployable. In this case, you can do the following:
4906 shell$ mkdir -p /tmp/newfiles/etc
4907 shell$ cd /tmp/newfiles/etc
4908 # Craft the new files
4909 shell$ cd ..
4910 # craft a shell script to be executed remotely and set the exec bit
4911 # Suppose it's called deploy.sh
4912 shell$ deployable -o deploy.pl -R etc deploy.sh -d deploy.sh
4914 # Now, for each server
4915 shell$ scp deploy.pl $server:/tmp
4916 shell$ ssh $server /tmp/deploy.pl
4918 And you're done. This can be particularly useful if you have another
4919 layer of deployment, e.g. if you have to run a script to decide which
4920 of a group of archives should be deployed. For example, you could craft
4921 a different new "etc" for each server (which is particularly true if
4922 network configurations are in the package), and produce a simple script
4923 to choose which file to use based on the MAC address of the machine. In
4924 this case you could have:
4926 =over
4928 =item newetc.*.tar.gz
4930 a bunch of tar files with the configurations for each different server
4932 =item newetc.list
4934 a list file with the association between the MAC addresses and the
4935 real tar file to deploy from the bunch in the previous bullet
4937 =item deploy-the-right-stuff.sh
4939 a script to get the real MAC address of the machine, select the right
4940 tar file and do the deployment.
4942 =back
4944 So, you can do the following:
4946 shell$ deployable -o deploy.pl newetc.*.tar.gz newetc.list \
4947 deploy-the-right-stuff.sh --exec deploy-the-right-stuff.sh
4949 # Now, for each server:
4950 shell$ scp deploy.pl $server:/tmp
4951 shell$ ssh $server /tmp/deploy.pl
4953 So, once you have the deploy script on the target machine all you need
4954 to do is to execute it. This can come handy when you cannot access the
4955 machines from the network, but you have to go there physically: you
4956 can prepare all in advance, and just call the deploy script.
4959 =head1 OPTIONS
4961 Meta-options:
4963 =over
4965 =item B<--help>
4967 print a somewhat more verbose help, showing usage, this description of
4968 the options and some examples from the synopsis.
4970 =item B<--man>
4972 print out the full documentation for the script.
4974 =item B<--usage>
4976 print a concise usage line and exit.
4978 =item B<--version>
4980 print the version of the script.
4982 =back
4984 Real-world options:
4986 =over
4988 =item B<< --bundle | --all-exec | -X >>
4990 Set bundle flag in the produced script. If the bundle flag is set, the
4991 I<deploy script> will treat all executables in the main deployment
4992 directory as scripts to be executed.
4994 By default the flag is not set.
4996 =item B<< --bzip2 | --bz2 | -j >>
4998 Compress tar archives with bzip2.
5000 =item B<< --cleanup | -c >>
5002 Set cleanup flag in the produced script. If the cleanup flag is set, the
5003 I<deploy script> will clean up after having performed all operations.
5005 You can set this flag to C<0> by using C<--no-cleanup>.
5007 =item B<< --deploy | --exec | -d <filename> >>
5009 Set the name of a program to execute after extraction. You can provide
5010 multiple program names, they will be executed in the same order.
5012 =item B<< --gzip | --gz | -z >>
5014 Compress tar archives with gzip.
5016 =item B<< --heredir | -H <path> >>
5018 Set the name of a "here directory" (see L<DESCRIPTION>). You can use this
5019 option multiple times to provide multiple directories.
5021 =item B<< --include-archive-tar | -T >>
5023 Embed L<Archive::Tar> (with its dependencies L<Archive::Tar::Constant> and
5024 L<Archive::Tar::File>) inside the final script. Use this when you know (or
5025 aren't sure) that L<Archive::Tar> will not be available in the target
5026 machine.
5028 =item B<< --no-tar >>
5030 Don't use system C<tar>.
5032 =item B<< --output | -o <filename> >>
5034 Set the output file name. By default the I<deploy script> will be given
5035 out on the standard output; if you provide a filename (different from
5036 C<->, of course!) the script will be saved there and the permissions will
5037 be set to 0755.
5039 =item B<< --root | -r <dirname> >>
5041 Include C<dirname> contents for deployment under root directory. The
5042 actual production procedure is: hop into C<dirname> and grab a tarball
5043 of C<.>. During deployment, hop into C</> and extract the tarball.
5045 This is useful if you're already building up the absolute deployment
5046 layout under a given directory: just treat that directory as if it were
5047 the root of the target system.
5049 =item B<< --rootdir | --in-root | -R <filename> >>
5051 Include C<filename> as an item that will be extracted under root
5052 directory. The actual production procedure is: grab a tarball of
5053 C<filename>. During deployment, hop into C</> and extract the tarball.
5055 This is useful e.g. if you have a directory (or a group of directories)
5056 that you want to deploy directly under the root.
5058 Note that the C<--rootdir> alias is kept for backwards compatibility
5059 but is not 100% correct - you can specify both a dirname (like it was
5060 previously stated) or a single file with this option. This is why it's
5061 more readably to use C<--in-root> instead.
5063 =item B<< --tar | -t <program-path> >>
5065 Set the system C<tar> program to use.
5067 =item B<< --tempdir-mode | -m >>
5069 set default permissions for temporary directory of deployable script
5071 =item B<< --workdir | --deploy-directory | -w <path> >>
5073 Set the working directory for the deploy.
5075 =back
5077 =head1 ROOT OR ROOTDIR?
5079 There are two options that allow you to specify things to be deployed
5080 in C</>, so what should you use? Thing is... whatever you want!
5082 If you have a bunch of directories that have to appear under root, probably
5083 your best bet is to put them all inside a directory called C<myroot> and
5084 use option C<--root>:
5086 shell$ mkdir -p myroot/{etc,opt,var,lib,usr,whatever}
5087 # Now put stuff in the directories created above...
5088 shell$ deployable --root myroot ...
5090 On the other hand, if you just want to put stuff starting from one or
5091 two directories that have to show up in C</>, you can avoid creating
5092 the extra C<myroot> directory and use C<--in-root> instead:
5094 shell$ mkdir -p etc/whatever
5095 # Now put stuff in etc/whatever...
5096 shell$ deployable --in-root etc ...
5098 They are indeed somehow equivalent, the first avoiding you much typing
5099 when you have many directories to be deployed starting from root (just
5100 put them into the same subdirectory), the second allowing you to avoid
5101 putting an extra directory layer.
5103 There is indeed an additional catch that makes them quite different. When
5104 you use C<root>, the whole content of the directory specified will be
5105 used as a base, so you will end up with a listing like this:
5107 opt/
5108 opt/local/
5109 opt/local/application/
5110 opt/local/application/myfile.txt
5111 opt/local/application/otherfile.txt
5113 i.e. all intermediate directories will be saved. On the other hand, when
5114 you specify a directory with C<--in-root>, you're not limited to provide
5115 a "single-step" directory, so for example:
5117 shell$ deployable --in-root opt/local/application
5119 will result in the following list of files/directories to be stored:
5121 opt/local/application/
5122 opt/local/application/myfile.txt
5123 opt/local/application/otherfile.txt
5125 i.e. the upper level directories will not be included. What is better for
5126 you is for you to judge.
5128 =head1 THE DEPLOY SCRIPT
5130 The net result of calling this script is to produce another script,
5131 that we call the I<deploy script>. This script is made of two parts: the
5132 code, which is fixed, and the configurations/files, which is what is
5133 actually produced. The latter part is put after the C<__END__> marker,
5134 as usual.
5136 Stuff in the configuration part is always hexified in order to prevent
5137 strange tricks or errors. Comments will help you devise what's inside the
5138 configurations themselves.
5140 The I<deploy script> has options itself, even if they are quite minimal.
5141 In particular, it supports the same options C<--workdir|-w> and
5142 C<--cleanup> described above, allowing the final user to override the
5143 configured values. By default, the I<workdir> is set to C</tmp>
5144 and the script will clean up after itself.
5146 The following options are supported in the I<deploy script>:
5148 =over
5150 =item B<--usage | --man | --help>
5152 print a minimal help and exit
5154 =item B<--version>
5156 print script version and exit
5158 =item B<--bundle | --all-exec | -X>
5160 treat all executables in the main deployment directory as scripts
5161 to be executed
5163 =item B<--cleanup | --no-cleanup>
5165 perform / don't perform temporary directory cleanup after work done
5167 =item B<< --deploy | --no-deploy >>
5169 deploy scripts are executed by default (same as specifying '--deploy')
5170 but you can prevent it.
5172 =item B<--dryrun | --dry-run>
5174 print final options and exit
5176 =item B<< --filelist | --list | -l >>
5178 print a list of files that are shipped in the deploy script
5180 =item B<< --heretar | --here-tar | -H >>
5182 print out the tar file that contains all the files that would be
5183 extracted in the temporary directory, useful to redirect to file or
5184 pipe to the tar program
5186 =item B<< --inspect <dirname> >>
5188 just extract all the stuff into <dirname> for inspection. Implies
5189 C<--no-deploy>, C<--no-tempdir>, ignores C<--bundle> (as a consequence of
5190 C<--no-deploy>), disables C<--cleanup> and sets the working directory
5191 to C<dirname>
5193 =item B<< --no-tar >>
5195 don't use system C<tar>
5197 =item B<< --rootar | --root-tar | -R >>
5199 print out the tar file that contains all the files that would be
5200 extracted in the root directory, useful to redirect to file or
5201 pipe to the tar program
5203 =item B<--show | --show-options | -s>
5205 print configured options and exit
5207 =item B<< --tar | -t <program-path> >>
5209 set the system C<tar> program to use.
5211 =item B<< --tarfile | -F <filename> >>
5213 add the specified C<filename> (assumed to be an uncompressed
5214 TAR file) to the lot for root extraction. This can come handy
5215 when you already have all the files backed up in a TAR archive
5216 and you're not willing to expand them (e.g. because your
5217 filesystem is case-insensitive...).
5219 =item B<< --tempdir | --no-tempdir >>
5221 by default a temporary directory is created (same as specifying
5222 C<--tempdir>), but you can execute directly in the workdir (see below)
5223 without creating it.
5225 =item B<< --tempdir-mode | -m >>
5227 temporary directories (see C<--tempdir>) created by File::Temp have
5228 permission 600 that prevents group/others from even looking at the
5229 contents. You might want to invoke some of the internal scripts
5230 from another user (e.g. via C<su>), so you can pass a mode to be
5231 set on the temporary directory.
5233 Works only if C<--tempdir> is active.
5235 =item B<< --xform | -x <src:filename> >>
5237 include file or directory C<src> as path C<filename>. The latter can be
5238 either an absolute path (included in C<root>) or a relative one
5239 (included in the working directory).
5241 =item B<--workdir | --work-directory | --deploy-directory | -w>
5243 working base directory (a temporary subdirectory will be created
5244 there anyway)
5246 =back
5248 Note the difference between C<--show> and C<--dryrun>: the former will
5249 give you the options that are "embedded" in the I<deploy script> without
5250 taking into account other options given on the command line, while the
5251 latter will give you the final options that would be used if the script
5252 were called without C<--dryrun>.
5254 =head2 Deploy Script Example Usage
5256 In the following, we'll assume that the I<deploy script> is called
5257 C<deploy.pl>.
5259 To execute the script with the already configured options, you just have
5260 to call it:
5262 shell$ ./deploy.pl
5264 If you just want to see which configurations are in the I<deploy script>:
5266 shell$ ./deploy.pl --show
5268 To see which files are included, you have two options. One is asking the
5269 script:
5271 shell$ ./deploy.pl --filelist
5273 the other is piping to tar:
5275 shell$ ./deploy.pl --tar | tar tvf -
5277 Extract contents of the script in a temp directory and simply inspect
5278 what's inside:
5280 # extract stuff into subdirectory 'inspect' for... inspection
5281 shell$ ./deploy.pl --no-tempdir --no-deploy --workdir inspect
5283 =head2 Deploy Script Requirements
5285 You'll need a working Perl with version at least 5.6.2.
5287 If you specify L</--include-archive-tar>, the module L<Archive::Tar> will
5288 be included as well. This should ease your life and avoid you to have
5289 B<tar> on the target machine. On the other hand, if you already know
5290 that B<tar> will be available, you can avoid including C<Archive::Tar>
5291 and have the generated script use it (it could be rather slower anyway).
5293 =head1 DIAGNOSTICS
5295 Each error message should be enough explicit to be understood without the
5296 need for furter explainations. Which is another way to say that I'm way
5297 too lazy to list all possible ways that this script has to fail.
5300 =head1 CONFIGURATION AND ENVIRONMENT
5302 deployable requires no configuration files or environment variables.
5304 Please note that deployable B<needs> to find its master B<remote> file
5305 to produce the final script. This must be put in the same directory where
5306 deployable is put. You should be able to B<symlink> deployable where you
5307 think it's better, anyway - it will go search for the original file
5308 and look for B<remote> inside the same directory. This does not apply to
5309 hard links, of course.
5312 =head1 DEPENDENCIES
5314 All core modules, apart the following:
5316 =over
5318 =item B<< Archive::Tar >>
5320 =item B<< File::Find::Rule >>
5322 =back
5324 =head1 BUGS AND LIMITATIONS
5326 No bugs have been reported.
5328 Please report any bugs or feature requests to the AUTHOR below.
5330 Be sure to read L<CONFIGURATION AND ENVIRONMENT> for a slight limitation
5331 about the availability of the B<remote> script.
5333 =head1 AUTHOR
5335 Flavio Poletti C<flavio [AT] polettix.it>
5338 =head1 LICENSE AND COPYRIGHT
5340 Copyright (c) 2008, Flavio Poletti C<flavio [AT] polettix.it>. All rights reserved.
5342 This script is free software; you can redistribute it and/or
5343 modify it under the same terms as Perl itself. See L<perlartistic>
5344 and L<perlgpl>.
5346 =head1 DISCLAIMER OF WARRANTY
5348 BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
5349 FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
5350 OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
5351 PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
5352 EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
5353 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
5354 ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
5355 YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
5356 NECESSARY SERVICING, REPAIR, OR CORRECTION.
5358 IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
5359 WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
5360 REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE
5361 LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
5362 OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
5363 THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
5364 RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
5365 FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
5366 SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
5367 SUCH DAMAGES.
5369 =cut
5371 package main; # ensure DATA is main::DATA
5372 __DATA__
5373 #!/usr/bin/env perl
5374 # *** NOTE *** LEAVE THIS MODULE LIST AS A PARAGRAPH
5375 use strict;
5376 use warnings;
5377 use 5.006_002;
5378 our $VERSION = '0.2.0';
5379 use English qw( -no_match_vars );
5380 use Fatal qw( close chdir opendir closedir );
5381 use File::Temp qw( tempdir );
5382 use File::Path qw( mkpath );
5383 use File::Spec::Functions qw( file_name_is_absolute catfile );
5384 use File::Basename qw( basename dirname );
5385 use POSIX qw( strftime );
5386 use Getopt::Long qw( :config gnu_getopt );
5387 use Cwd qw( getcwd );
5388 use Fcntl qw( :seek );
5390 # *** NOTE *** LEAVE EMPTY LINE ABOVE
5391 my %default_config = ( # default values
5392 workdir => '/tmp',
5393 cleanup => 1,
5394 'no-exec' => 0,
5395 tempdir => 1,
5396 passthrough => 0,
5397 verbose => 0,
5400 my $DATA_POSITION = tell DATA; # GLOBAL VARIABLE
5401 my %script_config = (%default_config, get_config());
5403 my %config = %script_config;
5404 if ($ENV{DEPLOYABLE_DISABLE_PASSTHROUGH} || (!$config{passthrough})) {
5405 my %cmdline_config;
5406 GetOptions(
5407 \%cmdline_config,
5409 usage|help|man!
5410 version!
5412 bundle|all-exec|X!
5413 cleanup|c!
5414 dryrun|dry-run|n!
5415 filelist|list|l!
5416 heretar|here-tar|H!
5417 inspect|i=s
5418 no-exec!
5419 no-tar!
5420 roottar|root-tar|R!
5421 show|show-options|s!
5422 tar|t=s
5423 tempdir!
5424 tempdir-mode|m=s
5425 verbose!
5426 workdir|work-directory|deploy-directory|w=s
5428 ) or short_usage();
5429 %config = (%config, %cmdline_config);
5430 } ## end if ($ENV{DEPLOYABLE_DISABLE_PASSTHROUGH...})
5432 usage() if $config{usage};
5433 version() if $config{version};
5435 if ($config{roottar}) {
5436 binmode STDOUT;
5437 my ($fh, $size) = locate_file('root');
5438 copy($fh, \*STDOUT, $size);
5439 exit 0;
5440 } ## end if ($config{roottar})
5442 if ($config{heretar}) {
5443 binmode STDOUT;
5444 my ($fh, $size) = locate_file('here');
5445 copy($fh, \*STDOUT, $size);
5446 exit 0;
5447 } ## end if ($config{heretar})
5449 if ($config{show}) {
5450 require Data::Dumper;
5451 print {*STDOUT} Data::Dumper::Dumper(\%script_config);
5452 exit 1;
5455 if ($config{inspect}) {
5456 $config{cleanup} = 0;
5457 $config{'no-exec'} = 1;
5458 $config{'tempdir'} = 0;
5459 $config{workdir} = $config{inspect};
5460 } ## end if ($config{inspect})
5462 if ($config{dryrun}) {
5463 require Data::Dumper;
5464 print {*STDOUT} Data::Dumper::Dumper(\%config);
5465 exit 1;
5468 if ($config{filelist}) {
5469 my $root_tar = get_sub_tar('root');
5470 print "root:\n";
5471 $root_tar->print_filelist();
5472 my $here_tar = get_sub_tar('here');
5473 print "here:\n";
5474 $here_tar->print_filelist();
5475 exit 0;
5476 } ## end if ($config{filelist})
5478 # here we have to do things for real... probably, so save the current
5479 # working directory for consumption by the scripts
5480 $ENV{OLD_PWD} = getcwd();
5482 # go into the working directory, creating any intermediate if needed
5483 mkpath($config{workdir});
5484 chdir($config{workdir});
5485 print {*STDERR} "### Got into working directory '$config{workdir}'\n\n"
5486 if $config{verbose};
5488 my $tempdir;
5489 if ($config{'tempdir'}) { # Only if allowed
5490 my $me = basename(__FILE__) || 'deploy';
5491 my $now = strftime('%Y-%m-%d_%H-%M-%S', localtime);
5492 $tempdir = tempdir(
5493 join('-', $me, $now, ('X' x 10)),
5494 DIR => '.',
5495 CLEANUP => $config{cleanup}
5498 if ($config{'tempdir-mode'}) {
5499 chmod oct($config{'tempdir-mode'}), $tempdir
5500 or die "chmod('$tempdir'): $OS_ERROR\n";
5503 chdir $tempdir
5504 or die "chdir('$tempdir'): $OS_ERROR\n";
5506 if ($config{verbose}) {
5507 print {*STDERR}
5508 "### Created and got into temporary directory '$tempdir'\n";
5509 print {*STDERR} "### (will clean it up later)\n" if $config{cleanup};
5510 print {*STDERR} "\n";
5511 } ## end if ($config{verbose})
5512 } ## end if ($config{'tempdir'})
5514 eval { # Not really needed, but you know...
5515 $ENV{PATH} = '/bin:/usr/bin:/sbin:/usr/sbin';
5516 save_files();
5517 execute_deploy_programs() unless $config{'no-exec'};
5519 warn "$EVAL_ERROR\n" if $EVAL_ERROR;
5521 # Get back so that cleanup can successfully happen, if requested
5522 chdir '..' if defined $tempdir;
5524 sub locate_file {
5525 my ($filename) = @_;
5526 my $fh = \*DATA;
5527 seek $fh, $DATA_POSITION, SEEK_SET;
5528 while (!eof $fh) {
5529 chomp(my $sizes = <$fh>);
5530 my ($name_size, $file_size) = split /\s+/, $sizes;
5531 my $name = full_read($fh, $name_size);
5532 full_read($fh, 1); # "\n"
5533 return ($fh, $file_size) if $name eq $filename;
5534 seek $fh, $file_size + 2, SEEK_CUR; # includes "\n\n"
5535 } ## end while (!eof $fh)
5536 die "could not find '$filename'";
5537 } ## end sub locate_file
5539 sub full_read {
5540 my ($fh, $size) = @_;
5541 my $retval = '';
5542 while ($size) {
5543 my $buffer;
5544 my $nread = read $fh, $buffer, $size;
5545 die "read(): $OS_ERROR" unless defined $nread;
5546 die "unexpected end of file" unless $nread;
5547 $retval .= $buffer;
5548 $size -= $nread;
5549 } ## end while ($size)
5550 return $retval;
5551 } ## end sub full_read
5553 sub copy {
5554 my ($ifh, $ofh, $size) = @_;
5555 while ($size) {
5556 my $buffer;
5557 my $nread = read $ifh, $buffer, ($size < 4096 ? $size : 4096);
5558 die "read(): $OS_ERROR" unless defined $nread;
5559 die "unexpected end of file" unless $nread;
5560 print {$ofh} $buffer;
5561 $size -= $nread;
5562 } ## end while ($size)
5563 return;
5564 } ## end sub copy
5566 sub get_sub_tar {
5567 my ($filename) = @_;
5568 my ($fh, $size) = locate_file($filename);
5569 return Deployable::Tar->new(%config, fh => $fh, size => $size);
5572 sub get_config {
5573 my ($fh, $size) = locate_file('config.pl');
5574 my $config_text = full_read($fh, $size);
5575 my $config = eval 'my ' . $config_text or return;
5576 return $config unless wantarray;
5577 return %$config;
5578 } ## end sub get_config
5580 sub save_files {
5581 my $here_tar = get_sub_tar('here');
5582 $here_tar->extract();
5584 my $root_dir = $config{inspect} ? 'root' : '/';
5585 mkpath $root_dir unless -d $root_dir;
5586 my $cwd = getcwd();
5587 chdir $root_dir;
5588 my $root_tar = get_sub_tar('root');
5589 $root_tar->extract();
5590 chdir $cwd;
5592 return;
5593 } ## end sub save_files
5595 sub execute_deploy_programs {
5596 my @deploy_programs = @{$config{deploy} || []};
5598 if ($config{bundle}) { # add all executable scripts in current directory
5599 print {*STDERR} "### Auto-deploying all executables in main dir\n\n"
5600 if $config{verbose};
5601 my %flag_for = map { $_ => 1 } @deploy_programs;
5602 opendir my $dh, '.';
5603 for my $item (sort readdir $dh) {
5604 next if $flag_for{$item};
5605 next unless ((-f $item) || (-l $item)) && (-x $item);
5606 $flag_for{$item} = 1;
5607 push @deploy_programs, $item;
5608 } ## end for my $item (sort readdir...)
5609 closedir $dh;
5610 } ## end if ($config{bundle})
5612 DEPLOY:
5613 for my $deploy (@deploy_programs) {
5614 $deploy = catfile('.', $deploy)
5615 unless file_name_is_absolute($deploy);
5616 if (!-x $deploy) {
5617 print {*STDERR} "### Skipping '$deploy', not executable\n\n"
5618 if $config{verbose};
5619 next DEPLOY;
5621 print {*STDERR} "### Executing '$deploy'...\n"
5622 if $config{verbose};
5623 system {$deploy} $deploy, @ARGV;
5624 print {*STDERR} "\n"
5625 if $config{verbose};
5626 } ## end DEPLOY: for my $deploy (@deploy_programs)
5628 return;
5629 } ## end sub execute_deploy_programs
5631 sub short_usage {
5632 my $progname = basename($0);
5633 print {*STDOUT} <<"END_OF_USAGE" ;
5635 $progname version $VERSION - for help on calling and options, run:
5637 $0 --usage
5638 END_OF_USAGE
5639 exit 1;
5640 } ## end sub short_usage
5642 sub usage {
5643 my $progname = basename($0);
5644 print {*STDOUT} <<"END_OF_USAGE" ;
5645 $progname version $VERSION
5647 More or less, this script is intended to be launched without parameters.
5648 Anyway, you can also set the following options, which will override any
5649 present configuration (except in "--show-options"):
5651 * --usage | --man | --help
5652 print these help lines and exit
5654 * --version
5655 print script version and exit
5657 * --bundle | --all-exec | -X
5658 treat all executables in the main deployment directory as scripts
5659 to be executed
5661 * --cleanup | -c | --no-cleanup
5662 perform / don't perform temporary directory cleanup after work done
5664 * --deploy | --no-deploy
5665 deploy scripts are executed by default (same as specifying '--deploy')
5666 but you can prevent it.
5668 * --dryrun | --dry-run
5669 print final options and exit
5671 * --filelist | --list | -l
5672 print a list of files that are shipped in the deploy script
5674 * --heretar | --here-tar | -H
5675 print out the tar file that contains all the files that would be
5676 extracted in the temporary directory, useful to redirect to file or
5677 pipe to the tar program
5679 * --inspect | -i <dirname>
5680 just extract all the stuff into <dirname> for inspection. Implies
5681 --no-deploy, --no-tempdir, ignores --bundle (as a consequence of
5682 --no-deploy), disables --cleanup and sets the working directory
5683 to <dirname>
5685 * --no-tar
5686 don't use system "tar"
5688 * --roottar | --root-tar | -R
5689 print out the tar file that contains all the files that would be
5690 extracted in the root directory, useful to redirect to file or
5691 pipe to the tar program
5693 * --show | --show-options | -s
5694 print configured options and exit
5696 * --tar | -t <program-path>
5697 set the system "tar" program to use.
5699 * --tempdir | --no-tempdir
5700 by default a temporary directory is created (same as specifying
5701 '--tempdir'), but you can execute directly in the workdir (see below)
5702 without creating it.
5704 * --tempdir-mode | -m
5705 set permissions of temporary directory (octal string)
5707 * --workdir | --work-directory | --deploy-directory | -w
5708 working base directory (a temporary subdirectory will be created
5709 there anyway)
5711 END_OF_USAGE
5712 exit 1;
5713 } ## end sub usage
5715 sub version {
5716 print "$0 version $VERSION\n";
5717 exit 1;
5720 package Deployable::Tar;
5722 sub new {
5723 my $package = shift;
5724 my $self = {ref $_[0] ? %{$_[0]} : @_};
5725 $package = 'Deployable::Tar::Internal';
5726 if (!$self->{'no-tar'}) {
5727 if ((exists $self->{tar}) || (open my $fh, '-|', 'tar', '--help')) {
5728 $package = 'Deployable::Tar::External';
5729 $self->{tar} ||= 'tar';
5731 } ## end if (!$self->{'no-tar'})
5732 bless $self, $package;
5733 $self->initialise() if $self->can('initialise');
5734 return $self;
5735 } ## end sub new
5737 package Deployable::Tar::External;
5738 use English qw( -no_match_vars );
5740 sub initialise {
5741 my $self = shift;
5742 my $compression =
5743 $self->{bzip2} ? 'j'
5744 : $self->{gzip} ? 'z'
5745 : '';
5746 $self->{_list_command} = 'tv' . $compression . 'f';
5747 $self->{_extract_command} = 'x' . $compression . 'f';
5748 } ## end sub initialise
5750 sub print_filelist {
5751 my $self = shift;
5752 if ($self->{size}) {
5753 open my $tfh, '|-', $self->{tar}, $self->{_list_command}, '-'
5754 or die "open() on pipe to tar: $OS_ERROR";
5755 main::copy($self->{fh}, $tfh, $self->{size});
5757 return $self;
5758 } ## end sub print_filelist
5760 sub extract {
5761 my $self = shift;
5762 if ($self->{size}) {
5763 open my $tfh, '|-', $self->{tar}, $self->{_extract_command}, '-'
5764 or die "open() on pipe to tar: $OS_ERROR";
5765 main::copy($self->{fh}, $tfh, $self->{size});
5767 return $self;
5768 } ## end sub extract
5770 package Deployable::Tar::Internal;
5771 use English qw( -no_match_vars );
5773 sub initialise {
5774 my $self = shift;
5776 if ($self->{size}) {
5777 my $data = main::full_read($self->{fh}, $self->{size});
5778 open my $fh, '<', \$data
5779 or die "open() on internal variable: $OS_ERROR";
5781 require Archive::Tar;
5782 $self->{_tar} = Archive::Tar->new();
5783 $self->{_tar}->read($fh);
5784 } ## end if ($self->{size})
5786 return $self;
5787 } ## end sub initialise
5789 sub print_filelist {
5790 my $self = shift;
5791 if ($self->{size}) {
5792 print {*STDOUT} " $_\n" for $self->{_tar}->list_files();
5794 return $self;
5795 } ## end sub print_filelist
5797 sub extract {
5798 my $self = shift;
5799 if ($self->{size}) {
5800 $self->{_tar}->extract();
5802 return $self;
5803 } ## end sub extract
5805 __END__