gzwrite.c revision 1.4 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