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