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 )