1/* gzwrite.c -- zlib functions for writing gzip files
2 * Copyright (C) 2004-2017 Mark Adler
3 * For conditions of distribution and use, see copyright notice in zlib.h
4 */
5
6#include "zbuild.h"
7#include "zutil_p.h"
8#include <stdarg.h>
9#include "gzguts.h"
10
11/* Local functions */
12static int gz_init(gz_state *);
13static int gz_comp(gz_state *, int);
14static int gz_zero(gz_state *, z_off64_t);
15static size_t gz_write(gz_state *, void const *, size_t);
16
17/* Initialize state for writing a gzip file. Mark initialization by setting
18 state->size to non-zero. Return -1 on a memory allocation failure, or 0 on
19 success. */
20static int gz_init(gz_state *state) {
21 int ret;
22 PREFIX3(stream) *strm = &(state->strm);
23
24 /* allocate input buffer (double size for gzprintf) */
25 state->in = (unsigned char *)zng_alloc(size: state->want << 1);
26 if (state->in == NULL) {
27 gz_error(state, Z_MEM_ERROR, "out of memory");
28 return -1;
29 }
30 memset(s: state->in, c: 0, n: state->want << 1);
31
32 /* only need output buffer and deflate state if compressing */
33 if (!state->direct) {
34 /* allocate output buffer */
35 state->out = (unsigned char *)zng_alloc(size: state->want);
36 if (state->out == NULL) {
37 zng_free(ptr: 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 = NULL;
44 strm->zfree = NULL;
45 strm->opaque = NULL;
46 ret = PREFIX(deflateInit2)(strm, state->level, Z_DEFLATED, MAX_WBITS + 16, DEF_MEM_LEVEL, state->strategy);
47 if (ret != Z_OK) {
48 zng_free(ptr: state->out);
49 zng_free(ptr: state->in);
50 gz_error(state, Z_MEM_ERROR, "out of memory");
51 return -1;
52 }
53 strm->next_in = NULL;
54 }
55
56 /* mark state as initialized */
57 state->size = state->want;
58
59 /* initialize write buffer if compressing */
60 if (!state->direct) {
61 strm->avail_out = state->size;
62 strm->next_out = state->out;
63 state->x.next = strm->next_out;
64 }
65 return 0;
66}
67
68/* Compress whatever is at avail_in and next_in and write to the output file.
69 Return -1 if there is an error writing to the output file or if gz_init()
70 fails to allocate memory, otherwise 0. flush is assumed to be a valid
71 deflate() flush value. If flush is Z_FINISH, then the deflate() state is
72 reset to start a new gzip stream. If gz->direct is true, then simply write
73 to the output file without compressing, and ignore flush. */
74static int gz_comp(gz_state *state, int flush) {
75 int ret;
76 ssize_t got;
77 unsigned have;
78 PREFIX3(stream) *strm = &(state->strm);
79
80 /* allocate memory if this is the first time through */
81 if (state->size == 0 && gz_init(state) == -1)
82 return -1;
83
84 /* write directly if requested */
85 if (state->direct) {
86 got = write(fd: state->fd, buf: strm->next_in, n: strm->avail_in);
87 if (got < 0 || (unsigned)got != strm->avail_in) {
88 gz_error(state, Z_ERRNO, zstrerror());
89 return -1;
90 }
91 strm->avail_in = 0;
92 return 0;
93 }
94
95 /* check for a pending reset */
96 if (state->reset) {
97 /* don't start a new gzip member unless there is data to write */
98 if (strm->avail_in == 0)
99 return 0;
100 PREFIX(deflateReset)(strm);
101 state->reset = 0;
102 }
103
104 /* run deflate() on provided input until it produces no more output */
105 ret = Z_OK;
106 do {
107 /* write out current buffer contents if full, or if flushing, but if
108 doing Z_FINISH then don't write until we get to Z_STREAM_END */
109 if (strm->avail_out == 0 || (flush != Z_NO_FLUSH && (flush != Z_FINISH || ret == Z_STREAM_END))) {
110 have = (unsigned)(strm->next_out - state->x.next);
111 if (have && ((got = write(fd: state->fd, buf: state->x.next, n: (unsigned long)have)) < 0 || (unsigned)got != have)) {
112 gz_error(state, Z_ERRNO, zstrerror());
113 return -1;
114 }
115 if (strm->avail_out == 0) {
116 strm->avail_out = state->size;
117 strm->next_out = state->out;
118 state->x.next = state->out;
119 }
120 state->x.next = strm->next_out;
121 }
122
123 /* compress */
124 have = strm->avail_out;
125 ret = PREFIX(deflate)(strm, flush);
126 if (ret == Z_STREAM_ERROR) {
127 gz_error(state, Z_STREAM_ERROR, "internal error: deflate stream corrupt");
128 return -1;
129 }
130 have -= strm->avail_out;
131 } while (have);
132
133 /* if that completed a deflate stream, allow another to start */
134 if (flush == Z_FINISH)
135 state->reset = 1;
136 /* all done, no errors */
137 return 0;
138}
139
140/* Compress len zeros to output. Return -1 on a write error or memory
141 allocation failure by gz_comp(), or 0 on success. */
142static int gz_zero(gz_state *state, z_off64_t len) {
143 int first;
144 unsigned n;
145 PREFIX3(stream) *strm = &(state->strm);
146
147 /* consume whatever's left in the input buffer */
148 if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
149 return -1;
150
151 /* compress len zeros (len guaranteed > 0) */
152 first = 1;
153 while (len) {
154 n = GT_OFF(state->size) || (z_off64_t)state->size > len ? (unsigned)len : state->size;
155 if (first) {
156 memset(s: state->in, c: 0, n: n);
157 first = 0;
158 }
159 strm->avail_in = n;
160 strm->next_in = state->in;
161 state->x.pos += n;
162 if (gz_comp(state, Z_NO_FLUSH) == -1)
163 return -1;
164 len -= n;
165 }
166 return 0;
167}
168
169/* Write len bytes from buf to file. Return the number of bytes written. If
170 the returned value is less than len, then there was an error. */
171static size_t gz_write(gz_state *state, void const *buf, size_t len) {
172 size_t put = len;
173
174 /* if len is zero, avoid unnecessary operations */
175 if (len == 0)
176 return 0;
177
178 /* allocate memory if this is the first time through */
179 if (state->size == 0 && gz_init(state) == -1)
180 return 0;
181
182 /* check for seek request */
183 if (state->seek) {
184 state->seek = 0;
185 if (gz_zero(state, len: state->skip) == -1)
186 return 0;
187 }
188
189 /* for small len, copy to input buffer, otherwise compress directly */
190 if (len < state->size) {
191 /* copy to input buffer, compress when full */
192 do {
193 unsigned have, copy;
194
195 if (state->strm.avail_in == 0)
196 state->strm.next_in = state->in;
197 have = (unsigned)((state->strm.next_in + state->strm.avail_in) -
198 state->in);
199 copy = state->size - have;
200 if (copy > len)
201 copy = (unsigned)len;
202 memcpy(dest: state->in + have, src: buf, n: copy);
203 state->strm.avail_in += copy;
204 state->x.pos += copy;
205 buf = (const char *)buf + copy;
206 len -= copy;
207 if (len && gz_comp(state, Z_NO_FLUSH) == -1)
208 return 0;
209 } while (len);
210 } else {
211 /* consume whatever's left in the input buffer */
212 if (state->strm.avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
213 return 0;
214
215 /* directly compress user buffer to file */
216 state->strm.next_in = (z_const unsigned char *) buf;
217 do {
218 unsigned n = (unsigned)-1;
219 if (n > len)
220 n = (unsigned)len;
221 state->strm.avail_in = n;
222 state->x.pos += n;
223 if (gz_comp(state, Z_NO_FLUSH) == -1)
224 return 0;
225 len -= n;
226 } while (len);
227 }
228
229 /* input was all buffered or compressed */
230 return put;
231}
232
233/* -- see zlib.h -- */
234int Z_EXPORT PREFIX(gzwrite)(gzFile file, void const *buf, unsigned len) {
235 gz_state *state;
236
237 /* get internal structure */
238 if (file == NULL)
239 return 0;
240 state = (gz_state *)file;
241
242 /* check that we're writing and that there's no error */
243 if (state->mode != GZ_WRITE || state->err != Z_OK)
244 return 0;
245
246 /* since an int is returned, make sure len fits in one, otherwise return
247 with an error (this avoids a flaw in the interface) */
248 if ((int)len < 0) {
249 gz_error(state, Z_DATA_ERROR, "requested length does not fit in int");
250 return 0;
251 }
252
253 /* write len bytes from buf (the return value will fit in an int) */
254 return (int)gz_write(state, buf, len);
255}
256
257/* -- see zlib.h -- */
258size_t Z_EXPORT PREFIX(gzfwrite)(void const *buf, size_t size, size_t nitems, gzFile file) {
259 size_t len;
260 gz_state *state;
261
262 /* Exit early if size is zero, also prevents potential division by zero */
263 if (size == 0)
264 return 0;
265
266 /* get internal structure */
267 if (file == NULL)
268 return 0;
269 state = (gz_state *)file;
270
271 /* check that we're writing and that there's no error */
272 if (state->mode != GZ_WRITE || state->err != Z_OK)
273 return 0;
274
275 /* compute bytes to read -- error on overflow */
276 len = nitems * size;
277 if (size && len / size != nitems) {
278 gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t");
279 return 0;
280 }
281
282 /* write len bytes to buf, return the number of full items written */
283 return len ? gz_write(state, buf, len) / size : 0;
284}
285
286/* -- see zlib.h -- */
287int Z_EXPORT PREFIX(gzputc)(gzFile file, int c) {
288 unsigned have;
289 unsigned char buf[1];
290 gz_state *state;
291 PREFIX3(stream) *strm;
292
293 /* get internal structure */
294 if (file == NULL)
295 return -1;
296 state = (gz_state *)file;
297 strm = &(state->strm);
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 -1;
302
303 /* check for seek request */
304 if (state->seek) {
305 state->seek = 0;
306 if (gz_zero(state, len: state->skip) == -1)
307 return -1;
308 }
309
310 /* try writing to input buffer for speed (state->size == 0 if buffer not
311 initialized) */
312 if (state->size) {
313 if (strm->avail_in == 0)
314 strm->next_in = state->in;
315 have = (unsigned)((strm->next_in + strm->avail_in) - state->in);
316 if (have < state->size) {
317 state->in[have] = (unsigned char)c;
318 strm->avail_in++;
319 state->x.pos++;
320 return c & 0xff;
321 }
322 }
323
324 /* no room in buffer or not initialized, use gz_write() */
325 buf[0] = (unsigned char)c;
326 if (gz_write(state, buf, len: 1) != 1)
327 return -1;
328 return c & 0xff;
329}
330
331/* -- see zlib.h -- */
332int Z_EXPORT PREFIX(gzputs)(gzFile file, const char *s) {
333 size_t len, put;
334 gz_state *state;
335
336 /* get internal structure */
337 if (file == NULL)
338 return -1;
339 state = (gz_state *)file;
340
341 /* check that we're writing and that there's no error */
342 if (state->mode != GZ_WRITE || state->err != Z_OK)
343 return -1;
344
345 /* write string */
346 len = strlen(s: s);
347 if ((int)len < 0 || (unsigned)len != len) {
348 gz_error(state, Z_STREAM_ERROR, "string length does not fit in int");
349 return -1;
350 }
351 put = gz_write(state, buf: s, len);
352 return put < len ? -1 : (int)len;
353}
354
355/* -- see zlib.h -- */
356int Z_EXPORTVA PREFIX(gzvprintf)(gzFile file, const char *format, va_list va) {
357 int len;
358 unsigned left;
359 char *next;
360 gz_state *state;
361 PREFIX3(stream) *strm;
362
363 /* get internal structure */
364 if (file == NULL)
365 return Z_STREAM_ERROR;
366 state = (gz_state *)file;
367 strm = &(state->strm);
368
369 /* check that we're writing and that there's no error */
370 if (state->mode != GZ_WRITE || state->err != Z_OK)
371 return Z_STREAM_ERROR;
372
373 /* make sure we have some buffer space */
374 if (state->size == 0 && gz_init(state) == -1)
375 return state->err;
376
377 /* check for seek request */
378 if (state->seek) {
379 state->seek = 0;
380 if (gz_zero(state, len: state->skip) == -1)
381 return state->err;
382 }
383
384 /* do the printf() into the input buffer, put length in len -- the input
385 buffer is double-sized just for this function, so there is guaranteed to
386 be state->size bytes available after the current contents */
387 if (strm->avail_in == 0)
388 strm->next_in = state->in;
389 next = (char *)(state->in + (strm->next_in - state->in) + strm->avail_in);
390 next[state->size - 1] = 0;
391 len = vsnprintf(s: next, maxlen: state->size, format: format, arg: va);
392
393 /* check that printf() results fit in buffer */
394 if (len == 0 || (unsigned)len >= state->size || next[state->size - 1] != 0)
395 return 0;
396
397 /* update buffer and position, compress first half if past that */
398 strm->avail_in += (unsigned)len;
399 state->x.pos += len;
400 if (strm->avail_in >= state->size) {
401 left = strm->avail_in - state->size;
402 strm->avail_in = state->size;
403 if (gz_comp(state, Z_NO_FLUSH) == -1)
404 return state->err;
405 memmove(dest: state->in, src: state->in + state->size, n: left);
406 strm->next_in = state->in;
407 strm->avail_in = left;
408 }
409 return len;
410}
411
412int Z_EXPORTVA PREFIX(gzprintf)(gzFile file, const char *format, ...) {
413 va_list va;
414 int ret;
415
416 va_start(va, format);
417 ret = PREFIX(gzvprintf)(file, format, va);
418 va_end(va);
419 return ret;
420}
421
422/* -- see zlib.h -- */
423int Z_EXPORT PREFIX(gzflush)(gzFile file, int flush) {
424 gz_state *state;
425
426 /* get internal structure */
427 if (file == NULL)
428 return Z_STREAM_ERROR;
429 state = (gz_state *)file;
430
431 /* check that we're writing and that there's no error */
432 if (state->mode != GZ_WRITE || state->err != Z_OK)
433 return Z_STREAM_ERROR;
434
435 /* check flush parameter */
436 if (flush < 0 || flush > Z_FINISH)
437 return Z_STREAM_ERROR;
438
439 /* check for seek request */
440 if (state->seek) {
441 state->seek = 0;
442 if (gz_zero(state, len: state->skip) == -1)
443 return state->err;
444 }
445
446 /* compress remaining data with requested flush */
447 (void)gz_comp(state, flush);
448 return state->err;
449}
450
451/* -- see zlib.h -- */
452int Z_EXPORT PREFIX(gzsetparams)(gzFile file, int level, int strategy) {
453 gz_state *state;
454 PREFIX3(stream) *strm;
455
456 /* get internal structure */
457 if (file == NULL)
458 return Z_STREAM_ERROR;
459 state = (gz_state *)file;
460 strm = &(state->strm);
461
462 /* check that we're writing and that there's no error */
463 if (state->mode != GZ_WRITE || state->err != Z_OK)
464 return Z_STREAM_ERROR;
465
466 /* if no change is requested, then do nothing */
467 if (level == state->level && strategy == state->strategy)
468 return Z_OK;
469
470 /* check for seek request */
471 if (state->seek) {
472 state->seek = 0;
473 if (gz_zero(state, len: state->skip) == -1)
474 return state->err;
475 }
476
477 /* change compression parameters for subsequent input */
478 if (state->size) {
479 /* flush previous input with previous parameters before changing */
480 if (strm->avail_in && gz_comp(state, Z_BLOCK) == -1)
481 return state->err;
482 PREFIX(deflateParams)(strm, level, strategy);
483 }
484 state->level = level;
485 state->strategy = strategy;
486 return Z_OK;
487}
488
489/* -- see zlib.h -- */
490int Z_EXPORT PREFIX(gzclose_w)(gzFile file) {
491 int ret = Z_OK;
492 gz_state *state;
493
494 /* get internal structure */
495 if (file == NULL)
496 return Z_STREAM_ERROR;
497 state = (gz_state *)file;
498
499 /* check that we're writing */
500 if (state->mode != GZ_WRITE)
501 return Z_STREAM_ERROR;
502
503 /* check for seek request */
504 if (state->seek) {
505 state->seek = 0;
506 if (gz_zero(state, len: state->skip) == -1)
507 ret = state->err;
508 }
509
510 /* flush, free memory, and close file */
511 if (gz_comp(state, Z_FINISH) == -1)
512 ret = state->err;
513 if (state->size) {
514 if (!state->direct) {
515 (void)PREFIX(deflateEnd)(strm: &(state->strm));
516 zng_free(ptr: state->out);
517 }
518 zng_free(ptr: state->in);
519 }
520 gz_error(state, Z_OK, NULL);
521 free(ptr: state->path);
522 if (close(fd: state->fd) == -1)
523 ret = Z_ERRNO;
524 zng_free(ptr: state);
525 return ret;
526}
527