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