diff options
-rw-r--r-- | MANIFEST | 1 | ||||
-rw-r--r-- | Makefile.PL | 2 | ||||
-rw-r--r-- | NEWS | 1 | ||||
-rw-r--r-- | URPM.xs | 17 | ||||
-rw-r--r-- | xfile.h | 177 |
5 files changed, 190 insertions, 8 deletions
@@ -2,6 +2,7 @@ README MANIFEST Makefile.PL typemap +xfile.h URPM.xs URPM.pm URPM/Build.pm diff --git a/Makefile.PL b/Makefile.PL index 26a1fbc..ed3e63c 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -50,7 +50,7 @@ ChangeLog: } my @rpmflags; -my $ldflags = `pkg-config --libs rpm`; +my $ldflags = `pkg-config --libs rpm liblzma`; my $ccflags = join(' ', '-Wall -Wextra -fno-strict-aliasing', @rpmflags); print "Found RPM version $version (compiling with flags: $ccflags)\n"; @@ -1,5 +1,6 @@ Version 4.0 - ? October 2010, by Per Øyvind Karlsen +- add support for uncompressed & xz/lzma compressed synthesis - fix URPM::DB::open() to work properly with relative paths - ditch legacy behaviour compatibility for packages without epoch, always promote epoch @@ -20,7 +20,6 @@ #include <sys/wait.h> #include <fcntl.h> #include <unistd.h> -#include <zlib.h> #include <libintl.h> #undef Fflush @@ -41,6 +40,8 @@ #include <rpmbuild.h> #include <rpmlog.h> +#include "xfile.h" + struct s_Package { char *info; int filesize; @@ -3443,7 +3444,8 @@ Urpm_parse_synthesis__XS(urpm, filename, ...) char *p, *eol; int buff_len; struct s_Package pkg; - gzFile gzF; + xFile xF; + lzma_ret ret = LZMA_STREAM_END; int start_id = 1 + av_len(depslist); SV *callback = NULL; @@ -3460,12 +3462,12 @@ Urpm_parse_synthesis__XS(urpm, filename, ...) } PUTBACK; - if ((gzF = gzopen(filename, "rb")) != NULL) { + if ((xF = xOpen(filename)).type < XF_FAIL) { memset(&pkg, 0, sizeof(struct s_Package)); buff[sizeof(buff)-1] = 0; p = buff; int ok = 1; - while ((buff_len = gzread(gzF, p, sizeof(buff)-1-(p-buff))) >= 0 && + while ((buff_len = xRead(&xF, &ret, p, sizeof(buff)-1-(p-buff))) >= 0 && (buff_len += p-buff)) { buff[buff_len] = 0; p = buff; @@ -3477,11 +3479,11 @@ Urpm_parse_synthesis__XS(urpm, filename, ...) } while ((eol = strchr(p, '\n')) != NULL); } else { /* a line larger than sizeof(buff) has been encountered, bad file problably */ - fprintf(stderr, "invalid line <%s>\n", p); + fprintf(stderr, "invalid line <%s>\n%s\n", p, buff); ok = 0; break; } - if (gzeof(gzF)) { + if (xF.eof) { if (!parse_line(depslist, provides, obsoletes, &pkg, p, urpm, callback)) ok = 0; break; } else { @@ -3491,7 +3493,8 @@ Urpm_parse_synthesis__XS(urpm, filename, ...) p = &buff[buff_len-(p-buff)]; } } - if (gzclose(gzF) != 0) ok = 0; + if(ret != LZMA_STREAM_END) ok = 0; + if (xClose(&xF) != 0) ok = 0; SPAGAIN; if (ok) { XPUSHs(sv_2mortal(newSViv(start_id))); @@ -0,0 +1,177 @@ +#include <magic.h> +#include <lzma.h> +#include <zlib.h> + +#define kBufferSize (1 << 15) + +typedef struct lzma_file { + uint8_t buf[kBufferSize]; + lzma_stream strm; + FILE *fp; + lzma_bool eof; +} lzma_FILE; + +typedef enum xFile_e { + XF_ASCII, + XF_GZIP, + XF_LZMA, + XF_XZ, + XF_FAIL +} xFile_t; + +typedef struct xFile_s { + xFile_t type; + lzma_bool eof; + union { + gzFile gz; + lzma_FILE *xz; + } f; + FILE *fp; +} xFile; + +static lzma_FILE *lzma_open(lzma_ret *lzma_error, FILE *fp, uint64_t memlimit) +{ + lzma_ret *ret = lzma_error; + lzma_FILE *lzma_file; + lzma_stream tmp = LZMA_STREAM_INIT; + + lzma_file = calloc(1, sizeof(*lzma_file)); + + lzma_file->fp = fp; + lzma_file->eof = 0; + lzma_file->strm = tmp; + + *ret = lzma_auto_decoder(&lzma_file->strm, memlimit, 0); + + if (*ret != LZMA_OK) { + (void) fclose(lzma_file->fp); + memset(lzma_file, 0, sizeof(*lzma_file)); + free(lzma_file); + return NULL; + } + return lzma_file; +} + +static ssize_t lzma_read(lzma_ret *lzma_error, lzma_FILE *lzma_file, void *buf, size_t len) +{ + lzma_ret *ret = lzma_error; + lzma_bool eof = 0; + + if (!lzma_file) + return -1; + if (lzma_file->eof) + return 0; + + lzma_file->strm.next_out = buf; + lzma_file->strm.avail_out = len; + for (;;) { + if (!lzma_file->strm.avail_in) { + lzma_file->strm.next_in = (uint8_t *)lzma_file->buf; + lzma_file->strm.avail_in = fread(lzma_file->buf, 1, kBufferSize, lzma_file->fp); + if (!lzma_file->strm.avail_in) + eof = 1; + } + *ret = lzma_code(&lzma_file->strm, LZMA_RUN); + if (*ret == LZMA_STREAM_END) { + lzma_file->eof = 1; + return len - lzma_file->strm.avail_out; + } + if (*ret != LZMA_OK) + return -1; + if (!lzma_file->strm.avail_out) + return len; + if (eof) + return -1; + } +} + + +static xFile xOpen(const char *path) { + xFile xF = {XF_FAIL, 0, {NULL}, NULL}; + lzma_ret ret = LZMA_OK; + const char *message, *tmp; + magic_t cookie; + cookie = magic_open(MAGIC_NONE); + if(!magic_load(cookie, NULL)) { + message = magic_file(cookie, path); + if(strstr(message, "gzip compressed")) + xF.type = XF_GZIP; + else if(strstr(message, "xz compressed")) + xF.type = XF_XZ; + else if(strstr(message, "LZMA compressed")) + xF.type = XF_LZMA; + else if(strstr(message, "ASCII")) + xF.type = XF_ASCII; + magic_close(cookie); + } + if(xF.type == XF_FAIL && (tmp = rindex(path, '.'))) { + if(!strcmp(tmp, ".cz") || !strcmp(tmp, ".cz")) + xF.type = XF_GZIP; + else if(!strcmp(tmp, ".xz")) + xF.type = XF_XZ; + else if(!strcmp(tmp, ".lzma")) + xF.type = XF_LZMA; + } + + switch(xF.type) { + case XF_GZIP: + xF.f.gz = gzopen(path, "rb"); + break; + case XF_ASCII: + case XF_LZMA: + case XF_XZ: + xF.fp = fopen(path, "rb"); + if(xF.type == XF_ASCII) break; + xF.f.xz = lzma_open(&ret, xF.fp, -1); + if(ret != LZMA_OK) + xF.type = XF_FAIL; + break; + default: + break; + } + + return xF; +} + +static int xClose(xFile *xF) { + int ret = -1; + switch(xF->type) { + case XF_GZIP: + ret = gzclose(xF->f.gz); + break; + case XF_LZMA: + case XF_XZ: + lzma_end(&xF->f.xz->strm); + free(xF->f.xz); + case XF_ASCII: + ret = fclose(xF->fp); + break; + default: + break; + } + return ret; +} + +static ssize_t xRead(xFile *xF, lzma_ret *ret, void *buf, size_t len) { + ssize_t sz; + switch(xF->type) { + case XF_GZIP: + sz = gzread(xF->f.gz, buf, len); + xF->eof = gzeof(xF->f.gz); + break; + case XF_LZMA: + case XF_XZ: + sz = lzma_read(ret, xF->f.xz, buf, len); + xF->eof = xF->f.xz->eof; + break; + case XF_ASCII: + sz = fread(buf, 1, len, xF->fp); + xF->eof = feof(xF->fp); + break; + default: + break; + } + return sz; +} + + |