Coverage Report

Created: 2025-07-12 06:08

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