Coverage Report

Created: 2025-12-31 07:53

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/zlib/gzwrite.c
Line
Count
Source
1
/* gzwrite.c -- zlib functions for writing gzip files
2
 * Copyright (C) 2004-2025 Mark Adler
3
 * For conditions of distribution and use, see copyright notice in zlib.h
4
 */
5
6
#include "gzguts.h"
7
8
/* Initialize state for writing a gzip file.  Mark initialization by setting
9
   state->size to non-zero.  Return -1 on a memory allocation failure, or 0 on
10
   success. */
11
0
local int gz_init(gz_statep state) {
12
0
    int ret;
13
0
    z_streamp strm = &(state->strm);
14
15
    /* allocate input buffer (double size for gzprintf) */
16
0
    state->in = (unsigned char *)malloc(state->want << 1);
17
0
    if (state->in == NULL) {
18
0
        gz_error(state, Z_MEM_ERROR, "out of memory");
19
0
        return -1;
20
0
    }
21
22
    /* only need output buffer and deflate state if compressing */
23
0
    if (!state->direct) {
24
        /* allocate output buffer */
25
0
        state->out = (unsigned char *)malloc(state->want);
26
0
        if (state->out == NULL) {
27
0
            free(state->in);
28
0
            gz_error(state, Z_MEM_ERROR, "out of memory");
29
0
            return -1;
30
0
        }
31
32
        /* allocate deflate memory, set up for gzip compression */
33
0
        strm->zalloc = Z_NULL;
34
0
        strm->zfree = Z_NULL;
35
0
        strm->opaque = Z_NULL;
36
0
        ret = deflateInit2(strm, state->level, Z_DEFLATED,
37
0
                           MAX_WBITS + 16, DEF_MEM_LEVEL, state->strategy);
38
0
        if (ret != Z_OK) {
39
0
            free(state->out);
40
0
            free(state->in);
41
0
            gz_error(state, Z_MEM_ERROR, "out of memory");
42
0
            return -1;
43
0
        }
44
0
        strm->next_in = NULL;
45
0
    }
46
47
    /* mark state as initialized */
48
0
    state->size = state->want;
49
50
    /* initialize write buffer if compressing */
51
0
    if (!state->direct) {
52
0
        strm->avail_out = state->size;
53
0
        strm->next_out = state->out;
54
0
        state->x.next = strm->next_out;
55
0
    }
56
0
    return 0;
57
0
}
58
59
/* Compress whatever is at avail_in and next_in and write to the output file.
60
   Return -1 if there is an error writing to the output file or if gz_init()
61
   fails to allocate memory, otherwise 0.  flush is assumed to be a valid
62
   deflate() flush value.  If flush is Z_FINISH, then the deflate() state is
63
   reset to start a new gzip stream.  If gz->direct is true, then simply write
64
   to the output file without compressing, and ignore flush. */
