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