Coverage Report

Created: 2025-11-06 06:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/zlib-ng/gzlib.c
Line
Count
Source
1
/* gzlib.c -- zlib functions common to reading and writing gzip files
2
 * Copyright (C) 2004-2024 Mark Adler
3
 * For conditions of distribution and use, see copyright notice in zlib.h
4
 */
5
6
#include "zbuild.h"
7
#include "zutil.h"
8
#include "zutil_p.h"
9
#include "gzguts.h"
10
11
#if defined(_WIN32)
12
#  define LSEEK _lseeki64
13
#else
14
#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0
15
6.10k
#  define LSEEK lseek64
16
#else
17
#  define LSEEK lseek
18
#endif
19
#endif
20
21
/* Local functions */
22
static gzFile gz_state_init(void);
23
static void gz_reset(gz_state *);
24
static gzFile gz_open(const void *, int, const char *);
25
26
/* Initialize struct for gzFile state */
27
12.2k
static gzFile gz_state_init(void) {
28
    /* allocate gzFile structure to return */
29
12.2k
    gz_state *state = (gz_state *)zng_alloc(sizeof(gz_state));
30
12.2k
    if (state == NULL)
31
0
        return NULL;
32
33
12.2k
    state->strm.zalloc = NULL;
34
12.2k
    state->strm.zfree = NULL;
35
12.2k
    state->strm.opaque = NULL;
36
12.2k
    state->strm.next_in = NULL;
37
38
12.2k
    state->size = 0;
39
12.2k
    state->want = GZBUFSIZE;
40
12.2k
    state->in = NULL;
41
12.2k
    state->out = NULL;
42
12.2k
    state->direct = 0;
43
12.2k
    state->mode = GZ_NONE;
44
12.2k
    state->level = Z_DEFAULT_COMPRESSION;
45
12.2k
    state->strategy = Z_DEFAULT_STRATEGY;
46
12.2k
    state->msg = NULL;
47
12.2k
    return (gzFile)state;
48
12.2k
}
49
50
6.11k
void Z_INTERNAL gz_state_free(gz_state *state) {
51
6.11k
    zng_free(state);
52
6.11k
}
53
54
/* Reset gzip file state */
55
12.2k
static void gz_reset(gz_state *state) {
56
12.2k
    state->x.have = 0;              /* no output data available */
57
12.2k
    if (state->mode == GZ_READ) {   /* for reading ... */
58
6.10k
        state->eof = 0;             /* not at end of file */
59
6.10k
        state->past = 0;            /* have not read past end yet */
60
6.10k
        state->how = LOOK;          /* look for gzip header */
61
6.10k
    }
62
6.11k
    else                            /* for writing ... */
63
6.11k
        state->reset = 0;           /* no deflateReset pending */
64
12.2k
    state->seek = 0;                /* no seek request pending */
65
12.2k
    gz_error(state, Z_OK, NULL);    /* clear error */
66
12.2k
    state->x.pos = 0;               /* no uncompressed data yet */
67
12.2k
    state->strm.avail_in = 0;       /* no input data yet */
68
12.2k
}
69
70
/* Allocate in/out buffers for gzFile */
71
12.2k
int Z_INTERNAL gz_buffer_alloc(gz_state *state) {
72
12.2k
    int want = state->want;
73
12.2k
    int in_size = want, out_size = want;
74
75
12.2k
    if (state->mode == GZ_WRITE) {
76
6.11k
        in_size = want * 2; // double input buffer for compression (ref: gzprintf)
77
6.11k
        if (state->direct)
78
5
            out_size = 0; // output buffer not needed in write + direct mode
79
6.11k
    } else if (state->mode == GZ_READ) {
80
6.10k
        out_size = want * 2;  // double output buffer for decompression
81
6.10k
    }
82
83
12.2k
    state->buffers = (unsigned char *)zng_alloc_aligned((in_size + out_size), 64);
84
12.2k
    state->in = state->buffers;
85
12.2k
    if (out_size) {
86
12.2k
        state->out = state->buffers + (in_size); // Outbuffer goes after inbuffer
87
12.2k
    }
88
89
    /* Return error if memory allocation failed */
90
12.2k
    if (state->in == NULL || (out_size && state->out == NULL)) {
91
0
        gz_buffer_free(state);
92
0
        gz_error(state, Z_MEM_ERROR, "out of memory");
93
0
        return -1;
94
0
    }
95
96
12.2k
    state->size = want; // mark state as initialized
97
12.2k
    return 0;
98
12.2k
}
99
100
12.2k
void Z_INTERNAL gz_buffer_free(gz_state *state) {
101
12.2k
    zng_free_aligned(state->buffers);
102
12.2k
    state->buffers = NULL;
103
12.2k
    state->out = NULL;
104
12.2k
    state->in = NULL;
105
12.2k
    state->size = 0;
106
12.2k
}
107
108
/* Open a gzip file either by name or file descriptor. */
109
12.2k
static gzFile gz_open(const void *path, int fd, const char *mode) {
110
12.2k
    gz_state *state;
111
12.2k
    size_t len;
112
12.2k
    int oflag;
113
12.2k
#ifdef O_CLOEXEC
114
12.2k
    int cloexec = 0;
115
12.2k
#endif
116
12.2k
#ifdef O_EXCL
117
12.2k
    int exclusive = 0;
118
12.2k
#endif
119
120
    /* check input */
121
12.2k
    if (path == NULL)
122
0
        return NULL;
123
124
    /* Initialize gzFile state */
125
12.2k
    state = (gz_state *)gz_state_init();
126
12.2k
    if (state == NULL)
127
0
        return NULL;
128
129
    /* interpret mode */
130
47.0k
    while (*mode) {
131
34.8k
        if (*mode >= '0' && *mode <= '9') {
132
6.11k
            state->level = *mode - '0';
133
28.7k
        } else {
134
28.7k
            switch (*mode) {
135
6.10k
            case 'r':
136
6.10k
                state->mode = GZ_READ;
137
6.10k
                break;
138
0
#ifndef NO_GZCOMPRESS
139
6.11k
            case 'w':
140
6.11k
                state->mode = GZ_WRITE;
141
6.11k
                break;
142
0
            case 'a':
143
0
                state->mode = GZ_APPEND;
144
0
                break;
145
0
#endif
146
0
            case '+':       /* can't read and write at the same time */
147
0
                gz_state_free(state);
148
0
                return NULL;
149
12.2k
            case 'b':       /* ignore -- will request binary anyway */
150
12.2k
                break;
151
0
#ifdef O_CLOEXEC
152
0
            case 'e':
153
0
                cloexec = 1;
154
0
                break;
155
0
#endif
156
0
#ifdef O_EXCL
157
0
            case 'x':
158
0
                exclusive = 1;
159
0
                break;
160
0
#endif
161
992
            case 'f':
162
992
                state->strategy = Z_FILTERED;
163
992
                break;
164
627
            case 'h':
165
627
                state->strategy = Z_HUFFMAN_ONLY;
166
627
                break;
167
1.76k
            case 'R':
168
1.76k
                state->strategy = Z_RLE;
169
1.76k
                break;
170
885
            case 'F':
171
885
                state->strategy = Z_FIXED;
172
885
                break;
173
5
            case 'T':
174
5
                state->direct = 1;
175
5
                break;
176
0
            default:        /* could consider as an error, but just ignore */
177
0
                {}
178
28.7k
            }
179
28.7k
        }
180
34.8k
        mode++;
181
34.8k
    }
182
183
    /* must provide an "r", "w", or "a" */
184
12.2k
    if (state->mode == GZ_NONE) {
185
0
        gz_state_free(state);
186
0
        return NULL;
187
0
    }
188
189
    /* can't force transparent read */
190
12.2k
    if (state->mode == GZ_READ) {
191
6.10k
        if (state->direct) {
192
0
            gz_state_free(state);
193
0
            return NULL;
194
0
        }
195
6.10k
        state->direct = 1;      /* for empty file */
196
6.10k
    }
197
198
    /* save the path name for error messages */
199
#ifdef WIDECHAR
200
    if (fd == -2) {
201
        len = wcstombs(NULL, (const wchar_t *)path, 0);
202
        if (len == (size_t)-1)
203
            len = 0;
204
    } else
205
#endif
206
12.2k
        len = strlen((const char *)path);
207
12.2k
    state->path = (char *)malloc(len + 1);
208
12.2k
    if (state->path == NULL) {
209
0
        gz_state_free(state);
210
0
        return NULL;
211
0
    }
212
#ifdef WIDECHAR
213
    if (fd == -2)
214
        if (len) {
215
            wcstombs(state->path, (const wchar_t *)path, len + 1);
216
        } else {
217
            *(state->path) = 0;
218
        }
219
    else
220
#endif
221
12.2k
        (void)snprintf(state->path, len + 1, "%s", (const char *)path);
222
223
    /* compute the flags for open() */
224
12.2k
    oflag =
225
12.2k
#ifdef O_LARGEFILE
226
12.2k
        O_LARGEFILE |
227
12.2k
#endif
228
#ifdef O_BINARY
229
        O_BINARY |
230
#endif
231
12.2k
#ifdef O_CLOEXEC
232
12.2k
        (cloexec ? O_CLOEXEC : 0) |
233
12.2k
#endif
234
12.2k
        (state->mode == GZ_READ ?
235
12.2k
         O_RDONLY :
236
12.2k
         (O_WRONLY | O_CREAT |
237
6.11k
#ifdef O_EXCL
238
6.11k
          (exclusive ? O_EXCL : 0) |
239
6.11k
#endif
240
6.11k
          (state->mode == GZ_WRITE ?
241
6.11k
           O_TRUNC :
242
6.11k
           O_APPEND)));
243
244
    /* open the file with the appropriate flags (or just use fd) */
245
12.2k
    state->fd = fd > -1 ? fd : (
246
#if defined(_WIN32)
247
        fd == -2 ? _wopen((const wchar_t *)path, oflag, 0666) :
248
#elif __CYGWIN__
249
        fd == -2 ? open(state->path, oflag, 0666) :
250
#endif
251
12.2k
        open((const char *)path, oflag, 0666));
252
12.2k
    if (state->fd == -1) {
253
0
        free(state->path);
254
0
        gz_state_free(state);
255
0
        return NULL;
256
0
    }
257
12.2k
    if (state->mode == GZ_APPEND) {
258
0
        LSEEK(state->fd, 0, SEEK_END);  /* so gzoffset() is correct */
259
0
        state->mode = GZ_WRITE;         /* simplify later checks */
260
0
    }
261
262
    /* save the current position for rewinding (only if reading) */
263
12.2k
    if (state->mode == GZ_READ) {
264
6.10k
        state->start = LSEEK(state->fd, 0, SEEK_CUR);
265
6.10k
        if (state->start == -1) state->start = 0;
266
6.10k
    }
267
268
    /* initialize stream */
269
12.2k
    gz_reset(state);
270
271
    /* return stream */
272
12.2k
    return (gzFile)state;
273
12.2k
}
274
275
/* -- see zlib.h -- */
276
12.2k
gzFile Z_EXPORT PREFIX(gzopen)(const char *path, const char *mode) {
277
12.2k
    return gz_open(path, -1, mode);
278
12.2k
}
279
280
#ifdef ZLIB_COMPAT
281
gzFile Z_EXPORT PREFIX4(gzopen)(const char *path, const char *mode) {
282
    return gz_open(path, -1, mode);
283
}
284
#endif
285
286
/* -- see zlib.h -- */
287
0
gzFile Z_EXPORT PREFIX(gzdopen)(int fd, const char *mode) {
288
0
    gzFile gz;
289
0
    char path[32];         /* identifier for error messages */
290
291
0
    if (fd == -1)
292
0
        return NULL;
293
0
    (void)snprintf(path, 32, "<fd:%d>", fd); /* for debugging */
294
0
    gz = gz_open(path, fd, mode);
295
0
    return gz;
296
0
}
297
298
/* -- see zlib.h -- */
299
#ifdef WIDECHAR
300
gzFile Z_EXPORT PREFIX(gzopen_w)(const wchar_t *path, const char *mode) {
301
    return gz_open(path, -2, mode);
302
}
303
#endif
304
305
12.2k
z_int32_t Z_EXPORT PREFIX(gzclose)(gzFile file) {
306
12.2k
#ifndef NO_GZCOMPRESS
307
12.2k
    gz_state *state;
308
309
12.2k
    if (file == NULL)
310
0
        return Z_STREAM_ERROR;
311
12.2k
    state = (gz_state *)file;
312
313
12.2k
    return state->mode == GZ_READ ? PREFIX(gzclose_r)(file) : PREFIX(gzclose_w)(file);
314
#else
315
    return PREFIX(gzclose_r)(file);
316
#endif
317
12.2k
}
318
319
/* -- see zlib.h -- */
320
0
z_int32_t Z_EXPORT PREFIX(gzbuffer)(gzFile file, z_uint32_t size) {
321
0
    gz_state *state;
322
323
    /* get internal structure and check integrity */
324
0
    if (file == NULL)
325
0
        return -1;
326
0
    state = (gz_state *)file;
327
0
    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
328
0
        return -1;
329
330
    /* make sure we haven't already allocated memory */
331
0
    if (state->size != 0)
332
0
        return -1;
333
334
    /* check and set requested size */
335
0
    if ((size << 1) < size)
336
0
        return -1;              /* need to be able to double it */
337
0
    if (size < 8)
338
0
        size = 8;               /* needed to behave well with flushing */
339
0
    state->want = size;
340
0
    return 0;
341
0
}
342
343
/* -- see zlib.h -- */
344
0
z_int32_t Z_EXPORT PREFIX(gzrewind)(gzFile file) {
345
0
    gz_state *state;
346
347
    /* get internal structure */
348
0
    if (file == NULL)
349
0
        return -1;
350
0
    state = (gz_state *)file;
351
352
    /* check that we're reading and that there's no error */
353
0
    if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR))
