Coverage Report

Created: 2026-04-13 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/elfutils/zlib/gzread.c
Line
Count
Source
1
/* gzread.c -- zlib functions for reading gzip files
2
 * Copyright (C) 2004-2017 Mark Adler
3
 * For conditions of distribution and use, see copyright notice in zlib.h
4
 */
5
6
#include "gzguts.h"
7
8
/* Use read() to load a buffer -- return -1 on error, otherwise 0.  Read from
9
   state->fd, and update state->eof, state->err, and state->msg as appropriate.
10
   This function needs to loop on read(), since read() is not guaranteed to
11
   read the number of bytes requested, depending on the type of descriptor. */
12
local int gz_load(gz_statep state, unsigned char *buf, unsigned len,
13
10.4k
                  unsigned *have) {
14
10.4k
    int ret;
15
10.4k
    unsigned get, max = ((unsigned)-1 >> 2) + 1;
16
17
10.4k
    *have = 0;
18
14.7k
    do {
19
14.7k
        get = len - *have;
20
14.7k
        if (get > max)
21
0
            get = max;
22
14.7k
        ret = read(state->fd, buf + *have, get);
23
14.7k
        if (ret <= 0)
24
4.32k
            break;
25
10.3k
        *have += (unsigned)ret;
26
10.3k
    } while (*have < len);
27
10.4k
    if (ret < 0) {
28
0
        gz_error(state, Z_ERRNO, zstrerror());
29
0
        return -1;
30
0
    }
31
10.4k
    if (ret == 0)
32
4.32k
        state->eof = 1;
33
10.4k
    return 0;
34
10.4k
}
35
36
/* Load up input buffer and set eof flag if last data loaded -- return -1 on
37
   error, 0 otherwise.  Note that the eof flag is set when the end of the input
38
   file is reached, even though there may be unused data in the buffer.  Once
39
   that data has been used, no more attempts will be made to read the file.
40
   If strm->avail_in != 0, then the current data is moved to the beginning of
41
   the input buffer, and then the remainder of the buffer is loaded with the
42
   available data from the input file. */
43
14.0k
local int gz_avail(gz_statep state) {
44
14.0k
    unsigned got;
45
14.0k
    z_streamp strm = &(state->strm);
46
47
14.0k
    if (state->err != Z_OK && state->err != Z_BUF_ERROR)
48
0
        return -1;
49
14.0k
    if (state->eof == 0) {
50
10.4k
        if (strm->avail_in) {       /* copy what's there to the start */
51
26
            unsigned char *p = state->in;
52
26
            unsigned const char *q = strm->next_in;
53
26
            unsigned n = strm->avail_in;
54
26
            do {
55
26
                *p++ = *q++;
56
26
            } while (--n);
57
26
        }
58
10.4k
        if (gz_load(state, state->in + strm->avail_in,
59
10.4k
                    state->size - strm->avail_in, &got) == -1)
60
0
            return -1;
61
10.4k
        strm->avail_in += got;
62
10.4k
        strm->next_in = state->in;
63
10.4k
    }
64
14.0k
    return 0;
65
14.0k
}
66
67
/* Look for gzip header, set up for inflate or copy.  state->x.have must be 0.
68
   If this is the first time in, allocate required memory.  state->how will be
69
   left unchanged if there is no more input data available, will be set to COPY
70
   if there is no gzip header and direct copying will be performed, or it will
71
   be set to GZIP for decompression.  If direct copying, then leftover input
72
   data from the input buffer will be copied to the output buffer.  In that
73
   case, all further file reads will be directly to either the output buffer or
74
   a user buffer.  If decompressing, the inflate state will be initialized.
75
   gz_look() will return 0 on success or -1 on failure. */
