File-Raw-Archive

 view release on metacpan or  search on metacpan

Archive.xs  view on Meta::CPAN

            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)) {

Archive.xs  view on Meta::CPAN

    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 )