65
0
local int gz_comp(gz_statep state, int flush) {
66
0
    int ret, writ;
67
0
    unsigned have, put, max = ((unsigned)-1 >> 2) + 1;
68
0
    z_streamp strm = &(state->strm);
69
70
    /* allocate memory if this is the first time through */
71
0
    if (state->size == 0 && gz_init(state) == -1)
72
0
        return -1;
73
74
    /* write directly if requested */
75
0
    if (state->direct) {
76
0
        while (strm->avail_in) {
77
0
            errno = 0;
78
0
            state->again = 0;
79
0
            put = strm->avail_in > max ? max : strm->avail_in;
80
0
            writ = write(state->fd, strm->next_in, put);
81
0
            if (writ < 0) {
82
0
                if (errno == EAGAIN || errno == EWOULDBLOCK)
83
0
                    state->again = 1;
84
0
                gz_error(state, Z_ERRNO, zstrerror());
85
0
                return -1;
86
0
            }
87
0
            strm->avail_in -= (unsigned)writ;
88
0
            strm->next_in += writ;
89
0
        }
90
0
        return 0;
91
0
    }
92
93
    /* check for a pending reset */
94
0
    if (state->reset) {
95
        /* don't start a new gzip member unless there is data to write and
96
           we're not flushing */
97
0
        if (strm->avail_in == 0 && flush == Z_NO_FLUSH)
98
0
            return 0;
99
0
        deflateReset(strm);
100
0
        state->reset = 0;
101
0
    }
102
103
    /* run deflate() on provided input until it produces no more output */
104
0
    ret = Z_OK;
105
0
    do {
106
        /* write out current buffer contents if full, or if flushing, but if
107
           doing Z_FINISH then don't write until we get to Z_STREAM_END */
108
0
        if (strm->avail_out == 0 || (flush != Z_NO_FLUSH &&
109
0
            (flush != Z_FINISH || ret == Z_STREAM_END))) {
110
0
            while (strm->next_out > state->x.next) {
111
0
                errno = 0;
112
0
                state->again = 0;
113
0
                put = strm->next_out - state->x.next > (int)max ? max :
114
0
                      (unsigned)(strm->next_out - state->x.next);
115
0
                writ = write(state->fd, state->x.next, put);
116
0
                if (writ < 0) {
117
0
                    if (errno == EAGAIN || errno == EWOULDBLOCK)
118
0
                        state->again = 1;
119
0
                    gz_error(state, Z_ERRNO, zstrerror());
120
0
                    return -1;
121
0
                }
122
0
                state->x.next += writ;
123
0
            }
124
0
            if (strm->avail_out == 0) {
125
0
                strm->avail_out = state->size;
126
0
                strm->next_out = state->out;
127
0
                state->x.next = state->out;
128
0
            }
129
0
        }
130
131
        /* compress */
132
0
        have = strm->avail_out;
133
0
        ret = deflate(strm, flush);
134
0
        if (ret == Z_STREAM_ERROR) {
135
0
            gz_error(state, Z_STREAM_ERROR,
136
0
                      "internal error: deflate stream corrupt");
137
0
            return -1;
138
0
        }
139
0
        have -= strm->avail_out;
140
0
    } while (have);
141
142
    /* if that completed a deflate stream, allow another to start */
143
0
    if (flush == Z_FINISH)
144
0
        state->reset = 1;
145
146
    /* all done, no errors */
147
0
    return 0;
148
0
}
149
150
/* Compress state->skip (> 0) zeros to output.  Return -1 on a write error or
151
   memory allocation failure by gz_comp(), or 0 on success. state->skip is
152
   updated with the number of successfully written zeros, in case there is a
153
   stall on a non-blocking write destination. */
154
0
local int gz_zero(gz_statep state) {
155
0
    int first, ret;
156
0
    unsigned n;
157
0
    z_streamp strm = &(state->strm);
158
159
    /* consume whatever's left in the input buffer */
160
0
    if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
161
0
        return -1;
162
163
    /* compress state->skip zeros */
164
0
    first = 1;
165
0
    do {
166
0
        n = GT_OFF(state->size) || (z_off64_t)state->size > state->skip ?
167
0
            (unsigned)state->skip : state->size;
168
0
        if (first) {
169
0
            memset(state->in, 0, n);
170
0
            first = 0;
171
0
        }
172
0
        strm->avail_in = n;
173
0
        strm->next_in = state->in;
174
0
        ret = gz_comp(state, Z_NO_FLUSH);
175
0
        n -= strm->avail_in;
176
0
        state->x.pos += n;
177
0
        state->skip -= n;
178
0
        if (ret == -1)
179
0
            return -1;
180
0
    } while (state->skip);
181
0
    return 0;
182
0
}
183
184
/* Write len bytes from buf to file.  Return the number of bytes written.  If
185
   the returned value is less than len, then there was an error. If the error
186
   was a non-blocking stall, then the number of bytes consumed is returned.
187
   For any other error, 0 is returned. */