76
153k
local int gz_look(gz_statep state) {
77
153k
    z_streamp strm = &(state->strm);
78
79
    /* allocate read buffers and inflate memory */
80
153k
    if (state->size == 0) {
81
        /* allocate buffers */
82
4.34k
        state->in = (unsigned char *)malloc(state->want);
83
4.34k
        state->out = (unsigned char *)malloc(state->want << 1);
84
4.34k
        if (state->in == NULL || state->out == NULL) {
85
0
            free(state->out);
86
0
            free(state->in);
87
0
            gz_error(state, Z_MEM_ERROR, "out of memory");
88
0
            return -1;
89
0
        }
90
4.34k
        state->size = state->want;
91
92
        /* allocate inflate memory */
93
4.34k
        state->strm.zalloc = Z_NULL;
94
4.34k
        state->strm.zfree = Z_NULL;
95
4.34k
        state->strm.opaque = Z_NULL;
96
4.34k
        state->strm.avail_in = 0;
97
4.34k
        state->strm.next_in = Z_NULL;
98
4.34k
        if (inflateInit2(&(state->strm), 15 + 16) != Z_OK) {    /* gunzip */
99
0
            free(state->out);
100
0
            free(state->in);
101
0
            state->size = 0;
102
0
            gz_error(state, Z_MEM_ERROR, "out of memory");
103
0
            return -1;
104
0
        }
105
4.34k
    }
106
107
    /* get at least the magic bytes in the input buffer */
108
153k
    if (strm->avail_in < 2) {
109
4.44k
        if (gz_avail(state) == -1)
110
0
            return -1;
111
4.44k
        if (strm->avail_in == 0)
112
0
            return 0;
113
4.44k
    }
114
115
    /* look for gzip magic bytes -- if there, do gzip decoding (note: there is
116
       a logical dilemma here when considering the case of a partially written
117
       gzip file, to wit, if a single 31 byte is written, then we cannot tell
118
       whether this is a single-byte file, or just a partially written gzip
119
       file -- for here we assume that if a gzip file is being written, then
120
       the header will be written in a single operation, so that reading a
121
       single byte is sufficient indication that it is not a gzip file) */
122
153k
    if (strm->avail_in > 1 &&
123
153k
            strm->next_in[0] == 31 && strm->next_in[1] == 139) {
124
153k
        inflateReset(strm);
125
153k
        state->how = GZIP;
126
153k
        state->direct = 0;
127
153k
        return 0;
128
153k
    }
129
130
    /* no gzip header -- if we were decoding gzip before, then this is trailing
131
       garbage.  Ignore the trailing garbage and finish. */
132
68
    if (state->direct == 0) {
133
68
        strm->avail_in = 0;
134
68
        state->eof = 1;
135
68
        state->x.have = 0;
136
68
        return 0;
137
68
    }
138
139
    /* doing raw i/o, copy any leftover input to output -- this assumes that
140
       the output buffer is larger than the input buffer, which also assures
141
       space for gzungetc() */
142
0
    state->x.next = state->out;
143
0
    memcpy(state->x.next, strm->next_in, strm->avail_in);
144
0
    state->x.have = strm->avail_in;
145
0
    strm->avail_in = 0;
146
0
    state->how = COPY;
147
0
    state->direct = 1;
148
0
    return 0;
149
68
}
150
151
/* Decompress from input to the provided next_out and avail_out in the state.
152
   On return, state->x.have and state->x.next point to the just decompressed
153
   data.  If the gzip stream completes, state->how is reset to LOOK to look for
154
   the next gzip stream or raw data, once state->x.have is depleted.  Returns 0
155
   on success, -1 on failure. */
156
160k
local int gz_decomp(gz_statep state) {
157
160k
    int ret = Z_OK;
158
160k
    unsigned had;
159
160k
    z_streamp strm = &(state->strm);
160
161
    /* fill output buffer up to end of deflate stream */
162
160k
    had = strm->avail_out;
163
170k
    do {
164
        /* get more input for inflate() */
165
170k
        if (strm->avail_in == 0 && gz_avail(state) == -1)
166
0
            return -1;
167
170k
        if (strm->avail_in == 0) {
168
3.62k
            gz_error(state, Z_BUF_ERROR, "unexpected end of file");
169
3.62k
            break;
170
3.62k
        }
171
172
        /* decompress and handle errors */
173
166k
        ret = inflate(strm, Z_NO_FLUSH);
174
166k
        if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) {
175
0
            gz_error(state, Z_STREAM_ERROR,
176
0
                     "internal error: inflate stream corrupt");
177
0
            return -1;
178
0
        }
179
166k
        if (ret == Z_MEM_ERROR) {
180
0
            gz_error(state, Z_MEM_ERROR, "out of memory");
181
0
            return -1;
182
0
        }
183
166k
        if (ret == Z_DATA_ERROR) {              /* deflate stream invalid */
184
603
            gz_error(state, Z_DATA_ERROR,
185
603
                     strm->msg == NULL ? "compressed data error" : strm->msg);
186
603
            return -1;
187
603
        }
188
166k
    } while (strm->avail_out && ret != Z_STREAM_END);
