Archive-Ar-Libarchive
view release on metacpan or search on metacpan
lib/Archive/Ar/Libarchive.xs view on Meta::CPAN
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"
#include "perl_math_int64_types.h"
#define MATH_INT64_NATIVE_IF_AVAILABLE
#include "perl_math_int64.h"
#include <archive.h>
#include <archive_entry.h>
#if ARCHIVE_VERSION_NUMBER < 3000000
# if !defined(__LA_INT64_T)
# if defined(_WIN32) && !defined(__CYGWIN__)
# define __LA_INT64_T __int64
# else
# if defined(_SCO_DS)
# define __LA_INT64_T long long
# else
# define __LA_INT64_T int64_t
# endif
# endif
# endif
#endif
#define ARCHIVE_AR_UNDEF 0
#define ARCHIVE_AR_COMMON 1
#define ARCHIVE_AR_BSD 2
#define ARCHIVE_AR_GNU 3
#if ARCHIVE_VERSION_NUMBER < 3000000
#define archive_write_free(archive) archive_write_finish(archive)
#endif
#define _error(ar, message) { \
if(ar->opt_warn) \
warn("%s", message); \
if(ar->error != NULL) \
SvREFCNT_dec(ar->error); \
if(ar->longmess != NULL) \
SvREFCNT_dec(ar->longmess); \
ar->error = ar->longmess = SvREFCNT_inc(newSVpv(message,0)); \
}
struct ar_entry;
struct ar {
struct ar_entry *first;
SV *callback;
unsigned int opt_warn : 2;
unsigned int opt_chmod : 1;
unsigned int opt_same_perms : 1;
unsigned int opt_chown : 1;
unsigned int opt_type : 2;
SV *error;
SV *longmess;
SV *opt_symbols;
};
struct ar_entry {
struct archive_entry *entry;
const char *data;
size_t data_size;
struct ar_entry *next;
unsigned int is_symbol_table : 1;
};
static int ar_disk_options(struct ar *ar)
{
int flags = ARCHIVE_EXTRACT_TIME;
if(ar->opt_chown)
flags |= ARCHIVE_EXTRACT_OWNER;
if(ar->opt_same_perms)
flags |= ARCHIVE_EXTRACT_PERM;
return flags;
}
static void
ar_free_entry(struct ar_entry *entry)
{
archive_entry_free(entry->entry);
if(entry->data != NULL)
Safefree(entry->data);
}
static void
ar_reset(struct ar *ar)
{
struct ar_entry *entry, *old;
if(ar->error != NULL)
SvREFCNT_dec(ar->error);
if(ar->longmess != NULL)
SvREFCNT_dec(ar->longmess);
ar->error = NULL;
ar->longmess = NULL;
entry = ar->first;
while(entry != NULL)
{
ar_free_entry(entry);
old = entry;
entry = entry->next;
Safefree(old);
}
ar->first = NULL;
lib/Archive/Ar/Libarchive.xs view on Meta::CPAN
return archive_position_uncompressed(archive);
#else
return archive_filter_bytes(archive, 0);
#endif
}
else
{
archive_entry_free(entry);
_error(ar,archive_error_string(archive));
ar_reset(ar);
return 0;
}
Newx(next, 1, struct ar_entry);
next->data_size = archive_entry_size(entry);
Newx(next->data, next->data_size, char);
r = archive_read_data(archive, (void*)next->data, next->data_size);
next->is_symbol_table = is_symbol_table;
if(r == ARCHIVE_WARN)
{
_error(ar,archive_error_string(archive));
}
else if(r < ARCHIVE_OK && r != ARCHIVE_EOF)
{
archive_entry_free(entry);
_error(ar,archive_error_string(archive));
Safefree(next->data);
Safefree(next);
return 0;
}
next->entry = entry;
next->next = NULL;
if(ar->first == NULL)
ar->first = next;
else
e->next = next;
e = next;
}
}
MODULE = Archive::Ar::Libarchive PACKAGE = Archive::Ar::Libarchive
BOOT:
PERL_MATH_INT64_LOAD_OR_CROAK;
struct ar*
_new()
CODE:
struct ar *self;
Newx(self, 1, struct ar);
self->first = NULL;
self->callback = NULL;
self->error = NULL;
self->longmess = NULL;
self->opt_symbols = NULL;
self->opt_warn = 0;
self->opt_chmod = 1; /* ignored */
self->opt_same_perms = 1; /* different: pp version this is true for root only */
self->opt_chown = 1;
ar_reset(self);
RETVAL = self;
OUTPUT:
RETVAL
int
set_opt(self, name, value)
struct ar *self
const char *name
SV *value
CODE:
if(!strcmp(name, "warn"))
RETVAL = self->opt_warn = SvIV(value);
else if(!strcmp(name, "chmod"))
RETVAL = self->opt_chmod = SvIV(value);
else if(!strcmp(name, "same_perms"))
RETVAL = self->opt_same_perms = SvIV(value);
else if(!strcmp(name, "chown"))
RETVAL = self->opt_chown = SvIV(value);
else if(!strcmp(name, "type"))
RETVAL = self->opt_type = SvIV(value);
else if(!strcmp(name, "symbols"))
self->opt_symbols = SvREFCNT_inc(value); /* TODO: make set_opt return void; maybe */
else
warn("unknown or unsupported option %s", name);
OUTPUT:
RETVAL
int
get_opt(self, name)
struct ar *self
const char *name
CODE:
if(!strcmp(name, "warn"))
RETVAL = self->opt_warn;
else if(!strcmp(name, "chmod"))
RETVAL = self->opt_chmod;
else if(!strcmp(name, "same_perms"))
RETVAL = self->opt_same_perms;
else if(!strcmp(name, "chown"))
RETVAL = self->opt_chown;
else if(!strcmp(name, "type"))
{
if(self->opt_type == ARCHIVE_AR_UNDEF)
XSRETURN_EMPTY;
else
RETVAL = self->opt_type;
}
else
warn("unknown or unsupported option %s", name);
OUTPUT:
RETVAL
void
_set_error(self, message, longmess)
struct ar *self
SV *message
SV *longmess
CODE:
if(self->error != NULL)
SvREFCNT_dec(self->error);
if(self->longmess != NULL)
SvREFCNT_dec(self->longmess);
self->error = SvREFCNT_inc(message);
self->longmess = SvREFCNT_inc(longmess);
SV *
error(self, ...)
struct ar *self
CODE:
if(self->error == NULL)
XSRETURN_EMPTY;
if(items >= 2 && SvTRUE(ST(1)))
RETVAL = SvREFCNT_inc(self->longmess);
else
RETVAL = SvREFCNT_inc(self->error);
OUTPUT:
RETVAL
int
_read_from_filename(self, filename)
struct ar *self
const char *filename
CODE:
struct archive *archive;
int r;
ar_reset(self);
archive = archive_read_new();
archive_read_support_format_ar(archive);
r = archive_read_open_filename(archive, filename, 1024);
if(r == ARCHIVE_OK || r == ARCHIVE_WARN)
{
if(r == ARCHIVE_WARN)
_error(self, archive_error_string(archive));
RETVAL = ar_read_archive(archive, self);
lib/Archive/Ar/Libarchive.xs view on Meta::CPAN
struct ar *self
const char *filename
CODE:
struct ar_entry *entry;
struct archive *disk;
int ok;
entry = ar_find_by_name(self, filename);
if(entry == NULL)
XSRETURN_EMPTY;
disk = archive_write_disk_new();
archive_write_disk_set_options(disk, ar_disk_options(self));
archive_write_disk_set_standard_lookup(disk);
ok = ar_entry_extract(self, entry, disk);
archive_write_close(disk);
archive_write_free(disk);
if(ok)
RETVAL = 1;
else
XSRETURN_EMPTY;
OUTPUT:
RETVAL
int
type(self)
struct ar *self
CODE:
RETVAL = self->opt_type;
OUTPUT:
RETVAL
int
contains_file(self, filename)
struct ar *self
const char *filename
CODE:
if(ar_find_by_name(self, filename))
RETVAL = 1;
else
XSRETURN_EMPTY;
OUTPUT:
RETVAL
void
clear(self)
struct ar *self
CODE:
ar_reset(self);
int
_chmod(self, filename, mode)
struct ar *self
const char *filename
int mode
CODE:
struct ar_entry *entry;
entry = ar_find_by_name(self, filename);
if(entry != NULL)
{
archive_entry_set_mode(entry->entry, mode);
RETVAL = 1;
}
else
{
XSRETURN_EMPTY;
}
OUTPUT:
RETVAL
int
_chown(self, filename, uid, gid)
struct ar *self
const char *filename
int uid
SV *gid
CODE:
struct ar_entry *entry;
entry = ar_find_by_name(self, filename);
if(entry != NULL)
{
if(uid >= 0)
archive_entry_set_uid(entry->entry, uid);
if(SvOK(gid) && SvIV(gid) >= 0)
{
archive_entry_set_gid(entry->entry, SvIV(gid));
}
}
else
{
XSRETURN_EMPTY;
}
const char *
_libarchive_version()
CODE:
RETVAL = ARCHIVE_VERSION_STRING;
OUTPUT:
RETVAL
( run in 2.290 seconds using v1.01-cache-2.11-cpan-5a3173703d6 )