"Fossies" - the Fresh Open Source Software Archive

Member "gretl-2020e/plugin/zipunzip/zipwork.c" (29 Aug 2019, 19506 Bytes) of package /linux/misc/gretl-2020e.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "zipwork.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2   The code here is based on code by Mark Adler et al. which is
    3   Copyright (c) 1990-2005 Info-ZIP.  Specifically, it derives from zip
    4   version 2.31.  Modifications are by Allin Cottrell, March, 2006.
    5   Please see the included file "LICENSE" which contains the Info-ZIP
    6   license information.
    7 */
    8 
    9 #include "zunz_private.h"
   10 
   11 #include <ctype.h>
   12 #include <sys/stat.h>
   13 #include <sys/types.h>
   14 #include <dirent.h>
   15 #include <errno.h>
   16 
   17 /* Read a new block from the current input file; update the crc and
   18    input file size; check for over-sized files.
   19 */
   20 
   21 static guint32 file_read_chunk (FILE *fin, guchar *buf, unsigned size, 
   22                 guint32 *crc, guint32 *isize, int *err)
   23 {
   24     guint32 len;
   25 
   26     len = fread(buf, 1, size, fin);
   27     if (len == 0) {
   28     return len;
   29     }
   30 
   31     *crc = crc32(*crc, buf, len);
   32     *isize += len;
   33 
   34     if ((*isize & (guint32) 0xffffffffL) < len) {
   35     ziperr(ZE_BIG, "file exceeds Zip's 4GB uncompressed size limit");
   36     *err = ZE_BIG;
   37     }
   38 
   39     return len;
   40 }
   41 
   42 static int zlib_check_version (void)
   43 {
   44     int err = 0;
   45 
   46     if (zlib_version[0] != ZLIB_VERSION[0]) {
   47     err = ziperr(ZE_LOGIC, "incompatible zlib version (expected %s, found %s)",
   48              ZLIB_VERSION, zlib_version);
   49     } else if (strcmp(zlib_version, ZLIB_VERSION) != 0) {
   50         fprintf(stderr,
   51                 "warning:  different zlib version (expected %s, using %s)\n",
   52                 ZLIB_VERSION, zlib_version);
   53     }
   54 
   55     return err;
   56 }
   57 
   58 /* Convert from zlib error code Z_* to zip error code ZE_*:
   59    we're standardizing on (an extended version of) ZE_* for
   60    reporting errors from this library. */
   61 
   62 static int translate_zlib_error (int zerr)
   63 {
   64     int err = ZE_LOGIC;
   65 
   66     if (zerr == Z_DATA_ERROR) {
   67     err = ZE_DATA;
   68     } else if (zerr == Z_MEM_ERROR) {
   69     err = ZE_MEM;
   70     }
   71 
   72     return err;
   73 }
   74 
   75 /* Re. the negative values for the windowBits argument to inflateInit2
   76    and deflateInit2 value below: giving the negative is the special
   77    code needed to get zlib to treat the data as a raw deflate stream,
   78    not zlib-wrapped (see zlib.h).
   79 */
   80 
   81 static int zlib_inflate_init (z_stream *strm)
   82 {
   83     int windowBits = 15;
   84     int err;
   85 
   86     err = zlib_check_version();
   87     if (err) {
   88     return err;
   89     }
   90 
   91     strm->zalloc = Z_NULL;
   92     strm->zfree = Z_NULL;
   93     strm->opaque = Z_NULL;
   94     strm->avail_in = 0;
   95     strm->next_in = Z_NULL;
   96 
   97     err = inflateInit2(strm, -windowBits);
   98 
   99     if (err != Z_OK) {
  100     err = translate_zlib_error(err);
  101     ziperr(err, "zlib inflateInit2 failure");
  102     }
  103 
  104     return err;
  105 }
  106 
  107 static int zlib_deflate_init (z_stream *strm, int level)
  108 {
  109     int windowBits = 15;
  110     int err = 0;
  111 
  112     err = zlib_check_version();
  113     if (err) {
  114     return err;
  115     }
  116 
  117     strm->zalloc = Z_NULL;
  118     strm->zfree = Z_NULL;
  119 
  120     err = deflateInit2(strm, level, Z_DEFLATED, -windowBits, 8, 0);
  121 
  122     if (err != Z_OK) {
  123     err = translate_zlib_error(err);
  124         ziperr(err, "zlib deflateInit2 failure");
  125     }
  126 
  127     return err;
  128 }
  129 
  130 static guint32 compress_file (zfile *zf, zlist *z_entry, FILE *fin, 
  131                   guint32 *crc, guint32 *isize, 
  132                   int *method, int *err)
  133 {
  134     guchar inbuf[WSIZE];
  135     guchar outbuf[WSIZE];
  136     int maybe_stored = 0;
  137     guint32 csize = 0;
  138 
  139     if (!zf->strm_initted) {
  140         *err = zlib_deflate_init(&zf->strm, zf->level);
  141         if (*err) {
  142             return 0;
  143     }
  144     zf->strm_initted = 1;
  145     }
  146 
  147     if (zf->level <= 2) {
  148         z_entry->flags |= 4;
  149     } else if (zf->level >= 8) {
  150         z_entry->flags |= 2;
  151     }
  152 
  153     zf->strm.next_in = inbuf;
  154     zf->strm.avail_in = file_read_chunk(fin, zf->strm.next_in, WSIZE,
  155                     crc, isize, err);
  156     if (*err) {
  157     return 0;
  158     }
  159     
  160 
  161     if (zf->strm.avail_in < WSIZE) {
  162         size_t more = file_read_chunk(fin, zf->strm.next_in + zf->strm.avail_in,
  163                       (WSIZE - zf->strm.avail_in), crc, isize,
  164                       err);
  165 
  166     if (*err) {
  167         return 0;
  168     }
  169         if (more == EOF || more == 0) {
  170             maybe_stored = 1;
  171         } else {
  172             zf->strm.avail_in += more;
  173         }
  174     }
  175 
  176     zf->strm.next_out = outbuf;
  177     zf->strm.avail_out = WSIZE;
  178 
  179     trace(3, "compress_file: maybe_stored = %d\n", maybe_stored);
  180 
  181     if (!maybe_stored) {
  182     while (zf->strm.avail_in != 0 && zf->strm.avail_in != EOF) {
  183         *err = deflate(&zf->strm, Z_NO_FLUSH);
  184         if (*err != Z_OK && *err != Z_STREAM_END) {
  185         *err = translate_zlib_error(*err);
  186         return 0;
  187         }
  188         if (zf->strm.avail_out == 0) {
  189         if (fwrite(outbuf, 1, WSIZE, zf->fp) != WSIZE) {
  190             *err = ZE_TEMP;
  191             return 0;
  192         }
  193         zf->strm.next_out = outbuf;
  194         zf->strm.avail_out = WSIZE;
  195         }
  196         if (zf->strm.avail_in == 0) {
  197         zf->strm.next_in = inbuf;
  198         zf->strm.avail_in = file_read_chunk(fin, zf->strm.next_in, WSIZE,
  199                             crc, isize, err);
  200         if (*err) {
  201             return 0;
  202         }
  203         }
  204     }
  205     }
  206 
  207     do {
  208         *err = deflate(&zf->strm, Z_FINISH);
  209         if (maybe_stored) {
  210             if (*err == Z_STREAM_END && zf->strm.total_out >= zf->strm.total_in) {
  211                 unsigned len_out = (unsigned) zf->strm.total_in;
  212 
  213         trace(2, "deflation does not reduce size, switch to STORE\n");
  214 
  215                 if (fwrite(inbuf, 1, len_out, zf->fp) != len_out) {
  216             *err = ZE_TEMP;
  217             return 0;
  218                 }
  219                 zf->strm.total_out = (guint32) len_out;
  220                 *method = STORE;
  221                 break;
  222             } else {
  223                 maybe_stored = 0;
  224             }
  225         }
  226         if (zf->strm.avail_out < WSIZE) {
  227             unsigned len_out = WSIZE - zf->strm.avail_out;
  228 
  229             if (fwrite(outbuf, 1, len_out, zf->fp) != len_out) {
  230         *err = ZE_TEMP;
  231         return 0;
  232             }
  233             zf->strm.next_out = outbuf;
  234             zf->strm.avail_out = WSIZE;
  235         }
  236     } while (*err == Z_OK);
  237 
  238     if (*err != Z_STREAM_END) {
  239     *err = translate_zlib_error(*err);
  240     return 0;
  241     }
  242 
  243     if (z_entry->att == (guint16) UNKNOWN) {
  244         z_entry->att = (guint16) (zf->strm.data_type == Z_ASCII ? ASCII : BINARY);
  245     }
  246 
  247     csize = zf->strm.total_out;
  248 
  249     *err = deflateReset(&zf->strm);
  250     if (*err != Z_OK) { 
  251     *err = translate_zlib_error(*err);
  252     return 0;
  253     }
  254 
  255     return csize;
  256 }
  257 
  258 static void free_old_extra_fields (zlist *z)
  259 {
  260     if (z->extlen) {
  261     free(z->extra);
  262     }
  263     if (z->cextlen && z->extra != z->cextra) {
  264     free(z->cextra);
  265     }
  266     z->extra = z->cextra = NULL;
  267     z->extlen = z->cextlen = 0;
  268 }
  269 
  270 /* Compress the file z->name into the zip entry described by *z and
  271    write it to the file zf->fp.  Return an error code in the ZE_ class.
  272    Also, update zf->tempzn by the number of bytes written.
  273 
  274    Note: a zip "entry" includes a local header (which includes the file
  275    name), an encryption header if encrypting, the compressed data
  276    and possibly an extended local header.
  277 */
  278 
  279 int zipup (zfile *zf, zlist *z)
  280 {
  281     guchar b[WSIZE];      /* read buffer */
  282     FILE *fin = NULL;     /* input file pointer */
  283     iztimes f_utim;       /* UNIX timestamps, filled by file_mod_time() */
  284     guint32 ftime;        /* time returned by file_mod_time() */
  285     guint32 attr = 0L;    /* attributes from file_mod_time() */
  286     long fsize = -3L;     /* size returned by file_mod_time */
  287     size_t k = 0;         /* result of read */
  288     int method;           /* compression method for this entry */
  289     guint32 o, p;         /* offsets in zip file */
  290     guint32 s = 0L;       /* size of compressed data */
  291     int isdir;            /* set for a directory name */
  292     int islink = 0;       /* set for a symbolic link */
  293     int set_type = 0;     /* set if file type (ascii/binary) unknown */
  294     guint32 isize = 0;    /* length of input file */
  295     guint32 crc = 0;      /* CRC for input data */
  296     int err = 0;
  297 
  298     trace(3, "at top of 'zipup': tempzn = %d\n", (int) zf->tempzn);
  299 
  300     z->namelen = strlen(z->iname);
  301     isdir = z->iname[z->namelen-1] == '/';
  302 
  303     ftime = file_mod_time(z->name, &attr, &fsize, &f_utim, zf);
  304     if (ftime == 0 || fsize == -3L) {
  305     return ZE_OPEN;
  306     }
  307 
  308     /* fsize is set to -1 if the input file is a device, -2 for a volume label */
  309     if (fsize == -2L) {
  310     isdir = 1;
  311     fsize = 0;
  312     } else if (isdir != ((attr & MSDOS_DIR_ATTR) != 0)) {
  313     /* don't overwrite a directory with a file and vice-versa */
  314     return ZE_MISS;
  315     }
  316 
  317     z->att = (guint16) UNKNOWN; /* will be changed later */
  318     z->atx = 0; /* may be changed by set_extra_field() */
  319 
  320     free_old_extra_fields(z);
  321 
  322     /* initialize method based on the global method */
  323     method = zf->method;
  324 
  325     /* create extra field and change z->att and z->atx */
  326     set_extra_field(zf, z, &f_utim);
  327 
  328     /* Open input file to be zipped up */
  329     islink = is_symlink(attr);
  330     if (islink) {
  331     trace(2, "'%s': is symlink, using STORE\n", z->name);
  332     method = STORE;
  333     } else if (isdir) { 
  334     trace(2, "'%s': is directory, using STORE\n", z->name);
  335     method = STORE;
  336     fsize = 0;
  337     } else {
  338     trace(2, "'%s': is regular file, trying DEFLATE\n", z->name);
  339     fin = gretl_fopen(z->name, "rb");
  340     if (fin == NULL) {
  341         return ZE_OPEN;
  342     }
  343     }
  344 
  345     z->time = ftime;
  346 
  347     if (fsize == 0) {
  348     method = STORE;
  349     } 
  350 
  351     if (method == BEST) {
  352     method = DEFLATE;
  353     }
  354 
  355     /* Fill in header information and write local header to zip file.
  356        This header will later be re-written since compressed length
  357        and crc are not yet known.
  358      */
  359 
  360     /* (Assume ext, cext, com, and zname already filled in.) */
  361     z->version_made = (guint16) (OS_CODE + Z_MAJORVER * 10 + Z_MINORVER);
  362 
  363     z->version_extract = (guint16) (method == STORE ? 10 : 20);
  364     z->crc = 0;  /* to be updated later */
  365 
  366     /* Assume first that we will need an extended local header */
  367     z->flags = 8;
  368     z->lflags = z->flags;
  369     z->method = (guint16) method;
  370     z->csize = (guint32) (method == STORE && fsize >= 0 ? fsize : 0);
  371     z->usize = (guint32) (fsize != -1L ? fsize : 0); 
  372     z->dsk = 0; /* ?? */
  373     if (z->att == (guint16) UNKNOWN) {
  374     z->att = BINARY; /* set sensible value in header */
  375     set_type = 1;
  376     }
  377 
  378     /* Attributes from filetime(), flag bits from set_extra_field() */
  379 #ifdef WIN32
  380     z->atx = (z->dosflag)? attr & 0xff : attr | (z->atx & 0x0000ff00);
  381 #else
  382     z->atx = attr | (z->atx & 0x0000ff00);
  383 #endif /* WIN32 */
  384     z->off = zf->tempzn;
  385 
  386     err = put_local_header(z, zf->fp);
  387     if (err) {
  388     if (fin != NULL) {
  389         fclose(fin);
  390     }
  391     return err;
  392     }
  393 
  394     zf->tempzn += 4 + LOCHEAD + z->namelen + z->extlen;
  395     trace(3, "before compressing, zf->tempzn = %d\n", (int) zf->tempzn);
  396 
  397     if (ferror(zf->fp)) {
  398     if (fin != NULL) {
  399         fclose(fin);
  400     }
  401     return ziperr(ZE_WRITE, "unexpected error on zip file");
  402     }
  403 
  404     o = ftell(zf->fp);
  405     trace(3, "before compressing, ftell(zf->fp) gave o = %d\n", (int) o);
  406 
  407     if (ferror(zf->fp)) {
  408     clearerr(zf->fp);
  409     }
  410 
  411     /* Write stored or deflated file to zip file */
  412 
  413     isize = 0L;
  414     crc = 0L;
  415 
  416     if (method == DEFLATE) {
  417     if (set_type) {
  418         z->att = (guint16) UNKNOWN; /* finally set in filecompress() */
  419     }
  420     s = compress_file(zf, z, fin, &crc, &isize, &method, &err);
  421     trace(1, "compress_file returned size s = %d\n", (int) s);
  422     } else if (!isdir) {
  423     if (islink) {
  424         k = read_symlink(z->name, (char *) b, WSIZE);
  425         crc = crc32(crc, (guchar *) b, k);
  426         if (fwrite(b, 1, k, zf->fp) != k) {
  427         return ZE_TEMP;
  428         }
  429         isize = k;
  430     } else {
  431         while ((k = file_read_chunk(fin, b, WSIZE, &crc, &isize, &err)) > 0 
  432            && k != (size_t) EOF) {
  433         if (fwrite(b, 1, k, zf->fp) != k) {
  434             if (fin != NULL) {
  435             fclose(fin);
  436             }
  437             return ZE_TEMP;
  438         }
  439         }
  440     }
  441     s = isize;
  442     }
  443 
  444     if (fin != NULL && ferror(fin)) {
  445     perror("\nzip warning");
  446     clearerr(fin);
  447     }
  448 
  449     if (fin != NULL) {
  450     fclose(fin);
  451     }
  452 
  453     zf->tempzn += s;
  454     p = zf->tempzn; /* save for future fseek() */
  455     trace(2, "after compressing, p = zf->tempzn = %d\n", (int) p);
  456 
  457     if (fsize != -1L && isize != (guint32) fsize) {
  458     trace(2, " isize=%lu, fsize=%lu\n", isize, fsize);
  459     }
  460 
  461     /* now rewrite the local header with correct information */
  462     z->crc = crc;
  463     z->csize = s;
  464     z->usize = isize;
  465 
  466     if (fseek(zf->fp, z->off, SEEK_SET)) {
  467     if (z->method != (guint16) method) {
  468         return ziperr(1, "can't rewrite method");
  469     }
  470     if (method == STORE && fsize < 0) {
  471         return ziperr(ZE_PARMS, "zip -0 not supported "
  472               "for I/O on pipes or devices");
  473     }
  474     err = put_extended_header(z, zf->fp);
  475     if (err) {
  476         return err;
  477     }
  478     zf->tempzn += 16L;
  479     z->flags = z->lflags; /* if flags modified by inflate */
  480     } else {
  481     /* seek ok, ftell() should work, check compressed size */
  482     if (p - o != s) {
  483         fprintf(stderr, " s=%ld, actual=%ld ", (glong) s, (glong) (p-o));
  484         return ziperr(ZE_FORM, "incorrect compressed size");
  485     }
  486     z->method = (guint16) method;
  487     /* Need PKUNZIP 2.0 unless STORED */
  488     z->version_extract = (guint16) (method == STORE ? 10 : 20);
  489     if ((z->flags & 1) == 0) {
  490         z->flags &= ~8; /* clear the extended local header flag */
  491     }
  492     z->lflags = z->flags;
  493     /* rewrite the local header */
  494     err = put_local_header(z, zf->fp);
  495     if (err) {
  496         return err;
  497     }
  498     if (fseek(zf->fp, p, SEEK_SET)) {
  499         return ZE_READ;
  500     }
  501     if ((z->flags & 1) != 0) {
  502         /* encrypted file, extended header still required (??) */
  503         if ((err = put_extended_header(z, zf->fp)) != ZE_OK) {
  504         return err;
  505         }
  506         zf->tempzn += 16L;
  507     }
  508     }
  509 
  510     /* Free the local extra field, no longer needed */
  511     if (z->extlen) {
  512     if (z->extra != z->cextra) {
  513         free(z->extra);
  514         z->extra = NULL;
  515     }
  516     z->extlen = 0;
  517     }
  518 
  519     return ZE_OK;
  520 }
  521 
  522 void zlib_deflate_free (zfile *zf)
  523 {
  524     int err;
  525 
  526     if (zf->strm_initted) {
  527         err = deflateEnd(&zf->strm);
  528         if (err != Z_OK && err !=Z_DATA_ERROR) {
  529             ziperr(ZE_LOGIC, "zlib deflateEnd failed");
  530         }
  531     }
  532 }
  533 
  534 /* now stuff pertaining to unzipping */
  535 
  536 static int make_dirs_in_path (const char *fname,
  537                   const char *prefix)
  538 {
  539     char *dtarg, dirname[FILENAME_MAX];
  540     const char *p = fname;
  541     GDir *dir;
  542     int len = 0;
  543     int err = 0;
  544 
  545     errno = 0;
  546 
  547     if (fname == NULL) {
  548     return ZE_READ;
  549     }
  550 
  551     if (prefix != NULL && *prefix != '\0') {
  552     int n = strlen(prefix);
  553     
  554     strcpy(dirname, prefix);
  555     if (prefix[n-1] != G_DIR_SEPARATOR) {
  556         strcat(dirname, G_DIR_SEPARATOR_S);
  557         n++;
  558     }
  559     dtarg = dirname + n;
  560     } else {
  561     dtarg = dirname;
  562     }
  563 
  564     trace(2, "doing make_dirs_in_path for '%s'\n", fname);
  565 
  566     while (strchr(p, G_DIR_SEPARATOR) && !err) {
  567     len += strcspn(p, G_DIR_SEPARATOR_S);
  568     *dtarg = '\0';
  569     strncat(dtarg, fname, len);
  570     trace(2, "got dirname = '%s'\n", dirname);
  571     dir = gretl_opendir(dirname);
  572     if (dir != NULL) {
  573         g_dir_close(dir);
  574     } else if (errno == ENOENT) {
  575         if (gretl_mkdir(dirname) != 0) {
  576         err = ZE_CREAT;
  577         }
  578     } else {
  579         err = ZE_READ;
  580     }
  581     if (!err) {
  582         p = fname + len;
  583         while (*p == G_DIR_SEPARATOR) {
  584         p++;
  585         len++;
  586         }
  587     }
  588     }
  589 
  590     if (err) {
  591     ziperr(err, "trying to create or open directory");
  592     }    
  593 
  594     return err;
  595 }
  596 
  597 static int 
  598 zip_inflate (FILE *src, FILE *dest, z_stream *strm, int *initted, guint32 *crc)
  599 {
  600     guchar inbuf[WSIZE];
  601     guchar outbuf[WSIZE];
  602     unsigned have;
  603     int zret = Z_OK;
  604     int err = 0;
  605 
  606     if (!*initted) {
  607     err = zlib_inflate_init(strm);
  608     if (err) {
  609         return err;
  610     }
  611     *initted = 1;
  612     }
  613 
  614     /* decompress until z stream ends or end of file */
  615     do {
  616         strm->avail_in = fread(inbuf, 1, WSIZE, src);
  617 
  618         if (ferror(src)) {
  619             return ZE_READ;
  620         }
  621         if (strm->avail_in == 0) {
  622             break;
  623     }
  624 
  625         strm->next_in = inbuf;
  626 
  627         /* run inflate() on input until output buffer not full */
  628         do {
  629             strm->avail_out = WSIZE;
  630             strm->next_out = outbuf;
  631             zret = inflate(strm, Z_NO_FLUSH);
  632         if (zret == Z_NEED_DICT || zret == Z_DATA_ERROR || zret == Z_MEM_ERROR) {
  633         err = translate_zlib_error(zret);
  634                 return err;
  635             }
  636             have = WSIZE - strm->avail_out;
  637             if (fwrite(outbuf, 1, have, dest) != have || ferror(dest)) {
  638                 return ZE_WRITE;
  639             }
  640         *crc = crc32(*crc, outbuf, have);
  641         } while (strm->avail_out == 0);
  642 
  643     } while (zret != Z_STREAM_END);
  644 
  645     inflateReset(strm);
  646 
  647     if (zret == Z_DATA_ERROR) {
  648     err = translate_zlib_error(zret);
  649     }
  650 
  651     return err;
  652 }
  653 
  654 /* extract an uncompressed archive member */
  655 
  656 static int zip_unstore (FILE *src, FILE *dest, guint32 usize,
  657             guint32 *crc)
  658 {
  659     guchar buf[WSIZE];
  660     guint32 b, rem = usize;
  661     int err = 0;
  662 
  663     while (rem > 0 && !err) {
  664     b = fread(buf, 1, (rem > WSIZE)? WSIZE : rem, src);
  665     if (ferror(src)) {
  666         err = ZE_READ;
  667     } else if (b > 0) {
  668         *crc = crc32(*crc, buf, b);
  669         if (fwrite(buf, 1, b, dest) != b) {
  670         err = ZE_WRITE;
  671         } else {
  672         rem -= b;
  673         }
  674     }
  675     }
  676 
  677     return err;
  678 }
  679 
  680 #ifndef WIN32
  681 
  682 /* recreate a symbolic link */
  683 
  684 static int zip_relink (FILE *src, const char *targ, guint32 usize)
  685 {
  686     char *lname;
  687     int err = 0;
  688 
  689     lname = calloc(usize + 1, 1);
  690     if (lname == NULL) {
  691     return ZE_MEM;
  692     }
  693 
  694     if (fread(lname, 1, usize, src) != usize) {
  695     err = ZE_READ;
  696     } else {
  697     gretl_remove(targ);
  698     if (symlink(lname, targ)) {
  699         err = ziperr(ZE_CREAT, targ);
  700     }
  701     }
  702 
  703     free(lname);
  704 
  705     return err;
  706 }
  707 
  708 #endif
  709 
  710 static FILE *open_zip_output (const char *name, const char *prefix)
  711 {
  712     FILE *fp;
  713 
  714     if (prefix != NULL && *prefix != '\0') {
  715     int n = strlen(prefix);
  716     gchar *fname;
  717 
  718     if (prefix[n-1] == G_DIR_SEPARATOR) {
  719         fname = g_strdup_printf("%s%s", prefix, name);
  720     } else {
  721         fname = g_strdup_printf("%s%c%s", prefix,
  722                     G_DIR_SEPARATOR, name);
  723     }
  724     fp = gretl_fopen(fname, "wb");
  725     g_free(fname);
  726     } else {
  727     fp = gretl_fopen(name, "wb");
  728     }
  729 
  730     return fp;
  731 }
  732 
  733 /* driver for zlib decompression or simple extraction */
  734 
  735 int decompress_to_file (zfile *zf, zlist *z, long offset)
  736 {
  737 #ifndef WIN32
  738     unsigned xattr = (unsigned) (z->atx >> 16) & 0xFFFF;
  739 #endif
  740     FILE *fout = NULL;
  741     int islink = 0;
  742     guint32 crc = 0;
  743     int err;
  744 
  745     if (z->flags & 1) {
  746     /* encrypted: not handled */
  747     return ziperr(ZE_CRYPT, NULL);
  748     } 
  749 
  750     err = make_dirs_in_path(z->zname, zf->eprefix);
  751     if (err) {
  752     return err;
  753     }
  754 
  755     if (z->iname[strlen(z->iname) - 1] == '/') {
  756     /* the stored item is a directory */
  757     trace(2, "'%s' is a directory, skipping decompression\n", z->iname);
  758     return 0;
  759     }
  760 
  761 #ifndef WIN32
  762     islink = (xattr & S_IFMT) == S_IFLNK;
  763 #endif
  764 
  765     /* overwriting existing file(s)? */
  766 
  767     if (!islink) {
  768     fout = open_zip_output(z->name, zf->eprefix);
  769     if (fout == NULL) {
  770         err = ZE_CREAT;
  771     }
  772     } else if (zf->eprefix != NULL) {
  773     /* never mind, too complicated! */
  774     return 0;
  775     }
  776 
  777     if (!err) {
  778     fseek(zf->fp, offset, SEEK_SET);
  779     if (z->method == STORE) {
  780         if (islink) {
  781         trace(1, "'%s' is a symlink, re-linking\n", z->iname);
  782 #ifndef WIN32
  783         err = zip_relink(zf->fp, z->name, z->usize);
  784 #endif
  785         } else {
  786         trace(1, "extracting %s at offset %d\n", z->name, (int) offset);
  787         err = zip_unstore(zf->fp, fout, z->usize, &crc);
  788         }
  789     } else {
  790         trace(1, "decompressing %s at offset %d\n", z->name, (int) offset);
  791         err = zip_inflate(zf->fp, fout, &zf->strm, &zf->strm_initted,
  792                   &crc);
  793     }
  794     if (fout != NULL) {
  795         fclose(fout);
  796     }
  797     }
  798 
  799     if (!err && !islink) {
  800     trace(2, "crc: original = %u, extracted = %u\n",
  801           z->crc, crc);
  802     if (crc != z->crc) {
  803         err = ZE_CRC;
  804     }
  805     }
  806 
  807     if (!err && !islink) {
  808     unsigned attr = (unsigned) (z->atx >> 16);
  809 
  810     if (attr == 0) {
  811         attr = get_ef_mode(z);
  812     }
  813 
  814     time_stamp_file(z->name, z->time);
  815     if (attr) {
  816         /* set permissions from zipfile */
  817         chmod(z->name, attr);
  818     }
  819     }
  820 
  821     return err;
  822 }
  823 
  824