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