188
0
local z_size_t gz_write(gz_statep state, voidpc buf, z_size_t len) {
189
0
    z_size_t put = len;
190
0
    int ret;
191
192
    /* if len is zero, avoid unnecessary operations */
193
0
    if (len == 0)
194
0
        return 0;
195
196
    /* allocate memory if this is the first time through */
197
0
    if (state->size == 0 && gz_init(state) == -1)
198
0
        return 0;
199
200
    /* check for seek request */
201
0
    if (state->skip && gz_zero(state) == -1)
202
0
        return 0;
203
204
    /* for small len, copy to input buffer, otherwise compress directly */
205
0
    if (len < state->size) {
206
        /* copy to input buffer, compress when full */
207
0
        for (;;) {
208
0
            unsigned have, copy;
209
210
0
            if (state->strm.avail_in == 0)
211
0
                state->strm.next_in = state->in;
212
0
            have = (unsigned)((state->strm.next_in + state->strm.avail_in) -
213
0
                              state->in);
214
0
            copy = state->size - have;
215
0
            if (copy > len)
216
0
                copy = (unsigned)len;
217
0
            memcpy(state->in + have, buf, copy);
218
0
            state->strm.avail_in += copy;
219
0
            state->x.pos += copy;
220
0
            buf = (const char *)buf + copy;
221
0
            len -= copy;
222
0
            if (len == 0)
223
0
                break;
224
0
            if (gz_comp(state, Z_NO_FLUSH) == -1)
225
0
                return state->again ? put - len : 0;
226
0
        }
227
0
    }
228
0
    else {
229
        /* consume whatever's left in the input buffer */
230
0
        if (state->strm.avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
231
0
            return 0;
232
233
        /* directly compress user buffer to file */
234
0
        state->strm.next_in = (z_const Bytef *)buf;
235
0
        do {
236
0
            unsigned n = (unsigned)-1;
237
238
0
            if (n > len)
239
0
                n = (unsigned)len;
240
0
            state->strm.avail_in = n;
241
0
            ret = gz_comp(state, Z_NO_FLUSH);
242
0
            n -= state->strm.avail_in;
243
0
            state->x.pos += n;
244
0
            len -= n;
245
0
            if (ret == -1)
246
0
                return state->again ? put - len : 0;
247
0
        } while (len);
248
0
    }
249
250
    /* input was all buffered or compressed */
251
0
    return put;
252
0
}
253
254
/* -- see zlib.h -- */
255
0
int ZEXPORT gzwrite(gzFile file, voidpc buf, unsigned len) {
256
0
    gz_statep state;
257
258
    /* get internal structure */
259
0
    if (file == NULL)
260
0
        return 0;
261
0
    state = (gz_statep)file;
262
263
    /* check that we're writing and that there's no (serious) error */
264
0
    if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again))
265
0
        return 0;
266
0
    gz_error(state, Z_OK, NULL);
267
268
    /* since an int is returned, make sure len fits in one, otherwise return
269
       with an error (this avoids a flaw in the interface) */
270
0
    if ((int)len < 0) {
271
0
        gz_error(state, Z_DATA_ERROR, "requested length does not fit in int");
272
0
        return 0;
273
0
    }
274
275
    /* write len bytes from buf (the return value will fit in an int) */
276
0
    return (int)gz_write(state, buf, len);
277
0
}
278
279
/* -- see zlib.h -- */
280
z_size_t ZEXPORT gzfwrite(voidpc buf, z_size_t size, z_size_t nitems,
281
0
                          gzFile file) {
282
0
    z_size_t len;
283
0
    gz_statep state;
284
285
    /* get internal structure */
286
0
    if (file == NULL)
287
0
        return 0;
288
0
    state = (gz_statep)file;
289
290
    /* check that we're writing and that there's no (serious) error */
291
0
    if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again))
292
0
        return 0;
293
0
    gz_error(state, Z_OK, NULL);
294
295
    /* compute bytes to read -- error on overflow */
296
0
    len = nitems * size;
297
0
    if (size && len / size != nitems) {
298
0
        gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t");
299
0
        return 0;
300
0
    }
301
302
    /* write len bytes to buf, return the number of full items written */
303
0
    return len ? gz_write(state, buf, len) / size : 0;
304
0
}
305
306
/* -- see zlib.h -- */
307
0
int ZEXPORT gzputc(gzFile file, int c) {
308
0
    unsigned have;
309
0
    unsigned char buf[1];
310
0
    gz_statep state;
311
0
    z_streamp strm;
312
313
    /* get internal structure */
314
0
    if (file == NULL)
315
0
        return -1;
316
0
    state = (gz_statep)file;
317
0
    strm = &(state->strm);
318
319
    /* check that we're writing and that there's no (serious) error */
320
0
    if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again))
321
0
        return -1;
322
0
    gz_error(state, Z_OK, NULL);
323
324
    /* check for seek request */
325
0
    if (state->skip && gz_zero(state) == -1)
326
0
        return -1;
