Main lzma rpmio part based on SuSE patches, thanks for them!
authorJindrich Novy <jnovy@redhat.com>
Tue, 22 Apr 2008 10:38:51 +0000 (12:38 +0200)
committerJindrich Novy <jnovy@redhat.com>
Tue, 22 Apr 2008 10:38:51 +0000 (12:38 +0200)
rpmio/rpmio.c

index 7675d23..6fc574b 100644 (file)
@@ -37,6 +37,7 @@ extern int h_errno;
 #define        FDONLY(fd)      assert(fdGetIo(fd) == fdio)
 #define        GZDONLY(fd)     assert(fdGetIo(fd) == gzdio)
 #define        BZDONLY(fd)     assert(fdGetIo(fd) == bzdio)
+#define        LZDONLY(fd)     assert(fdGetIo(fd) == lzdio)
 
 #define        UFDONLY(fd)     /* assert(fdGetIo(fd) == ufdio) */
 
@@ -91,6 +92,7 @@ static const FDIO_t fpio;
 static const FDIO_t ufdio;
 static const FDIO_t gzdio;
 static const FDIO_t bzdio;
+static const FDIO_t lzdio;
 
 /**
  */
@@ -142,6 +144,10 @@ static const char * fdbg(FD_t fd)
        } else if (fps->io == bzdio) {
            sprintf(be, "BZD %p fdno %d", fps->fp, fps->fdno);
 #endif
+#if HAVE_LZMA_H
+       } else if (fps->io == lzdio) {
+           sprintf(be, "LZD %p fdno %d", fps->fp, fps->fdno);
+#endif
        } else if (fps->io == fpio) {
            sprintf(be, "%s %p(%d) fdno %d",
                (fps->fdno < 0 ? "LIBIO" : "FP"),
@@ -1233,7 +1239,11 @@ static const char * getFdErrstr (FD_t fd)
        errstr = fd->errcookie;
     } else
 #endif /* HAVE_BZLIB_H */
-
+#ifdef HAVE_LZMA_H
+    if (fdGetIo(fd) == lzdio) {
+       errstr = fd->errcookie;
+    } else
+#endif /* HAVE_LZMA_H */
     {
        errstr = (fd->syserrno ? strerror(fd->syserrno) : "");
     }
@@ -1242,6 +1252,318 @@ static const char * getFdErrstr (FD_t fd)
 }
 
 /* =============================================================== */