354
0
        return -1;
355
356
    /* back up and start over */
357
0
    if (LSEEK(state->fd, state->start, SEEK_SET) == -1)
358
0
        return -1;
359
0
    gz_reset(state);
360
0
    return 0;
361
0
}
362
363
/* -- see zlib.h -- */
364
0
z_off64_t Z_EXPORT PREFIX4(gzseek)(gzFile file, z_off64_t offset, int whence) {
365
0
    unsigned n;
366
0
    z_off64_t ret;
367
0
    gz_state *state;
368
369
    /* get internal structure and check integrity */
370
0
    if (file == NULL)
371
0
        return -1;
372
0
    state = (gz_state *)file;
373
0
    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
374
0
        return -1;
375
376
    /* check that there's no error */
377
0
    if (state->err != Z_OK && state->err != Z_BUF_ERROR)
378
0
        return -1;
379
380
    /* can only seek from start or relative to current position */
381
0
    if (whence != SEEK_SET && whence != SEEK_CUR)
382
0
        return -1;
383
384
    /* normalize offset to a SEEK_CUR specification */
385
0
    if (whence == SEEK_SET)
386
0
        offset -= state->x.pos;
387
0
    else if (state->seek)
388
0
        offset += state->skip;
389
0
    state->seek = 0;
390
391
    /* if within raw area while reading, just go there */
392
0
    if (state->mode == GZ_READ && state->how == COPY && state->x.pos + offset >= 0) {
393
0
        ret = LSEEK(state->fd, offset - (z_off64_t)state->x.have, SEEK_CUR);
394
0
        if (ret == -1)
395
0
            return -1;
396
0
        state->x.have = 0;
397
0
        state->eof = 0;
398
0
        state->past = 0;
399
0
        state->seek = 0;
400
0
        gz_error(state, Z_OK, NULL);
401
0
        state->strm.avail_in = 0;
402
0
        state->x.pos += offset;
403
0
        return state->x.pos;
404
0
    }
405
406
    /* calculate skip amount, rewinding if needed for back seek when reading */
407
0
    if (offset < 0) {
408
0
        if (state->mode != GZ_READ)         /* writing -- can't go backwards */
409
0
            return -1;
410
0
        offset += state->x.pos;
411
0
        if (offset < 0)                     /* before start of file! */
412
0
            return -1;
413
0
        if (PREFIX(gzrewind)(file) == -1)   /* rewind, then skip to offset */
414
0
            return -1;
415
0
    }
416
417
    /* if reading, skip what's in output buffer (one less gzgetc() check) */
418
0
    if (state->mode == GZ_READ) {
419
0
        n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ? (unsigned)offset : state->x.have;
420
0
        state->x.have -= n;
421
0
        state->x.next += n;
422
0
        state->x.pos += n;
423
0
        offset -= n;
424
0
    }
425
426
    /* request skip (if not zero) */
427
0
    if (offset) {
428
0
        state->seek = 1;
429
0
        state->skip = offset;
430
0
    }
431
0
    return state->x.pos + offset;
432
0
}
433
434
/* -- see zlib.h -- */
435
#ifdef ZLIB_COMPAT
436
z_off_t Z_EXPORT PREFIX(gzseek)(gzFile file, z_off_t offset, int whence) {
437
    z_off64_t ret;
438
439
    ret = PREFIX4(gzseek)(file, (z_off64_t)offset, whence);
440
    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
441
}
442
#endif
443
444
/* -- see zlib.h -- */
445
0
z_off64_t Z_EXPORT PREFIX4(gztell)(gzFile file) {
446
0
    gz_state *state;
447
448
    /* get internal structure and check integrity */
449
0
    if (file == NULL)
450
0
        return -1;
451
0
    state = (gz_state *)file;
452
0
    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
453
0
        return -1;
454
455
    /* return position */
456
0
    return state->x.pos + (state->seek ? state->skip : 0);
457
0
}
458
459
/* -- see zlib.h -- */
460
#ifdef ZLIB_COMPAT
461
z_off_t Z_EXPORT PREFIX(gztell)(gzFile file) {
462
463
    z_off64_t ret;
464
465
    ret = PREFIX4(gztell)(file);
466
    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
467
}
468
#endif
469
470
/* -- see zlib.h -- */
471
0
z_off64_t Z_EXPORT PREFIX4(gzoffset)(gzFile file) {
472
0
    z_off64_t offset;
473
0
    gz_state *state;
474
475
    /* get internal structure and check integrity */
476
0
    if (file == NULL)
477
0
        return -1;
478
0
    state = (gz_state *)file;
479
0
    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
480
0
        return -1;
481
482
    /* compute and return effective offset in file */
483
0
    offset = LSEEK(state->fd, 0, SEEK_CUR);
484
0
    if (offset == -1)
485
0
        return -1;
486
0
    if (state->mode == GZ_READ)             /* reading */
487
0
        offset -= state->strm.avail_in;     /* don't count buffered input */
488
0
    return offset;
489
0
}
490
491
/* -- see zlib.h -- */
492
#ifdef ZLIB_COMPAT
493
z_off_t Z_EXPORT PREFIX(gzoffset)(gzFile file) {
494
    z_off64_t ret;
495
496
    ret = PREFIX4(gzoffset)(file);
497
    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
498
}
499
#endif
500
501
/* -- see zlib.h -- */
502
0
z_int32_t Z_EXPORT PREFIX(gzeof)(gzFile file) {
503
0
    gz_state *state;
504
505
    /* get internal structure and check integrity */
506
0
    if (file == NULL)
507
0
        return 0;
508
0
    state = (gz_state *)file;
509
0
    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
510
0
        return 0;
511
512
    /* return end-of-file state */
513
0
    return state->mode == GZ_READ ? state->past : 0;
514
0
}
515
516
/* -- see zlib.h -- */
517
0
const char * Z_EXPORT PREFIX(gzerror)(gzFile file, z_int32_t *errnum) {
518
0
    gz_state *state;
519
520
    /* get internal structure and check integrity */
521
0
    if (file == NULL)
522
0
        return NULL;
523
0
    state = (gz_state *)file;
524
0
    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
525
0
        return NULL;
526
527
    /* return error information */
528
0
    if (errnum != NULL)
529
0
        *errnum = state->err;
530
0
    return state->err == Z_MEM_ERROR ? "out of memory" : (state->msg == NULL ? "" : state->msg);
531
0
}
532
533
/* -- see zlib.h -- */
534
0
void Z_EXPORT PREFIX(gzclearerr)(gzFile file) {
535
0
    gz_state *state;
536
537
    /* get internal structure and check integrity */
538
0
    if (file == NULL)
539
0
        return;
540
0
    state = (gz_state *)file;
541
0
    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
542
0
        return;
543
544
    /* clear error and end-of-file */
545
0
    if (state->mode == GZ_READ) {
546
0
        state->eof = 0;
547
0
        state->past = 0;
548
0
    }
549
0
    gz_error(state, Z_OK, NULL);
550
0
}
551
552
/* Create an error message in allocated memory and set state->err and
553
   state->msg accordingly.  Free any previous error message already there.  Do
554
   not try to free or allocate space if the error is Z_MEM_ERROR (out of
555
   memory).  Simply save the error message as a static string.  If there is an
556
   allocation failure constructing the error message, then convert the error to
557
   out of memory. */
