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