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