+/* Support for LZMA library.
+ */
+
+#ifdef HAVE_LZMA_H
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <lzma.h>
+
+#define kBufferSize (1 << 15)
+
+typedef struct lzfile {
+  /* IO buffer */
+    uint8_t buf[kBufferSize];
+
+    lzma_stream strm;
+
+    FILE *file;
+
+    int encoding;
+    int eof;
+
+} LZFILE;
+
+static LZFILE *lzopen_internal(const char *path, const char *mode, int fd)
+{
+    int level = 5;
+    int encoding = 0;
+    FILE *fp;
+    LZFILE *lzfile;
+    lzma_ret ret;
+
+    for (; *mode; mode++) {
+       if (*mode == 'w')
+           encoding = 1;
+       else if (*mode == 'r')
+           encoding = 0;
+       else if (*mode >= '1' && *mode <= '9')
+           level = *mode - '0';
+    }
+    if (fd != -1)
+       fp = fdopen(fd, encoding ? "w" : "r");
+    else
+       fp = fopen(path, encoding ? "w" : "r");
+    if (!fp)
+       return 0;
+    lzfile = calloc(1, sizeof(*lzfile));
+    if (!lzfile) {
+       fclose(fp);
+       return 0;
+    }
+    lzfile->file = fp;
+    lzfile->encoding = encoding;
+    lzfile->eof = 0;
+    lzfile->strm = LZMA_STREAM_INIT_VAR;
+    if (encoding) {
+       lzma_options_alone alone;
+       alone.uncompressed_size = LZMA_VLI_VALUE_UNKNOWN;
+       memcpy(&alone.lzma, &lzma_preset_lzma[level - 1], sizeof(alone.lzma));
+       ret = lzma_alone_encoder(&lzfile->strm, &alone);
+    } else {
+       ret = lzma_auto_decoder(&lzfile->strm, 0, 0);
+    }
+    if (ret != LZMA_OK) {
+       fclose(fp);
+       free(lzfile);
+       return 0;
+    }
+    return lzfile;
+}
+
+static LZFILE *lzopen(const char *path, const char *mode)
+{
+    return lzopen_internal(path, mode, -1);
+}
+
+static LZFILE *lzdopen(int fd, const char *mode)
+{
+    if (fd < 0)
+       return 0;
+    return lzopen_internal(0, mode, fd);
+}
+
+static int lzflush(LZFILE *lzfile)
+{
+    return fflush(lzfile->file);
+}
+
+static int lzclose(LZFILE *lzfile)
+{
+    lzma_ret ret;
+    int n;
+
+    if (!lzfile)
+       return -1;
+    if (lzfile->encoding) {
+       for (;;) {
+           lzfile->strm.avail_out = kBufferSize;
+           lzfile->strm.next_out = lzfile->buf;
+           ret = lzma_code(&lzfile->strm, LZMA_FINISH);
+           if (ret != LZMA_OK && ret != LZMA_STREAM_END)
+               return -1;
+           n = kBufferSize - lzfile->strm.avail_out;
+           if (n && fwrite(lzfile->buf, 1, n, lzfile->file) != n)
+               return -1;
+           if (ret == LZMA_STREAM_END)
+               break;
+       }
+    }
+    lzma_end(&lzfile->strm);
+    return fclose(lzfile->file);
+    free(lzfile);
+}
+
+static ssize_t lzread(LZFILE *lzfile, void *buf, size_t len)
+{
+    lzma_ret ret;
+    int eof = 0;
+
+    if (!lzfile || lzfile->encoding)
+      return -1;
+    if (lzfile->eof)
+      return 0;
+    lzfile->strm.next_out = buf;
+    lzfile->strm.avail_out = len;
+    for (;;) {
+       if (!lzfile->strm.avail_in) {
+           lzfile->strm.next_in = lzfile->buf;
+           lzfile->strm.avail_in = fread(lzfile->buf, 1, kBufferSize, lzfile->file);
+           if (!lzfile->strm.avail_in)
+               eof = 1;
+       }
+       ret = lzma_code(&lzfile->strm, LZMA_RUN);
+       if (ret == LZMA_STREAM_END) {
+           lzfile->eof = 1;
+           return len - lzfile->strm.avail_out;
+       }
+       if (ret != LZMA_OK)
+           return -1;
+       if (!lzfile->strm.avail_out)
+           return len;
+       if (eof)
+           return -1;
+      }
+}
+
+static ssize_t lzwrite(LZFILE *lzfile, void *buf, size_t len)
+{
+    lzma_ret ret;
+    int n;
+    if (!lzfile || !lzfile->encoding)
+       return -1;
+    if (!len)
+       return 0;
+    lzfile->strm.next_in = buf;
+    lzfile->strm.avail_in = len;
+    for (;;) {
+       lzfile->strm.next_out = lzfile->buf;
+       lzfile->strm.avail_out = kBufferSize;
+       ret = lzma_code(&lzfile->strm, LZMA_RUN);
+       if (ret != LZMA_OK)
+           return -1;
+       n = kBufferSize - lzfile->strm.avail_out;
+       if (n && fwrite(lzfile->buf, 1, n, lzfile->file) != n)
+           return -1;
+       if (!lzfile->strm.avail_in)
+           return len;
+    }
+}
+
+/* =============================================================== */
+
+static inline void * lzdFileno(FD_t fd)
+{
+    void * rc = NULL;
+    int i;
+
+    FDSANE(fd);
+    for (i = fd->nfps; i >= 0; i--) {
+           FDSTACK_t * fps = &fd->fps[i];
+           if (fps->io != lzdio)
+               continue;
+           rc = fps->fp;
+       break;
+    }
+    
+    return rc;
+}
+
+static FD_t lzdOpen(const char * path, const char * mode)
+{
+    FD_t fd;
+    LZFILE *lzfile;
+    if ((lzfile = lzopen(path, mode)) == NULL)
+       return NULL;
+    fd = fdNew("open (lzdOpen)");
+    fdPop(fd); fdPush(fd, lzdio, lzfile, -1);
+    return fdLink(fd, "lzdOpen");
+}
+
+static FD_t lzdFdopen(void * cookie, const char * fmode)
+{
+    FD_t fd = c2f(cookie);
+    int fdno;
+    LZFILE *lzfile;
+
+    if (fmode == NULL) return NULL;
+    fdno = fdFileno(fd);
+    fdSetFdno(fd, -1);          /* XXX skip the fdio close */
+    if (fdno < 0) return NULL;
+    lzfile = lzdopen(fdno, fmode);
+    if (lzfile == NULL) return NULL;
+    fdPush(fd, lzdio, lzfile, fdno);
+    return fdLink(fd, "lzdFdopen");
+}
+
+static int lzdFlush(FD_t fd)
+{
+    return lzflush(lzdFileno(fd));
+}
+
+/* =============================================================== */
+static ssize_t lzdRead(void * cookie, char * buf, size_t count)
+{
+    FD_t fd = c2f(cookie);
+    LZFILE *lzfile;
+    ssize_t rc = 0;
+
+    if (fd->bytesRemain == 0) return 0; /* XXX simulate EOF */
+    lzfile = lzdFileno(fd);
+    fdstat_enter(fd, FDSTAT_READ);
+    if (lzfile)
+       rc = lzread(lzfile, buf, count);
+    if (rc == -1) {
+       fd->errcookie = "Lzma: decoding error";
+    } else if (rc >= 0) {
+       fdstat_exit(fd, FDSTAT_READ, rc);
+       if (fd->ndigests && rc > 0) fdUpdateDigests(fd, (void *)buf, rc);
+    }
+    return rc;
+}
+
+static ssize_t lzdWrite(void * cookie, const char * buf, size_t count)
+{
+    FD_t fd = c2f(cookie);
+    LZFILE *lzfile;
+    ssize_t rc = 0;
+
+    if (fd == NULL || fd->bytesRemain == 0) return 0;   /* XXX simulate EOF */
+
+    if (fd->ndigests && count > 0) fdUpdateDigests(fd, (void *)buf, count);
+
+    lzfile = lzdFileno(fd);
+
+    fdstat_enter(fd, FDSTAT_WRITE);
+    rc = lzwrite(lzfile, (void *)buf, count);
+    if (rc < 0) {
+       fd->errcookie = "Lzma: encoding error";
+    } else if (rc > 0) {
+       fdstat_exit(fd, FDSTAT_WRITE, rc);
+    }
+    return rc;
+}
+
+static inline int lzdSeek(void * cookie, _libio_pos_t pos, int whence)
+{
+    FD_t fd = c2f(cookie);
+
+    LZDONLY(fd);
+    return -2;
+}
+
+static int lzdClose(void * cookie)
+{
+    FD_t fd = c2f(cookie);
+    LZFILE *lzfile;
+    int rc;
+
+    lzfile = lzdFileno(fd);
+
+    if (lzfile == NULL) return -2;
+    fdstat_enter(fd, FDSTAT_CLOSE);
+    rc = lzclose(lzfile);
+
+    /* XXX TODO: preserve fd if errors */
+
+    if (fd) {
+       if (rc == -1) {
+           fd->errcookie = strerror(ferror(lzfile->file));
+       } else if (rc >= 0) {
+           fdstat_exit(fd, FDSTAT_CLOSE, rc);
+       }
+    }
+
+DBGIO(fd, (stderr, "==>\tlzdClose(%p) rc %lx %s\n", cookie, (unsigned long)rc, fdbg(fd)));
+
+    if (_rpmio_debug || rpmIsDebug()) fdstat_print(fd, "LZDIO", stderr);
+    if (rc == 0)
+       fd = fdFree(fd, "open (lzdClose)");
+    return rc;
+}
+
+static struct FDIO_s lzdio_s = {
+  lzdRead, lzdWrite, lzdSeek, lzdClose, NULL, NULL, NULL, fdFileno,
+  NULL, lzdOpen, lzdFileno, lzdFlush
+};
+
+static const FDIO_t lzdio = &lzdio_s;
+
+#endif /* HAVE_LZMA_H */
+
+/* =============================================================== */
 
 const char *Fstrerror(FD_t fd)
 {
@@ -1473,6 +1795,11 @@ fprintf(stderr, "*** Fdopen(%p,%s) %s\n", fd, fmode, fdbg(fd));
            iof = bzdio;
            fd = bzdFdopen(fd, zstdio);
 #endif
+#if HAVE_LZMA_H
+       } else if (!strcmp(end, "lzdio")) {
+           iof = lzdio;
+           fd = lzdFdopen(fd, zstdio);
+#endif
        } else if (!strcmp(end, "ufdio")) {
            iof = ufdio;
        } else if (!strcmp(end, "fpio")) {
@@ -1624,6 +1951,11 @@ int Ferror(FD_t fd)
            ec = (fd->syserrno  || fd->errcookie != NULL) ? -1 : 0;
            i--;        /* XXX fdio under bzdio always has fdno == -1 */
 #endif
+#if HAVE_LZMA_H
+       } else if (fps->io == lzdio) {
+           ec = (fd->syserrno  || fd->errcookie != NULL) ? -1 : 0;
+           i--;        /* XXX fdio under lzdio always has fdno == -1 */
+#endif
        } else {
        /* XXX need to check ufdio/gzdio/bzdio/fdio errors correctly. */
            ec = (fdFileno(fd) < 0 ? -1 : 0);
@@ -1719,3 +2051,4 @@ static const struct FDIO_s fpio_s = {
   ufdOpen, NULL, fdGetFp, NULL
 };
 static const FDIO_t fpio = &fpio_s ;
+