Coverage Report

Created: 2026-05-28 06:48

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.1k
static int gz_read_init(gz_state *state) {
22
    /* Allocate gz buffers */
23
11.1k
    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.1k
    int ret = PREFIX(inflateInit2)(&(state->strm), MAX_WBITS + 16);
30
11.1k
    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.1k
    return 0;
40
11.1k
}
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.3k
static int gz_load(gz_state *state, unsigned char *buf, unsigned len, unsigned *have) {
47
13.3k
    ssize_t ret;
48
49
13.3k
    *have = 0;
50
24.5k
    do {
51
24.5k
        ret = read(state->fd, buf + *have, len - *have);
52
24.5k
        if (ret <= 0)
53
11.1k
            break;
54
13.3k
        *have += (unsigned)ret;
55
13.3k
    } while (*have < len);
56
13.3k
    if (ret < 0) {
57
0
        PREFIX(gz_error)(state, Z_ERRNO, zstrerror());
58
0
        return -1;
59
0
    }
60
13.3k
    if (ret == 0)
61
11.1k
        state->eof = 1;
62
13.3k
    return 0;
63
13.3k
}
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.3k
static int gz_avail(gz_state *state) {
73
13.3k
    unsigned got;
74
13.3k
    PREFIX3(stream) *strm = &(state->strm);
75
76
13.3k
    if (state->err != Z_OK && state->err != Z_BUF_ERROR)
77
0
        return -1;
78
13.3k
    if (state->eof == 0) {
79
13.3k
        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.3k
        if (gz_load(state, state->in + strm->avail_in, state->size - strm->avail_in, &got) == -1)
88
0
            return -1;
89
13.3k
        strm->avail_in += got;
90
13.3k
        strm->next_in = state->in;
91
13.3k
    }
92
13.3k
    return 0;
93
13.3k
}
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.1k
static int gz_look(gz_state *state) {
105
11.1k
    PREFIX3(stream) *strm = &(state->strm);
106
107
    /* allocate memory if this is the first time through */
108
11.1k
    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.1k
    if (strm->avail_in < 2) {
113
11.1k
        if (gz_avail(state) == -1)
114
0
            return -1;
115
11.1k
        if (strm->avail_in == 0)
116
8
            return 0;
117
11.1k
    }
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.1k
    if (strm->avail_in > 1 &&
127
11.1k
            strm->next_in[0] == 31 && strm->next_in[1] == 139) {
128
11.1k
        PREFIX(inflateReset)(strm);
129
11.1k
        state->how = GZIP;
130
11.1k
        state->direct = 0;
131
11.1k
        return 0;
132
11.1k
    }
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.2k
static int gz_decomp(gz_state *state) {
161
12.2k
    int ret = Z_OK;
162
12.2k
    unsigned had;
163
12.2k
    PREFIX3(stream) *strm = &(state->strm);
164
165
    /* fill output buffer up to end of deflate stream */
166
12.2k
    had = strm->avail_out;
167
14.4k
    do {
168
        /* get more input for inflate() */
169
14.4k
        if (strm->avail_in == 0 && gz_avail(state) == -1)
170
0
            return -1;
171
14.4k
        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.4k
        ret = PREFIX(inflate)(strm, Z_NO_FLUSH);
178
14.4k
        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.4k
        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.4k
        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.4k
    } while (strm->avail_out && ret != Z_STREAM_END);
191
192
    /* update available output */
193
12.2k
    state->x.have = had - strm->avail_out;
194
12.2k
    state->x.next = strm->next_out - state->x.have;
195
196
    /* if the gzip stream completed successfully, look for another */
197
12.2k
    if (ret == Z_STREAM_END)
198
11.1k
        state->how = LOOK;
199
200
    /* good decompression */
201
12.2k
    return 0;
202
12.2k
}
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.2k
static int gz_fetch(gz_state *state) {
211
12.2k
    PREFIX3(stream) *strm = &(state->strm);
212
12.2k
    Assert(state->x.have == 0, "Invalid state->x.have");
213
214
23.3k
    do {
215
23.3k
        switch (state->how) {
216
11.1k
        case LOOK:      /* -> LOOK, COPY (only if never GZIP), or GZIP */
217
11.1k
            if (gz_look(state) == -1)
218
0
                return -1;
219
11.1k
            if (state->how == LOOK)
220
8
                return 0;
221
11.1k
            break;
222
11.1k
        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.2k
        case GZIP:      /* -> GZIP or LOOK (if end of gzip stream) */
229
12.2k
            strm->avail_out = state->size << 1;
230
12.2k
            strm->next_out = state->out;
231
12.2k
            if (gz_decomp(state) == -1)
232
0
                return -1;
233
12.2k
            continue;
234
12.2k
        default:    // Can't happen
235
0
            Z_UNREACHABLE();
236
0
#if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 202311L
237
0
            return -1;
238
23.3k
#endif
239
23.3k
        }
240
23.3k
    } while (state->x.have == 0 && (!state->eof || strm->avail_in));
241
12.2k
    return 0;
242
12.2k
}
243
244
/* Skip len uncompressed bytes of output.  Return -1 on error, 0 on success. */
245
0
static int gz_skip(gz_state *state, z_off64_t len) {
246
0
    unsigned n;
247
248
    /* skip over len bytes or reach end-of-file, whichever comes first */
249
0
    while (len)
250
        /* skip over whatever is in output buffer */
251
0
        if (state->x.have) {
252
0
            n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > len ?
253
0
                (unsigned)len : state->x.have;
254
0
            state->x.have -= n;
255
0
            state->x.next += n;
256
0
            state->x.pos += n;
257
0
            len -= n;
258
0
        } else if (state->eof && state->strm.avail_in == 0) {
259
            /* output buffer empty -- return if we're at the end of the input */
260
0
            break;
261
0
        } else {
262
            /* need more data to skip -- load up output buffer */
263
            /* get more output, looking for header if required */
264
0
            if (gz_fetch(state) == -1)
265
0
                return -1;
266
0
        }
267
0
    return 0;
268
0
}
269
270
/* Read len bytes into buf from file, or less than len up to the end of the
271
   input.  Return the number of bytes read.  If zero is returned, either the
272
   end of file was reached, or there was an error.  state->err must be
273
   consulted in that case to determine which. */
274
31.7k
static size_t gz_read(gz_state *state, void *buf, size_t len) {
275
31.7k
    size_t got;
276
31.7k
    unsigned n;
277
278
    /* if len is zero, avoid unnecessary operations */
279
31.7k
    if (len == 0)
280
0
        return 0;
281
282
    /* process a skip request */
283
31.7k
    if (state->seek) {
284
0
        state->seek = 0;
285
0
        if (gz_skip(state, state->skip) == -1)
286
0
            return 0;
287
0
    }
288
289
    /* get len bytes to buf, or less than len if at the end */
290
31.7k
    got = 0;
291
56.0k
    do {
292
        /* set n to the maximum amount of len that fits in an unsigned int */
293
56.0k
        n = (unsigned)-1;
294
56.0k
        if (n > len)
295
56.0k
            n = (unsigned)len;
296
297
        /* first just try copying data from the output buffer */
298
56.0k
        if (state->x.have) {
299
21.5k
            if (state->x.have < n)
300
12.0k
                n = state->x.have;
301
21.5k
            memcpy(buf, state->x.next, n);
302
21.5k
            state->x.next += n;
303
21.5k
            state->x.have -= n;
304
21.5k
        }
305
306
        /* output buffer empty -- return if we're at the end of the input */
307
34.5k
        else if (state->eof && state->strm.avail_in == 0) {
308
22.2k
            state->past = 1;        /* tried to read past end */
309
22.2k
            break;
310
22.2k
        }
311
312
        /* need output data -- for small len or new stream load up our output
313
           buffer */
314
12.2k
        else if (state->how == LOOK || n < (state->size << 1)) {
315
            /* get more output, looking for header if required */
316
12.2k
            if (gz_fetch(state) == -1)
317
0
                return 0;
318
12.2k
            continue;       /* no progress yet -- go back to copy above */
319
            /* the copy above assures that we will leave with space in the
320
               output buffer, allowing at least one gzungetc() to succeed */
321
12.2k
        }
322
323
        /* large len -- read directly into user buffer */
324
0
        else if (state->how == COPY) {      /* read directly */
325
0
            if (gz_load(state, (unsigned char *)buf, n, &n) == -1)
326
0
                return 0;
327
0
        }
328
329
        /* large len -- decompress directly into user buffer */
330
0
        else {  /* state->how == GZIP */
331
0
            state->strm.avail_out = n;
332
0
            state->strm.next_out = (unsigned char *)buf;
333
0
            if (gz_decomp(state) == -1)
334
0
                return 0;
335
0
            n = state->x.have;
336
0
            state->x.have = 0;
337
0
        }
338
339
        /* update progress */
340
21.5k
        len -= n;
341
21.5k
        buf = (char *)buf + n;
342
21.5k
        got += n;
343
21.5k
        state->x.pos += n;
344
33.7k
    } while (len);
345
346
    /* return number of bytes read into user buffer */
347
31.7k
    return got;
348
31.7k
}
349
350
/* -- see zlib.h -- */
351
31.7k
z_int32_t Z_EXPORT PREFIX(gzread)(gzFile file, void *buf, z_uint32_t len) {
352
31.7k
    gz_state *state;
353
354
    /* get internal structure */
355
31.7k
    if (file == NULL)
356
0
        return -1;
357
31.7k
    state = (gz_state *)file;
358
359
    /* check that we're reading and that there's no (serious) error */
360
31.7k
    if (state->mode != GZ_READ ||
361
31.7k
            (state->err != Z_OK && state->err != Z_BUF_ERROR))
362
0
        return -1;
363
364
    /* since an int is returned, make sure len fits in one, otherwise return
365
       with an error (this avoids a flaw in the interface) */
366
31.7k
    if ((z_int32_t)len < 0) {
367
0
        PREFIX(gz_error)(state, Z_STREAM_ERROR, "request does not fit in an int");
368
0
        return -1;
369
0
    }
370
371
    /* read len or fewer bytes to buf */
372
31.7k
    len = (unsigned)gz_read(state, buf, len);
373
374
    /* check for an error */
375
31.7k
    if (len == 0 && state->err != Z_OK && state->err != Z_BUF_ERROR)
376
0
        return -1;
377
378
    /* return the number of bytes read (this is assured to fit in an int) */
379
31.7k
    return (z_int32_t)len;
380
31.7k
}
381
382
/* -- see zlib.h -- */
383
0
size_t Z_EXPORT PREFIX(gzfread)(void *buf, size_t size, size_t nitems, gzFile file) {
384
0
    size_t len;
385
0
    gz_state *state;
386
387
    /* Exit early if size is zero, also prevents potential division by zero */
388
0
    if (size == 0)
389
0
        return 0;
390
391
    /* get internal structure */
392
0
    if (file == NULL)
393
0
        return 0;
394
0
    state = (gz_state *)file;
395
396
    /* check that we're reading and that there's no (serious) error */
397
0
    if (state->mode != GZ_READ ||
398
0
            (state->err != Z_OK && state->err != Z_BUF_ERROR))
399
0
        return 0;
400
401
    /* compute bytes to read -- error on overflow */
402
0
    if (size && SIZE_MAX / size < nitems) {
403
0
        PREFIX(gz_error)(state, Z_STREAM_ERROR, "request does not fit in a size_t");
404
0
        return 0;
405
0
    }
406
0
    len = nitems * size;
407
408
    /* read len or fewer bytes to buf, return the number of full items read */
409
0
    return len ? gz_read(state, buf, len) / size : 0;
410
0
}
411
412
/* -- see zlib.h -- */
413
0
z_int32_t Z_EXPORT PREFIX(gzgetc)(gzFile file) {
414
0
    unsigned char buf[1];
415
0
    gz_state *state;
416
417
    /* get internal structure */
418
0
    if (file == NULL)
419
0
        return -1;
420
0
    state = (gz_state *)file;
421
422
    /* check that we're reading and that there's no (serious) error */
423
0
    if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR))