189
190
    /* update available output */
191
160k
    state->x.have = had - strm->avail_out;
192
160k
    state->x.next = strm->next_out - state->x.have;
193
194
    /* if the gzip stream completed successfully, look for another */
195
160k
    if (ret == Z_STREAM_END)
196
148k
        state->how = LOOK;
197
198
    /* good decompression */
199
160k
    return 0;
200
160k
}
201
202
/* Fetch data and put it in the output buffer.  Assumes state->x.have is 0.
203
   Data is either copied from the input file or decompressed from the input
204
   file depending on state->how.  If state->how is LOOK, then a gzip header is
205
   looked for to determine whether to copy or decompress.  Returns -1 on error,
206
   otherwise 0.  gz_fetch() will leave state->how as COPY or GZIP unless the
207
   end of the input file has been reached and all data has been processed.  */
208
10.7k
local int gz_fetch(gz_statep state) {
209
10.7k
    z_streamp strm = &(state->strm);
210
211
302k
    do {
212
302k
        switch(state->how) {
213
148k
        case LOOK:      /* -> LOOK, COPY (only if never GZIP), or GZIP */
214
148k
            if (gz_look(state) == -1)
215
0
                return -1;
216
148k
            if (state->how == LOOK)
217
68
                return 0;
218
148k
            break;
219
148k
        case COPY:      /* -> COPY */
220
0
            if (gz_load(state, state->out, state->size << 1, &(state->x.have))
221
0
                    == -1)
222
0
                return -1;
223
0
            state->x.next = state->out;
224
0
            return 0;
225
153k
        case GZIP:      /* -> GZIP or LOOK (if end of gzip stream) */
226
153k
            strm->avail_out = state->size << 1;
227
153k
            strm->next_out = state->out;
228
153k
            if (gz_decomp(state) == -1)
229
524
                return -1;
230
302k
        }
231
302k
    } while (state->x.have == 0 && (!state->eof || strm->avail_in));
232
10.1k
    return 0;
233
10.7k
}
234
235
/* Skip len uncompressed bytes of output.  Return -1 on error, 0 on success. */
236
0
local int gz_skip(gz_statep state, z_off64_t len) {
237
0
    unsigned n;
238
239
    /* skip over len bytes or reach end-of-file, whichever comes first */
240
0
    while (len)
241
        /* skip over whatever is in output buffer */
242
0
        if (state->x.have) {
243
0
            n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > len ?
244
0
                (unsigned)len : state->x.have;
245
0
            state->x.have -= n;
246
0
            state->x.next += n;
247
0
            state->x.pos += n;
248
0
            len -= n;
249
0
        }
250
251
        /* output buffer empty -- return if we're at the end of the input */
252
0
        else if (state->eof && state->strm.avail_in == 0)
253
0
            break;
254
255
        /* need more data to skip -- load up output buffer */
256
0
        else {
257
            /* get more output, looking for header if required */
258
0
            if (gz_fetch(state) == -1)
259
0
                return -1;
260
0
        }
261
0
    return 0;
262
0
}
263
264
/* Read len bytes into buf from file, or less than len up to the end of the
265
   input.  Return the number of bytes read.  If zero is returned, either the
266
   end of file was reached, or there was an error.  state->err must be
267
   consulted in that case to determine which. */
