Coverage Report

Created: 2026-08-30 07:12

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
11.6k
                  unsigned *have) {
14
11.6k
    int ret;
15
11.6k
    unsigned get, max = ((unsigned)-1 >> 2) + 1;
16
17
11.6k
    *have = 0;
18
15.8k
    do {
19
15.8k
        get = len - *have;
20
15.8k
        if (get > max)
21
0
            get = max;
22
15.8k
        ret = read(state->fd, buf + *have, get);
23
15.8k
        if (ret <= 0)
24
4.17k
            break;
25
11.6k
        *have += (unsigned)ret;
26
11.6k
    } while (*have < len);
27
11.6k
    if (ret < 0) {
28
0
        gz_error(state, Z_ERRNO, zstrerror());
29
0
        return -1;
30
0
    }
31
11.6k
    if (ret == 0)
32
4.17k
        state->eof = 1;
33
11.6k
    return 0;
34
11.6k
}
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
15.1k
local int gz_avail(gz_statep state) {
44
15.1k
    unsigned got;
45
15.1k
    z_streamp strm = &(state->strm);
46
47
15.1k
    if (state->err != Z_OK && state->err != Z_BUF_ERROR)
48
0
        return -1;
49
15.1k
    if (state->eof == 0) {
50
11.6k
        if (strm->avail_in) {       /* copy what's there to the start */
51
21
            unsigned char *p = state->in;
52
21
            unsigned const char *q = strm->next_in;
53
21
            unsigned n = strm->avail_in;
54
21
            do {
55
21
                *p++ = *q++;
56
21
            } while (--n);
57
21
        }
58
11.6k
        if (gz_load(state, state->in + strm->avail_in,
59
11.6k
                    state->size - strm->avail_in, &got) == -1)
60
0
            return -1;
61
11.6k
        strm->avail_in += got;
62
11.6k
        strm->next_in = state->in;
63
11.6k
    }
64
15.1k
    return 0;
65
15.1k
}
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
195k
local int gz_look(gz_statep state) {
77
195k
    z_streamp strm = &(state->strm);
78
79
    /* allocate read buffers and inflate memory */
80
195k
    if (state->size == 0) {
81
        /* allocate buffers */
82
4.20k
        state->in = (unsigned char *)malloc(state->want);
83
4.20k
        state->out = (unsigned char *)malloc(state->want << 1);
84
4.20k
        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.20k
        state->size = state->want;
91
92
        /* allocate inflate memory */
93
4.20k
        state->strm.zalloc = Z_NULL;
94
4.20k
        state->strm.zfree = Z_NULL;
95
4.20k
        state->strm.opaque = Z_NULL;
96
4.20k
        state->strm.avail_in = 0;
97
4.20k
        state->strm.next_in = Z_NULL;
98
4.20k
        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.20k
    }
106
107
    /* get at least the magic bytes in the input buffer */
108
195k
    if (strm->avail_in < 2) {
109
4.30k
        if (gz_avail(state) == -1)
110
0
            return -1;
111
4.30k
        if (strm->avail_in == 0)
112
1
            return 0;
113
4.30k
    }
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
195k
    if (strm->avail_in > 1 &&
123
195k
            strm->next_in[0] == 31 && strm->next_in[1] == 139) {
124
195k
        inflateReset(strm);
125
195k
        state->how = GZIP;
126
195k
        state->direct = 0;
127
195k
        return 0;
128
195k
    }
129
130
    /* no gzip header -- if we were decoding gzip before, then this is trailing
131
       garbage.  Ignore the trailing garbage and finish. */
132
82
    if (state->direct == 0) {
133
82
        strm->avail_in = 0;
134
82
        state->eof = 1;
135
82
        state->x.have = 0;
136
82
        return 0;
137
82
    }
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
82
}
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
202k
local int gz_decomp(gz_statep state) {
157
202k
    int ret = Z_OK;
158
202k
    unsigned had;
159
202k
    z_streamp strm = &(state->strm);
160
161
    /* fill output buffer up to end of deflate stream */
162
202k
    had = strm->avail_out;
163
213k
    do {
164
        /* get more input for inflate() */
165
213k
        if (strm->avail_in == 0 && gz_avail(state) == -1)
166
0
            return -1;
167
213k
        if (strm->avail_in == 0) {
168
3.49k
            gz_error(state, Z_BUF_ERROR, "unexpected end of file");
169
3.49k
            break;
170
3.49k
        }
171
172
        /* decompress and handle errors */
173
209k
        ret = inflate(strm, Z_NO_FLUSH);
174
209k
        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
209k
        if (ret == Z_MEM_ERROR) {
180
0
            gz_error(state, Z_MEM_ERROR, "out of memory");
181
0
            return -1;
182
0
        }
183
209k
        if (ret == Z_DATA_ERROR) {              /* deflate stream invalid */
184
599
            gz_error(state, Z_DATA_ERROR,
185
599
                     strm->msg == NULL ? "compressed data error" : strm->msg);
186
599
            return -1;
187
599
        }
188
209k
    } while (strm->avail_out && ret != Z_STREAM_END);
189
190
    /* update available output */
191
201k
    state->x.have = had - strm->avail_out;
192
201k
    state->x.next = strm->next_out - state->x.have;
193
194
    /* if the gzip stream completed successfully, look for another */
195
201k
    if (ret == Z_STREAM_END)
196
190k
        state->how = LOOK;
197
198
    /* good decompression */
199
201k
    return 0;
200
202k
}
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
8.87k
local int gz_fetch(gz_statep state) {
209
8.87k
    z_streamp strm = &(state->strm);
210
211
386k
    do {
212
386k
        switch(state->how) {
213
190k
        case LOOK:      /* -> LOOK, COPY (only if never GZIP), or GZIP */
214
190k
            if (gz_look(state) == -1)
215
0
                return -1;
216
190k
            if (state->how == LOOK)
217
83
                return 0;
218
190k
            break;
219
190k
        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
195k
        case GZIP:      /* -> GZIP or LOOK (if end of gzip stream) */
226
195k
            strm->avail_out = state->size << 1;
227
195k
            strm->next_out = state->out;
228
195k
            if (gz_decomp(state) == -1)
229
534
                return -1;
230
386k
        }
231
386k
    } while (state->x.have == 0 && (!state->eof || strm->avail_in));
232
8.26k
    return 0;
233
8.87k
}
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
22.4k
local z_size_t gz_read(gz_statep state, voidp buf, z_size_t len) {
269
22.4k
    z_size_t got;
270
22.4k
    unsigned n;
271
272
    /* if len is zero, avoid unnecessary operations */
273
22.4k
    if (len == 0)
274
0
        return 0;
275
276
    /* process a skip request */
277
22.4k
    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
22.4k
    got = 0;
285
38.4k
    do {
286
        /* set n to the maximum amount of len that fits in an unsigned int */
287
38.4k
        n = (unsigned)-1;
288
38.4k
        if (n > len)
289
38.4k
            n = (unsigned)len;
290
291
        /* first just try copying data from the output buffer */
292
38.4k
        if (state->x.have) {
293
15.7k
            if (state->x.have < n)
294
6.25k
                n = state->x.have;
295
15.7k
            memcpy(buf, state->x.next, n);
296
15.7k
            state->x.next += n;
297
15.7k
            state->x.have -= n;
298
15.7k
        }
299
300
        /* output buffer empty -- return if we're at the end of the input */
301
22.6k
        else if (state->eof && state->strm.avail_in == 0) {
302
6.51k
            state->past = 1;        /* tried to read past end */
303
6.51k
            break;
304
6.51k
        }
305
306
        /* need output data -- for small len or new stream load up our output
307
           buffer */
308
16.1k
        else if (state->how == LOOK || n < (state->size << 1)) {
309
            /* get more output, looking for header if required */
310
8.87k
            if (gz_fetch(state) == -1)
311
534
                return 0;
312
8.34k
            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
8.87k
        }
316
317
        /* large len -- read directly into user buffer */
318
7.27k
        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.27k
        else {  /* state->how == GZIP */
325
7.27k
            state->strm.avail_out = n;
326
7.27k
            state->strm.next_out = (unsigned char *)buf;
327
7.27k
            if (gz_decomp(state) == -1)
328
65
                return 0;
329
7.21k
            n = state->x.have;
330
7.21k
            state->x.have = 0;
331
7.21k
        }
332
333
        /* update progress */
334
22.9k
        len -= n;
335
22.9k
        buf = (char *)buf + n;
336
22.9k
        got += n;
337
22.9k
        state->x.pos += n;
338
31.3k
    } while (len);
339
340
    /* return number of bytes read into user buffer */
341
21.8k
    return got;
342
22.4k
}
343
344
/* -- see zlib.h -- */
345
22.4k
int ZEXPORT gzread(gzFile file, voidp buf, unsigned len) {
346
22.4k
    gz_statep state;
347
348
    /* get internal structure */
349
22.4k
    if (file == NULL)
350
0
        return -1;
351
22.4k
    state = (gz_statep)file;
352
353
    /* check that we're reading and that there's no (serious) error */
354
22.4k
    if (state->mode != GZ_READ ||
355
22.4k
            (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
22.4k
    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
22.4k
    len = (unsigned)gz_read(state, buf, len);
367
368
    /* check for an error */
369
22.4k
    if (len == 0 && state->err != Z_OK && state->err != Z_BUF_ERROR)
370
599
        return -1;
371
372
    /* return the number of bytes read (this is assured to fit in an int) */
373
21.8k
    return (int)len;
374
22.4k
}
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.20k
int ZEXPORT gzdirect(gzFile file) {
560
4.20k
    gz_statep state;
561
562
    /* get internal structure */
563
4.20k
    if (file == NULL)
564
0
        return 0;
565
4.20k
    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.20k
    if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0)
570
4.20k
        (void)gz_look(state);
571
572
    /* return 1 if transparent, 0 if processing a gzip stream */
573
4.20k
    return state->direct;
574
4.20k
}
575
576
/* -- see zlib.h -- */
577
4.20k
int ZEXPORT gzclose_r(gzFile file) {
578
4.20k
    int ret, err;
579
4.20k
    gz_statep state;
580
581
    /* get internal structure */
582
4.20k
    if (file == NULL)
583
0
        return Z_STREAM_ERROR;
584
4.20k
    state = (gz_statep)file;
585
586
    /* check that we're reading */
587
4.20k
    if (state->mode != GZ_READ)
588
0
        return Z_STREAM_ERROR;
589
590
    /* free memory and close file */
591
4.20k
    if (state->size) {
592
4.20k
        inflateEnd(&(state->strm));
593
4.20k
        free(state->out);
594
4.20k
        free(state->in);
595
4.20k
    }
596
4.20k
    err = state->err == Z_BUF_ERROR ? Z_BUF_ERROR : Z_OK;
597
4.20k
    gz_error(state, Z_OK, NULL);
598
4.20k
    free(state->path);
599
4.20k
    ret = close(state->fd);
600
4.20k
    free(state);
601
4.20k
    return ret ? Z_ERRNO : err;
602
4.20k
}