Archive-Libarchive
view release on metacpan or search on metacpan
lib/Archive/Libarchive.pm view on Meta::CPAN
# archive_version_number
my $int = archive_version_number();
The C<libarchive> version expressed as an integer. This will be the major, minor and patch
levels each using up to three digits, so 3.5.1 will be C<3005001>.
=head2 archive_version_string
# archive_version_string
my $string = archive_version_string();
The C<libarchive> version as a string.
=head2 archive_zlib_version
# archive_zlib_version
my $string = archive_zlib_version();
The C<zlib> version that C<libarchive> was built with. This will return C<undef> if the library was
not found at build time.
=head2 versions
my %versions = Archive::Libarchive->versions();
This returns a hash of C<libarchive> and L<Archive::Libarchive> versions and dependency versions. This
may be useful in a test report diagnostic.
=head1 EXAMPLES
These examples are translated from the C<libarchive> C examples, which can be found here:
=over 4
=item L<https://github.com/libarchive/libarchive/wiki/Examples>
=back
=head2 List contents of archive stored in file
The main L<Archive::Libarchive> API is based around two basic type of classes. The L<Archive::Libarchive::Archive>
class serves as a basis for all archive objects. The L<Archive::Libarchive::Entry> represents the header or metadata
for files stored inside an archive (or as we will see later, files on disk).
The basic life cycle of an archive instance is:
=over 4
=item Create one using its C<new> constructor
The constructor does not take any arguments, instead you will configure it in the
next step.
=item Configure it using "support" or "set" calls
Support calls allow L<Archive::Libarchive> to decide when to use a feature; "set" calls
enable the feature unconditionally.
=item "Open" a particular data source
This can be using callbacks for a custom source, or one of the pre-canned data sources supported directly by
L<Archive::Libarchive>.
=item Iterate over the contents
Ask alternatively for "header" or entry/file metadata (which is represented by a L<Archive::Libarchive::Entry> instance),
and entry/file content.
=item Finish by calling "close"
This will be called automatically if the archive instance falls out of scope.
=back
Writing an archive is very similar, except that you provide the "header" and content data to L<Archive::Libarchive> instead
of asking for them.
Here is a very basic example that simply opens a file and lists the contents of the archive.
use 5.020;
use Archive::Libarchive qw( ARCHIVE_OK );
my $r = Archive::Libarchive::ArchiveRead->new;
$r->support_filter_all;
$r->support_format_all;
my $ret = $r->open_filename("archive.tar", 10240);
if($ret != ARCHIVE_OK) {
exit 1;
}
my $e = Archive::Libarchive::Entry->new;
while($r->next_header($e) == ARCHIVE_OK) {
say $e->pathname;
$r->read_data_skip;
}
Note that L<open_filename|Archive::Libarchive::ArchiveRead/open_filename> method inspects the file before deciding
how to handle the block size. If the filename provided refers to a tape device, for example, it will use exactly
the block size you specify. For other devices, it may adjust the requested block size in order to obtain better
performance.
Note that the call to L<read_data_skip|Archive::Libarchive::API/read_data_skip> here is not actually necessary, since
L<Archive::Libarchive> will invoke it automatically if you request the next header without reading the data for the
last entry.
The module L<Archive::Libarchive::Peek> also provides similar functionality to this example in a simple, less
powerful interface.
=head2 List contents of archive stored in memory
There are several variants of the open methods. The "filename" variant used above is intended to be simple
to use in the common case of reading from a file from disk, but you may find the "memory" variant useful in other
cases.
use 5.020;
use Path::Tiny qw( path );
use Archive::Libarchive qw( ARCHIVE_OK );
my $r = Archive::Libarchive::ArchiveRead->new;
$r->support_filter_all;
$r->support_format_all;
my $buffer = path('archive.tar')->slurp_raw;
my $ret = $r->open_memory(\$buffer);
if($ret != ARCHIVE_OK) {
exit 1;
}
my $e = Archive::Libarchive::Entry->new;
while($r->next_header($e) == ARCHIVE_OK) {
say $e->pathname;
$r->read_data_skip;
}
There are also variants to read from an already-opened file descriptor, a C<libc> C<FILE> pointer, or a Perl
file handle.
=head2 List contents of archive with custom read functions
Sometimes, none of the packaged open methods will work for you. In that case, you can use the lower-level C<open>
method, which accepts a number of callbacks. For this example we will use the C<open>, C<read> and C<close>
callbacks.
use 5.020;
use Archive::Libarchive qw( :const );
my $r = Archive::Libarchive::ArchiveRead->new;
$r->support_filter_all;
$r->support_format_all;
my $fh;
$r->open(
open => sub {
open $fh, '<', 'archive.tar';
binmode $fh;
return ARCHIVE_OK;
},
read => sub {
my(undef, $ref) = @_;
my $size = read $fh, $$ref, 512;
return $size;
},
close => sub {
close $fh;
return ARCHIVE_OK;
},
) == ARCHIVE_OK or die $r->error_string;
my $e = Archive::Libarchive::Entry->new;
while(1) {
my $ret = $r->next_header($e);
last if $ret == ARCHIVE_EOF;
die $r->error_string if $ret < ARCHIVE_WARN;
warn $r->error_string if $ret != ARCHIVE_OK;
say $e->pathname;
}
$r->close;
For full power of read callbacks see the L<open method's documentation|Archive::Libarchive::ArchiveRead/open>.
When writing to an archive the L<Archive::Libarchive::ArchiveWrite> class also has its own
L<open method and callbacks|Archive::Libarchive::ArchiveWrite/open>.
=head2 A universal decompressor / defilter-er
The "raw" format handler treats arbitrary binary input as a single-element archive. This allows you to get the
output of a libarchive filter chain, including files with multiple encodings, such as C<gz.uu> files:
use 5.020;
use Archive::Libarchive;
my $r = Archive::Libarchive::ArchiveRead->new;
$r->support_filter_all;
$r->support_format_raw;
$r->open_filename("hello.txt.uu");
$r->next_header(Archive::Libarchive::Entry->new);
my $buffer;
while($r->read_data(\$buffer)) {
print $buffer;
}
$r->close;
Note that the "raw" format is not enabled by the
L<support_format_all method on Archive::Libarchive::ArchiveRead|Archive::Libarchive::API/support_format_all>.
Also note that the "raw" format handler does not recognize or accept empty files. If you specifically want to be
able to read empty files, you'll need to also invoke the
L<support_format_empty method on Archive::Libarchive::ArchiveRead|Archive::Libarchive::API/support_format_empty>.
The module L<Archive::Libarchive::Unwrap> also provides similar functionality to this example in a simple, less
powerful interface.
=head2 A basic write example
The following is a very simple example of using L<Archive::Libarchive> to write a group of files into a tar archive.
This is a little more complex than the read examples above because the write example actually does something with
the file bodies.
use 5.020;
use Archive::Libarchive;
use Path::Tiny qw( path );
my $w = Archive::Libarchive::ArchiveWrite->new;
$w->set_format_pax_restricted;
$w->open_filename("outarchive.tar");
path('.')->visit(sub ($path, $) {
my $path = shift;
return if $path->is_dir;
my $e = Archive::Libarchive::Entry->new;
$e->set_pathname("$path");
$e->set_size(-s $path);
$e->set_filetype('reg');
$e->set_perm( oct('0644') );
$w->write_header($e);
$w->write_data(\$path->slurp_raw);
}, { recurse => 1 });
( run in 0.779 second using v1.01-cache-2.11-cpan-39bf76dae61 )