327
328
    /* try writing to input buffer for speed (state->size == 0 if buffer not
329
       initialized) */
330
0
    if (state->size) {
331
0
        if (strm->avail_in == 0)
332
0
            strm->next_in = state->in;
333
0
        have = (unsigned)((strm->next_in + strm->avail_in) - state->in);
334
0
        if (have < state->size) {
335
0
            state->in[have] = (unsigned char)c;
336
0
            strm->avail_in++;
337
0
            state->x.pos++;
338
0
            return c & 0xff;
339
0
        }
340
0
    }
341
342
    /* no room in buffer or not initialized, use gz_write() */
343
0
    buf[0] = (unsigned char)c;
344
0
    if (gz_write(state, buf, 1) != 1)
345
0
        return -1;
346
0
    return c & 0xff;
347
0
}
348
349
/* -- see zlib.h -- */
350
0
int ZEXPORT gzputs(gzFile file, const char *s) {
351
0
    z_size_t len, put;
352
0
    gz_statep state;
353
354
    /* get internal structure */
355
0
    if (file == NULL)
356
0
        return -1;
357
0
    state = (gz_statep)file;
358
359
    /* check that we're writing and that there's no (serious) error */
360
0
    if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again))
361
0
        return -1;
362
0
    gz_error(state, Z_OK, NULL);
363
364
    /* write string */
365
0
    len = strlen(s);
366
0
    if ((int)len < 0 || (unsigned)len != len) {
367
0
        gz_error(state, Z_STREAM_ERROR, "string length does not fit in int");
368
0
        return -1;
369
0
    }
370
0
    put = gz_write(state, s, len);
371
0
    return len && put == 0 ? -1 : (int)put;
372
0
}
373
374
/* If the second half of the input buffer is occupied, write out the contents.
375
   If there is any input remaining due to a non-blocking stall on write, move
376
   it to the start of the buffer. Return true if this did not open up the
377
   second half of the buffer.  state->err should be checked after this to
378
   handle a gz_comp() error. */
379
0
local int gz_vacate(gz_statep state) {
380
0
    z_streamp strm;
381
382
0
    strm = &(state->strm);
383
0
    if (strm->next_in + strm->avail_in <= state->in + state->size)
384
0
        return 0;
385
0
    (void)gz_comp(state, Z_NO_FLUSH);
386
0
    if (strm->avail_in == 0) {
387
0
        strm->next_in = state->in;
388
0
        return 0;
389
0
    }
390
0
    memmove(state->in, strm->next_in, strm->avail_in);
391
0
    strm->next_in = state->in;
392
0
    return strm->avail_in > state->size;
393
0
}
394
395
#if defined(STDC) || defined(Z_HAVE_STDARG_H)
396
#include <stdarg.h>
397
398
/* -- see zlib.h -- */
399
0
int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) {
400
0
    int len, ret;
401
0
    char *next;
402
0
    gz_statep state;
403
0
    z_streamp strm;
404
405
    /* get internal structure */
406
0
    if (file == NULL)
407
0
        return Z_STREAM_ERROR;
408
0
    state = (gz_statep)file;
409
0
    strm = &(state->strm);
410
411
    /* check that we're writing and that there's no (serious) error */
412
0
    if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again))
413
0
        return Z_STREAM_ERROR;
414
0
    gz_error(state, Z_OK, NULL);
415
416
    /* make sure we have some buffer space */
417
0
    if (state->size == 0 && gz_init(state) == -1)
418
0
        return state->err;
419
420
    /* check for seek request */
421
0
    if (state->skip && gz_zero(state) == -1)
422
0
        return state->err;
423
424
    /* do the printf() into the input buffer, put length in len -- the input
425
       buffer is double-sized just for this function, so there should be
426
       state->size bytes available after the current contents */
427
0
    ret = gz_vacate(state);
428
0
    if (state->err) {
429
0
        if (ret && state->again) {
430
            /* There was a non-blocking stall on write, resulting in the part
431
               of the second half of the output buffer being occupied.  Return
432
               a Z_BUF_ERROR to let the application know that this gzprintf()
433
               needs to be retried. */
434
0
            gz_error(state, Z_BUF_ERROR, "stalled write on gzprintf");
435
0
        }
436
0
        if (!state->again)
437
0
            return state->err;
438
0
    }