268
23.0k
local z_size_t gz_read(gz_statep state, voidp buf, z_size_t len) {
269
23.0k
    z_size_t got;
270
23.0k
    unsigned n;
271
272
    /* if len is zero, avoid unnecessary operations */
273
23.0k
    if (len == 0)
274
0
        return 0;
275
276
    /* process a skip request */
277
23.0k
    if (state->seek) {
278
0
        state->seek = 0;
279
0
        if (gz_skip(state, state->skip) == -1)
280
0
            return 0;
281
0
    }
282
283
    /* get len bytes to buf, or less than len if at the end */
284
23.0k
    got = 0;
285
42.6k
    do {
286
        /* set n to the maximum amount of len that fits in an unsigned int */
287
42.6k
        n = (unsigned)-1;
288
42.6k
        if (n > len)
289
42.6k
            n = (unsigned)len;
290
291
        /* first just try copying data from the output buffer */
292
42.6k
        if (state->x.have) {
293
17.8k
            if (state->x.have < n)
294
7.95k
                n = state->x.have;
295
17.8k
            memcpy(buf, state->x.next, n);
296
17.8k
            state->x.next += n;
297
17.8k
            state->x.have -= n;
298
17.8k
        }
299
300
        /* output buffer empty -- return if we're at the end of the input */
301
24.8k
        else if (state->eof && state->strm.avail_in == 0) {
302
6.65k
            state->past = 1;        /* tried to read past end */
303
6.65k
            break;
304
6.65k
        }
305
306
        /* need output data -- for small len or new stream load up our output
307
           buffer */
308
18.1k
        else if (state->how == LOOK || n < (state->size << 1)) {
309
            /* get more output, looking for header if required */
310
10.7k
            if (gz_fetch(state) == -1)
311
524
                return 0;
312
10.2k
            continue;       /* no progress yet -- go back to copy above */
313
            /* the copy above assures that we will leave with space in the
314
               output buffer, allowing at least one gzungetc() to succeed */
315
10.7k
        }
316
317
        /* large len -- read directly into user buffer */
318
7.39k
        else if (state->how == COPY) {      /* read directly */
319
0
            if (gz_load(state, (unsigned char *)buf, n, &n) == -1)
320
0
                return 0;
321
0
        }
322
323
        /* large len -- decompress directly into user buffer */
324
7.39k
        else {  /* state->how == GZIP */
325
7.39k
            state->strm.avail_out = n;
326
7.39k
            state->strm.next_out = (unsigned char *)buf;
327
7.39k
            if (gz_decomp(state) == -1)
328
79
                return 0;
329
7.31k
            n = state->x.have;
330
7.31k
            state->x.have = 0;
331
7.31k
        }
332
333
        /* update progress */
334
25.1k
        len -= n;
335
25.1k
        buf = (char *)buf + n;
336
25.1k
        got += n;
337
25.1k
        state->x.pos += n;
338
35.4k
    } while (len);
339
340
    /* return number of bytes read into user buffer */
341
22.4k
    return got;
342
23.0k
}
343
344
/* -- see zlib.h -- */
345
23.0k
int ZEXPORT gzread(gzFile file, voidp buf, unsigned len) {
346
23.0k
    gz_statep state;
347
348
    /* get internal structure */
349
23.0k
    if (file == NULL)
350
0
        return -1;
351
23.0k
    state = (gz_statep)file;
352
353
    /* check that we're reading and that there's no (serious) error */
354
23.0k
    if (state->mode != GZ_READ ||
355
23.0k
            (state->err != Z_OK && state->err != Z_BUF_ERROR))
356
0
        return -1;
357
358
    /* since an int is returned, make sure len fits in one, otherwise return
359
       with an error (this avoids a flaw in the interface) */
360
23.0k
    if ((int)len < 0) {
361
1
        gz_error(state, Z_STREAM_ERROR, "request does not fit in an int");
362
1
        return -1;
363
1
    }
364
365
    /* read len or fewer bytes to buf */
366
23.0k
    len = (unsigned)gz_read(state, buf, len);
367
368
    /* check for an error */
369
23.0k
    if (len == 0 && state->err != Z_OK && state->err != Z_BUF_ERROR)
370
603
        return -1;
371
372
    /* return the number of bytes read (this is assured to fit in an int) */
373
22.4k
    return (int)len;
374
23.0k
}
375
376
/* -- see zlib.h -- */
377
0
z_size_t ZEXPORT gzfread(voidp buf, z_size_t size, z_size_t nitems, gzFile file) {
378
0
    z_size_t len;
379
0
    gz_statep state;
380
381
    /* get internal structure */
382
0
    if (file == NULL)
383
0
        return 0;
384
0
    state = (gz_statep)file;
385
386
    /* check that we're reading and that there's no (serious) error */
387
0
    if (state->mode != GZ_READ ||
388
0
            (state->err != Z_OK && state->err != Z_BUF_ERROR))
389
0
        return 0;
390
391
    /* compute bytes to read -- error on overflow */
392
0
    len = nitems * size;
393
0
    if (size && len / size != nitems) {
394
0
        gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t");
395
0
        return 0;
396
0
    }
397
398
    /* read len or fewer bytes to buf, return the number of full items read */
399
0
    return len ? gz_read(state, buf, len) / size : 0;
400
0
}
401
402
/* -- see zlib.h -- */
403
#ifdef Z_PREFIX_SET
404
#  undef z_gzgetc
405
#else
406
#  undef gzgetc
407
#endif
408
0
int ZEXPORT gzgetc(gzFile file) {
409
0
    unsigned char buf[1];
410
0
    gz_statep state;
411
412
    /* get internal structure */
413
0
    if (file == NULL)
414
0
        return -1;
415
0
    state = (gz_statep)file;
416
417
    /* check that we're reading and that there's no (serious) error */
418
0
    if (state->mode != GZ_READ ||
419
0
        (state->err != Z_OK && state->err != Z_BUF_ERROR))
420
0
        return -1;
421
422
    /* try output buffer (no need to check for skip request) */
423
0
    if (state->x.have) {
424
0
        state->x.have--;
425
0
        state->x.pos++;
426
0
        return *(state->x.next)++;
427
0
    }
428
429
    /* nothing there -- try gz_read() */
430
0
    return gz_read(state, buf, 1) < 1 ? -1 : buf[0];
431
0
}
432
433
0
int ZEXPORT gzgetc_(gzFile file) {
434
0
    return gzgetc(file);
435
0
}
436
437
/* -- see zlib.h -- */
438
0
int ZEXPORT gzungetc(int c, gzFile file) {
439
0
    gz_statep state;
440
441
    /* get internal structure */
442
0
    if (file == NULL)
443
0
        return -1;
444
0
    state = (gz_statep)file;
445
446
    /* in case this was just opened, set up the input buffer */
447
0
    if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0)