558
24.4k
void Z_INTERNAL gz_error(gz_state *state, int err, const char *msg) {
559
    /* free previously allocated message and clear */
560
24.4k
    if (state->msg != NULL) {
561
0
        if (state->err != Z_MEM_ERROR)
562
0
            free(state->msg);
563
0
        state->msg = NULL;
564
0
    }
565
566
    /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */
567
24.4k
    if (err != Z_OK && err != Z_BUF_ERROR)
568
0
        state->x.have = 0;
569
570
    /* set error code, and if no message, then done */
571
24.4k
    state->err = err;
572
24.4k
    if (msg == NULL)
573
24.4k
        return;
574
575
    /* for an out of memory error, return literal string when requested */
576
0
    if (err == Z_MEM_ERROR)
577
0
        return;
578
579
    /* construct error message with path */
580
0
    if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) == NULL) {
581
0
        state->err = Z_MEM_ERROR;
582
0
        return;
583
0
    }
584
0
    (void)snprintf(state->msg, strlen(state->path) + strlen(msg) + 3, "%s%s%s", state->path, ": ", msg);
585
0
}
586
587
#ifdef ZLIB_COMPAT
588
unsigned Z_INTERNAL gz_intmax(void) {
589
    return INT_MAX;
590
}
591
#endif