439
0
    if (strm->avail_in == 0)
440
0
        strm->next_in = state->in;
441
0
    next = (char *)(state->in + (strm->next_in - state->in) + strm->avail_in);
442
0
    next[state->size - 1] = 0;
443
#ifdef NO_vsnprintf
444
#  ifdef HAS_vsprintf_void
445
    (void)vsprintf(next, format, va);
446
    for (len = 0; len < state->size; len++)
447
        if (next[len] == 0) break;
448
#  else
449
    len = vsprintf(next, format, va);
450
#  endif
451
#else
452
#  ifdef HAS_vsnprintf_void
453
    (void)vsnprintf(next, state->size, format, va);
454
    len = strlen(next);
455
#  else
456
0
    len = vsnprintf(next, state->size, format, va);
457
0
#  endif
458
0
#endif
459
460
    /* check that printf() results fit in buffer */
461
0
    if (len == 0 || (unsigned)len >= state->size || next[state->size - 1] != 0)
462
0
        return 0;
463
464
    /* update buffer and position */
465
0
    strm->avail_in += (unsigned)len;
466
0
    state->x.pos += len;
467
468
    /* write out buffer if more than half is occupied */
469
0
    ret = gz_vacate(state);
470
0
    if (state->err && !state->again)
471
0
        return state->err;
472
0
    return len;
473
0
}
474
475
0
int ZEXPORTVA gzprintf(gzFile file, const char *format, ...) {
476
0
    va_list va;
477
0
    int ret;
478
479
0
    va_start(va, format);
480
0
    ret = gzvprintf(file, format, va);
481
0
    va_end(va);
482
0
    return ret;
483
0
}
484
485
#else /* !STDC && !Z_HAVE_STDARG_H */
486
487
/* -- see zlib.h -- */
488
int ZEXPORTVA gzprintf(gzFile file, const char *format, int a1, int a2, int a3,
489
                       int a4, int a5, int a6, int a7, int a8, int a9, int a10,
490
                       int a11, int a12, int a13, int a14, int a15, int a16,
491
                       int a17, int a18, int a19, int a20) {
492
    unsigned len, left;
493
    char *next;
494
    gz_statep state;
495
    z_streamp strm;
496
497
    /* get internal structure */
498
    if (file == NULL)
499
        return Z_STREAM_ERROR;
500
    state = (gz_statep)file;
501
    strm = &(state->strm);
502
503
    /* check that can really pass pointer in ints */
504
    if (sizeof(int) != sizeof(void *))
505
        return Z_STREAM_ERROR;
506
507
    /* check that we're writing and that there's no (serious) error */
508
    if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again))
509
        return Z_STREAM_ERROR;
510
    gz_error(state, Z_OK, NULL);
511
512
    /* make sure we have some buffer space */
513
    if (state->size == 0 && gz_init(state) == -1)
514
        return state->error;
515
516
    /* check for seek request */
517
    if (state->skip && gz_zero(state) == -1)
518
        return state->error;
519
520
    /* do the printf() into the input buffer, put length in len -- the input
521
       buffer is double-sized just for this function, so there is guaranteed to
522
       be state->size bytes available after the current contents */
523
    ret = gz_vacate(state);
524
    if (state->err) {
525
        if (ret && state->again) {
526
            /* There was a non-blocking stall on write, resulting in the part
527
               of the second half of the output buffer being occupied.  Return
528
               a Z_BUF_ERROR to let the application know that this gzprintf()
529
               needs to be retried. */
530
            gz_error(state, Z_BUF_ERROR, "stalled write on gzprintf");
531
        }
532
        if (!state->again)
533
            return state->err;
534
    }
535
    if (strm->avail_in == 0)
536
        strm->next_in = state->in;
537
    next = (char *)(strm->next_in + strm->avail_in);
538
    next[state->size - 1] = 0;
539
#ifdef NO_snprintf
540
#  ifdef HAS_sprintf_void
541
    sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12,
542
            a13, a14, a15, a16, a17, a18, a19, a20);
543
    for (len = 0; len < size; len++)
544
        if (next[len] == 0)
545
            break;
546
#  else
547
    len = sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11,
548
                  a12, a13, a14, a15, a16, a17, a18, a19, a20);
549
#  endif
550
#else
551
#  ifdef HAS_snprintf_void
552
    snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8, a9,
