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