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