553
             a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
554
    len = strlen(next);
555
#  else
556
    len = snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8,
557
                   a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
558
#  endif
559
#endif
560
561
    /* check that printf() results fit in buffer */
562
    if (len == 0 || len >= state->size || next[state->size - 1] != 0)
563
        return 0;
564
565
    /* update buffer and position, compress first half if past that */
566
    strm->avail_in += len;
567
    state->x.pos += len;
568
569
    /* write out buffer if more than half is occupied */
570
    ret = gz_vacate(state);
571
    if (state->err && !state->again)
572
        return state->err;
573
    return (int)len;
574
}
575
576
#endif
577
578
/* -- see zlib.h -- */
579
0
int ZEXPORT gzflush(gzFile file, int flush) {
580
0
    gz_statep state;
581
582
    /* get internal structure */
583
0
    if (file == NULL)
584
0
        return Z_STREAM_ERROR;
585
0
    state = (gz_statep)file;
586
587
    /* check that we're writing and that there's no (serious) error */
588
0
    if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again))
589
0
        return Z_STREAM_ERROR;
590
0
    gz_error(state, Z_OK, NULL);
591
592
    /* check flush parameter */
593
0
    if (flush < 0 || flush > Z_FINISH)
594
0
        return Z_STREAM_ERROR;
595
596
    /* check for seek request */
597
0
    if (state->skip && gz_zero(state) == -1)
598
0
        return state->err;
599
600
    /* compress remaining data with requested flush */
601
0
    (void)gz_comp(state, flush);
602
0
    return state->err;
603
0
}
604
605
/* -- see zlib.h -- */
606
0
int ZEXPORT gzsetparams(gzFile file, int level, int strategy) {
607
0
    gz_statep state;
608
0
    z_streamp strm;
609
610
    /* get internal structure */
611
0
    if (file == NULL)
612
0
        return Z_STREAM_ERROR;
613
0
    state = (gz_statep)file;
614
0
    strm = &(state->strm);
615
616
    /* check that we're compressing and that there's no (serious) error */
617
0
    if (state->mode != GZ_WRITE || (state->err != Z_OK && !state->again) ||
618
0
            state->direct)
619
0
        return Z_STREAM_ERROR;
620
0
    gz_error(state, Z_OK, NULL);
621
622
    /* if no change is requested, then do nothing */
623
0
    if (level == state->level && strategy == state->strategy)
624
0
        return Z_OK;
625
626
    /* check for seek request */
627
0
    if (state->skip && gz_zero(state) == -1)
628
0
        return state->err;
629
630
    /* change compression parameters for subsequent input */
631
0
    if (state->size) {
632
        /* flush previous input with previous parameters before changing */
633
0
        if (strm->avail_in && gz_comp(state, Z_BLOCK) == -1)
634
0
            return state->err;
635
0
        deflateParams(strm, level, strategy);
636
0
    }
637
0
    state->level = level;
638
0
    state->strategy = strategy;
639
0
    return Z_OK;
640
0
}
641
642
/* -- see zlib.h -- */
643
0
int ZEXPORT gzclose_w(gzFile file) {
644
0
    int ret = Z_OK;
645
0
    gz_statep state;
646
647
    /* get internal structure */
648
0
    if (file == NULL)
649
0
        return Z_STREAM_ERROR;
650
0
    state = (gz_statep)file;
651
652
    /* check that we're writing */
653
0
    if (state->mode != GZ_WRITE)
654
0
        return Z_STREAM_ERROR;
655
656
    /* check for seek request */
657
0
    if (state->skip && gz_zero(state) == -1)
658
0
        ret = state->err;
659
660
    /* flush, free memory, and close file */
661
0
    if (gz_comp(state, Z_FINISH) == -1)
662
0
        ret = state->err;
663
0
    if (state->size) {
664
0
        if (!state->direct) {
665
0
            (void)deflateEnd(&(state->strm));
666
0
            free(state->out);
667
0
        }
668
0
        free(state->in);
669
0
    }
670
0
    gz_error(state, Z_OK, NULL);
671
0
    free(state->path);
672
0
    if (close(state->fd) == -1)
673
0
        ret = Z_ERRNO;
674
0
    free(state);
675
0
    return ret;
676
0
}