Coverage Report

Created: 2025-11-24 06:41

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