Coverage Report

Created: 2025-11-24 06:16

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