Coverage Report

Created: 2025-07-18 06:42

/src/zlib/gzwrite.c
Line
Count
Source (jump to first uncovered line)
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
4.67k
local int gz_init(gz_statep state) {
12
4.67k
    int ret;
13
4.67k
    z_streamp strm = &(state->strm);
14
15
    /* allocate input buffer (double size for gzprintf) */
16
4.67k
    state->in = (unsigned char *)malloc(state->want << 1);
17
4.67k
    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
4.67k
    if (!state->direct) {
24
        /* allocate output buffer */
25
4.66k
        state->out = (unsigned char *)malloc(state->want);
26
4.66k
        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
4.66k
        strm->zalloc = Z_NULL;
34
4.66k
        strm->zfree = Z_NULL;
35
4.66k
        strm->opaque = Z_NULL;
36
4.66k
        ret = deflateInit2(strm, state->level, Z_DEFLATED,
37
4.66k
                           MAX_WBITS + 16, DEF_MEM_LEVEL, state->strategy);
38
4.66k
        if (ret != Z_OK) {
39
48
            free(state->out);
40
48
            free(state->in);
41
48
            gz_error(state, Z_MEM_ERROR, "out of memory");
42
48
            return -1;
43
48
        }
44
4.61k
        strm->next_in = NULL;
45
4.61k
    }
46
47
    /* mark state as initialized */
48
4.63k
    state->size = state->want;
49
50
    /* initialize write buffer if compressing */
51
4.63k
    if (!state->direct) {
52
4.61k
        strm->avail_out = state->size;
53
4.61k
        strm->next_out = state->out;
54
4.61k
        state->x.next = strm->next_out;
55
4.61k
    }
56
4.63k
    return 0;
57
4.67k
}
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
18.7k
local int gz_comp(gz_statep state, int flush) {
66
18.7k
    int ret, writ;
67
18.7k
    unsigned have, put, max = ((unsigned)-1 >> 2) + 1;
68
18.7k
    z_streamp strm = &(state->strm);
69
70
    /* allocate memory if this is the first time through */
71
18.7k
    if (state->size == 0 && gz_init(state) == -1)
72
43
        return -1;
73
74
    /* write directly if requested */
75
18.7k
    if (state->direct) {
76
105
        while (strm->avail_in) {
77
46
            put = strm->avail_in > max ? max : strm->avail_in;
78
46
            writ = write(state->fd, strm->next_in, put);
79
46
            if (writ < 0) {
80
0
                gz_error(state, Z_ERRNO, zstrerror());
81
0
                return -1;
82
0
            }
83
46
            strm->avail_in -= (unsigned)writ;
84
46
            strm->next_in += writ;
85
46
        }
86
59
        return 0;
87
59
    }
88
89
    /* check for a pending reset */
90
18.6k
    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
18.6k
    ret = Z_OK;
100
50.5k
    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
50.5k
        if (strm->avail_out == 0 || (flush != Z_NO_FLUSH &&
104
33.9k
            (flush != Z_FINISH || ret == Z_STREAM_END))) {
105
42.6k
            while (strm->next_out > state->x.next) {
106
21.2k
                put = strm->next_out - state->x.next > (int)max ? max :
107
21.2k
                      (unsigned)(strm->next_out - state->x.next);
108
21.2k
                writ = write(state->fd, state->x.next, put);
109
21.2k
                if (writ < 0) {
110
0
                    gz_error(state, Z_ERRNO, zstrerror());
111
0
                    return -1;
112
0
                }
113
21.2k
                state->x.next += writ;
114
21.2k
            }
115
21.3k
            if (strm->avail_out == 0) {
116
16.6k
                strm->avail_out = state->size;
117
16.6k
                strm->next_out = state->out;
118
16.6k
                state->x.next = state->out;
119
16.6k
            }
120
21.3k
        }
121
122
        /* compress */
123
50.5k
        have = strm->avail_out;
124
50.5k
        ret = deflate(strm, flush);
125
50.5k
        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
50.5k
        have -= strm->avail_out;
131
50.5k
    } while (have);
132
133
    /* if that completed a deflate stream, allow another to start */
134
18.6k
    if (flush == Z_FINISH)
135
4.61k
        state->reset = 1;
136
137
    /* all done, no errors */
