Archive-Tar-Wrapper-0.18/0000755000175000017500000000000012171157733015366 5ustar mschillimschilliArchive-Tar-Wrapper-0.18/eg/0000755000175000017500000000000012171157733015761 5ustar mschillimschilliArchive-Tar-Wrapper-0.18/eg/tarflat0000755000175000017500000000341411331752614017342 0ustar mschillimschilli#!/usr/bin/perl ########################################### # tarflat # 2005, Mike Schilli ########################################### use strict; use warnings; use Getopt::Std; use Pod::Usage; use Archive::Tar::Wrapper; use Sysadm::Install qw(:all); use vars qw($CVSVERSION); $CVSVERSION = '$Revision: 1.1 $'; getopts("hv", \my %opts); pod2usage() if $opts{h}; if($opts{v}) { my ($version) = $CVSVERSION =~ /(\d\S+)/; die "$0 $version\n"; } my($target_dir, @tarfiles) = @ARGV; if(!defined $target_dir or !@tarfiles) { pod2usage("Wrong number of arguments"); } if(! -d $target_dir) { my $create = ask "$target_dir doesn't exist. Create it [y]", "y"; mkd $target_dir if $create =~ /[yY]/; } my $arch = Archive::Tar::Wrapper->new(); for my $tarfile (@tarfiles) { $arch->read($tarfile); } $arch->list_reset(); while(my $entry = $arch->list_next()) { my($tar_path, $phys_path) = @$entry; if(-f $phys_path) { cp $phys_path, $target_dir; } } __END__ =head1 NAME tarflat - Unpack tarfiles and put their content flat in a single directory =head1 SYNOPSIS tarflat target_dir tarfile ... =head1 OPTIONS =over 8 =item B<-h> Prints this manual page in text format. =item B<-v> Prints the script version. =back =head1 DESCRIPTION C =head1 EXAMPLES # Unpack foo.tgz and bar.tgz and store all of their files # (anywhere in the directory hierarchy) in the directory # /tmp/junk. $ mkdir /tmp/junk $ tarflat /tmp/junk foo.tgz bar.tgz =head1 LEGALESE Copyright 2005 by Mike Schilli, all rights reserved. This program is free software, you can redistribute it and/or modify it under the same terms as Perl itself. =head1 AUTHOR 2005, Mike Schilli Archive-Tar-Wrapper-0.18/lib/0000755000175000017500000000000012171157733016134 5ustar mschillimschilliArchive-Tar-Wrapper-0.18/lib/Archive/0000755000175000017500000000000012171157733017515 5ustar mschillimschilliArchive-Tar-Wrapper-0.18/lib/Archive/Tar/0000755000175000017500000000000012171157733020243 5ustar mschillimschilliArchive-Tar-Wrapper-0.18/lib/Archive/Tar/Wrapper.pm0000644000175000017500000005450512171157363022231 0ustar mschillimschilli########################################### # Archive::Tar::Wrapper -- 2005, Mike Schilli ########################################### ########################################### package Archive::Tar::Wrapper; ########################################### use strict; use warnings; use File::Temp qw(tempdir); use Log::Log4perl qw(:easy); use File::Spec::Functions; use File::Spec; use File::Path; use File::Copy; use File::Find; use File::Basename; use File::Which qw(which); use IPC::Run qw(run); use Cwd; our $VERSION = "0.18"; ########################################### sub new { ########################################### my($class, %options) = @_; my $self = { tar => undef, tmpdir => undef, tar_read_options => '', tar_write_options => '', tar_gnu_read_options => [], dirs => 0, max_cmd_line_args => 512, ramdisk => undef, %options, }; bless $self, $class; $self->{tar} = which("tar") unless defined $self->{tar}; $self->{tar} = which("gtar") unless defined $self->{tar}; if( ! defined $self->{tar} ) { LOGDIE "tar not found in PATH, please specify location"; } if(defined $self->{ramdisk}) { my $rc = $self->ramdisk_mount( %{ $self->{ramdisk} } ); if(!$rc) { LOGDIE "Mounting ramdisk failed"; } $self->{tmpdir} = $self->{ramdisk}->{tmpdir}; } else { $self->{tmpdir} = tempdir($self->{tmpdir} ? (DIR => $self->{tmpdir}) : ()); } $self->{tardir} = File::Spec->catfile($self->{tmpdir}, "tar"); mkpath [$self->{tardir}], 0, 0755 or LOGDIE "Cannot mkpath $self->{tardir} ($!)"; $self->{objdir} = tempdir(); return $self; } ########################################### sub tardir { ########################################### my($self) = @_; return $self->{tardir}; } ########################################### sub read { ########################################### my($self, $tarfile, @files) = @_; my $cwd = getcwd(); unless(File::Spec::Functions::file_name_is_absolute($tarfile)) { $tarfile = File::Spec::Functions::rel2abs($tarfile, $cwd); } chdir $self->{tardir} or LOGDIE "Cannot chdir to $self->{tardir}"; my $compr_opt = ""; $compr_opt = "z" if $self->is_compressed($tarfile); my $cmd = [$self->{tar}, "${compr_opt}x$self->{tar_read_options}", @{$self->{tar_gnu_read_options}}, "-f", $tarfile, @files]; DEBUG "Running @$cmd"; my $rc = run($cmd, \my($in, $out, $err)); if(!$rc) { ERROR "@$cmd failed: $err"; chdir $cwd or LOGDIE "Cannot chdir to $cwd"; return undef; } WARN $err if $err; chdir $cwd or LOGDIE "Cannot chdir to $cwd"; return 1; } ########################################### sub is_compressed { ########################################### my($self, $tarfile) = @_; return 1 if $tarfile =~ /\.t?gz$/i; # Sloppy check for gzip files open FILE, "<$tarfile" or die "Cannot open $tarfile"; binmode FILE; my $read = sysread(FILE, my $two, 2, 0) or die "Cannot sysread"; close FILE; return 1 if ord(substr($two, 0, 1)) eq 0x1F and ord(substr($two, 1, 1)) eq 0x8B; return 0; } ########################################### sub locate { ########################################### my($self, $rel_path) = @_; my $real_path = File::Spec->catfile($self->{tardir}, $rel_path); if(-e $real_path) { DEBUG "$real_path exists"; return $real_path; } DEBUG "$real_path doesn't exist"; WARN "$rel_path not found in tarball"; return undef; } ########################################### sub add { ########################################### my($self, $rel_path, $path_or_stringref, $opts) = @_; if($opts) { if(!ref($opts) or ref($opts) ne 'HASH') { LOGDIE "Option parameter given to add() not a hashref."; } } my $perm = $opts->{perm} if defined $opts->{perm}; my $uid = $opts->{uid} if defined $opts->{uid}; my $gid = $opts->{gid} if defined $opts->{gid}; my $binmode = $opts->{binmode} if defined $opts->{binmode}; my $target = File::Spec->catfile($self->{tardir}, $rel_path); my $target_dir = dirname($target); if( ! -d $target_dir ) { if( ref($path_or_stringref) ) { $self->add( dirname( $rel_path ), dirname( $target_dir ) ); } else { $self->add( dirname( $rel_path ), dirname( $path_or_stringref ) ); } } if(ref($path_or_stringref)) { open FILE, ">$target" or LOGDIE "Can't open $target ($!)"; if(defined $binmode) { binmode FILE, $binmode; } print FILE $$path_or_stringref; close FILE; } elsif( -d $path_or_stringref ) { # perms will be fixed further down mkpath($target, 0, 0755) unless -d $target; } else { copy $path_or_stringref, $target or LOGDIE "Can't copy $path_or_stringref to $target ($!)"; } if(defined $uid) { chown $uid, -1, $target or LOGDIE "Can't chown $target uid to $uid ($!)"; } if(defined $gid) { chown -1, $gid, $target or LOGDIE "Can't chown $target gid to $gid ($!)"; } if(defined $perm) { chmod $perm, $target or LOGDIE "Can't chmod $target to $perm ($!)"; } if(!defined $uid and !defined $gid and !defined $perm and !ref($path_or_stringref)) { perm_cp($path_or_stringref, $target) or LOGDIE "Can't perm_cp $path_or_stringref to $target ($!)"; } 1; } ###################################### sub perm_cp { ###################################### # Lifted from Ben Okopnik's # http://www.linuxgazette.com/issue87/misc/tips/cpmod.pl.txt my $perms = perm_get($_[0]); perm_set($_[1], $perms); } ###################################### sub perm_get { ###################################### my($filename) = @_; my @stats = (stat $filename)[2,4,5] or LOGDIE "Cannot stat $filename ($!)"; return \@stats; } ###################################### sub perm_set { ###################################### my($filename, $perms) = @_; chown($perms->[1], $perms->[2], $filename) or LOGDIE "Cannot chown $filename ($!)"; chmod($perms->[0] & 07777, $filename) or LOGDIE "Cannot chmod $filename ($!)"; } ########################################### sub remove { ########################################### my($self, $rel_path) = @_; my $target = File::Spec->catfile($self->{tardir}, $rel_path); rmtree($target) or LOGDIE "Can't rmtree $target ($!)"; } ########################################### sub list_all { ########################################### my($self) = @_; my @entries = (); $self->list_reset(); while(my $entry = $self->list_next()) { push @entries, $entry; } return \@entries; } ########################################### sub list_reset { ########################################### my($self) = @_; my $list_file = File::Spec->catfile($self->{objdir}, "list"); open FILE, ">$list_file" or LOGDIE "Can't open $list_file"; my $cwd = getcwd(); chdir $self->{tardir} or LOGDIE "Can't chdir to $self->{tardir} ($!)"; find(sub { my $entry = $File::Find::name; $entry =~ s#^\./##; my $type = (-d $_ ? "d" : -l $_ ? "l" : "f" ); print FILE "$type $entry\n"; }, "."); chdir $cwd or LOGDIE "Can't chdir to $cwd ($!)"; close FILE; $self->offset(0); } ########################################### sub list_next { ########################################### my($self) = @_; my $offset = $self->offset(); my $list_file = File::Spec->catfile($self->{objdir}, "list"); open FILE, "<$list_file" or LOGDIE "Can't open $list_file"; seek FILE, $offset, 0; { my $line = ; return undef unless defined $line; chomp $line; my($type, $entry) = split / /, $line, 2; redo if $type eq "d" and ! $self->{dirs}; $self->offset(tell FILE); return [$entry, File::Spec->catfile($self->{tardir}, $entry), $type]; } } ########################################### sub offset { ########################################### my($self, $new_offset) = @_; my $offset_file = File::Spec->catfile($self->{objdir}, "offset"); if(defined $new_offset) { open FILE, ">$offset_file" or LOGDIE "Can't open $offset_file"; print FILE "$new_offset\n"; close FILE; } open FILE, "<$offset_file" or LOGDIE "Can't open $offset_file (Did you call list_next() without a previous list_reset()?)"; my $offset = ; chomp $offset; return $offset; close FILE; } ########################################### sub write { ########################################### my($self, $tarfile, $compress) = @_; my $cwd = getcwd(); chdir $self->{tardir} or LOGDIE "Can't chdir to $self->{tardir} ($!)"; unless(File::Spec::Functions::file_name_is_absolute($tarfile)) { $tarfile = File::Spec::Functions::rel2abs($tarfile, $cwd); } my $compr_opt = ""; $compr_opt = "z" if $compress; opendir DIR, "." or LOGDIE "Cannot open $self->{tardir}"; my @top_entries = grep { $_ !~ /^\.\.?$/ } readdir DIR; closedir DIR; my $cmd; if(@top_entries > $self->{max_cmd_line_args}) { my $filelist_file = $self->{tmpdir}."/file-list"; open FLIST, ">$filelist_file" or LOGDIE "Cannot open $filelist_file ($!)"; for(@top_entries) { print FLIST "$_\n"; } close FLIST; $cmd = [$self->{tar}, "${compr_opt}cf$self->{tar_write_options}", $tarfile, "-T", $filelist_file]; } else { $cmd = [$self->{tar}, "${compr_opt}cf$self->{tar_write_options}", $tarfile, @top_entries]; } DEBUG "Running @$cmd"; my $rc = run($cmd, \my($in, $out, $err)); if(!$rc) { ERROR "@$cmd failed: $err"; chdir $cwd or LOGDIE "Cannot chdir to $cwd"; return undef; } WARN $err if $err; chdir $cwd or LOGDIE "Cannot chdir to $cwd"; return 1; } ########################################### sub DESTROY { ########################################### my($self) = @_; $self->ramdisk_unmount() if defined $self->{ramdisk}; rmtree($self->{objdir}) if defined $self->{objdir}; rmtree($self->{tmpdir}) if defined $self->{tmpdir}; } ########################################### sub is_gnu { ########################################### my($self) = @_; open PIPE, "$self->{tar} --version |" or return 0; my $output = join "\n", ; close PIPE; return $output =~ /GNU/; } ########################################### sub ramdisk_mount { ########################################### my($self, %options) = @_; # mkdir -p /mnt/myramdisk # mount -t tmpfs -o size=20m tmpfs /mnt/myramdisk $self->{mount} = which("mount") unless $self->{mount}; $self->{umount} = which("umount") unless $self->{umount}; for (qw(mount umount)) { if(!defined $self->{$_}) { LOGWARN "No $_ command found in PATH"; return undef; } } $self->{ramdisk} = { %options }; $self->{ramdisk}->{size} = "100m" unless defined $self->{ramdisk}->{size}; if(! defined $self->{ramdisk}->{tmpdir}) { $self->{ramdisk}->{tmpdir} = tempdir( CLEANUP => 1 ); } my @cmd = ($self->{mount}, "-t", "tmpfs", "-o", "size=$self->{ramdisk}->{size}", "tmpfs", $self->{ramdisk}->{tmpdir}); INFO "Mounting ramdisk: @cmd"; my $rc = system( @cmd ); if($rc) { LOGWARN "Mount command '@cmd' failed: $?"; LOGWARN "Note that this only works on Linux and as root"; return; } $self->{ramdisk}->{mounted} = 1; return 1; } ########################################### sub ramdisk_unmount { ########################################### my($self) = @_; return if !exists $self->{ramdisk}->{mounted}; my @cmd = ($self->{umount}, $self->{ramdisk}->{tmpdir}); INFO "Unmounting ramdisk: @cmd"; my $rc = system( @cmd ); if($rc) { LOGWARN "Unmount command '@cmd' failed: $?"; return; } delete $self->{ramdisk}; return 1; } 1; __END__ =head1 NAME Archive::Tar::Wrapper - API wrapper around the 'tar' utility =head1 SYNOPSIS use Archive::Tar::Wrapper; my $arch = Archive::Tar::Wrapper->new(); # Open a tarball, expand it into a temporary directory $arch->read("archive.tgz"); # Iterate over all entries in the archive $arch->list_reset(); # Reset Iterator # Iterate through archive while(my $entry = $arch->list_next()) { my($tar_path, $phys_path) = @$entry; print "$tar_path\n"; } # Get a huge list with all entries for my $entry (@{$arch->list_all()}) { my($tar_path, $real_path) = @$entry; print "Tarpath: $tar_path Tempfile: $real_path\n"; } # Add a new entry $arch->add($logic_path, $file_or_stringref); # Remove an entry $arch->remove($logic_path); # Find the physical location of a temporary file my($tmp_path) = $arch->locate($tar_path); # Create a tarball $arch->write($tarfile, $compress); =head1 DESCRIPTION Archive::Tar::Wrapper is an API wrapper around the 'tar' command line utility. It never stores anything in memory, but works on temporary directory structures on disk instead. It provides a mapping between the logical paths in the tarball and the 'real' files in the temporary directory on disk. It differs from Archive::Tar in two ways: =over 4 =item * Archive::Tar::Wrapper doesn't hold anything in memory. Everything is stored on disk. =item * Archive::Tar::Wrapper is 100% compliant with the platform's C utility, because it uses it internally. =back =head1 METHODS =over 4 =item Bnew()> Constructor for the tar wrapper class. Finds the C executable by searching C and returning the first hit. In case you want to use a different tar executable, you can specify it as a parameter: my $arch = Archive::Tar::Wrapper->new(tar => '/path/to/tar'); Since C creates temporary directories to store tar data, the location of the temporary directory can be specified: my $arch = Archive::Tar::Wrapper->new(tmpdir => '/path/to/tmpdir'); Tremendous performance increases can be achieved if the temporary directory is located on a ram disk. Check the "Using RAM Disks" section below for details. Additional options can be passed to the C command by using the C and C parameters. Example: my $arch = Archive::Tar::Wrapper->new( tar_read_options => "p" ); will use C to extract the tarball instead of just C. Gnu tar supports even more options, these can be passed in via my $arch = Archive::Tar::Wrapper->new( tar_gnu_read_options => ["--numeric-owner"], ); By default, the C functions will return only file entries. Directories will be suppressed. To have C return directories as well, use my $arch = Archive::Tar::Wrapper->new( dirs => 1 ); If more files are added to a tarball than the command line can handle, C will switch from using the command tar cfv tarfile file1 file2 file3 ... to tar cfv tarfile -T filelist where C is a file containing all file to be added. The default for this switch is 512, but it can be changed by setting the parameter C: my $arch = Archive::Tar::Wrapper->new( max_cmd_line_args => 1024 ); =item B<$arch-Eread("archive.tgz")> C opens the given tarball, expands it into a temporary directory and returns 1 on success und C on failure. The temporary directory holding the tar data gets cleaned up when C<$arch> goes out of scope. C handles both compressed and uncompressed files. To find out if a file is compressed or uncompressed, it tries to guess by extension, then by checking the first couple of bytes in the tarfile. If only a limited number of files is needed from a tarball, they can be specified after the tarball name: $arch->read("archive.tgz", "path/file.dat", "path/sub/another.txt"); The file names are passed unmodified to the C command, make sure that the file paths match exactly what's in the tarball, otherwise C will fail. =item B<$arch-Elist_reset()> Resets the list iterator. To be used before the first call to B<$arch->list_next()>. =item Blist_next()> Returns the next item in the tarfile. It returns a list of three scalars: the relative path of the item in the tarfile, the physical path to the unpacked file or directory on disk, and the type of the entry (f=file, d=directory, l=symlink). Note that by default, Archive::Tar::Wrapper won't display directories, unless the C parameter is set when running the constructor. =item Blist_all()> Returns a reference to a (possibly huge) array of items in the tarfile. Each item is a reference to an array, containing two elements: the relative path of the item in the tarfile and the physical path to the unpacked file or directory on disk. To iterate over the list, the following construct can be used: # Get a huge list with all entries for my $entry (@{$arch->list_all()}) { my($tar_path, $real_path) = @$entry; print "Tarpath: $tar_path Tempfile: $real_path\n"; } If the list of items in the tarfile is big, use C and C instead of C. =item B<$arch-Eadd($logic_path, $file_or_stringref, [$options])> Add a new file to the tarball. C<$logic_path> is the virtual path of the file within the tarball. C<$file_or_stringref> is either a scalar, in which case it holds the physical path of a file on disk to be transferred (i.e. copied) to the tarball. Or it is a reference to a scalar, in which case its content is interpreted to be the data of the file. If no additional parameters are given, permissions and user/group id settings of a file to be added are copied. If you want different settings, specify them in the options hash: $arch->add($logic_path, $stringref, { perm => 0755, uid => 123, gid => 10 }); If $file_or_stringref is a reference to a Unicode string, the C option has to be set to make sure the string gets written as proper UTF-8 into the tarfile: $arch->add($logic_path, $stringref, { binmode => ":utf8" }); =item B<$arch-Eremove($logic_path)> Removes a file from the tarball. C<$logic_path> is the virtual path of the file within the tarball. =item B<$arch-Elocate($logic_path)> Finds the physical location of a file, specified by C<$logic_path>, which is the virtual path of the file within the tarball. Returns a path to the temporary file C created to manipulate the tarball on disk. =item B<$arch-Ewrite($tarfile, $compress)> Write out the tarball by tarring up all temporary files and directories and store it in C<$tarfile> on disk. If C<$compress> holds a true value, compression is used. =item B<$arch-Etardir()> Return the directory the tarball was unpacked in. This is sometimes useful to play dirty tricks on C by mass-manipulating unpacked files before wrapping them back up into the tarball. =item B<$arch-Eis_gnu()> Checks if the tar executable is a GNU tar by running 'tar --version' and parsing the output for "GNU". =back =head1 Using RAM Disks On Linux, it's quite easy to create a RAM disk and achieve tremendous speedups while untarring or modifying a tarball. You can either create the RAM disk by hand by running # mkdir -p /mnt/myramdisk # mount -t tmpfs -o size=20m tmpfs /mnt/myramdisk and then feeding the ramdisk as a temporary directory to Archive::Tar::Wrapper, like my $tar = Archive::Tar::Wrapper->new( tmpdir => '/mnt/myramdisk' ); or using Archive::Tar::Wrapper's built-in option 'ramdisk': my $tar = Archive::Tar::Wrapper->new( ramdisk => { type => 'tmpfs', size => '20m', # 20 MB }, ); Only drawback with the latter option is that creating the RAM disk needs to be performed as root, which often isn't desirable for security reasons. For this reason, Archive::Tar::Wrapper offers a utility functions that mounts the ramdisk and returns the temporary directory it's located in: # Create new ramdisk (as root): my $tmpdir = Archive::Tar::Wrapper->ramdisk_mount( type => 'tmpfs', size => '20m', # 20 MB ); # Delete a ramdisk (as root): Archive::Tar::Wrapper->ramdisk_unmount(); Optionally, the C command accepts a C parameter pointing to a temporary directory for the ramdisk if you wish to set it yourself instead of letting Archive::Tar::Wrapper create it automatically. =head1 KNOWN LIMITATIONS =over 4 =item * Currently, only C programs supporting the C option (for compressing/decompressing) are supported. Future version will use C alternatively. =item * Currently, you can't add empty directories to a tarball directly. You could add a temporary file within a directory, and then C the file. =item * If you delete a file, the empty directories it was located in stay in the tarball. You could try to C them and delete them. This will be fixed, though. =item * Filenames containing newlines are causing problems with the list iterators. To be fixed. =back =head1 BUGS Archive::Tar::Wrapper doesn't currently handle filenames with embedded newlines. =head1 LEGALESE Copyright 2005 by Mike Schilli, all rights reserved. This program is free software, you can redistribute it and/or modify it under the same terms as Perl itself. =head1 AUTHOR 2005, Mike Schilli Archive-Tar-Wrapper-0.18/MYMETA.json0000644000175000017500000000217112171157733017256 0ustar mschillimschilli{ "abstract" : "API wrapper around the 'tar' utility", "author" : [ "Mike Schilli " ], "dynamic_config" : 0, "generated_by" : "ExtUtils::MakeMaker version 6.62, CPAN::Meta::Converter version 2.120351", "license" : [ "unknown" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : "2" }, "name" : "Archive-Tar-Wrapper", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "runtime" : { "requires" : { "Cwd" : "0", "File::Temp" : "0", "File::Which" : "0", "IPC::Run" : "0", "Log::Log4perl" : "0" } } }, "release_status" : "stable", "resources" : { "repository" : { "url" : "http://github.com/mschilli/archive-tar-wrapper-perl" } }, "version" : "0.18" } Archive-Tar-Wrapper-0.18/Makefile.PL0000644000175000017500000000177612164231557017352 0ustar mschillimschilli###################################################################### # Makefile.PL for Archive::Tar::Wrapper # 2005, Mike Schilli ###################################################################### use ExtUtils::MakeMaker; my $meta_merge = { META_MERGE => { resources => { repository => 'http://github.com/mschilli/archive-tar-wrapper-perl', }, } }; WriteMakefile( 'NAME' => 'Archive::Tar::Wrapper', 'VERSION_FROM' => 'lib/Archive/Tar/Wrapper.pm', # finds $VERSION 'PREREQ_PM' => { File::Temp => 0, Cwd => 0, Log::Log4perl => 0, IPC::Run => 0, File::Which => 0, }, # e.g., Module::Name => 1.1 $ExtUtils::MakeMaker::VERSION >= 6.50 ? (%$meta_merge) : (), ($] >= 5.005 ? ## Add these new keywords supported since 5.005 (ABSTRACT_FROM => 'lib/Archive/Tar/Wrapper.pm', AUTHOR => 'Mike Schilli ') : ()), ); Archive-Tar-Wrapper-0.18/MANIFEST.SKIP0000644000175000017500000000012111331755637017262 0ustar mschillimschilliblib ^Makefile$ ^Makefile.old$ CVS .cvsignore docs MANIFEST.bak adm/release .git Archive-Tar-Wrapper-0.18/META.json0000664000175000017500000000217112171157733017012 0ustar mschillimschilli{ "abstract" : "API wrapper around the 'tar' utility", "author" : [ "Mike Schilli " ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 6.62, CPAN::Meta::Converter version 2.120351", "license" : [ "unknown" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : "2" }, "name" : "Archive-Tar-Wrapper", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "runtime" : { "requires" : { "Cwd" : "0", "File::Temp" : "0", "File::Which" : "0", "IPC::Run" : "0", "Log::Log4perl" : "0" } } }, "release_status" : "stable", "resources" : { "repository" : { "url" : "http://github.com/mschilli/archive-tar-wrapper-perl" } }, "version" : "0.18" } Archive-Tar-Wrapper-0.18/MANIFEST0000644000175000017500000000056312171157733016523 0ustar mschillimschilliChanges eg/tarflat lib/Archive/Tar/Wrapper.pm Makefile.PL MANIFEST This list of files MANIFEST.SKIP META.yml Module meta-data (added by MakeMaker) MYMETA.json MYMETA.yml README t/001Basic.t t/002Mult.t t/003Dirs.t t/004Utf8.t t/005Cwd.t t/006DirPerms.t t/data/bar.tar t/data/foo.tgz META.json Module JSON meta-data (added by MakeMaker) Archive-Tar-Wrapper-0.18/MYMETA.yml0000644000175000017500000000120512171157733017103 0ustar mschillimschilli--- abstract: "API wrapper around the 'tar' utility" author: - 'Mike Schilli ' build_requires: ExtUtils::MakeMaker: 0 configure_requires: ExtUtils::MakeMaker: 0 dynamic_config: 0 generated_by: 'ExtUtils::MakeMaker version 6.62, CPAN::Meta::Converter version 2.120351' license: unknown meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: 1.4 name: Archive-Tar-Wrapper no_index: directory: - t - inc requires: Cwd: 0 File::Temp: 0 File::Which: 0 IPC::Run: 0 Log::Log4perl: 0 resources: repository: http://github.com/mschilli/archive-tar-wrapper-perl version: 0.18 Archive-Tar-Wrapper-0.18/t/0000755000175000017500000000000012171157733015631 5ustar mschillimschilliArchive-Tar-Wrapper-0.18/t/001Basic.t0000644000175000017500000000710111331754526017257 0ustar mschillimschilli###################################################################### # Test suite for Archive::Tar::Wrapper # by Mike Schilli ###################################################################### use warnings; use strict; use Log::Log4perl qw(:easy); Log::Log4perl->easy_init($ERROR); use File::Temp qw(tempfile); my $TARDIR = "data"; $TARDIR = "t/$TARDIR" unless -d $TARDIR; use Test::More tests => 23; BEGIN { use_ok('Archive::Tar::Wrapper') }; umask(0); my $arch = Archive::Tar::Wrapper->new(); ok($arch->read("$TARDIR/foo.tgz"), "opening compressed tarfile"); ok($arch->locate("001Basic.t"), "find 001Basic.t"); ok($arch->locate("./001Basic.t"), "find ./001Basic.t"); ok(!$arch->locate("nonexist"), "find nonexist"); # Add a new file my $tmploc = $arch->locate("001Basic.t"); ok($arch->add("foo/bar/baz", $tmploc), "adding file"); # Add data my $data = "this is data"; ok($arch->add("foo/bar/string", \$data), "adding data"); ok($arch->locate("foo/bar/baz"), "find added file"); ok($arch->add("foo/bar/permtest", $tmploc, {perm => 0770}), "adding file"); # Make a tarball my($fh, $filename) = tempfile(UNLINK => 1); ok($arch->write($filename), "Tarring up"); # List my $a2 = Archive::Tar::Wrapper->new(); ok($a2->read($filename), "Reading in new tarball"); my $elements = $a2->list_all(); my $got = join " ", sort map { $_->[0] } @$elements; is($got, "001Basic.t foo/bar/baz foo/bar/permtest foo/bar/string", "Check list"); my $f1 = $a2->locate("001Basic.t"); my $f2 = $a2->locate("foo/bar/baz"); ok(-s $f1 > 0, "Checking tarball files sizes"); ok(-s $f2 > 0, "Checking tarball files sizes"); is(-s $f1, -s $f2, "Comparing tarball files sizes"); my $f3 = $a2->locate("foo/bar/permtest"); my $perm = ((stat($f3))[2] & 07777); is($perm, 0770, "permtest"); my $f4 = $a2->locate("foo/bar/string"); open FILE, "<$f4" or die "Cannot open $f4"; my $got_data = join '', ; close FILE; is($got_data, $data, "comparing file data"); # Iterators $arch->list_reset(); my @elements = (); while(my $entry = $arch->list_next()) { push @elements, $entry->[0]; } $got = join " ", sort @elements; is($got, "001Basic.t foo/bar/baz foo/bar/permtest foo/bar/string", "Check list"); # Check optional file names for extraction #data/bar.tar #drwxrwxr-x mschilli/mschilli 0 2005-07-24 12:15:34 bar/ #-rw-rw-r-- mschilli/mschilli 11 2005-07-24 12:15:27 bar/bar.dat #-rw-rw-r-- mschilli/mschilli 11 2005-07-24 12:15:34 bar/foo.dat my $a3 = Archive::Tar::Wrapper->new(); $a3->read("$TARDIR/bar.tar", "bar/bar.dat"); $elements = $a3->list_all(); is(scalar @$elements, 1, "only one file extracted"); is($elements->[0]->[0], "bar/bar.dat", "only one file extracted"); # Ask for non-existent files in tarball my $a4 = Archive::Tar::Wrapper->new(); # Suppress the warning Log::Log4perl->get_logger("")->level($FATAL); my $rc; SKIP: { $rc = $a4->read("$TARDIR/bar.tar", "bar/bar.dat", "quack/schmack"); if($^O =~ /freebsd/i) { skip("FreeBSD's tar is too lenient - skipping", 1); } is($rc, undef, "Failure to ask for non-existent files"); } # Permissions umask(022); my $a5 = Archive::Tar::Wrapper->new( tar_read_options => "p", ); $a5->read("$TARDIR/bar.tar"); $f1 = $a5->locate("bar/bar.dat"); $perm = ((stat($f1))[2] & 07777); is($perm, 0664, "permtest"); SKIP: { # gnu options my $a6 = Archive::Tar::Wrapper->new( tar_gnu_read_options => ["--numeric-owner"], ); skip "Only with gnu tar", 1 unless $a6->is_gnu(); $a6->read("$TARDIR/bar.tar"); $f1 = $a6->locate("bar/bar.dat"); ok(defined $f1, "numeric owner works"); } Archive-Tar-Wrapper-0.18/t/006DirPerms.t0000644000175000017500000000213011732231732017757 0ustar mschillimschilli###################################################################### # Test suite for Archive::Tar::Wrapper # by Mike Schilli ###################################################################### use warnings; use strict; use Log::Log4perl qw(:easy); Log::Log4perl->easy_init($ERROR); use File::Temp qw(tempfile tempdir); my $TARDIR = "data"; $TARDIR = "t/$TARDIR" unless -d $TARDIR; use Test::More tests => 4; BEGIN { use_ok('Archive::Tar::Wrapper') }; my $arch = Archive::Tar::Wrapper->new(); my $tempdir = tempdir( CLEANUP => 1 ); my($fh, $tarfile) = tempfile(UNLINK => 1); my $foodir = "$tempdir/foo"; my $foofile = "$foodir/foofile"; mkdir "$foodir"; chmod 0710, $foodir; open FILE, ">$foofile" or die "Cannot open $foofile ($!)"; print FILE "blech\n"; close FILE; ok($arch->add("foo/foofile", $foofile), "adding file"); # Make a tarball ok($arch->write($tarfile), "Tarring up"); my $tarread = Archive::Tar::Wrapper->new(); $tarread->read( $tarfile ); my $loc = $tarread->locate( "foo" ); my $mode = (stat $loc)[2] & 07777; is $mode, 0710, "check dir mode"; Archive-Tar-Wrapper-0.18/t/002Mult.t0000644000175000017500000000206312171157172017157 0ustar mschillimschilli###################################################################### # Test suite for Archive::Tar::Wrapper # by Mike Schilli ###################################################################### use warnings; use strict; use Log::Log4perl qw(:easy); use File::Path; use File::Temp qw(tempfile tempdir); my $TARDIR = "data"; $TARDIR = "t/$TARDIR" unless -d $TARDIR; my $TMPDIR = tempdir( CLEANUP => 1 ); use Test::More tests => 5; BEGIN { use_ok('Archive::Tar::Wrapper') }; my $arch = Archive::Tar::Wrapper->new(tmpdir => $TMPDIR); ok($arch->read("$TARDIR/foo.tgz"), "opening compressed tarfile"); ok($arch->read("$TARDIR/bar.tar"), "opening uncompressed"); my $elements = $arch->list_all(); my $got = join " ", sort map { $_->[0] } @$elements; is($got, "001Basic.t bar/bar.dat bar/foo.dat", "file check"); # Iterators $arch->list_reset(); my @elements = (); while(my $entry = $arch->list_next()) { push @elements, $entry->[0]; } $got = join " ", sort @elements; is($got, "001Basic.t bar/bar.dat bar/foo.dat", "file check via iterator"); Archive-Tar-Wrapper-0.18/t/005Cwd.t0000644000175000017500000000135611674305553016767 0ustar mschillimschilli###################################################################### # Test suite for Archive::Tar::Wrapper # by Mike Schilli ###################################################################### use warnings; use strict; use File::Temp qw(tempfile); use Cwd; use Test::More tests => 4; BEGIN { use_ok('Archive::Tar::Wrapper') }; my $cwd = getcwd(); my $evaled = eval { my $arch = Archive::Tar::Wrapper->new(); my(undef, $filename) = tempfile(UNLINK => 1); unlink $filename; # OPEN => 0 gave a stupid warning # attempt to generate error from tar by not adding any files $arch->write($filename, 9); 1; }; is $@, '', 'no error'; is $evaled, 1, 'survived eval'; is getcwd(), $cwd, 'still in original directory'; Archive-Tar-Wrapper-0.18/t/003Dirs.t0000644000175000017500000000170512171157256017145 0ustar mschillimschilli###################################################################### # Test suite for Archive::Tar::Wrapper # by Mike Schilli ###################################################################### use warnings; use strict; use Log::Log4perl qw(:easy); use File::Path; use File::Temp qw(tempfile tempdir); my $TARDIR = "data"; $TARDIR = "t/$TARDIR" unless -d $TARDIR; my $TMPDIR = tempdir( CLEANUP => 1 ); use Test::More tests => 4; BEGIN { use_ok('Archive::Tar::Wrapper') }; rmdir $TMPDIR if -d $TMPDIR; mkdir $TMPDIR or die "Cannot mkdir $TMPDIR"; END { rmtree $TMPDIR } my $arch = Archive::Tar::Wrapper->new(tmpdir => $TMPDIR, dirs => 1); ok($arch->read("$TARDIR/bar.tar"), "opening compressed tarfile"); my $e = $arch->list_all(); my $all = join " ", sort(map { $_->[0] } @$e); is($all, ". bar bar/bar.dat bar/foo.dat", "list all dirs"); my @dirs = map { $_->[0] } grep { $_->[2] eq "d" } @$e; is("@dirs", ". bar", "dirs only"); Archive-Tar-Wrapper-0.18/t/data/0000755000175000017500000000000012171157733016542 5ustar mschillimschilliArchive-Tar-Wrapper-0.18/t/data/bar.tar0000644000175000017500000002400011331752614020006 0ustar mschillimschillibar/0040775000076400007640000000000010270764326012041 5ustar mschillimschillibar/bar.dat0100664000076400007640000000001310270764317013266 0ustar mschillimschillibarcontent bar/foo.dat0100664000076400007640000000001310270764326013305 0ustar mschillimschillifoocontent Archive-Tar-Wrapper-0.18/t/data/foo.tgz0000644000175000017500000000053011331752614020045 0ustar mschillimschilliZBj@ eb؆V*Rҥajss&HwEt-[$.91,zs6gl{=/1bh! b;җB9^Ur?IMKS)U!%tm$s9"ϥfj-qMr^ZHe {QFVT+3LUTيs{ ifnX]T^v2~D=fg4[Hmq<=;"[{hwîc~^9:޻nʭgufLƦz)tW_ (Archive-Tar-Wrapper-0.18/t/004Utf8.t0000644000175000017500000000242711331752614017071 0ustar mschillimschilli###################################################################### # Test suite for Archive::Tar::Wrapper # by Mike Schilli ###################################################################### use warnings; use strict; use Log::Log4perl qw(:easy); Log::Log4perl->easy_init($ERROR); use File::Temp qw(tempfile); my $TARDIR = "data"; $TARDIR = "t/$TARDIR" unless -d $TARDIR; use Test::More tests => 6; BEGIN { use_ok('Archive::Tar::Wrapper') }; SKIP: { if($] < 5.008) { skip "Unicode tests skipped with perl < 5.8", 5; } umask(0); my $arch = Archive::Tar::Wrapper->new(); ok($arch->read("$TARDIR/foo.tgz"), "opening compressed tarfile"); # Add data my $data = "this is data \x{00fc}"; ok($arch->add("foo/bar/string", \$data, {binmode => ":utf8"}), "adding data"); # Make a tarball my($fh, $filename) = tempfile(UNLINK => 1); ok($arch->write($filename), "Tarring up"); # List my $a2 = Archive::Tar::Wrapper->new(); ok($a2->read($filename), "Reading in new tarball"); my $f1 = $a2->locate("foo/bar/string"); open FILE, "<:utf8", $f1 or die "Cannot open $f1"; my $got_data = join '', ; close FILE; is($got_data, $data, "comparing file utf8 data"); } Archive-Tar-Wrapper-0.18/Changes0000644000175000017500000000523312171157354016663 0ustar mschillimschilli###################################################################### Revision history for Perl extension Archive::Tar::Wrapper 0.18 (2013/07/15) (ms) Moved to tmpdir() in t/002Mult.t because some smoke testers don't like writing into t/data. 0.17 (2013/07/01) (ms) Sanko Robinson replaced bin_find() by File::Which::which() to allow for better Win32 portability. 0.16 (2012/03/19) (ms) [rt.cpan.org 75770] Allow add() with directories, and now preserves directory permissions. 0.15 (2011/12/20) (ms) [RT 73046] Randy Stauner submitted a patch to reset the directory if a write() fails (e.g. because no files have been added). https://github.com/mschilli/archive-tar-wrapper-perl/pull/1 0.14 (2011/02/12) (ms) Added 'ramdisk' feature for Linux (ms) More search paths for 'tar' 0.13 2010/02/01 (ms) Added GNU tar check is_gnu() (ms) Added tar_gnu_read_options to specify options like --numeric-owner 0.12 2008/07/03 (ms) Applied modified patch by Daniel Barthel to enable more files added to a tarball than there are allowed on the command line. 0.11 2008/03/09 (ms) Skipping one test case for FreeBSD's tar, which does not complain if asked to extract non-existent files. 0.10 2007/07/21 (ms) Skipping unicode tests for perl < 5.8 0.09 2007/07/20 (ms) Added utf8 support in add($dataref) (ms) Fixed bug in add($ref) for adding string data, patch submitted by Karthik Joshi. (ms) Changed tempfile CLEANUP to UNLINK in test suite 0.08 2006/08/21 (ms) Added tardir() method to obtain the directory the tarball was unpacked in. 0.07 2006/04/02 (ms) Fixed list_all() to return a ref to an array of arrayrefs, as explained in the docs. (ms) Added "dirs" option to list directories as well. 0.06 2005/09/22 (ms) Fixed logging message in tar->read(). (ms) Additional options can be passed to tar (tar_read/write_options) (ms) failed read() no longer chdirs out of the current directory (ms) Fixed test suite for different umasks 0.05 2005/09/10 (ms) 'tar' is now running via IPC::Run (ms) read() takes an optional list of files to save space in case only a limited number of files is needed from the tarball. 0.04 2005/07/24 (ms) Added eg/tarflat and more test cases 0.03 2005/05/23 (ms) tarup() no longer uses "." as a directory, but globs for all top-level entries (ms) critical fix for location of tarred files (ms) tmp dir cleanup now handled manually to avoid File::Temp warnings 0.02 2005/04/20 (ms) Added lots of documentation. 0.01 2005/04/10 (ms) Where it all began. Archive-Tar-Wrapper-0.18/README0000644000175000017500000002532412171157732016253 0ustar mschillimschilli###################################################################### Archive::Tar::Wrapper 0.18 ###################################################################### NAME Archive::Tar::Wrapper - API wrapper around the 'tar' utility SYNOPSIS use Archive::Tar::Wrapper; my $arch = Archive::Tar::Wrapper->new(); # Open a tarball, expand it into a temporary directory $arch->read("archive.tgz"); # Iterate over all entries in the archive $arch->list_reset(); # Reset Iterator # Iterate through archive while(my $entry = $arch->list_next()) { my($tar_path, $phys_path) = @$entry; print "$tar_path\n"; } # Get a huge list with all entries for my $entry (@{$arch->list_all()}) { my($tar_path, $real_path) = @$entry; print "Tarpath: $tar_path Tempfile: $real_path\n"; } # Add a new entry $arch->add($logic_path, $file_or_stringref); # Remove an entry $arch->remove($logic_path); # Find the physical location of a temporary file my($tmp_path) = $arch->locate($tar_path); # Create a tarball $arch->write($tarfile, $compress); DESCRIPTION Archive::Tar::Wrapper is an API wrapper around the 'tar' command line utility. It never stores anything in memory, but works on temporary directory structures on disk instead. It provides a mapping between the logical paths in the tarball and the 'real' files in the temporary directory on disk. It differs from Archive::Tar in two ways: * Archive::Tar::Wrapper doesn't hold anything in memory. Everything is stored on disk. * Archive::Tar::Wrapper is 100% compliant with the platform's "tar" utility, because it uses it internally. METHODS my $arch = Archive::Tar::Wrapper->new() Constructor for the tar wrapper class. Finds the "tar" executable by searching "PATH" and returning the first hit. In case you want to use a different tar executable, you can specify it as a parameter: my $arch = Archive::Tar::Wrapper->new(tar => '/path/to/tar'); Since "Archive::Tar::Wrapper" creates temporary directories to store tar data, the location of the temporary directory can be specified: my $arch = Archive::Tar::Wrapper->new(tmpdir => '/path/to/tmpdir'); Tremendous performance increases can be achieved if the temporary directory is located on a ram disk. Check the "Using RAM Disks" section below for details. Additional options can be passed to the "tar" command by using the "tar_read_options" and "tar_write_options" parameters. Example: my $arch = Archive::Tar::Wrapper->new( tar_read_options => "p" ); will use "tar xfp archive.tgz" to extract the tarball instead of just "tar xf archive.tgz". Gnu tar supports even more options, these can be passed in via my $arch = Archive::Tar::Wrapper->new( tar_gnu_read_options => ["--numeric-owner"], ); By default, the "list_*()" functions will return only file entries. Directories will be suppressed. To have "list_*()" return directories as well, use my $arch = Archive::Tar::Wrapper->new( dirs => 1 ); If more files are added to a tarball than the command line can handle, "Archive::Tar::Wrapper" will switch from using the command tar cfv tarfile file1 file2 file3 ... to tar cfv tarfile -T filelist where "filelist" is a file containing all file to be added. The default for this switch is 512, but it can be changed by setting the parameter "max_cmd_line_args": my $arch = Archive::Tar::Wrapper->new( max_cmd_line_args => 1024 ); $arch->read("archive.tgz") "read()" opens the given tarball, expands it into a temporary directory and returns 1 on success und "undef" on failure. The temporary directory holding the tar data gets cleaned up when $arch goes out of scope. "read" handles both compressed and uncompressed files. To find out if a file is compressed or uncompressed, it tries to guess by extension, then by checking the first couple of bytes in the tarfile. If only a limited number of files is needed from a tarball, they can be specified after the tarball name: $arch->read("archive.tgz", "path/file.dat", "path/sub/another.txt"); The file names are passed unmodified to the "tar" command, make sure that the file paths match exactly what's in the tarball, otherwise "read()" will fail. $arch->list_reset() Resets the list iterator. To be used before the first call to $arch-list_next()>. my($tar_path, $phys_path, $type) = $arch->list_next() Returns the next item in the tarfile. It returns a list of three scalars: the relative path of the item in the tarfile, the physical path to the unpacked file or directory on disk, and the type of the entry (f=file, d=directory, l=symlink). Note that by default, Archive::Tar::Wrapper won't display directories, unless the "dirs" parameter is set when running the constructor. my $items = $arch->list_all() Returns a reference to a (possibly huge) array of items in the tarfile. Each item is a reference to an array, containing two elements: the relative path of the item in the tarfile and the physical path to the unpacked file or directory on disk. To iterate over the list, the following construct can be used: # Get a huge list with all entries for my $entry (@{$arch->list_all()}) { my($tar_path, $real_path) = @$entry; print "Tarpath: $tar_path Tempfile: $real_path\n"; } If the list of items in the tarfile is big, use "list_reset()" and "list_next()" instead of "list_all". $arch->add($logic_path, $file_or_stringref, [$options]) Add a new file to the tarball. $logic_path is the virtual path of the file within the tarball. $file_or_stringref is either a scalar, in which case it holds the physical path of a file on disk to be transferred (i.e. copied) to the tarball. Or it is a reference to a scalar, in which case its content is interpreted to be the data of the file. If no additional parameters are given, permissions and user/group id settings of a file to be added are copied. If you want different settings, specify them in the options hash: $arch->add($logic_path, $stringref, { perm => 0755, uid => 123, gid => 10 }); If $file_or_stringref is a reference to a Unicode string, the "binmode" option has to be set to make sure the string gets written as proper UTF-8 into the tarfile: $arch->add($logic_path, $stringref, { binmode => ":utf8" }); $arch->remove($logic_path) Removes a file from the tarball. $logic_path is the virtual path of the file within the tarball. $arch->locate($logic_path) Finds the physical location of a file, specified by $logic_path, which is the virtual path of the file within the tarball. Returns a path to the temporary file "Archive::Tar::Wrapper" created to manipulate the tarball on disk. $arch->write($tarfile, $compress) Write out the tarball by tarring up all temporary files and directories and store it in $tarfile on disk. If $compress holds a true value, compression is used. $arch->tardir() Return the directory the tarball was unpacked in. This is sometimes useful to play dirty tricks on "Archive::Tar::Wrapper" by mass-manipulating unpacked files before wrapping them back up into the tarball. $arch->is_gnu() Checks if the tar executable is a GNU tar by running 'tar --version' and parsing the output for "GNU". Using RAM Disks On Linux, it's quite easy to create a RAM disk and achieve tremendous speedups while untarring or modifying a tarball. You can either create the RAM disk by hand by running # mkdir -p /mnt/myramdisk # mount -t tmpfs -o size=20m tmpfs /mnt/myramdisk and then feeding the ramdisk as a temporary directory to Archive::Tar::Wrapper, like my $tar = Archive::Tar::Wrapper->new( tmpdir => '/mnt/myramdisk' ); or using Archive::Tar::Wrapper's built-in option 'ramdisk': my $tar = Archive::Tar::Wrapper->new( ramdisk => { type => 'tmpfs', size => '20m', # 20 MB }, ); Only drawback with the latter option is that creating the RAM disk needs to be performed as root, which often isn't desirable for security reasons. For this reason, Archive::Tar::Wrapper offers a utility functions that mounts the ramdisk and returns the temporary directory it's located in: # Create new ramdisk (as root): my $tmpdir = Archive::Tar::Wrapper->ramdisk_mount( type => 'tmpfs', size => '20m', # 20 MB ); # Delete a ramdisk (as root): Archive::Tar::Wrapper->ramdisk_unmount(); Optionally, the "ramdisk_mount()" command accepts a "tmpdir" parameter pointing to a temporary directory for the ramdisk if you wish to set it yourself instead of letting Archive::Tar::Wrapper create it automatically. KNOWN LIMITATIONS * Currently, only "tar" programs supporting the "z" option (for compressing/decompressing) are supported. Future version will use "gzip" alternatively. * Currently, you can't add empty directories to a tarball directly. You could add a temporary file within a directory, and then "remove()" the file. * If you delete a file, the empty directories it was located in stay in the tarball. You could try to "locate()" them and delete them. This will be fixed, though. * Filenames containing newlines are causing problems with the list iterators. To be fixed. BUGS Archive::Tar::Wrapper doesn't currently handle filenames with embedded newlines. LEGALESE Copyright 2005 by Mike Schilli, all rights reserved. This program is free software, you can redistribute it and/or modify it under the same terms as Perl itself. AUTHOR 2005, Mike Schilli Archive-Tar-Wrapper-0.18/META.yml0000664000175000017500000000120512171157733016637 0ustar mschillimschilli--- abstract: "API wrapper around the 'tar' utility" author: - 'Mike Schilli ' build_requires: ExtUtils::MakeMaker: 0 configure_requires: ExtUtils::MakeMaker: 0 dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 6.62, CPAN::Meta::Converter version 2.120351' license: unknown meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: 1.4 name: Archive-Tar-Wrapper no_index: directory: - t - inc requires: Cwd: 0 File::Temp: 0 File::Which: 0 IPC::Run: 0 Log::Log4perl: 0 resources: repository: http://github.com/mschilli/archive-tar-wrapper-perl version: 0.18