Coverage Report

Created: 2026-08-31 06:47

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