Coverage Report

Created: 2025-06-16 07:00

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