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