File-Raw-Archive
view release on metacpan or search on metacpan
hv_store(xh, e->xattrs[i].key, (I32)e->xattrs[i].key_len,
newSVpvn(e->xattrs[i].value, e->xattrs[i].value_len), 0);
}
av_store(meta, M_XATTRS, newRV_noinc((SV *)xh));
}
return newRV_noinc((SV *)meta);
}
/* Decode a Perl entry hashref into ArchiveEntry. The returned entry
* borrows pointers into SVs that must outlive the call - caller keeps
* the hash alive until write_add returns. */
static void
hv_to_entry(pTHX_ HV *h, ArchiveEntry *e,
ArchiveXattr *xattr_buf, size_t xattr_buf_n,
size_t *xattr_used)
{
memset(e, 0, sizeof *e);
*xattr_used = 0;
SV **sv = hv_fetchs(h, "name", 0);
if (sv && *sv && SvOK(*sv)) {
if (pipe(err_pipe) < 0) croak("pipe: %s", strerror(errno));
err_r = err_pipe[0];
err_w = err_pipe[1];
workers = (parallel_worker_t *)calloc(parallel, sizeof *workers);
if (!workers) {
close(err_r); close(err_w);
croak("File::Raw::Archive: out of memory");
}
/* Ignore SIGPIPE while workers are alive. A worker crash would
* otherwise SIGPIPE the parent on the next dispatch write. */
new_sa.sa_handler = SIG_IGN;
sigemptyset(&new_sa.sa_mask);
new_sa.sa_flags = 0;
sigaction(SIGPIPE, &new_sa, &old_sigpipe);
for (i = 0; i < parallel; i++) {
int job_pipe[2];
if (pipe(job_pipe) < 0) {
int saved = errno;
t/26-stashed-entries.t view on Meta::CPAN
#!perl
# Refcount lifecycle: an Entry holds a back-ref to its Reader; if the
# user stashes an Entry past Reader scope, the C handle should stay
# alive for accessor calls (which only look at the cached meta AV)
# but slurp on a Reader that the user explicitly closed should fail
# cleanly rather than crash.
use 5.010;
use strict;
use warnings;
use Test::More;
use File::Temp qw(tempdir);
use File::Raw::Archive;
my $dir = tempdir(CLEANUP => 1);
my $tar = "$dir/stash.tar";
my $w = File::Raw::Archive->create($tar);
$w->add(name => 'one.txt', content => 'first content');
$w->add(name => 'two.txt', content => 'second content');
$w->close;
# Case 1: stash an entry past Reader scope. The Reader stays alive
# because the entry holds a ref to it. Accessors keep working;
# slurp also works because the C handle is still allocated.
{
my $stashed;
{
my $r = File::Raw::Archive->open($tar);
$stashed = $r->next; # entry holds ref to $r
$stashed->slurp; # cache the bytes inside the entry
# $r goes out of scope here. Refcount drops by 1, but
# $stashed's back-link keeps the C handle alive.
}
is($stashed->name, 'one.txt',
'stashed entry: name accessor still works after Reader out of scope');
is($stashed->size, length('first content'),
'stashed entry: size accessor still works');
is($stashed->slurp, 'first content',
'stashed slurp returns memoised bytes');
# Let $stashed go out of scope: chain unwinds, C handle freed.
}
ok(1, 'stashed-past-scope teardown completed without panic');
t/26-stashed-entries.t view on Meta::CPAN
# Case 3: Reader DESTROY runs cleanly when implicitly torn down with
# stashed entries kept around in an outer scope.
{
my @stashed;
my $r = File::Raw::Archive->open($tar);
while (my $e = $r->next) {
$e->slurp; # memoise so post-close accessors work
push @stashed, $e;
}
undef $r; # drop direct reference
# Entries still hold the back-link, so the handle is alive.
is($stashed[0]->name, 'one.txt', 'first entry name post-undef');
is($stashed[1]->slurp, 'second content', 'second entry slurp memoised');
# Let @stashed go out of scope: full chain teardown.
}
ok(1, 'implicit Reader teardown via stashed-entries chain');
done_testing;
( run in 1.858 second using v1.01-cache-2.11-cpan-14f38c9f855 )