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