Coverage Report

Created: 2026-02-14 07:07

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