448
0
        (void)gz_look(state);
449
450
    /* check that we're reading and that there's no (serious) error */
451
0
    if (state->mode != GZ_READ ||
452
0
        (state->err != Z_OK && state->err != Z_BUF_ERROR))
453
0
        return -1;
454
455
    /* process a skip request */
456
0
    if (state->seek) {
457
0
        state->seek = 0;
458
0
        if (gz_skip(state, state->skip) == -1)
459
0
            return -1;
460
0
    }
461
462
    /* can't push EOF */
463
0
    if (c < 0)
464
0
        return -1;
465
466
    /* if output buffer empty, put byte at end (allows more pushing) */
467
0
    if (state->x.have == 0) {
468
0
        state->x.have = 1;
469
0
        state->x.next = state->out + (state->size << 1) - 1;
470
0
        state->x.next[0] = (unsigned char)c;
471
0
        state->x.pos--;
472
0
        state->past = 0;
473
0
        return c;
474
0
    }
475
476
    /* if no room, give up (must have already done a gzungetc()) */
477
0
    if (state->x.have == (state->size << 1)) {
478
0
        gz_error(state, Z_DATA_ERROR, "out of room to push characters");
479
0
        return -1;
480
0
    }
481
482
    /* slide output data if needed and insert byte before existing data */
483
0
    if (state->x.next == state->out) {
484
0
        unsigned char *src = state->out + state->x.have;
485
0
        unsigned char *dest = state->out + (state->size << 1);
486
0
        while (src > state->out)
487
0
            *--dest = *--src;
488
0
        state->x.next = dest;
489
0
    }
490
0
    state->x.have++;
491
0
    state->x.next--;
492
0
    state->x.next[0] = (unsigned char)c;
493
0
    state->x.pos--;
494
0
    state->past = 0;
495
0
    return c;
