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