424
0
        return -1;
425
426
    /* try output buffer (no need to check for skip request) */
427
0
    if (state->x.have) {
428
0
        state->x.have--;
429
0
        state->x.pos++;
430
0
        return *(state->x.next)++;
431
0
    }
432
433
    /* nothing there -- try gz_read() */
434
0
    return gz_read(state, buf, 1) < 1 ? -1 : buf[0];
435
0
}
436
437
#ifdef ZLIB_COMPAT
438
int Z_EXPORT PREFIX(gzgetc_)(gzFile file) {
439
    return PREFIX(gzgetc)(file);
440
}
441
#endif
442
443
/* -- see zlib.h -- */
444
0
z_int32_t Z_EXPORT PREFIX(gzungetc)(z_int32_t c, gzFile file) {
445
0
    gz_state *state;
446
447
    /* get internal structure */
448
0
    if (file == NULL)
449
0
        return -1;
450
0
    state = (gz_state *)file;
451
452
    /* in case this was just opened, set up the input buffer */
453
0
    if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0)
454
0
        (void)gz_look(state);
455
456
    /* check that we're reading and that there's no (serious) error */
457
0
    if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR))
458
0
        return -1;
459
460
    /* process a skip request */
461
0
    if (state->seek) {
462
0
        state->seek = 0;
463
0
        if (gz_skip(state, state->skip) == -1)
464
0
            return -1;
465
0
    }