496
0
}
497
498
/* -- see zlib.h -- */
499
0
char * ZEXPORT gzgets(gzFile file, char *buf, int len) {
500
0
    unsigned left, n;
501
0
    char *str;
502
0
    unsigned char *eol;
503
0
    gz_statep state;
504
505
    /* check parameters and get internal structure */
506
0
    if (file == NULL || buf == NULL || len < 1)
507
0
        return NULL;
508
0
    state = (gz_statep)file;
509
510
    /* check that we're reading and that there's no (serious) error */
511
0
    if (state->mode != GZ_READ ||
512
0
        (state->err != Z_OK && state->err != Z_BUF_ERROR))
513
0
        return NULL;
514
515
    /* process a skip request */
516
0
    if (state->seek) {
517
0
        state->seek = 0;
518
0
        if (gz_skip(state, state->skip) == -1)
519
0
            return NULL;
520
0
    }
521
522
    /* copy output bytes up to new line or len - 1, whichever comes first --
523
       append a terminating zero to the string (we don't check for a zero in
524
       the contents, let the user worry about that) */
525
0
    str = buf;
526
0
    left = (unsigned)len - 1;
527
0
    if (left) do {
528
        /* assure that something is in the output buffer */
529
0
        if (state->x.have == 0 && gz_fetch(state) == -1)
530
0
            return NULL;                /* error */
531
0
        if (state->x.have == 0) {       /* end of file */
532
0
            state->past = 1;            /* read past end */
533
0
            break;                      /* return what we have */
534
0
        }
535
536
        /* look for end-of-line in current output buffer */
537
0
        n = state->x.have > left ? left : state->x.have;
538
0
        eol = (unsigned char *)memchr(state->x.next, '\n', n);
539
0
        if (eol != NULL)
540
0
            n = (unsigned)(eol - state->x.next) + 1;
541
542
        /* copy through end-of-line, or remainder if not found */
543
0
        memcpy(buf, state->x.next, n);
544
0
        state->x.have -= n;
545
0
        state->x.next += n;
546
0
        state->x.pos += n;
547
0
        left -= n;
548
0
        buf += n;
549
0
    } while (left && eol == NULL);
550
551
    /* return terminated string, or if nothing, end of file */
552
0
    if (buf == str)
553
0
        return NULL;
554
0
    buf[0] = 0;
555
0
    return str;
556
0
}
557
558
/* -- see zlib.h -- */
559
4.34k
int ZEXPORT gzdirect(gzFile file) {
560
4.34k
    gz_statep state;
561
562
    /* get internal structure */
563
4.34k
    if (file == NULL)
564
0
        return 0;
565
4.34k
    state = (gz_statep)file;
566
567
    /* if the state is not known, but we can find out, then do so (this is
568
       mainly for right after a gzopen() or gzdopen()) */
569
4.34k
    if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0)
570
4.34k
        (void)gz_look(state);
571
572
    /* return 1 if transparent, 0 if processing a gzip stream */
573
4.34k
    return state->direct;
574
4.34k
}
575
576
/* -- see zlib.h -- */
577
4.34k
int ZEXPORT gzclose_r(gzFile file) {
578
4.34k
    int ret, err;
579
4.34k
    gz_statep state;
580
581
    /* get internal structure */
582
4.34k
    if (file == NULL)
583
0
        return Z_STREAM_ERROR;
584
4.34k
    state = (gz_statep)file;
585
586
    /* check that we're reading */
587
4.34k
    if (state->mode != GZ_READ)
588
0
        return Z_STREAM_ERROR;
589
590
    /* free memory and close file */
591
4.34k
    if (state->size) {
592
4.34k
        inflateEnd(&(state->strm));
593
4.34k
        free(state->out);
594
4.34k
        free(state->in);
595
4.34k
    }
596
4.34k
    err = state->err == Z_BUF_ERROR ? Z_BUF_ERROR : Z_OK;
597
4.34k
    gz_error(state, Z_OK, NULL);
598
4.34k
    free(state->path);
599
4.34k
    ret = close(state->fd);
600
4.34k
    free(state);
601
4.34k
    return ret ? Z_ERRNO : err;
602
4.34k
}