Archive-Ar
view release on metacpan or search on metacpan
my $ar = Archive::Ar->new;
$ar->read('./foo.ar');
$ar->extract;
$ar->add_files('./bar.tar.gz', 'bat.pl')
$ar->add_data('newfile.txt','Some contents');
$ar->chmod('file1', 0644);
$ar->chown('file1', $uid, $gid);
$ar->remove('file1', 'file2');
my $filehash = $ar->get_content('bar.tar.gz');
my $data = $ar->get_data('bar.tar.gz');
my $handle = $ar->get_handle('bar.tar.gz');
my @files = $ar->list_files();
my $archive = $ar->write;
lib/Archive/Ar.pm view on Meta::CPAN
my $filename = shift;
my $target = shift || $filename;
my $meta = $self->{files}->{$filename};
return $self->_error("$filename: not in archive") unless $meta;
open my $fh, '>', $target or return $self->_error("$target: $!");
binmode $fh;
syswrite $fh, $meta->{data} or return $self->_error("$filename: $!");
close $fh or return $self->_error("$filename: $!");
if (CAN_CHOWN && $self->{opts}->{chown}) {
chown $meta->{uid}, $meta->{gid}, $filename or
return $self->_error("$filename: $!");
}
if ($self->{opts}->{chmod}) {
my $mode = $meta->{mode};
unless ($self->{opts}->{same_perms}) {
$mode &= ~(oct(7000) | (umask | 0));
}
chmod $mode, $filename or return $self->_error("$filename: $!");
}
utime $meta->{date}, $meta->{date}, $filename or
lib/Archive/Ar.pm view on Meta::CPAN
return unless $self->{files}->{$filename};
$self->{files}->{$filename}->{mode} =
$mode + 0 eq $mode ? $mode : oct($mode);
return 1;
}
sub chown {
my $self = shift;
my $filename = shift;
my $uid = shift;
my $gid = shift;
return unless $self->{files}->{$filename};
$self->{files}->{$filename}->{uid} = $uid if $uid >= 0;
$self->{files}->{$filename}->{gid} = $gid if defined $gid && $gid >= 0;
return 1;
}
sub remove {
my $self = shift;
my $files = ref $_[0] ? shift : \@_;
my $nfiles_orig = scalar @{$self->{names}};
for my $file (@$files) {
lib/Archive/Ar.pm view on Meta::CPAN
my $content = shift;
my $params = shift || {};
return $self->_error("No filename given") unless $path;
my $filename = (File::Spec->splitpath($path))[2];
$self->_add_data($filename, $content,
$params->{date} || timelocal(localtime()),
$params->{uid} || 0,
$params->{gid} || 0,
$params->{mode} || 0100644) or return;
return $self->{files}->{$filename}->{size};
}
sub write {
my $self = shift;
my $filename = shift;
my $opts = {(%{$self->{opts}}, %{shift || {}})};
my $type = $opts->{type} || $self->{type} || COMMON;
lib/Archive/Ar.pm view on Meta::CPAN
if ($type eq GNU) {
$fn = '' if defined $opts->{symbols} && $fn eq $opts->{symbols};
$name = $fn . '/';
}
else {
$name = $fn;
}
if (length($name) <= 16 || $type eq COMMON) {
push @body, pack('A16A12A6A6A8A10A2', $name,
@$meta{qw/date uid gid/}, $mode, $size, ARFMAG);
}
elsif ($type eq GNU) {
push @body, pack('A1A15A12A6A6A8A10A2', '/', $gnuindex{$fn},
@$meta{qw/date uid gid/}, $mode, $size, ARFMAG);
}
elsif ($type eq BSD) {
$size += length($name);
push @body, pack('A3A13A12A6A6A8A10A2', AR_EFMT1, length($name),
@$meta{qw/date uid gid/}, $mode, $size, ARFMAG),
$name;
}
else {
return $self->_error("$type: unexpected ar type");
}
push @body, $meta->{data};
push @body, "\n" if $size % 2; # padding
}
if ($filename) {
my $fh = $self->_get_handle($filename, '>');
lib/Archive/Ar.pm view on Meta::CPAN
sub _parse {
my $self = shift;
my $data = shift;
unless (substr($data, 0, SARMAG, '') eq ARMAG) {
return $self->_error("Bad magic number - not an ar archive");
}
my $type;
my $names;
while ($data =~ /\S/) {
my ($name, $date, $uid, $gid, $mode, $size, $magic) =
unpack('A16A12A6A6A8A10a2', substr($data, 0, 60, ''));
unless ($magic eq "`\n") {
return $self->_error("Bad file header");
}
if ($name =~ m|^/|) {
$type = GNU;
if ($name eq '//') {
$names = substr($data, 0, $size, '');
substr($data, 0, $size % 2, '');
next;
lib/Archive/Ar.pm view on Meta::CPAN
$name = substr($data, 0, int(substr($name, 3)), '');
$size -= length($name);
}
else {
if ($name =~ m|/$|) {
$type ||= GNU; # only gnu has trailing slashes
chop $name;
}
}
$uid = int($uid);
$gid = int($gid);
$mode = oct($mode);
my $content = substr($data, 0, $size, '');
substr($data, 0, $size % 2, '');
$self->_add_data($name, $content, $date, $uid, $gid, $mode, $size);
}
$self->{type} = $type || COMMON;
return scalar @{$self->{names}};
}
sub _add_data {
my $self = shift;
my $filename = shift;
my $content = shift || '';
my $date = shift;
my $uid = shift;
my $gid = shift;
my $mode = shift;
my $size = shift;
if (exists($self->{files}->{$filename})) {
return $self->_error("$filename: entry already exists");
}
$self->{files}->{$filename} = {
name => $filename,
date => defined $date ? $date : timelocal(localtime()),
uid => defined $uid ? $uid : 0,
gid => defined $gid ? $gid : 0,
mode => defined $mode ? $mode : 0100644,
size => defined $size ? $size : length($content),
data => $content,
};
push @{$self->{names}}, $filename;
return 1;
}
sub _get_handle {
my $self = shift;
lib/Archive/Ar.pm view on Meta::CPAN
my $ar = Archive::Ar->new;
$ar->read('./foo.ar');
$ar->extract;
$ar->add_files('./bar.tar.gz', 'bat.pl')
$ar->add_data('newfile.txt','Some contents');
$ar->chmod('file1', 0644);
$ar->chown('file1', $uid, $gid);
$ar->remove('file1', 'file2');
my $filehash = $ar->get_content('bar.tar.gz');
my $data = $ar->get_data('bar.tar.gz');
my $handle = $ar->get_handle('bar.tar.gz');
my @files = $ar->list_files();
my $archive = $ar->write;
lib/Archive/Ar.pm view on Meta::CPAN
Changes the name of a file in the in-memory archive.
=head2 chmod
$ar->chmod($filename, $mode);
Change the mode of the member to C<$mode>.
=head2 chown
$ar->chown($filename, $uid, $gid);
$ar->chown($filename, $uid);
Change the ownership of the member to user id C<$uid> and (optionally)
group id C<$gid>. Negative id values are ignored.
=head2 remove
$ar->remove(@filenames)
$ar->remove($arrayref)
Removes files from the in-memory archive. Returns the number of files
removed.
=head2 list_files
lib/Archive/Ar.pm view on Meta::CPAN
Returns a list of the names of all the files in the archive.
If called in a scalar context, returns a reference to an array.
=head2 add_files
$ar->add_files(@filenames)
$ar->add_files($arrayref)
Adds files to the archive. The arguments can be paths, but only the
filenames are stored in the archive. Stores the uid, gid, mode, size,
and modification timestamp of the file as returned by C<stat()>.
Returns the number of files successfully added, or undef if failure.
=head2 add_data
$ar->add_data("filename", $data)
$ar->add_data("filename", $data, $options)
Adds a file to the in-memory archive with name $filename and content
$data. File properties can be set with $optional_hashref:
$options = {
'data' => $data,
'uid' => $uid, #defaults to zero
'gid' => $gid, #defaults to zero
'date' => $date, #date in epoch seconds. Defaults to now.
'mode' => $mode, #defaults to 0100644;
}
You cannot add_data over another file however. This returns the file length in
bytes if it is successful, undef otherwise.
=head2 write
$data = $ar->write()
lib/Archive/Ar.pm view on Meta::CPAN
$content = $ar->get_content($filename)
This returns a hash with the file content in it, including the data
that the file would contain. If the file does not exist or no filename
is given, this returns undef. On success, a hash is returned:
$content = {
'name' => $filename,
'date' => $mtime,
'uid' => $uid,
'gid' => $gid,
'mode' => $mode,
'size' => $size,
'data' => $file_contents,
}
=head2 get_data
$data = $ar->get_data("filename")
Returns a scalar containing the file data of the given archive
t/20_add_data.t view on Meta::CPAN
my $ar = Archive::Ar->new;
is $ar->add_data("1", 'one'), 3, 'add_data';
is $ar->add_data("foo.txt", 'bar'), 3, 'add_data';
is $ar->add_data("2", 'two'), 3, 'add_data';
my $data = $ar->get_content('foo.txt');
is $data->{name}, 'foo.txt', 'name';
like $data->{date}, qr{^[1-9]\d*$}, 'date';
is $data->{uid}, 0, 'uid';
is $data->{gid}, 0, 'gid';
is $data->{mode}, 0100644, 'mode';
is $data->{data}, 'bar', 'data';
is $data->{size}, 3, 'size';
is $ar->get_content('goose'), undef, 'not found';
};
subtest 'non default values' => sub {
my $ar = Archive::Ar->new;
is $ar->add_data("1", 'one'), 3, 'add_data';
is $ar->add_data("foo.txt", 'barbaz', {
uid => 101,
gid => 201,
mode => 0644,
}), 6, 'add_data';
is $ar->add_data("2", 'two'), 3, 'add_data';
my $data = $ar->get_content('foo.txt');
is $data->{name}, 'foo.txt', 'name';
like $data->{date}, qr{^[1-9]\d*$}, 'date';
is $data->{uid}, 101, 'uid';
is $data->{gid}, 201, 'gid';
is $data->{mode}, 0644, 'mode';
is $data->{data}, 'barbaz', 'data';
is $data->{size}, 6, 'size';
is $ar->get_content('goose'), undef, 'not found';
};
t/40_mode.t view on Meta::CPAN
print $fh $content;
close $fh;
my $ar = Archive::Ar->new($file);
isa_ok $ar, 'Archive::Ar', 'object';
is_deeply [$ar->list_files], [qw(odd even)], 'list_files';
my $filedata = $ar->get_content('odd');
is $filedata->{name}, 'odd', 'file1, filedata/name';
is $filedata->{uid}, 2202, 'file1, filedata/uid';
is $filedata->{gid}, 2988, 'file1, filedata/gid';
is $filedata->{mode}, 0100644, 'file1, filedata/mode';
is $filedata->{date}, 1255532835, 'file1, filedata/date';
is $filedata->{size}, 11, 'file1, filedata/size';
is $filedata->{data}, "oddcontent\n", 'file1, filedata/data';
$filedata = $ar->get_content('even');
is $filedata->{name}, 'even', 'file2, filedata/name';
is $filedata->{uid}, 2202, 'file2, filedata/uid';
is $filedata->{gid}, 2988, 'file2, filedata/gid';
is $filedata->{mode}, 0100644, 'file2, filedata/mode';
is $filedata->{date}, 1255532831, 'file2, filedata/date';
is $filedata->{size}, 12, 'file2, filedata/size';
is $filedata->{data}, "evencontent\n", 'file2, filedata/data';
my ($nfh, $nfile) = tempfile(UNLINK => 1);
my $size = $ar->write($nfh);
is $size, 152, 'write size';
close $nfh;
( run in 0.562 second using v1.01-cache-2.11-cpan-ceb78f64989 )