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