138
18.6k
    return 0;
139
18.6k
}
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
184
local int gz_zero(gz_statep state, z_off64_t len) {
144
184
    int first;
145
184
    unsigned n;
146
184
    z_streamp strm = &(state->strm);
147
148
    /* consume whatever's left in the input buffer */
149
184
    if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
150
0
        return -1;
151
152
    /* compress len zeros (len guaranteed > 0) */
153
184
    first = 1;
154
655
    while (len) {
155
472
        n = GT_OFF(state->size) || (z_off64_t)state->size > len ?
156
290
            (unsigned)len : state->size;
157
472
        if (first) {
158
184
            memset(state->in, 0, n);
159
184
            first = 0;
160
184
        }
161
472
        strm->avail_in = n;
162
472
        strm->next_in = state->in;
163
472
        state->x.pos += n;
164
472
        if (gz_comp(state, Z_NO_FLUSH) == -1)
165
1
            return -1;
166
471
        len -= n;
167
471
    }
168
183
    return 0;
169
184
}
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
17.1k
local z_size_t gz_write(gz_statep state, voidpc buf, z_size_t len) {
174
17.1k
    z_size_t put = len;
175
176
    /* if len is zero, avoid unnecessary operations */
177
17.1k
    if (len == 0)
178
10
        return 0;
179
180
    /* allocate memory if this is the first time through */
181
17.1k
    if (state->size == 0 && gz_init(state) == -1)
182
4
        return 0;
183
184
    /* check for seek request */
185
17.1k
    if (state->seek) {
186
58
        state->seek = 0;
187
58
        if (gz_zero(state, state->skip) == -1)
188
0
            return 0;
189
58
    }
190
191
    /* for small len, copy to input buffer, otherwise compress directly */
192
17.1k
    if (len < state->size) {
193
        /* copy to input buffer, compress when full */
194
3.66k
        do {
195
3.66k
            unsigned have, copy;
196
197
3.66k
            if (state->strm.avail_in == 0)
198
3.39k
                state->strm.next_in = state->in;
199
3.66k
            have = (unsigned)((state->strm.next_in + state->strm.avail_in) -
200
3.66k
                              state->in);
201
3.66k
            copy = state->size - have;
202
3.66k
            if (copy > len)
203
3.66k
                copy = (unsigned)len;
204
3.66k
            memcpy(state->in + have, buf, copy);
205
3.66k
            state->strm.avail_in += copy;
206
3.66k
            state->x.pos += copy;
207
3.66k
            buf = (const char *)buf + copy;
208
3.66k
            len -= copy;
209
3.66k
            if (len && gz_comp(state, Z_NO_FLUSH) == -1)
210
0
                return 0;
211
3.66k
        } while (len);
212
3.66k
    }
213
13.4k
    else {
214
        /* consume whatever's left in the input buffer */
215
13.4k
        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
13.4k
        state->strm.next_in = (z_const Bytef *)buf;
220
13.4k
        do {
221
13.4k
            unsigned n = (unsigned)-1;
222
13.4k
            if (n > len)
223
13.4k
                n = (unsigned)len;
224
13.4k
            state->strm.avail_in = n;
225
13.4k
            state->x.pos += n;
226
13.4k
            if (gz_comp(state, Z_NO_FLUSH) == -1)
227
0
                return 0;
228
13.4k
            len -= n;
229
13.4k
        } while (len);
230
13.4k
    }
231
232
    /* input was all buffered or compressed */
233
17.1k
    return put;
234
17.1k
}
235
236
/* -- see zlib.h -- */
237
16.2k
int ZEXPORT gzwrite(gzFile file, voidpc buf, unsigned len) {
238
16.2k
    gz_statep state;
239
240
    /* get internal structure */
241
16.2k
    if (file == NULL)
242
0
        return 0;
243
16.2k
    state = (gz_statep)file;
244
245
    /* check that we're writing and that there's no error */
246
16.2k
    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
16.2k
    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
16.2k
    return (int)gz_write(state, buf, len);
258
16.2k
}
259
260
/* -- see zlib.h -- */
261
z_size_t ZEXPORT gzfwrite(voidpc buf, z_size_t size, z_size_t nitems,
262
827
                          gzFile file) {
263
827
    z_size_t len;
264
827
    gz_statep state;
265
266
    /* get internal structure */
267
827
    if (file == NULL)
268
28
        return 0;
269
799
    state = (gz_statep)file;
270
271
    /* check that we're writing and that there's no error */
272
799
    if (state->mode != GZ_WRITE || state->err != Z_OK)
273
1
        return 0;
274
275
    /* compute bytes to read -- error on overflow */
276
798
    len = nitems * size;
277
798
    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
798
    return len ? gz_write(state, buf, len) / size : 0;
284
798
}
285
286
/* -- see zlib.h -- */
287
97
int ZEXPORT gzputc(gzFile file, int c) {
288
97
    unsigned have;
289
97
    unsigned char buf[1];
290
97
    gz_statep state;
291
97
    z_streamp strm;
292
293
    /* get internal structure */
294
97
    if (file == NULL)
295
38
        return -1;
296
59
    state = (gz_statep)file;
297
59
    strm = &(state->strm);
298
299
    /* check that we're writing and that there's no error */
300
59
    if (state->mode != GZ_WRITE || state->err != Z_OK)
301
21
        return -1;
302
303
    /* check for seek request */
304
38
    if (state->seek) {
305
5
        state->seek = 0;
306
5
        if (gz_zero(state, state->skip) == -1)
307
0
            return -1;
308
5
    }
309
310
    /* try writing to input buffer for speed (state->size == 0 if buffer not
311
       initialized) */
312
38
    if (state->size) {
313
22
        if (strm->avail_in == 0)
314
5
            strm->next_in = state->in;
315
22
        have = (unsigned)((strm->next_in + strm->avail_in) - state->in);
316
22
        if (have < state->size) {
317
22
            state->in[have] = (unsigned char)c;
318
22
            strm->avail_in++;
319
22
            state->x.pos++;
320
22
            return c & 0xff;
321
22
        }
322
22
    }
323
324
    /* no room in buffer or not initialized, use gz_write() */
325
16
    buf[0] = (unsigned char)c;
326
16
    if (gz_write(state, buf, 1) != 1)
327
1
        return -1;
328
15
    return c & 0xff;
329
16
}
330
331
/* -- see zlib.h -- */
332
108
int ZEXPORT gzputs(gzFile file, const char *s) {
333
108
    z_size_t len, put;
334
108
    gz_statep state;
335
336
    /* get internal structure */
337
108
    if (file == NULL)
338
38
        return -1;
339
70
    state = (gz_statep)file;
340
341
    /* check that we're writing and that there's no error */
342
70
    if (state->mode != GZ_WRITE || state->err != Z_OK)
343
3
        return -1;
344
345
    /* write string */
346
67
    len = strlen(s);
347
67
    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
67
    put = gz_write(state, s, len);
352
67
    return put < len ? -1 : (int)len;
353
67
}
354
355
#if defined(STDC) || defined(Z_HAVE_STDARG_H)
356
#include <stdarg.h>
357
358
/* -- see zlib.h -- */
359
347
int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) {
360
347
    int len;
361
347
    unsigned left;
362
347
    char *next;
363
347
    gz_statep state;
364
347
    z_streamp strm;
365
366
    /* get internal structure */
367
347
    if (file == NULL)
368
169
        return Z_STREAM_ERROR;
369
178
    state = (gz_statep)file;
370
178
    strm = &(state->strm);
371
372
    /* check that we're writing and that there's no error */
373
178
    if (state->mode != GZ_WRITE || state->err != Z_OK)
374
8
        return Z_STREAM_ERROR;
375
376
    /* make sure we have some buffer space */
377
170
    if (state->size == 0 && gz_init(state) == -1)
378
1
        return state->err;
379
380
    /* check for seek request */
381
169
    if (state->seek) {
382
9
        state->seek = 0;
383
9
        if (gz_zero(state, state->skip) == -1)
384
0
            return state->err;
385
9
    }
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
169
    if (strm->avail_in == 0)
391
148
        strm->next_in = state->in;
392
169
    next = (char *)(state->in + (strm->next_in - state->in) + strm->avail_in);
393
169
    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
169
    len = vsnprintf(next, state->size, format, va);
408
169
#  endif
409
169
#endif
410
411
    /* check that printf() results fit in buffer */
412
169
    if (len == 0 || (unsigned)len >= state->size || next[state->size - 1] != 0)
413
33
        return 0;
414
415
    /* update buffer and position, compress first half if past that */
416
136
    strm->avail_in += (unsigned)len;
417
136
    state->x.pos += len;
418
136
    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
136
    return len;
428
136
}
429
430
347
int ZEXPORTVA gzprintf(gzFile file, const char *format, ...) {
431
347
    va_list va;
432
347
    int ret;
433
434
347
    va_start(va, format);
435
347
    ret = gzvprintf(file, format, va);
436
347
    va_end(va);
437
347
    return ret;
438
347
}
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
72
int ZEXPORT gzflush(gzFile file, int flush) {
529
72
    gz_statep state;
530
531
    /* get internal structure */
532
72
    if (file == NULL)
533
29
        return Z_STREAM_ERROR;
534
43
    state = (gz_statep)file;
535
536
    /* check that we're writing and that there's no error */
537
43
    if (state->mode != GZ_WRITE || state->err != Z_OK)
538
3
        return Z_STREAM_ERROR;
539
540
    /* check flush parameter */
541
40
    if (flush < 0 || flush > Z_FINISH)
542
15
        return Z_STREAM_ERROR;
543
544
    /* check for seek request */
545
25
    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
25
    (void)gz_comp(state, flush);
553
25
    return state->err;
554
25
}
555
556
/* -- see zlib.h -- */
557
163
int ZEXPORT gzsetparams(gzFile file, int level, int strategy) {
558
163
    gz_statep state;
559
163
    z_streamp strm;
560
561
    /* get internal structure */
562
163
    if (file == NULL)
563
26
        return Z_STREAM_ERROR;
564
137
    state = (gz_statep)file;
565
137
    strm = &(state->strm);
566
567
    /* check that we're writing and that there's no error */
568
137
    if (state->mode != GZ_WRITE || state->err != Z_OK || state->direct)
569
2
        return Z_STREAM_ERROR;
570
571
    /* if no change is requested, then do nothing */
572
135
    if (level == state->level && strategy == state->strategy)
573
1
        return Z_OK;
574
575
    /* check for seek request */
576
134
    if (state->seek) {
577
9
        state->seek = 0;
578
9
        if (gz_zero(state, state->skip) == -1)
579
0
            return state->err;
580
9
    }
581
582
    /* change compression parameters for subsequent input */
583
134
    if (state->size) {
584
        /* flush previous input with previous parameters before changing */
585
69
        if (strm->avail_in && gz_comp(state, Z_BLOCK) == -1)
586
0
            return state->err;
587
69
        deflateParams(strm, level, strategy);
588
69
    }
589
134
    state->level = level;
590
134
    state->strategy = strategy;
591
134
    return Z_OK;
592
134
}
593
594
/* -- see zlib.h -- */
595
4.67k
int ZEXPORT gzclose_w(gzFile file) {
596
4.67k
    int ret = Z_OK;
597
4.67k
    gz_statep state;
598
599
    /* get internal structure */
600
4.67k
    if (file == NULL)
601
0
        return Z_STREAM_ERROR;
602
4.67k
    state = (gz_statep)file;
603
604
    /* check that we're writing */
605
4.67k
    if (state->mode != GZ_WRITE)
606
0
        return Z_STREAM_ERROR;
607
608
    /* check for seek request */
609
4.67k
    if (state->seek) {
610
102
        state->seek = 0;
611
102
        if (gz_zero(state, state->skip) == -1)
612
1
            ret = state->err;
613
102
    }
614
615
    /* flush, free memory, and close file */
616
4.67k
    if (gz_comp(state, Z_FINISH) == -1)
617
42
        ret = state->err;
618
4.67k
    if (state->size) {
619
4.63k
        if (!state->direct) {
620
4.61k
            (void)deflateEnd(&(state->strm));
621
4.61k
            free(state->out);
622
4.61k
        }
623
4.63k
        free(state->in);
624
4.63k
    }
625
4.67k
    gz_error(state, Z_OK, NULL);
626
4.67k
    free(state->path);
627
4.67k
    if (close(state->fd) == -1)
628
0
        ret = Z_ERRNO;
629
4.67k
    free(state);
630
4.67k
    return ret;
631
4.67k
}