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