RPM Package Manager, CVS Repository
  http://rpm5.org/cvs/
  ____________________________________________________________________________

  Server: rpm5.org                         Name:   Jeff Johnson
  Root:   /v/rpm/cvs                       Email:  j...@rpm5.org
  Module: rpm                              Date:   17-Feb-2009 20:54:33
  Branch: HEAD                             Handle: 2009021719543201

  Modified files:
    rpm                     CHANGES
    rpm/rpmio               rpmz.c

  Log:
    - jbj: rpmz: handle gzip/bzip2/xz/lzma compression in 1 executable.

  Summary:
    Revision    Changes     Path
    1.2777      +1  -0      rpm/CHANGES
    1.9         +375 -100   rpm/rpmio/rpmz.c
  ____________________________________________________________________________

  patch -p0 <<'@@ .'
  Index: rpm/CHANGES
  ============================================================================
  $ cvs diff -u -r1.2776 -r1.2777 CHANGES
  --- rpm/CHANGES       17 Feb 2009 04:44:04 -0000      1.2776
  +++ rpm/CHANGES       17 Feb 2009 19:54:32 -0000      1.2777
  @@ -1,5 +1,6 @@
   
   5.2a2 -> 5.2a3:
  +    - jbj: rpmz: handle gzip/bzip2/xz/lzma compression in 1 executable.
       - proyvind: create %mipsel and also add more generations to the mips 
