Coverage Report

Created: 2025-10-13 07:18

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