466
467
    /* can't push EOF */
468
0
    if (c < 0)
469
0
        return -1;
470
471
    /* if output buffer empty, put byte at end (allows more pushing) */
472
0
    if (state->x.have == 0) {
473
0
        state->x.have = 1;
474
0
        state->x.next = state->out + (state->size << 1) - 1;
475
0
        state->x.next[0] = (unsigned char)c;
476
0
        state->x.pos--;
477
0
        state->past = 0;
478
0
        return c;
479
0
    }
480
481
    /* if no room, give up (must have already done a gzungetc()) */
482
0
    if (state->x.have == (state->size << 1)) {
483
0
        PREFIX(gz_error)(state, Z_DATA_ERROR, "out of room to push characters");
484
0
        return -1;
485
0
    }
486
487
    /* slide output data if needed and insert byte before existing data */
488
0
    if (state->x.next == state->out) {
489
0
        unsigned char *src = state->out + state->x.have;
490
0
        unsigned char *dest = state->out + (state->size << 1);
491
0
        while (src > state->out)
492
0
            *--dest = *--src;
493
0
        state->x.next = dest;
494
0
    }
495
0
    state->x.have++;
496
0
    state->x.next--;
497
0
    state->x.next[0] = (unsigned char)c;
498
0
    state->x.pos--;