macros. 
       - jbj: fix: avoid the assertion failure w LZMA lzdio by upgrading to XZ.
       - proyvind: add initial support for detecting automatically detecting
  @@ .
  patch -p0 <<'@@ .'
  Index: rpm/rpmio/rpmz.c
  ============================================================================
  $ cvs diff -u -r1.8 -r1.9 rpmz.c
  --- rpm/rpmio/rpmz.c  16 Feb 2009 23:54:23 -0000      1.8
  +++ rpm/rpmio/rpmz.c  17 Feb 2009 19:54:33 -0000      1.9
  @@ -26,6 +26,8 @@
   
   #include "debug.h"
   
  +static int _debug = 1;
  +
   enum tool_mode {
       MODE_COMPRESS,
       MODE_DECOMPRESS,
  @@ -40,8 +42,9 @@
       FORMAT_AUTO,
       FORMAT_XZ,
       FORMAT_LZMA,
  -    FORMAT_GZIP,
       FORMAT_RAW,
  +    FORMAT_GZIP,
  +    FORMAT_BZIP2,
   };
   /*...@unchecked@*/
   static enum format_type opt_format = FORMAT_AUTO;
  @@ -74,10 +77,10 @@
   /*...@unchecked@*/
   static size_t filters_count = 0;
   
  -// We don't modify or free() this, but we need to assign it in some
  -// non-const pointers.
  -/*...@unchecked@*/
  +/*...@unchecked@*/ /*...@observer@*/
   static const char *stdin_filename = "(stdin)";
  +/*...@unchecked@*/ /*...@observer@*/
  +static const char *stdout_filename = "(stdout)";
   
   /*...@unchecked@*/
   static int opt_threads;
  @@ -109,6 +112,50 @@
       OPT_FILES0,
   };
   
  +/**
  + */
  +typedef struct rpmz_s * rpmz;
  +
  +/**
  + */
  +struct rpmz_s {
  +    char * b;
  +    size_t nb;
  +
  +/*...@null@*/
  +    const char * isuffix;
  +    enum format_type ifmt;
  +    FDIO_t idio;
  +/*...@null@*/
  +    const char * ifn;
  +    char ifmode[32];
  +/*...@null@*/
  +    FD_t ifd;
  +
  +/*...@null@*/
  +    const char * osuffix;
  +    enum format_type ofmt;
  +    FDIO_t odio;
  +/*...@null@*/
  +    const char * ofn;
  +    char ofmode[32];
  +/*...@null@*/
  +    FD_t ofd;
  +
  +/*...@null@*/
  +    const char * suffix;
  +};
  +
  +/*...@unchecked@*/
  +static struct rpmz_s __rpmz = {
  +    .nb              = 16 * BUFSIZ,
  +    .ifmode  = "rb",
  +    .ofmode  = "wb",
  +    .suffix  = "",
  +};
  +/*...@unchecked@*/
  +static rpmz _rpmz = &__rpmz;
  +
   /*==============================================================*/
   static int checkfd(const char * devnull, int fdno, int flags)
        /*...@*/
  @@ -236,107 +283,299 @@
   
   /*==============================================================*/
   
  -#define GZ_SUFFIX    ".gz"
  -#define SUFFIX_LEN   (sizeof(GZ_SUFFIX)-1)
  -#define      BUFLEN          (16 * 1024)
  -#define      MAX_NAME_LEN    1024
  +/*...@unchecked@*/ /*...@observer@*/
  +static struct suffixPairs_s {
  +    enum format_type format;
  +/*...@null@*/
  +    const char * csuffix;
  +/*...@relnull@*/
  +    const char * usuffix;
  +} suffixPairs[] = {
  +    { FORMAT_XZ,     ".xz",  "" },
  +    { FORMAT_XZ,     ".txz", ".tar" },
  +    { FORMAT_LZMA,   ".lzma","" },
  +    { FORMAT_LZMA,   ".tlz", ".tar" },
  +    { FORMAT_GZIP,   ".gz",  "" },
  +    { FORMAT_GZIP,   ".tgz", ".tar" },
  +    { FORMAT_BZIP2,  ".bz2", "" },
  +    { FORMAT_RAW,    NULL,   NULL }
  +};
  +
  +/**
  + * Check string for a suffix.
  + * @param fn         string
  + * @param suffix     suffix
  + * @return           1 if string ends with suffix
  + */
  +static int chkSuffix(const char * fn, const char * suffix)
  +     /*...@*/
  +{
  +    size_t flen = strlen(fn);
  +    size_t slen = strlen(suffix);
  +    int rc = (flen > slen && !strcmp(fn + flen - slen, suffix));
  +if (_debug)
  +fprintf(stderr, "\tchk(%s,%s) ret %d\n", fn, suffix, rc);
  +    return rc;
  +}
  +
  +/**
  + * Return (malloc'd) string with new suffix substituted for old.
  + * @param fn         string
  + * @param old                old suffix
  + * @param new                new suffix
  + * @return           new string
  + */
  +static char * changeSuffix(const char * fn,
  +             /*...@null@*/ const char * old, 
  +             /*...@null@*/ const char * new)
  +     /*...@*/
  +{
  +    size_t nfn = strlen(fn);
  +    size_t nos = (old ? strlen(old) : 0);
  +    size_t nns = (new ? strlen(new) : 0);
  +    char * t = xmalloc(nfn - nos + nns + 1);
  +
  +    {        char * te = t;
  +
  +     strncpy(te, fn, (nfn - nos));
  +     te += (nfn - nos);
  +     if (new)
  +         te = stpcpy(te, new);
  +     *te = '\0';
  +    }
  +
  +    return t;
  +}
  +
  +/**
  + * Return (malloc'd) uncompressed file name.
  + * @param z          rpmz container
  + * @return           uncompressed file name
  + */
  +static const char * uncompressedFN(rpmz z)
  +     /*...@*/
  +{
  +    struct suffixPairs_s * sp;
  +    const char * fn = z->ifn;
  +    const char * t = NULL;
  +
  +    for (sp = suffixPairs; sp->csuffix != NULL; sp++) {
  +     if (opt_format != sp->format)
  +         continue;
  +     if (!chkSuffix(fn, sp->csuffix))
  +         continue;
  +     t = changeSuffix(fn, sp->csuffix, sp->usuffix);
  +     break;
  +    }
  +
  +    if (t == NULL)
  +     t = xstrdup(fn);
  +
  +if (_debug)
  +fprintf(stderr, "==> uncompressedFN: %s\n", t);
  +    return t;
  +}
  +
  +/**
  + * Return (malloc'd) compressed file name.
  + * @param z          rpmz container
  + * @return           compressed file name
  + */
  +static const char * compressedFN(rpmz z)
  +     /*...@*/
  +{
  +    struct suffixPairs_s * sp;
  +    const char * fn = z->ifn;
  +    const char * t = NULL;
  +
  +    for (sp = suffixPairs; sp->csuffix != NULL; sp++) {
  +     if (opt_format != sp->format || *sp->usuffix == '\0')
  +         continue;
  +     if (!chkSuffix(fn, sp->usuffix))
  +         continue;
  +     t = changeSuffix(fn, sp->usuffix, sp->csuffix);
  +     break;
  +    }
  +
  +    if (t == NULL)
  +     t = rpmGetPath(fn, (z->suffix ? z->suffix : z->osuffix), NULL);
  +
  +if (_debug)
  +fprintf(stderr, "==>   compressedFN: %s\n", t);
  +    return t;
  +}
   
   /*
    * Copy input to output.
    */
  -static rpmRC rpmz_copy(FD_t in, FD_t out)
  +static rpmRC rpmzCopy(rpmz z)
   {
  -    char buf[BUFLEN];
  -    size_t len;
  -
       for (;;) {
  -        len = Fread(buf, 1, sizeof(buf), in);
  -        if (Ferror(in))
  +     size_t len = Fread(z->b, 1, z->nb, z->ifd);
  +
  +     if (Ferror(z->ifd))
            return RPMRC_FAIL;
   
  -        if (len == 0) break;
  +     if (len == 0) break;
   
  -        if (Fwrite(buf, 1, len, out) != len)
  +     if (Fwrite(z->b, 1, len, z->ofd) != len)
            return RPMRC_FAIL;
       }
       return RPMRC_OK;
   }
   
  +static rpmRC rpmzFini(rpmz z, rpmRC rc)
  +{
  +    int xx;
  +
  +    if (z->ifd != NULL) {
  +     xx = Fclose(z->ifd);
  +     z->ifd = NULL;
  +    }
  +    if (z->ofd != NULL) {
  +     xx = Fclose(z->ofd);
  +     z->ofd = NULL;
  +    }
  +
  +    /* Clean up input/output files as needed. */
  +    switch (rc) {
  +    default:
  +     break;
  +    case RPMRC_FAIL:
  +     if (z->ofn != NULL && strcmp(z->ofn, stdout_filename)) {
  +         xx = Unlink(z->ofn);
  +if (_debug)
  +fprintf(stderr, "==> Unlink(%s) FAIL\n", z->ofn);
  +     }
  +     break;
  +    case RPMRC_OK:
  +     if (!opt_keep_original && z->ifn != stdin_filename) {
  +         xx = Unlink(z->ifn);
  +if (_debug)
  +fprintf(stderr, "==> Unlink(%s)\n", z->ifn);
  +     }
  +     break;
  +    }
  +    z->ofn = _free(z->ofn);
  +
  +    return rc;
  +}
  +
   /*
    * Compress the given file: create a corresponding .gz file and remove the
    * original.
    */
  -static rpmRC file_compress(const char *file, const char *fmode)
  +static rpmRC rpmzCompress(rpmz z)
   {
  -    const char * infile = file;
  -    char outfile[MAX_NAME_LEN];
  -    FD_t in;
  -    FD_t out;
  -    rpmRC rc;
  -    int xx;
  +    struct stat sb;
  +    rpmRC rc = RPMRC_FAIL;
   
  -    (void) stpcpy( stpcpy(outfile, file), GZ_SUFFIX);
  +if (_debug)
  +fprintf(stderr, "==> rpmzCompress(%p) ifn %s ofmode %s\n", z, z->ifn, 
z->ofmode);
  +    if (z->ifn == NULL) {
  +     z->ifn = stdin_filename;
  +     z->ifd = fdDup(STDIN_FILENO);
  +    } else {
  +     if (Stat(z->ifn, &sb) < 0) {
  +         fprintf(stderr, "%s: input %s doesn't exist, skipping\n",
  +                     __progname, z->ifn);
  +         goto exit;
  +     }
  +     if (!S_ISREG(sb.st_mode)) {
  +         fprintf(stderr, "%s: input %s is not a regular file, skipping\n",
  +                     __progname, z->ifn);
  +         goto exit;
  +     }
  +     z->ifd = Fopen(z->ifn, z->ifmode);
  +    }
  +    if (z->ifd == NULL || Ferror(z->ifd)) {
  +     fprintf(stderr, "%s: can't open %s\n", __progname, z->ifn);
  +     goto exit;
  +    }
   
  -    in = Fopen(infile, "rb");
  -    if (in == NULL) {
  -        fprintf(stderr, "%s: can't Fopen %s\n", __progname, infile);
  -     return RPMRC_FAIL;
  -    }
  -    out = gzdio->_fopen(outfile, fmode);
  -    if (out == NULL) {
  -        fprintf(stderr, "%s: can't _fopen %s\n", __progname, outfile);
  -     xx = Fclose(in);
  -     return RPMRC_FAIL;
  -    }
  -    rc = rpmz_copy(in, out);
  -    xx = Fclose(in);
  -    xx = Fclose(out);
  -    if (rc == RPMRC_OK)
  -     xx = Unlink(infile);
  -    return rc;
  +    if (opt_stdout) {
  +     z->ofn = xstrdup(stdout_filename);
  +     z->ofd = z->odio->_fdopen(fdDup(STDOUT_FILENO), z->ofmode);
  +    } else {
  +     if (z->ifn == stdin_filename)   /* XXX error needed here. */
  +         goto exit;
  +     z->ofn = compressedFN(z);
  +     if (!opt_force && Stat(z->ofn, &sb) == 0) {
  +         fprintf(stderr, "%s: output file %s already exists\n",
  +                     __progname, z->ofn);
  +         /* XXX TODO: ok to overwrite(y/N)? */
  +         goto exit;
  +     }
  +     z->ofd = z->odio->_fopen(z->ofn, z->ofmode);
  +     fdFree(z->ofd, NULL);           /* XXX adjust refcounts. */
  +    }
  +    if (z->ofd == NULL || Ferror(z->ofd)) {
  +     fprintf(stderr, "%s: can't open %s\n", __progname, z->ofn);
  +     goto exit;
  +    }
  +
  +    rc = rpmzCopy(z);
  +
  +exit:
  +    return rpmzFini(z, rc);
   }
   
   /*
    * Uncompress the given file and remove the original.
    */
  -static rpmRC file_uncompress(const char *file)
  +static rpmRC rpmzUncompress(rpmz z)
   {
  -    char buf[MAX_NAME_LEN];
  -    const char *infile, *outfile;
  -    FD_t out;
  -    FD_t in;
  -    size_t len = strlen(file);
  -    rpmRC rc;
  -    int xx;
  +    struct stat sb;
  +    rpmRC rc = RPMRC_FAIL;
   
  -    strcpy(buf, file);
  +if (_debug)
  +fprintf(stderr, "==> rpmzUncompress(%p) ifn %s ofmode %s\n", z, z->ifn, 
z->ofmode);
  +    if (z->ifn == NULL) {
  +     z->ifn = stdin_filename;
  +     z->ifd = z->idio->_fdopen(fdDup(STDIN_FILENO), z->ifmode);
  +    } else {
  +     if (Stat(z->ifn, &sb) < 0) {
  +         fprintf(stderr, "%s: input %s doesn't exist, skipping\n",
  +                     __progname, z->ifn);
  +         goto exit;
  +     }
  +     if (!S_ISREG(sb.st_mode)) {
  +         fprintf(stderr, "%s: input %s is not a regular file, skipping\n",
  +                     __progname, z->ifn);
  +         goto exit;
  +     }
  +     z->ifd = z->idio->_fopen(z->ifn, z->ifmode);
  +     fdFree(z->ifd, NULL);           /* XXX adjust refcounts. */
  +    }
  +    if (z->ifd == NULL || Ferror(z->ifd)) {
  +     fprintf(stderr, "%s: can't open %s\n", __progname, z->ifn);
  +     goto exit;
  +    }
   
  -    if (len > SUFFIX_LEN && strcmp(file+len-SUFFIX_LEN, GZ_SUFFIX) == 0) {
  -        buf[len-SUFFIX_LEN] = '\0';
  -        infile = file;
  -        outfile = buf;
  +    if (opt_stdout)  {
  +     z->ofn = xstrdup(stdout_filename);
  +     z->ofd = fdDup(STDOUT_FILENO);
       } else {
  -        strcat(buf, GZ_SUFFIX);
  -        outfile = file;
  -        infile = buf;
  -    }
  -    in = gzdio->_fopen(infile, "rb");
  -    if (in == NULL) {
  -        fprintf(stderr, "%s: can't _fopen %s\n", __progname, infile);
  -     return RPMRC_FAIL;
  -    }
  -    out = Fopen(outfile, "wb");
  -    if (out == NULL) {
  -        fprintf(stderr, "%s: can't Fopen %s\n", __progname, outfile);
  -     xx = Fclose(in);
  -     return RPMRC_FAIL;
  -    }
  -    rc = rpmz_copy(in, out);
  -    xx = Fclose(in);
  -    xx = Fclose(out);
  -    if (rc == RPMRC_OK)
  -     xx = Unlink(infile);
  -    return rc;
  +     if (z->ifn == stdin_filename)   /* XXX error needed here. */
  +         goto exit;
  +     z->ofn = uncompressedFN(z);
  +     if (!opt_force && Stat(z->ofn, &sb) == 0) {
  +         fprintf(stderr, "%s: output file %s already exists\n",
  +                     __progname, z->ofn);
  +         /* XXX TODO: ok to overwrite(y/N)? */
  +         goto exit;
  +     }
  +     z->ofd = Fopen(z->ofn, z->ofmode);
  +    }
  +    if (z->ofd == NULL || Ferror(z->ofd)) {
  +     fprintf(stderr, "%s: can't Fopen %s\n", __progname, z->ofn);
  +     goto exit;
  +    }
  +
  +    rc = rpmzCopy(z);
  +
  +exit:
  +    return rpmzFini(z, rc);
   }
   
   /*==============================================================*/
  @@ -512,7 +751,6 @@
        OPT_DIST,
   };
   
  -
   static void
   set_delta(void *options, rpmuint32_t key, rpmuint64_t value)
        /*...@*/
  @@ -659,11 +897,13 @@
   /**
    */
   static void rpmzArgCallback(poptContext con,
  -                /*...@unused@*/ enum poptCallbackReason reason,
  -                const struct poptOption * opt, const char * arg,
  -                /*...@unused@*/ void * data)
  +             /*...@unused@*/ enum poptCallbackReason reason,
  +             const struct poptOption * opt, const char * arg,
  +             /*...@unused@*/ void * data)
        /*...@*/
   {
  +    rpmz z = _rpmz;
  +
       /* XXX avoid accidental collisions with POPT_BIT_SET for flags */
       if (opt->arg == NULL)
       switch (opt->val) {
  @@ -708,19 +948,27 @@
        }
        break;
       case 'F':
  -     if (!strcmp(arg, "auto"))
  +     if (!strcmp(arg, "auto")) {
            opt_format = FORMAT_AUTO;
  -     else if (!strcmp(arg, "xz"))
  +     } else if (!strcmp(arg, "xz")) {
  +         z->idio = z->odio = xzdio;
  +         z->osuffix = ".xz";
            opt_format = FORMAT_XZ;
  -     else if (!strcmp(arg, "lzma"))
  +     } else if (!strcmp(arg, "lzma") || !strcmp(arg, "alone")) {
  +         z->idio = z->odio = lzdio;
  +         z->osuffix = ".lzma";
            opt_format = FORMAT_LZMA;
  -     else if (!strcmp(arg, "alone"))
  -         opt_format = FORMAT_LZMA;
  -     else if (!strcmp(arg, "gzip") || !strcmp(arg, "gz"))
  -         opt_format = FORMAT_GZIP;
  -     else if (!strcmp(arg, "raw"))
  +     } else if (!strcmp(arg, "raw")) {
            opt_format = FORMAT_RAW;
  -     else {
  +     } else if (!strcmp(arg, "gzip") || !strcmp(arg, "gz")) {
  +         z->idio = z->odio = gzdio;
  +         z->osuffix = ".gz";
  +         opt_format = FORMAT_GZIP;
  +     } else if (!strcmp(arg, "bzip2") || !strcmp(arg, "bz2")) {
  +         z->idio = z->odio = bzdio;
  +         z->osuffix = ".bz2";
  +         opt_format = FORMAT_BZIP2;
  +     } else {
            fprintf(stderr, _("%s: Unknown file format type \"%s\"\n"),
                __progname, arg);
            /*...@-exitarg@*/ exit(2); /*...@=exitarg@*/
  @@ -791,7 +1039,7 @@
   static struct poptOption optionsTable[] = {
   /*...@-type@*/ /* FIX: cast? */
    { NULL, '\0', POPT_ARG_CALLBACK | POPT_CBFLAG_INC_DATA | 
POPT_CBFLAG_CONTINUE,
  -        rpmzArgCallback, 0, NULL, NULL },
  +     rpmzArgCallback, 0, NULL, NULL },
   /*...@=type@*/
   
     /* ===== Operation modes */
  @@ -945,11 +1193,15 @@
        N_("display version and license information and exit"), NULL },
   #endif
   
  + { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmioAllPoptTable, 0,
  +     N_("Common options for all rpmio executables:"),
  +     NULL },
  +
     POPT_AUTOALIAS
     POPT_AUTOHELP
   
     { NULL, (char)-1, POPT_ARG_INCLUDE_TABLE, NULL, 0,
  -        N_("\
  +     N_("\
   Usage: rpmz [OPTION]... [FILE]...\n\
   Compress or decompress FILEs.\n\
   \n\
  @@ -967,47 +1219,69 @@
                rpmGlobalMacroContext, fileSystem, internalState @*/
   {
       poptContext optCon;
  +    rpmz z = _rpmz;
       const char ** av;
       int ac;
       int rc = 1;              /* assume failure. */
  +    int xx;
       int i;
   
   /*...@-observertrans -readonlytrans @*/
       __progname = "rpmz";
   /*...@=observertrans =readonlytrans @*/
   
  +    /* XXX TODO: Set modes and format based on argv[0]. */
  +
  +    z->b = xmalloc(z->nb);
  +#ifndef      DYING
  +    z->idio = z->odio = gzdio;
  +    z->osuffix = ".gz";
  +    opt_format = FORMAT_GZIP;
  +#endif
  +
       /* Make sure that stdin/stdout/stderr are open. */
       io_init();
   
       /* Set hardware specific parameters. */
       hw_init();
   
  -    /* Parse options. */
  +    /* XXX TODO: Parse environment options. */
  +
  +    /* Parse CLI options. */
       optCon = rpmioInit(argc, argv, optionsTable);
       av = poptGetArgs(optCon);
  -    if (av == NULL || av[0] == NULL) {
  -     poptPrintUsage(optCon, stderr, 0);
  -     goto exit;
  -    }
       ac = argvCount(av);
   
  +    /* With no arguments, act as a stdin/stdout filter. */
  +    if (av == NULL || av[0] == NULL)
  +     ac++;
  +
  +    if (opt_mode == MODE_COMPRESS) {
  +     xx = snprintf(z->ofmode, sizeof(z->ofmode)-1, "wb%u",
  +             (unsigned)(preset_number % 10));
  +    }
  +    z->suffix = opt_suffix;
  +
       /* Process arguments. */
  -    if (av != NULL)
       for (i = 0; i < ac; i++) {
  -     rpmRC frc;
  -     frc = RPMRC_OK;
  +     rpmRC frc = RPMRC_OK;
  +
  +     /* Use NULL for stdin. */
  +     z->ifn = (av && strcmp(av[i], "-") ? av[i] : NULL);
  +
        switch (opt_mode) {
        case MODE_COMPRESS:
  -         frc = file_compress(av[i], "wb6");
  +         frc = rpmzCompress(z);
            break;
        case MODE_DECOMPRESS:
  -         frc = file_uncompress(av[i]);
  +         frc = rpmzUncompress(z);
            break;
        case MODE_TEST:
            break;
        case MODE_LIST:
            break;
        }
  +
        if (frc != RPMRC_OK)
            goto exit;
       }
  @@ -1015,6 +1289,7 @@
       rc = 0;
   
   exit:
  +    z->b = _free(z->b);
       optCon = rpmioFini(optCon);
   
       return rc;
  @@ .
______________________________________________________________________
RPM Package Manager                                    http://rpm5.org
CVS Sources Repository                                rpm-cvs@rpm5.org

Reply via email to