Home | History | Annotate | Line # | Download | only in zlib
      1 /* gzwrite.c -- zlib functions for writing gzip files
      2  * Copyright (C) 2004-2019 Mark Adler
      3  * For conditions of distribution and use, see copyright notice in zlib.h
      4  */
      5 
      6 #include "gzguts.h"
      7 
      8 /* Initialize state for writing a gzip file.  Mark initialization by setting
      9    state->size to non-zero.  Return -1 on a memory allocation failure, or 0 on
     10    success. */
     11 local int gz_init(gz_statep state) {
     12     int ret;
     13     z_streamp strm = &(state->strm);
     14 
     15     /* allocate input buffer (double size for gzprintf) */
     16     state->in = (unsigned char *)malloc(state->want << 1);
     17     if (state->in == NULL) {
     18         gz_error(state, Z_MEM_ERROR, "out of memory");
     19         return -1;
     20     }
     21 
     22     /* only need output buffer and deflate state if compressing */
     23     if (!state->direct) {
     24         /* allocate output buffer */
     25         state->out = (unsigned char *)malloc(state->want);
     26         if (state->out == NULL) {
     27             free(state->in);
     28             gz_error(state, Z_MEM_ERROR, "out of memory");
     29             return -1;
     30         }
     31 
     32         /* allocate deflate memory, set up for gzip compression */
     33         strm->zalloc = Z_NULL;
     34         strm->zfree = Z_NULL;
     35         strm->opaque = Z_NULL;
     36         ret = deflateInit2(strm, state->level, Z_DEFLATED,
     37                            MAX_WBITS + 16, DEF_MEM_LEVEL, state->strategy);
     38         if (ret != Z_OK) {
     39             free(state->out);
     40             free(state->in);
     41             gz_error(state, Z_MEM_ERROR, "out of memory");
     42             return -1;
     43         }
     44         strm->next_in = NULL;
     45     }
     46 
     47     /* mark state as initialized */
     48     state->size = state->want;
     49 
     50     /* initialize write buffer if compressing */
     51     if (!state->direct) {
     52         strm->avail_out = state->size;
     53         strm->next_out = state->out;
     54         state->x.next = strm->next_out;
     55     }
     56     return 0;
     57 }
     58 
     59 /* Compress whatever is at avail_in and next_in and write to the output file.
     60    Return -1 if there is an error writing to the output file or if gz_init()
     61    fails to allocate memory, otherwise 0.  flush is assumed to be a valid
     62    deflate() flush value.  If flush is Z_FINISH, then the deflate() state is
     63    reset to start a new gzip stream.  If gz->direct is true, then simply write
     64    to the output file without compressing, and ignore flush. */
     65 local int gz_comp(gz_statep state, int flush) {
     66     int ret;
     67     ssize_t writ;
     68     size_t put;
     69     unsigned have, max = ((unsigned)-1 >> 2) + 1;
     70     z_streamp strm = &(state->strm);
     71 
     72     /* allocate memory if this is the first time through */
     73     if (state->size == 0 && gz_init(state) == -1)
     74         return -1;
     75 
     76     /* write directly if requested */
     77     if (state->direct) {
     78         while (strm->avail_in) {
     79             put = strm->avail_in > max ? max : strm->avail_in;
     80             writ = write(state->fd, strm->next_in, put);
     81             if (writ < 0) {
     82                 gz_error(state, Z_ERRNO, zstrerror());
     83                 return -1;
     84             }
     85             strm->avail_in -= (unsigned)writ;
     86             strm->next_in += writ;
     87         }
     88         return 0;
     89     }
     90 
     91     /* check for a pending reset */
     92     if (state->reset) {
     93         /* don't start a new gzip member unless there is data to write */
     94         if (strm->avail_in == 0)
     95             return 0;
     96         deflateReset(strm);
     97         state->reset = 0;
     98     }
     99 
    100     /* run deflate() on provided input until it produces no more output */
    101     ret = Z_OK;
    102     do {
    103         /* write out current buffer contents if full, or if flushing, but if
    104            doing Z_FINISH then don't write until we get to Z_STREAM_END */
    105         if (strm->avail_out == 0 || (flush != Z_NO_FLUSH &&
    106             (flush != Z_FINISH || ret == Z_STREAM_END))) {
    107             while (strm->next_out > state->x.next) {
    108                 put = strm->next_out - state->x.next > (int)max ? max :
    109                       (unsigned)(strm->next_out - state->x.next);
    110                 writ = write(state->fd, state->x.next, put);
    111                 if (writ < 0) {
    112                     gz_error(state, Z_ERRNO, zstrerror());
    113                     return -1;
    114                 }
    115                 state->x.next += writ;
    116             }
    117             if (strm->avail_out == 0) {
    118                 strm->avail_out = state->size;
    119                 strm->next_out = state->out;
    120                 state->x.next = state->out;
    121             }
    122         }
    123 
    124         /* compress */
    125         have = strm->avail_out;
    126         ret = deflate(strm, flush);
    127         if (ret == Z_STREAM_ERROR) {
    128             gz_error(state, Z_STREAM_ERROR,
    129                       "internal error: deflate stream corrupt");
    130             return -1;
    131         }
    132         have -= strm->avail_out;
    133     } while (have);
    134 
    135     /* if that completed a deflate stream, allow another to start */
    136     if (flush == Z_FINISH)
    137         state->reset = 1;
    138 
    139     /* all done, no errors */
    140     return 0;
    141 }
    142 
    143 /* Compress len zeros to output.  Return -1 on a write error or memory
    144    allocation failure by gz_comp(), or 0 on success. */
    145 local int gz_zero(gz_statep state, z_off64_t len) {
    146     int first;
    147     unsigned n;
    148     z_streamp strm = &(state->strm);
    149 
    150     /* consume whatever's left in the input buffer */
    151     if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
    152         return -1;
    153 
    154     /* compress len zeros (len guaranteed > 0) */
    155     first = 1;
    156     while (len) {
    157         n = GT_OFF(state->size) || (z_off64_t)state->size > len ?
    158             (unsigned)len : state->size;
    159         if (first) {
    160             memset(state->in, 0, n);
    161             first = 0;
    162         }
    163         strm->avail_in = n;
    164         strm->next_in = state->in;
    165         state->x.pos += n;
    166         if (gz_comp(state, Z_NO_FLUSH) == -1)
    167             return -1;
    168         len -= n;
    169     }
    170     return 0;
    171 }
    172 
    173 /* Write len bytes from buf to file.  Return the number of bytes written.  If
    174    the returned value is less than len, then there was an error. */
    175 local z_size_t gz_write(gz_statep state, voidpc buf, z_size_t len) {
    176     z_size_t put = len;
    177 
    178     /* if len is zero, avoid unnecessary operations */
    179     if (len == 0)
    180         return 0;
    181 
    182     /* allocate memory if this is the first time through */
    183     if (state->size == 0 && gz_init(state) == -1)
    184         return 0;
    185 
    186     /* check for seek request */
    187     if (state->seek) {
    188         state->seek = 0;
    189         if (gz_zero(state, state->skip) == -1)
    190             return 0;
    191     }
    192 
    193     /* for small len, copy to input buffer, otherwise compress directly */
    194     if (len < state->size) {
    195         /* copy to input buffer, compress when full */
    196         do {
    197             unsigned have, copy;
    198 
    199             if (state->strm.avail_in == 0)
    200                 state->strm.next_in = state->in;
    201             have = (unsigned)((state->strm.next_in + state->strm.avail_in) -
    202                               state->in);
    203             copy = state->size - have;
    204             if (copy > len)
    205                 copy = (unsigned)len;
    206             memcpy(state->in + have, buf, copy);
    207             state->strm.avail_in += copy;
    208             state->x.pos += copy;
    209             buf = (const char *)buf + copy;
    210             len -= copy;
    211             if (len && gz_comp(state, Z_NO_FLUSH) == -1)
    212                 return 0;
    213         } while (len);
    214     }
    215     else {
    216         /* consume whatever's left in the input buffer */
    217         if (state->strm.avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
    218             return 0;
    219 
    220         /* directly compress user buffer to file */
    221         state->strm.next_in = __UNCONST(buf);
    222         do {
    223             unsigned n = (unsigned)-1;
    224             if (n > len)
    225                 n = (unsigned)len;
    226             state->strm.avail_in = n;
    227             state->x.pos += n;
    228             if (gz_comp(state, Z_NO_FLUSH) == -1)
    229                 return 0;
    230             len -= n;
    231         } while (len);
    232     }
    233 
    234     /* input was all buffered or compressed */
    235     return put;
    236 }
    237 
    238 /* -- see zlib.h -- */
    239 int ZEXPORT gzwrite(gzFile file, voidpc buf, unsigned len) {
    240     gz_statep state;
    241 
    242     /* get internal structure */
    243     if (file == NULL)
    244         return 0;
    245     state = (gz_statep)file;
    246 
    247     /* check that we're writing and that there's no error */
    248     if (state->mode != GZ_WRITE || state->err != Z_OK)
    249         return 0;
    250 
    251     /* since an int is returned, make sure len fits in one, otherwise return
    252        with an error (this avoids a flaw in the interface) */
    253     if ((int)len < 0) {
    254         gz_error(state, Z_DATA_ERROR, "requested length does not fit in int");
    255         return 0;
    256     }
    257 
    258     /* write len bytes from buf (the return value will fit in an int) */
    259     return (int)gz_write(state, buf, len);
    260 }
    261 
    262 /* -- see zlib.h -- */
    263 z_size_t ZEXPORT gzfwrite(voidpc buf, z_size_t size, z_size_t nitems,
    264                           gzFile file) {
    265     z_size_t len;
    266     gz_statep state;
    267 
    268     /* get internal structure */
    269     if (file == NULL)
    270         return 0;
    271     state = (gz_statep)file;
    272 
    273     /* check that we're writing and that there's no error */
    274     if (state->mode != GZ_WRITE || state->err != Z_OK)
    275         return 0;
    276 
    277     /* compute bytes to read -- error on overflow */
    278     len = nitems * size;
    279     if (size && len / size != nitems) {
    280         gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t");
    281         return 0;
    282     }
    283 
    284     /* write len bytes to buf, return the number of full items written */
    285     return len ? gz_write(state, buf, len) / size : 0;
    286 }
    287 
    288 /* -- see zlib.h -- */
    289 int ZEXPORT gzputc(gzFile file, int c) {
    290     unsigned have;
    291     unsigned char buf[1];
    292     gz_statep state;
    293     z_streamp strm;
    294 
    295     /* get internal structure */
    296     if (file == NULL)
    297         return -1;
    298     state = (gz_statep)file;
    299     strm = &(state->strm);
    300 
    301     /* check that we're writing and that there's no error */
    302     if (state->mode != GZ_WRITE || state->err != Z_OK)
    303         return -1;
    304 
    305     /* check for seek request */
    306     if (state->seek) {
    307         state->seek = 0;
    308         if (gz_zero(state, state->skip) == -1)
    309             return -1;
    310     }
    311 
    312     /* try writing to input buffer for speed (state->size == 0 if buffer not
    313        initialized) */
    314     if (state->size) {
    315         if (strm->avail_in == 0)
    316             strm->next_in = state->in;
    317         have = (unsigned)((strm->next_in + strm->avail_in) - state->in);
    318         if (have < state->size) {
    319             state->in[have] = (unsigned char)c;
    320             strm->avail_in++;
    321             state->x.pos++;
    322             return c & 0xff;
    323         }
    324     }
    325 
    326     /* no room in buffer or not initialized, use gz_write() */
    327     buf[0] = (unsigned char)c;
    328     if (gz_write(state, buf, 1) != 1)
    329         return -1;
    330     return c & 0xff;
    331 }
    332 
    333 /* -- see zlib.h -- */
    334 int ZEXPORT gzputs(gzFile file, const char *s) {
    335     z_size_t len, put;
    336     gz_statep state;
    337 
    338     /* get internal structure */
    339     if (file == NULL)
    340         return -1;
    341     state = (gz_statep)file;
    342 
    343     /* check that we're writing and that there's no error */
    344     if (state->mode != GZ_WRITE || state->err != Z_OK)
    345         return -1;
    346 
    347     /* write string */
    348     len = strlen(s);
    349     if ((int)len < 0 || (unsigned)len != len) {
    350         gz_error(state, Z_STREAM_ERROR, "string length does not fit in int");
    351         return -1;
    352     }
    353     put = gz_write(state, s, len);
    354     return put < len ? -1 : (int)len;
    355 }
    356 
    357 #if defined(STDC) || defined(Z_HAVE_STDARG_H)
    358 #include <stdarg.h>
    359 
    360 /* -- see zlib.h -- */
    361 int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) {
    362     int len;
    363     unsigned left;
    364     char *next;
    365     gz_statep state;
    366     z_streamp strm;
    367 
    368     /* get internal structure */
    369     if (file == NULL)
    370         return Z_STREAM_ERROR;
    371     state = (gz_statep)file;
    372     strm = &(state->strm);
    373 
    374     /* check that we're writing and that there's no error */
    375     if (state->mode != GZ_WRITE || state->err != Z_OK)
    376         return Z_STREAM_ERROR;
    377 
    378     /* make sure we have some buffer space */
    379     if (state->size == 0 && gz_init(state) == -1)
    380         return state->err;
    381 
    382     /* check for seek request */
    383     if (state->seek) {
    384         state->seek = 0;
    385         if (gz_zero(state, state->skip) == -1)
    386             return state->err;
    387     }
    388 
    389     /* do the printf() into the input buffer, put length in len -- the input
    390        buffer is double-sized just for this function, so there is guaranteed to
    391        be state->size bytes available after the current contents */
    392     if (strm->avail_in == 0)
    393         strm->next_in = state->in;
    394     next = (char *)(state->in + (strm->next_in - state->in) + strm->avail_in);
    395     next[state->size - 1] = 0;
    396 #ifdef NO_vsnprintf
    397 #  ifdef HAS_vsprintf_void
    398     (void)vsprintf(next, format, va);
    399     for (len = 0; len < state->size; len++)
    400         if (next[len] == 0) break;
    401 #  else
    402     len = vsprintf(next, format, va);
    403 #  endif
    404 #else
    405 #  ifdef HAS_vsnprintf_void
    406     (void)vsnprintf(next, state->size, format, va);
    407     len = strlen(next);
    408 #  else
    409     len = vsnprintf(next, state->size, format, va);
    410 #  endif
    411 #endif
    412 
    413     /* check that printf() results fit in buffer */
    414     if (len == 0 || (unsigned)len >= state->size || next[state->size - 1] != 0)
    415         return 0;
    416 
    417     /* update buffer and position, compress first half if past that */
    418     strm->avail_in += (unsigned)len;
    419     state->x.pos += len;
    420     if (strm->avail_in >= state->size) {
    421         left = strm->avail_in - state->size;
    422         strm->avail_in = state->size;
    423         if (gz_comp(state, Z_NO_FLUSH) == -1)
    424             return state->err;
    425         memmove(state->in, state->in + state->size, left);
    426         strm->next_in = state->in;
    427         strm->avail_in = left;
    428     }
    429     return len;
    430 }
    431 
    432 int ZEXPORTVA gzprintf(gzFile file, const char *format, ...) {
    433     va_list va;
    434     int ret;
    435 
    436     va_start(va, format);
    437     ret = gzvprintf(file, format, va);
    438     va_end(va);
    439     return ret;
    440 }
    441 
    442 #else /* !STDC && !Z_HAVE_STDARG_H */
    443 
    444 /* -- see zlib.h -- */
    445 int ZEXPORTVA gzprintf(gzFile file, const char *format, int a1, int a2, int a3,
    446                        int a4, int a5, int a6, int a7, int a8, int a9, int a10,
    447                        int a11, int a12, int a13, int a14, int a15, int a16,
    448                        int a17, int a18, int a19, int a20) {
    449     unsigned len, left;
    450     char *next;
    451     gz_statep state;
    452     z_streamp strm;
    453 
    454     /* get internal structure */
    455     if (file == NULL)
    456         return Z_STREAM_ERROR;
    457     state = (gz_statep)file;
    458     strm = &(state->strm);
    459 
    460     /* check that can really pass pointer in ints */
    461     if (sizeof(int) != sizeof(void *))
    462         return Z_STREAM_ERROR;
    463 
    464     /* check that we're writing and that there's no error */
    465     if (state->mode != GZ_WRITE || state->err != Z_OK)
    466         return Z_STREAM_ERROR;
    467 
    468     /* make sure we have some buffer space */
    469     if (state->size == 0 && gz_init(state) == -1)
    470         return state->error;
    471 
    472     /* check for seek request */
    473     if (state->seek) {
    474         state->seek = 0;
    475         if (gz_zero(state, state->skip) == -1)
    476             return state->error;
    477     }
    478 
    479     /* do the printf() into the input buffer, put length in len -- the input
    480        buffer is double-sized just for this function, so there is guaranteed to
    481        be state->size bytes available after the current contents */
    482     if (strm->avail_in == 0)
    483         strm->next_in = state->in;
    484     next = (char *)(strm->next_in + strm->avail_in);
    485     next[state->size - 1] = 0;
    486 #ifdef NO_snprintf
    487 #  ifdef HAS_sprintf_void
    488     sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12,
    489             a13, a14, a15, a16, a17, a18, a19, a20);
    490     for (len = 0; len < size; len++)
    491         if (next[len] == 0)
    492             break;
    493 #  else
    494     len = sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11,
    495                   a12, a13, a14, a15, a16, a17, a18, a19, a20);
    496 #  endif
    497 #else
    498 #  ifdef HAS_snprintf_void
    499     snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8, a9,
    500              a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
    501     len = strlen(next);
    502 #  else
    503     len = snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8,
    504                    a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
    505 #  endif
    506 #endif
    507 
    508     /* check that printf() results fit in buffer */
    509     if (len == 0 || len >= state->size || next[state->size - 1] != 0)
    510         return 0;
    511 
    512     /* update buffer and position, compress first half if past that */
    513     strm->avail_in += len;
    514     state->x.pos += len;
    515     if (strm->avail_in >= state->size) {
    516         left = strm->avail_in - state->size;
    517         strm->avail_in = state->size;
    518         if (gz_comp(state, Z_NO_FLUSH) == -1)
    519             return state->err;
    520         memmove(state->in, state->in + state->size, left);
    521         strm->next_in = state->in;
    522         strm->avail_in = left;
    523     }
    524     return (int)len;
    525 }
    526 
    527 #endif
    528 
    529 /* -- see zlib.h -- */
    530 int ZEXPORT gzflush(gzFile file, int flush) {
    531     gz_statep state;
    532 
    533     /* get internal structure */
    534     if (file == NULL)
    535         return Z_STREAM_ERROR;
    536     state = (gz_statep)file;
    537 
    538     /* check that we're writing and that there's no error */
    539     if (state->mode != GZ_WRITE || state->err != Z_OK)
    540         return Z_STREAM_ERROR;
    541 
    542     /* check flush parameter */
    543     if (flush < 0 || flush > Z_FINISH)
    544         return Z_STREAM_ERROR;
    545 
    546     /* check for seek request */
    547     if (state->seek) {
    548         state->seek = 0;
    549         if (gz_zero(state, state->skip) == -1)
    550             return state->err;
    551     }
    552 
    553     /* compress remaining data with requested flush */
    554     (void)gz_comp(state, flush);
    555     return state->err;
    556 }
    557 
    558 /* -- see zlib.h -- */
    559 int ZEXPORT gzsetparams(gzFile file, int level, int strategy) {
    560     gz_statep state;
    561     z_streamp strm;
    562 
    563     /* get internal structure */
    564     if (file == NULL)
    565         return Z_STREAM_ERROR;
    566     state = (gz_statep)file;
    567     strm = &(state->strm);
    568 
    569     /* check that we're writing and that there's no error */
    570     if (state->mode != GZ_WRITE || state->err != Z_OK || state->direct)
    571         return Z_STREAM_ERROR;
    572 
    573     /* if no change is requested, then do nothing */
    574     if (level == state->level && strategy == state->strategy)
    575         return Z_OK;
    576 
    577     /* check for seek request */
    578     if (state->seek) {
    579         state->seek = 0;
    580         if (gz_zero(state, state->skip) == -1)
    581             return state->err;
    582     }
    583 
    584     /* change compression parameters for subsequent input */
    585     if (state->size) {
    586         /* flush previous input with previous parameters before changing */
    587         if (strm->avail_in && gz_comp(state, Z_BLOCK) == -1)
    588             return state->err;
    589         deflateParams(strm, level, strategy);
    590     }
    591     state->level = level;
    592     state->strategy = strategy;
    593     return Z_OK;
    594 }
    595 
    596 /* -- see zlib.h -- */
    597 int ZEXPORT gzclose_w(gzFile file) {
    598     int ret = Z_OK;
    599     gz_statep state;
    600 
    601     /* get internal structure */
    602     if (file == NULL)
    603         return Z_STREAM_ERROR;
    604     state = (gz_statep)file;
    605 
    606     /* check that we're writing */
    607     if (state->mode != GZ_WRITE)
    608         return Z_STREAM_ERROR;
    609 
    610     /* check for seek request */
    611     if (state->seek) {
    612         state->seek = 0;
    613         if (gz_zero(state, state->skip) == -1)
    614             ret = state->err;
    615     }
    616 
    617     /* flush, free memory, and close file */
    618     if (gz_comp(state, Z_FINISH) == -1)
    619         ret = state->err;
    620     if (state->size) {
    621         if (!state->direct) {
    622             (void)deflateEnd(&(state->strm));
    623             free(state->out);
    624         }
    625         free(state->in);
    626     }
    627     gz_error(state, Z_OK, NULL);
    628     free(state->path);
    629     if (close(state->fd) == -1)
    630         ret = Z_ERRNO;
    631     free(state);
    632     return ret;
    633 }
    634