499
0
    state->past = 0;
500
0
    return c;
501
0
}
502
503
/* -- see zlib.h -- */
504
0
char * Z_EXPORT PREFIX(gzgets)(gzFile file, char *buf, z_int32_t len) {
505
0
    unsigned left, n;
506
0
    char *str;
507
0
    unsigned char *eol;
508
0
    gz_state *state;
509
510
    /* check parameters and get internal structure */
511
0
    if (file == NULL || buf == NULL || len < 1)
512
0
        return NULL;
513
0
    state = (gz_state *)file;
514
515
    /* check that we're reading and that there's no (serious) error */
516
0
    if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR))
517
0
        return NULL;
518
519
    /* process a skip request */
520
0
    if (state->seek) {
521
0
        state->seek = 0;
522
0
        if (gz_skip(state, state->skip) == -1)
523
0
            return NULL;
524
0
    }
525
526
    /* copy output bytes up to new line or len - 1, whichever comes first --
527
       append a terminating zero to the string (we don't check for a zero in
528
       the contents, let the user worry about that) */
529
0
    str = buf;
530
0
    left = (unsigned)len - 1;
531
0
    if (left) {
532
0
        do {
533
            /* assure that something is in the output buffer */
534
0
            if (state->x.have == 0 && gz_fetch(state) == -1)
535
0
                return NULL;                /* error */
536
0
            if (state->x.have == 0) {       /* end of file */
537
0
                state->past = 1;            /* read past end */
538
0
                break;                      /* return what we have */
539
0
            }
540
541
            /* look for end-of-line in current output buffer */
542
0
            n = MIN(state->x.have, left);
543
0
            eol = (unsigned char *)memchr(state->x.next, '\n', n);
544
0
            if (eol != NULL)
545
0
                n = (unsigned)(eol - state->x.next) + 1;
546
547
            /* copy through end-of-line, or remainder if not found */
548
0
            memcpy(buf, state->x.next, n);
549
0
            state->x.have -= n;
550
0
            state->x.next += n;
551
0
            state->x.pos += n;
552
0
            left -= n;
553
0
            buf += n;
554
0
        } while (left && eol == NULL);
555
0
    }
556
557
    /* return terminated string, or if nothing, end of file */
558
0
    if (buf == str)
559
0
        return NULL;
560
0
    buf[0] = 0;
561
0
    return str;
562
0
}
563
564
/* -- see zlib.h -- */
565
0
z_int32_t Z_EXPORT PREFIX(gzdirect)(gzFile file) {
566
0
    gz_state *state;
567
568
    /* get internal structure */
569
0
    if (file == NULL)
570
0
        return 0;
571
572
0
    state = (gz_state *)file;
573
574
    /* if the state is not known, but we can find out, then do so (this is
575
       mainly for right after a gzopen() or gzdopen()) */
576
0
    if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0)
577
0
        (void)gz_look(state);
578
579
    /* return 1 if transparent, 0 if processing a gzip stream */
580
0
    return state->direct;
581
0
}
582
583
/* -- see zlib.h -- */
584
11.1k
z_int32_t Z_EXPORT PREFIX(gzclose_r)(gzFile file) {
585
11.1k
    int ret, err;
586
11.1k
    gz_state *state;
587
588
    /* get internal structure */
589
11.1k
    if (file == NULL)
590
0
        return Z_STREAM_ERROR;
591
592
11.1k
    state = (gz_state *)file;
593
594
    /* check that we're reading */
595
11.1k
    if (state->mode != GZ_READ)
596
0
        return Z_STREAM_ERROR;
597
598
    /* free memory and close file */
599
11.1k
    if (state->size) {
600
11.1k
        PREFIX(inflateEnd)(&(state->strm));
601
11.1k
        gz_buffer_free(state);
602
11.1k
    }
603
11.1k
    err = state->err == Z_BUF_ERROR ? Z_BUF_ERROR : Z_OK;
604
11.1k
    PREFIX(gz_error)(state, Z_OK, NULL);
605
11.1k
    free(state->path);
606
11.1k
    ret = close(state->fd);
607
11.1k
    zng_free(state);
608
11.1k
    return ret ? Z_ERRNO : err;
609
11.1k
}