Based on patch from Denis Ovsienko via
[obnox/wireshark/wip.git] / wiretap / file_wrappers.c
1 /* file_wrappers.c
2  *
3  * $Id$
4  *
5  * Wiretap Library
6  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  */
22
23 /* file_access interface based heavily on zlib gzread.c and gzlib.c from zlib
24  * Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler
25  * under licence:
26  *
27  *  This software is provided 'as-is', without any express or implied
28  *  warranty.  In no event will the authors be held liable for any damages
29  *  arising from the use of this software.
30  *
31  *  Permission is granted to anyone to use this software for any purpose,
32  *  including commercial applications, and to alter it and redistribute it
33  *  freely, subject to the following restrictions:
34  *
35  *  1. The origin of this software must not be misrepresented; you must not
36  *     claim that you wrote the original software. If you use this software
37  *     in a product, an acknowledgment in the product documentation would be
38  *     appreciated but is not required.
39  *  2. Altered source versions must be plainly marked as such, and must not be
40  *     misrepresented as being the original software.
41  *  3. This notice may not be removed or altered from any source distribution.
42 */
43
44 #ifdef HAVE_CONFIG_H
45 #include "config.h"
46 #endif
47
48 #ifdef HAVE_UNISTD_H
49 #include <unistd.h>
50 #endif /* HAVE_UNISTD_H */
51
52 #include <errno.h>
53 #include <stdio.h>
54 #ifdef HAVE_FCNTL_H
55 #include <fcntl.h>
56 #endif /* HAVE_FCNTL_H */
57 #include <string.h>
58 #include "wtap-int.h"
59 #include "file_wrappers.h"
60 #include <wsutil/file_util.h>
61
62 #ifdef HAVE_LIBZ
63 #include <zlib.h>
64 #endif /* HAVE_LIBZ */
65
66 /*
67  * See RFC 1952 for a description of the gzip file format.
68  *
69  * Some other compressed file formats we might want to support:
70  *
71  *      XZ format: http://tukaani.org/xz/
72  *
73  *      Bzip2 format: http://bzip.org/
74  */
75
76 /* #define GZBUFSIZE 8192 */
77 #define GZBUFSIZE 4096
78
79 struct wtap_reader {
80         int fd;                 /* file descriptor */
81         gint64 raw_pos;         /* current position in file (just to not call lseek()) */
82         gint64 pos;             /* current position in uncompressed data */
83         unsigned size;          /* buffer size */
84         unsigned char *in;      /* input buffer */
85         unsigned char *out;     /* output buffer (double-sized when reading) */
86         unsigned char *next;    /* next output data to deliver or write */
87
88         unsigned have;          /* amount of output data unused at next */
89         int eof;                /* true if end of input file reached */
90         gint64 start;           /* where the gzip data started, for rewinding */
91         gint64 raw;             /* where the raw data started, for seeking */
92         int compression;        /* 0: ?, 1: uncompressed, 2: zlib */
93         /* seek request */
94         gint64 skip;            /* amount to skip (already rewound if backwards) */
95         int seek;               /* true if seek request pending */
96         /* error information */
97         int err;                /* error code */
98         const char *err_info;   /* additional error information string for some errors */
99
100         unsigned int  avail_in;  /* number of bytes available at next_in */
101         unsigned char *next_in;  /* next input byte */
102 #ifdef HAVE_LIBZ
103         /* zlib inflate stream */
104         z_stream strm;          /* stream structure in-place (not a pointer) */
105         int dont_check_crc;     /* 1 if we aren't supposed to check the CRC */
106 #endif
107         /* fast seeking */
108         GPtrArray *fast_seek;
109         void *fast_seek_cur;
110 };
111
112 /* values for gz_state compression */
113 #define UNKNOWN         0       /* look for a gzip header */
114 #define UNCOMPRESSED    1       /* copy input directly */
115 #ifdef HAVE_LIBZ
116 #define ZLIB            2       /* decompress a zlib stream */
117 #define GZIP_AFTER_HEADER 3
118 #endif
119
120 static int      /* gz_load */
121 raw_read(FILE_T state, unsigned char *buf, unsigned int count, unsigned *have)
122 {
123         int ret;
124
125         *have = 0;
126         do {
127                 ret = read(state->fd, buf + *have, count - *have);
128                 if (ret <= 0)
129                         break;
130                 *have += ret;
131                 state->raw_pos += ret;
132         } while (*have < count);
133         if (ret < 0) {
134                 state->err = errno;
135                 state->err_info = NULL;
136                 return -1;
137         }
138         if (ret == 0)
139                 state->eof = 1;
140         return 0;
141 }
142
143 static int /* gz_avail */
144 fill_in_buffer(FILE_T state)
145 {
146         if (state->err)
147                 return -1;
148         if (state->eof == 0) {
149                 if (raw_read(state, state->in, state->size, (unsigned *)&(state->avail_in)) == -1)
150                         return -1;
151                 state->next_in = state->in;
152         }
153         return 0;
154 }
155
156 #define ZLIB_WINSIZE 32768
157
158 struct fast_seek_point {
159         gint64 out;     /* corresponding offset in uncompressed data */
160         gint64 in;              /* offset in input file of first full byte */
161
162         int compression;
163         union {
164                 struct {
165 #ifdef HAVE_INFLATEPRIME
166                         int bits;               /* number of bits (1-7) from byte at in - 1, or 0 */
167 #endif
168                         unsigned char window[ZLIB_WINSIZE];     /* preceding 32K of uncompressed data */
169
170                         /* be gentle with Z_STREAM_END, 8 bytes more... Another solution would be to comment checks out */
171                         guint32 adler;
172                         guint32 total_out;
173                 } zlib;
174         } data;
175 };
176
177 struct zlib_cur_seek_point {
178         unsigned char window[ZLIB_WINSIZE];     /* preceding 32K of uncompressed data */
179         unsigned int pos;
180         unsigned int have;
181 };
182
183 #define SPAN G_GINT64_CONSTANT(1048576)
184 static struct fast_seek_point *
185 fast_seek_find(FILE_T file, gint64 pos)
186 {
187         struct fast_seek_point *smallest = NULL;
188         struct fast_seek_point *item;
189         guint low, i, max;
190
191         if (!file->fast_seek)
192                 return NULL;
193
194         for (low = 0, max = file->fast_seek->len; low < max; ) {
195                 i = (low + max) / 2;
196                 item = file->fast_seek->pdata[i];
197
198                 if (pos < item->out)
199                         max = i;
200                 else if (pos > item->out) {
201                         smallest = item;
202                         low = i + 1;
203                 } else {
204                         return item;
205                 }
206         }
207         return smallest;
208 }
209
210 static void
211 fast_seek_header(FILE_T file, gint64 in_pos, gint64 out_pos, int compression)
212 {
213         struct fast_seek_point *item = NULL;
214
215         if (file->fast_seek->len != 0)
216                 item = file->fast_seek->pdata[file->fast_seek->len - 1];
217
218         if (!item || item->out < out_pos) {
219                 struct fast_seek_point *val = g_malloc(sizeof(struct fast_seek_point));
220                 val->in = in_pos;
221                 val->out = out_pos;
222                 val->compression = compression;
223
224                 g_ptr_array_add(file->fast_seek, val);
225         }
226 }
227
228 static void
229 fast_seek_reset(FILE_T state _U_)
230 {
231 #ifdef HAVE_LIBZ
232         if (state->compression == ZLIB && state->fast_seek_cur) {
233                 struct zlib_cur_seek_point *cur = (struct zlib_cur_seek_point *) state->fast_seek_cur;
234
235                 cur->have = 0;
236         }
237 #endif
238 }
239
240 #ifdef HAVE_LIBZ
241
242 /* Get next byte from input, or -1 if end or error.
243  *
244  * Note:
245  *
246  *      1) errors from raw_read(), and thus from fill_in_buffer(), are
247  *      "sticky", and fill_in_buffer() won't do any reading if there's
248  *      an error;
249  *
250  *      2) GZ_GETC() returns -1 on an EOF;
251  *
252  * so it's safe to make multiple GZ_GETC() calls and only check the
253  * last one for an error. */
254 #define GZ_GETC() ((state->avail_in == 0 && fill_in_buffer(state) == -1) ? -1 : \
255                 (state->avail_in == 0 ? -1 : \
256                  (state->avail_in--, *(state->next_in)++)))
257
258 /* Get a one-byte integer and return 0 on success and the value in *ret.
259    Otherwise -1 is returned, state->err is set, and *ret is not modified. */
260 static int
261 gz_next1(FILE_T state, guint8 *ret)
262 {
263         int ch;
264
265         ch = GZ_GETC();
266         if (ch == -1) {
267                 if (state->err == 0) {
268                         /* EOF */
269                         state->err = WTAP_ERR_SHORT_READ;
270                         state->err_info = NULL;
271                 }
272                 return -1;
273         }
274         *ret = ch;
275         return 0;
276 }
277
278 /* Get a two-byte little-endian integer and return 0 on success and the value
279    in *ret.  Otherwise -1 is returned, state->err is set, and *ret is not
280    modified. */
281 static int
282 gz_next2(FILE_T state, guint16 *ret)
283 {
284         guint16 val;
285         int ch;
286
287         val = GZ_GETC();
288         ch = GZ_GETC();
289         if (ch == -1) {
290                 if (state->err == 0) {
291                         /* EOF */
292                         state->err = WTAP_ERR_SHORT_READ;
293                         state->err_info = NULL;
294                 }
295                 return -1;
296         }
297         val += (guint16)ch << 8;
298         *ret = val;
299         return 0;
300 }
301
302 /* Get a four-byte little-endian integer and return 0 on success and the value
303    in *ret.  Otherwise -1 is returned, state->err is set, and *ret is not
304    modified. */
305 static int
306 gz_next4(FILE_T state, guint32 *ret)
307 {
308         guint32 val;
309         int ch;
310
311         val = GZ_GETC();
312         val += (unsigned)GZ_GETC() << 8;
313         val += (guint32)GZ_GETC() << 16;
314         ch = GZ_GETC();
315         if (ch == -1) {
316                 if (state->err == 0) {
317                         /* EOF */
318                         state->err = WTAP_ERR_SHORT_READ;
319                         state->err_info = NULL;
320                 }
321                 return -1;
322         }
323         val += (guint32)ch << 24;
324         *ret = val;
325         return 0;
326 }
327
328 /* Skip the specified number of bytes and return 0 on success.  Otherwise -1
329    is returned. */
330 static int
331 gz_skipn(FILE_T state, size_t n)
332 {
333         while (n != 0) {
334                 if (GZ_GETC() == -1) {
335                         if (state->err == 0) {
336                                 /* EOF */
337                                 state->err = WTAP_ERR_SHORT_READ;
338                                 state->err_info = NULL;
339                         }
340                         return -1;
341                 }
342                 n--;
343         }
344         return 0;
345 }
346
347 /* Skip a null-terminated string and return 0 on success.  Otherwise -1
348    is returned. */
349 static int
350 gz_skipzstr(FILE_T state)
351 {
352         int ch;
353
354         /* It's null-terminated, so scan until we read a byte with
355            the value 0 or get an error. */
356         while ((ch = GZ_GETC()) > 0)
357                 ;
358         if (ch == -1) {
359                 if (state->err == 0) {
360                         /* EOF */
361                         state->err = WTAP_ERR_SHORT_READ;
362                         state->err_info = NULL;
363                 }
364                 return -1;
365         }
366         return 0;
367 }
368
369 static void
370 zlib_fast_seek_add(FILE_T file, struct zlib_cur_seek_point *point, int bits, gint64 in_pos, gint64 out_pos)
371 {
372         /* it's for sure after gzip header, so file->fast_seek->len != 0 */
373         struct fast_seek_point *item = file->fast_seek->pdata[file->fast_seek->len - 1];;
374
375 #ifndef HAVE_INFLATEPRIME
376         if (bits)
377                 return;
378 #endif
379
380         /* Glib has got Balanced Binary Trees (GTree) but I couldn't find a way to do quick search for nearest (and smaller) value to seek (It's what fast_seek_find() do)
381          *      Inserting value in middle of sorted array is expensive, so we want to add only in the end.
382          *      It's not big deal, cause first-read don't usually invoke seeking
383          */
384         if (item->out + SPAN < out_pos) {
385                 struct fast_seek_point *val = g_malloc(sizeof(struct fast_seek_point));
386                 val->in = in_pos;
387                 val->out = out_pos;
388                 val->compression = ZLIB;
389 #ifdef HAVE_INFLATEPRIME
390                 val->data.zlib.bits = bits;
391 #endif
392                 if (point->pos != 0) {
393                         unsigned int left = ZLIB_WINSIZE - point->pos;
394
395                         memcpy(val->data.zlib.window, point->window + point->pos, left);
396                         memcpy(val->data.zlib.window + left, point->window, point->pos);
397                 } else
398                         memcpy(val->data.zlib.window, point->window, ZLIB_WINSIZE);
399
400                 val->data.zlib.adler = file->strm.adler;
401                 val->data.zlib.total_out = file->strm.total_out;
402                 g_ptr_array_add(file->fast_seek, val);
403         }
404 }
405
406 static void /* gz_decomp */
407 zlib_read(FILE_T state, unsigned char *buf, unsigned int count)
408 {
409         int ret = 0;    /* XXX */
410         guint32 crc, len;
411         z_streamp strm = &(state->strm);
412
413         unsigned char *buf2 = buf;
414         unsigned int count2 = count;
415
416         strm->avail_out = count;
417         strm->next_out = buf;
418
419         /* fill output buffer up to end of deflate stream or error */
420         do {
421                 /* get more input for inflate() */
422                 if (state->avail_in == 0 && fill_in_buffer(state) == -1)
423                         break;
424                 if (state->avail_in == 0) {
425                         /* EOF */
426                         state->err = WTAP_ERR_SHORT_READ;
427                         state->err_info = NULL;
428                         break;
429                 }
430
431                 strm->avail_in = state->avail_in;
432                 strm->next_in = state->next_in;
433                 /* decompress and handle errors */
434                 /* ret = inflate(strm, Z_NO_FLUSH); */
435                 ret = inflate(strm, Z_BLOCK);
436                 state->avail_in = strm->avail_in;
437                 state->next_in = strm->next_in;
438                 if (ret == Z_STREAM_ERROR) {
439                         state->err = WTAP_ERR_DECOMPRESS;
440                         state->err_info = strm->msg;
441                         break;
442                 }
443                 if (ret == Z_NEED_DICT) {
444                         state->err = WTAP_ERR_DECOMPRESS;
445                         state->err_info = "preset dictionary needed";
446                         break;
447                 }
448                 if (ret == Z_MEM_ERROR) {
449                         /* This means "not enough memory". */
450                         state->err = ENOMEM;
451                         state->err_info = NULL;
452                         break;
453                 }
454                 if (ret == Z_DATA_ERROR) {              /* deflate stream invalid */
455                         state->err = WTAP_ERR_DECOMPRESS;
456                         state->err_info = strm->msg;
457                         break;
458                 }
459                 /*
460                  * XXX - Z_BUF_ERROR?
461                  */
462
463                 strm->adler = crc32(strm->adler, buf2, count2 - strm->avail_out);
464                 if (state->fast_seek_cur) {
465                         struct zlib_cur_seek_point *cur = (struct zlib_cur_seek_point *) state->fast_seek_cur;
466                         unsigned int ready = count2 - strm->avail_out;
467
468                         if (ready < ZLIB_WINSIZE) {
469                                 unsigned left = ZLIB_WINSIZE - cur->pos;
470
471                                 if (ready >= left) {
472                                         memcpy(cur->window + cur->pos, buf2, left);
473                                         if (ready != left)
474                                                 memcpy(cur->window, buf2 + left, ready - left);
475
476                                         cur->pos = ready - left;
477                                         cur->have += ready;
478                                 } else {
479                                         memcpy(cur->window + cur->pos, buf2, ready);
480                                         cur->pos += ready;
481                                         cur->have += ready;
482                                 }
483
484                                 if (cur->have >= ZLIB_WINSIZE)
485                                         cur->have = ZLIB_WINSIZE;
486
487                         } else {
488                                 memcpy(cur->window, buf2 + (ready - ZLIB_WINSIZE), ZLIB_WINSIZE);
489                                 cur->pos = 0;
490                                 cur->have = ZLIB_WINSIZE;
491                         }
492
493                         if (cur->have >= ZLIB_WINSIZE && ret != Z_STREAM_END && (strm->data_type & 128) && !(strm->data_type & 64))
494                                 zlib_fast_seek_add(state, cur, (strm->data_type & 7), state->raw_pos - strm->avail_in, state->pos + (count - strm->avail_out));
495                 }
496                 buf2 = (buf2 + count2 - strm->avail_out);
497                 count2 = strm->avail_out;
498
499         } while (strm->avail_out && ret != Z_STREAM_END);
500
501         /* update available output and crc check value */
502         state->next = buf;
503         state->have = count - strm->avail_out;
504
505         /* Check gzip trailer if at end of deflate stream.
506            We don't fail immediately here, we just set an error
507            indication, so that we try to process what data we
508            got before the error.  The next attempt to read
509            something past that data will get the error. */
510         if (ret == Z_STREAM_END) {
511                 if (gz_next4(state, &crc) != -1 &&
512                     gz_next4(state, &len) != -1) {
513                         /*
514                          * XXX - compressed Windows Sniffer don't
515                          * all have the same CRC value; is it just
516                          * random crap, or are they running the
517                          * CRC on a different set of data than
518                          * you're supposed to (e.g., not CRCing
519                          * some of the data), or something such
520                          * as that?
521                          */
522                         if (crc != strm->adler && !state->dont_check_crc) {
523                                 state->err = WTAP_ERR_DECOMPRESS;
524                                 state->err_info = "bad CRC";
525                         } else if (len != (strm->total_out & 0xffffffffL)) {
526                                 state->err = WTAP_ERR_DECOMPRESS;
527                                 state->err_info = "length field wrong";
528                         }
529                 }
530                 state->compression = UNKNOWN;      /* ready for next stream, once have is 0 */
531                 g_free(state->fast_seek_cur);
532                 state->fast_seek_cur = NULL;
533         }
534 }
535 #endif
536
537 static int
538 gz_head(FILE_T state)
539 {
540         /* get some data in the input buffer */
541         if (state->avail_in == 0) {
542                 if (fill_in_buffer(state) == -1)
543                         return -1;
544                 if (state->avail_in == 0)
545                         return 0;
546         }
547
548         /* look for the gzip magic header bytes 31 and 139 */
549 #ifdef HAVE_LIBZ
550         if (state->next_in[0] == 31) {
551                 state->avail_in--;
552                 state->next_in++;
553                 if (state->avail_in == 0 && fill_in_buffer(state) == -1)
554                         return -1;
555                 if (state->avail_in && state->next_in[0] == 139) {
556                         guint8 cm;
557                         guint8 flags;
558                         guint16 len;
559                         guint16 hcrc;
560
561                         /* we have a gzip header, woo hoo! */
562                         state->avail_in--;
563                         state->next_in++;
564
565                         /* read rest of header */
566
567                         /* compression method (CM) */
568                         if (gz_next1(state, &cm) == -1)
569                                 return -1;
570                         if (cm != 8) {
571                                 state->err = WTAP_ERR_DECOMPRESS;
572                                 state->err_info = "unknown compression method";
573                                 return -1;
574                         }
575
576                         /* flags (FLG) */
577                         if (gz_next1(state, &flags) == -1)
578                                 return -1;
579                         if (flags & 0xe0) {     /* reserved flag bits */
580                                 state->err = WTAP_ERR_DECOMPRESS;
581                                 state->err_info = "reserved flag bits set";
582                                 return -1;
583                         }
584
585                         /* modification time (MTIME) */
586                         if (gz_skipn(state, 4) == -1)
587                                 return -1;
588
589                         /* extra flags (XFL) */
590                         if (gz_skipn(state, 1) == -1)
591                                 return -1;
592
593                         /* operating system (OS) */
594                         if (gz_skipn(state, 1) == -1)
595                                 return -1;
596
597                         if (flags & 4) {
598                                 /* extra field - get XLEN */
599                                 if (gz_next2(state, &len) == -1)
600                                         return -1;
601
602                                 /* skip the extra field */
603                                 if (gz_skipn(state, len) == -1)
604                                         return -1;
605                         }
606                         if (flags & 8) {
607                                 /* file name */
608                                 if (gz_skipzstr(state) == -1)
609                                         return -1;
610                         }
611                         if (flags & 16) {
612                                 /* comment */
613                                 if (gz_skipzstr(state) == -1)
614                                         return -1;
615                         }
616                         if (flags & 2) {
617                                 /* header crc */
618                                 if (gz_next2(state, &hcrc) == -1)
619                                         return -1;
620                                 /* XXX - check the CRC? */
621                         }
622
623                         /* set up for decompression */
624                         inflateReset(&(state->strm));
625                         state->strm.adler = crc32(0L, Z_NULL, 0);
626                         state->compression = ZLIB;
627
628                         if (state->fast_seek) {
629                                 struct zlib_cur_seek_point *cur = g_malloc(sizeof(struct zlib_cur_seek_point));
630
631                                 cur->pos = cur->have = 0;
632                                 g_free(state->fast_seek_cur);
633                                 state->fast_seek_cur = cur;
634                                 fast_seek_header(state, state->raw_pos - state->avail_in, state->pos, GZIP_AFTER_HEADER);
635                         }
636                         return 0;
637                 }
638                 else {
639                         /* not a gzip file -- save first byte (31) and fall to raw i/o */
640                         state->out[0] = 31;
641                         state->have = 1;
642                 }
643         }
644 #endif
645 #ifdef HAVE_LIBXZ
646         /* { 0xFD, '7', 'z', 'X', 'Z', 0x00 } */
647         /* FD 37 7A 58 5A 00 */
648 #endif
649         if (state->fast_seek)
650                 fast_seek_header(state, state->raw_pos - state->avail_in - state->have, state->pos, UNCOMPRESSED);
651
652         /* doing raw i/o, save start of raw data for seeking, copy any leftover
653            input to output -- this assumes that the output buffer is larger than
654            the input buffer, which also assures space for gzungetc() */
655         state->raw = state->pos;
656         state->next = state->out;
657         if (state->avail_in) {
658                 memcpy(state->next + state->have, state->next_in, state->avail_in);
659                 state->have += state->avail_in;
660                 state->avail_in = 0;
661         }
662         state->compression = UNCOMPRESSED;
663         return 0;
664 }
665
666 static int /* gz_make */
667 fill_out_buffer(FILE_T state)
668 {
669         if (state->compression == UNKNOWN) {           /* look for gzip header */
670                 if (gz_head(state) == -1)
671                         return -1;
672                 if (state->have)                /* got some data from gz_head() */
673                         return 0;
674         }
675         if (state->compression == UNCOMPRESSED) {           /* straight copy */
676                 if (raw_read(state, state->out, state->size /* << 1 */, &(state->have)) == -1)
677                         return -1;
678                 state->next = state->out;
679         }
680 #ifdef HAVE_LIBZ
681         else if (state->compression == ZLIB) {      /* decompress */
682                 zlib_read(state, state->out, state->size << 1);
683         }
684 #endif
685         return 0;
686 }
687
688 static int
689 gz_skip(FILE_T state, gint64 len)
690 {
691         unsigned n;
692
693         /* skip over len bytes or reach end-of-file, whichever comes first */
694         while (len)
695                 if (state->have) {
696                         /* We have stuff in the output buffer; skip over
697                            it. */
698                         n = (gint64)state->have > len ? (unsigned)len : state->have;
699                         state->have -= n;
700                         state->next += n;
701                         state->pos += n;
702                         len -= n;
703                 } else if (state->err) {
704                         /* We have nothing in the output buffer, and
705                            we have an error that may not have been
706                            reported yet; that means we can't generate
707                            any more data into the output buffer, so
708                            return an error indication. */
709                         return -1;
710                 } else if (state->eof && state->avail_in == 0) {
711                         /* We have nothing in the output buffer, and
712                            we're at the end of the input; just return. */
713                         break;
714                 } else {
715                         /* We have nothing in the output buffer, and
716                            we can generate more data; get more output,
717                            looking for header if required. */
718                         if (fill_out_buffer(state) == -1)
719                                 return -1;
720                 }
721         return 0;
722 }
723
724 static void
725 gz_reset(FILE_T state)
726 {
727         state->have = 0;              /* no output data available */
728         state->eof = 0;               /* not at end of file */
729         state->compression = UNKNOWN; /* look for gzip header */
730
731         state->seek = 0;              /* no seek request pending */
732         state->err = 0;               /* clear error */
733         state->err_info = NULL;
734         state->pos = 0;               /* no uncompressed data yet */
735         state->avail_in = 0;          /* no input data yet */
736 }
737
738 FILE_T
739 filed_open(int fd)
740 {
741 #ifdef _STATBUF_ST_BLKSIZE      /* XXX, _STATBUF_ST_BLKSIZE portable? */
742         struct stat st;
743 #endif
744         int want = GZBUFSIZE;
745         FILE_T state;
746
747         if (fd == -1)
748                 return NULL;
749
750         /* allocate FILE_T structure to return */
751         state = g_try_malloc(sizeof *state);
752         if (state == NULL)
753                 return NULL;
754
755         state->fast_seek_cur = NULL;
756         state->fast_seek = NULL;
757
758         /* open the file with the appropriate mode (or just use fd) */
759         state->fd = fd;
760
761         /* save the current position for rewinding (only if reading) */
762         state->start = ws_lseek64(state->fd, 0, SEEK_CUR);
763         if (state->start == -1) state->start = 0;
764         state->raw_pos = state->start;
765
766         /* initialize stream */
767         gz_reset(state);
768
769 #ifdef _STATBUF_ST_BLKSIZE
770         if (fstat(fd, &st) >= 0) {
771                 want = st.st_blksize;
772                 /* XXX, verify result? */
773         }
774 #endif
775
776         /* allocate buffers */
777         state->in = g_try_malloc(want);
778         state->out = g_try_malloc(want << 1);
779         state->size = want;
780         if (state->in == NULL || state->out == NULL) {
781                 g_free(state->out);
782                 g_free(state->in);
783                 g_free(state);
784                 errno = ENOMEM;
785                 return NULL;
786         }
787
788 #ifdef HAVE_LIBZ
789         /* allocate inflate memory */
790         state->strm.zalloc = Z_NULL;
791         state->strm.zfree = Z_NULL;
792         state->strm.opaque = Z_NULL;
793         state->strm.avail_in = 0;
794         state->strm.next_in = Z_NULL;
795         if (inflateInit2(&(state->strm), -15) != Z_OK) {    /* raw inflate */
796                 g_free(state->out);
797                 g_free(state->in);
798                 g_free(state);
799                 errno = ENOMEM;
800                 return NULL;
801         }
802
803         /* for now, assume we should check the crc */
804         state->dont_check_crc = 0;
805 #endif
806         /* return stream */
807         return state;
808 }
809
810 FILE_T
811 file_open(const char *path)
812 {
813         int fd;
814         FILE_T ft;
815 #ifdef HAVE_LIBZ
816         const char *suffixp;
817 #endif
818
819         /* open file and do correct filename conversions.
820
821            XXX - do we need O_LARGEFILE?  On UN*X, if we need to do
822            something special to get large file support, the configure
823            script should have set us up with the appropriate #defines,
824            so we should be getting a large-file-enabled file descriptor
825            here.  Pre-Large File Summit UN*Xes, and possibly even some
826            post-LFS UN*Xes, might require O_LARGEFILE here, though.
827            If so, we should probably handle that in ws_open(). */
828         if ((fd = ws_open(path, O_RDONLY|O_BINARY, 0000)) == -1)
829                 return NULL;
830
831         /* open file handle */
832         ft = filed_open(fd);
833         if (ft == NULL) {
834                 ws_close(fd);
835                 return NULL;
836         }
837
838 #ifdef HAVE_LIBZ
839         /*
840          * If this file's name ends in ".caz", it's probably a compressed
841          * Windows Sniffer file.  The compression is gzip, but they don't
842          * bother filling in the CRC; we set a flag to ignore CRC errors.
843          */
844         suffixp = strrchr(path, '.');
845         if (suffixp != NULL) {
846                 if (g_ascii_strcasecmp(suffixp, ".caz") == 0)
847                         ft->dont_check_crc = 1;
848         }
849 #endif
850
851         return ft;
852 }
853
854 void 
855 file_set_random_access(FILE_T stream, gboolean random _U_, GPtrArray *seek)
856 {
857         stream->fast_seek = seek;
858 }
859
860 gint64
861 file_seek(FILE_T file, gint64 offset, int whence, int *err)
862 {
863         struct fast_seek_point *here;
864         unsigned n;
865
866         /* can only seek from start or relative to current position */
867         if (whence != SEEK_SET && whence != SEEK_CUR) {
868                 g_assert_not_reached();
869 /*
870                 *err = EINVAL;
871                 return -1;
872  */
873         }
874
875         /* normalize offset to a SEEK_CUR specification */
876         if (whence == SEEK_SET)
877                 offset -= file->pos;
878         else if (file->seek)
879                 offset += file->skip;
880         file->seek = 0;
881
882         /* XXX, profile */
883         if ((here = fast_seek_find(file, file->pos + offset)) && (offset < 0 || offset > SPAN || here->compression == UNCOMPRESSED)) {
884                 gint64 off, off2;
885
886 #ifdef HAVE_LIBZ
887                 if (here->compression == ZLIB) {
888 #ifdef HAVE_INFLATEPRIME
889                         off = here->in - (here->data.zlib.bits ? 1 : 0);
890 #else
891                         off = here->in;
892 #endif
893                         off2 = here->out;
894                 } else if (here->compression == GZIP_AFTER_HEADER) {
895                         off = here->in;
896                         off2 = here->out;
897                 } else
898 #endif
899                 {
900                         off2 = (file->pos + offset);
901                         off = here->in + (off2 - here->out);
902                 }
903
904                 if (ws_lseek64(file->fd, off, SEEK_SET) == -1) {
905                         *err = errno;
906                         return -1;
907                 }
908                 fast_seek_reset(file);
909
910                 file->raw_pos = off;
911                 file->have = 0;
912                 file->eof = 0;
913                 file->seek = 0;
914                 file->err = 0;
915                 file->err_info = NULL;
916                 file->avail_in = 0;
917
918 #ifdef HAVE_LIBZ
919                 if (here->compression == ZLIB) {
920                         z_stream *strm = &file->strm;
921
922                         inflateReset(strm);
923                         strm->adler = here->data.zlib.adler;
924                         strm->total_out = here->data.zlib.total_out;
925 #ifdef HAVE_INFLATEPRIME
926                         if (here->data.zlib.bits) {
927                                 FILE_T state = file;
928                                 int ret = GZ_GETC();
929
930                                 if (ret == -1) {
931                                         if (state->err == 0) {
932                                                 /* EOF */
933                                                 *err = WTAP_ERR_SHORT_READ;
934                                         } else
935                                                 *err = state->err;
936                                         return -1;
937                                 }
938                                 (void)inflatePrime(strm, here->data.zlib.bits, ret >> (8 - here->data.zlib.bits));
939                         }
940 #endif
941                         (void)inflateSetDictionary(strm, here->data.zlib.window, ZLIB_WINSIZE);
942                         file->compression = ZLIB;
943                 } else if (here->compression == GZIP_AFTER_HEADER) {
944                         z_stream *strm = &file->strm;
945
946                         inflateReset(strm);
947                         strm->adler = crc32(0L, Z_NULL, 0);
948                         file->compression = ZLIB;
949                 } else
950 #endif
951                         file->compression = here->compression;
952
953                 offset = (file->pos + offset) - off2;
954                 file->pos = off2;
955                 /* g_print("OK! %ld\n", offset); */
956
957                 if (offset) {
958                         file->seek = 1;
959                         file->skip = offset;
960                 }
961                 return file->pos + offset;
962         }
963
964         /* if within raw area while reading, just go there */
965         if (file->compression == UNCOMPRESSED && file->pos + offset >= file->raw) {
966                 if (ws_lseek64(file->fd, offset - file->have, SEEK_CUR) == -1) {
967                         *err = errno;
968                         return -1;
969                 }
970                 file->raw_pos += (offset - file->have);
971                 file->have = 0;
972                 file->eof = 0;
973                 file->seek = 0;
974                 file->err = 0;
975                 file->err_info = NULL;
976                 file->avail_in = 0;
977                 file->pos += offset;
978                 return file->pos;
979         }
980
981         /* calculate skip amount, rewinding if needed for back seek when reading */
982         if (offset < 0) {
983                 offset += file->pos;
984                 if (offset < 0) {                    /* before start of file! */
985                         /* *err = ???; */
986                         return -1;
987                 }
988                 /* rewind, then skip to offset */
989
990                 /* back up and start over */
991                 if (ws_lseek64(file->fd, file->start, SEEK_SET) == -1) {
992                         *err = errno;
993                         return -1;
994                 }
995                 fast_seek_reset(file);
996                 file->raw_pos = file->start;
997                 gz_reset(file);
998         }
999
1000         /* skip what's in output buffer (one less gzgetc() check) */
1001         n = (gint64)file->have > offset ? (unsigned)offset : file->have;
1002         file->have -= n;
1003         file->next += n;
1004         file->pos += n;
1005         offset -= n;
1006
1007         /* request skip (if not zero) */
1008         if (offset) {
1009                 file->seek = 1;
1010                 file->skip = offset;
1011         }
1012         return file->pos + offset;
1013 }
1014
1015 gint64
1016 file_tell(FILE_T stream)
1017 {
1018         /* return position */
1019         return stream->pos + (stream->seek ? stream->skip : 0);
1020 }
1021
1022 gint64
1023 file_tell_raw(FILE_T stream)
1024 {
1025         return stream->raw_pos;
1026 }
1027
1028 int
1029 file_fstat(FILE_T stream, ws_statb64 *statb, int *err)
1030 {
1031         if (ws_fstat64(stream->fd, statb) == -1) {
1032                 if (err != NULL)
1033                         *err = errno;
1034                 return -1;
1035         }
1036         return 0;
1037 }
1038
1039 int 
1040 file_read(void *buf, unsigned int len, FILE_T file)
1041 {
1042         unsigned got, n;
1043
1044         /* if len is zero, avoid unnecessary operations */
1045         if (len == 0)
1046                 return 0;
1047
1048         /* process a skip request */
1049         if (file->seek) {
1050                 file->seek = 0;
1051                 if (gz_skip(file, file->skip) == -1)
1052                         return -1;
1053         }
1054
1055         /* get len bytes to buf, or less than len if at the end */
1056         got = 0;
1057         do {
1058                 if (file->have) {
1059                         /* We have stuff in the output buffer; copy
1060                            what we have. */
1061                         n = file->have > len ? len : file->have;
1062                         memcpy(buf, file->next, n);
1063                         file->next += n;
1064                         file->have -= n;
1065                 } else if (file->err) {
1066                         /* We have nothing in the output buffer, and
1067                            we have an error that may not have been
1068                            reported yet; that means we can't generate
1069                            any more data into the output buffer, so
1070                            return an error indication. */
1071                         return -1;
1072                 } else if (file->eof && file->avail_in == 0) {
1073                         /* We have nothing in the output buffer, and
1074                            we're at the end of the input; just return
1075                            with what we've gotten so far. */
1076                         break;
1077                 } else {
1078                         /* We have nothing in the output buffer, and
1079                            we can generate more data; get more output,
1080                            looking for header if required, and
1081                            keep looping to process the new stuff
1082                            in the output buffer. */
1083                         if (fill_out_buffer(file) == -1)
1084                                 return -1;
1085                         continue;       /* no progress yet -- go back to memcpy() above */
1086                 }
1087                 /* update progress */
1088                 len -= n;
1089                 buf = (char *)buf + n;
1090                 got += n;
1091                 file->pos += n;
1092         } while (len);
1093
1094         return (int)got;
1095 }
1096
1097 int
1098 file_getc(FILE_T file)
1099 {
1100         unsigned char buf[1];
1101         int ret;
1102
1103         /* check that we're reading and that there's no error */
1104         if (file->err)
1105                 return -1;
1106
1107         /* try output buffer (no need to check for skip request) */
1108         if (file->have) {
1109                 file->have--;
1110                 file->pos++;
1111                 return *(file->next)++;
1112         }
1113
1114         ret = file_read(buf, 1, file);
1115         return ret < 1 ? -1 : buf[0];
1116 }
1117
1118 char *
1119 file_gets(char *buf, int len, FILE_T file)
1120 {
1121         unsigned left, n;
1122         char *str;
1123         unsigned char *eol;
1124
1125         /* check parameters */
1126         if (buf == NULL || len < 1)
1127                 return NULL;
1128
1129         /* check that there's no error */
1130         if (file->err)
1131                 return NULL;
1132
1133         /* process a skip request */
1134         if (file->seek) {
1135                 file->seek = 0;
1136                 if (gz_skip(file, file->skip) == -1)
1137                         return NULL;
1138         }
1139
1140         /* copy output bytes up to new line or len - 1, whichever comes first --
1141            append a terminating zero to the string (we don't check for a zero in
1142            the contents, let the user worry about that) */
1143         str = buf;
1144         left = (unsigned)len - 1;
1145         if (left) do {
1146                 /* assure that something is in the output buffer */
1147                 if (file->have == 0) {
1148                         /* We have nothing in the output buffer. */
1149                         if (file->err) {
1150                                 /* We have an error that may not have
1151                                    been reported yet; that means we
1152                                    can't generate any more data into
1153                                    the output buffer, so return an
1154                                    error indication. */
1155                                 return NULL;
1156                         }
1157                         if (fill_out_buffer(file) == -1)
1158                                 return NULL;            /* error */
1159                         if (file->have == 0)  {     /* end of file */
1160                                 if (buf == str)         /* got bupkus */
1161                                         return NULL;
1162                                 break;                  /* got something -- return it */
1163                         }
1164                 }
1165
1166                 /* look for end-of-line in current output buffer */
1167                 n = file->have > left ? left : file->have;
1168                 eol = memchr(file->next, '\n', n);
1169                 if (eol != NULL)
1170                         n = (unsigned)(eol - file->next) + 1;
1171
1172                 /* copy through end-of-line, or remainder if not found */
1173                 memcpy(buf, file->next, n);
1174                 file->have -= n;
1175                 file->next += n;
1176                 file->pos += n;
1177                 left -= n;
1178                 buf += n;
1179         } while (left && eol == NULL);
1180
1181         /* found end-of-line or out of space -- terminate string and return it */
1182         buf[0] = 0;
1183         return str;
1184 }
1185
1186 int 
1187 file_eof(FILE_T file)
1188 {
1189         /* return end-of-file state */
1190         return (file->eof && file->avail_in == 0 && file->have == 0);
1191 }
1192
1193 /*
1194  * Routine to return a Wiretap error code (0 for no error, an errno
1195  * for a file error, or a WTAP_ERR_ code for other errors) for an
1196  * I/O stream.  Also returns an error string for some errors.
1197  */
1198 int
1199 file_error(FILE_T fh, gchar **err_info)
1200 {
1201         if (fh->err != 0) {
1202                 *err_info = (fh->err_info == NULL) ? NULL : g_strdup(fh->err_info);
1203                 return fh->err;
1204         }
1205         return 0;
1206 }
1207
1208 void
1209 file_clearerr(FILE_T stream)
1210 {
1211         /* clear error and end-of-file */
1212         stream->err = 0;
1213         stream->err_info = NULL;
1214         stream->eof = 0;
1215 }
1216
1217 int 
1218 file_close(FILE_T file)
1219 {
1220         int fd = file->fd;
1221
1222         /* free memory and close file */
1223         if (file->size) {
1224 #ifdef HAVE_LIBZ
1225                 inflateEnd(&(file->strm));
1226 #endif
1227                 g_free(file->out);
1228                 g_free(file->in);
1229         }
1230         g_free(file->fast_seek_cur);
1231         file->err = 0;
1232         file->err_info = NULL;
1233         g_free(file);
1234         return ws_close(fd);
1235 }
1236
1237 #ifdef HAVE_LIBZ
1238 /* internal gzip file state data structure for writing */
1239 struct wtap_writer {
1240     int fd;                 /* file descriptor */
1241     gint64 pos;             /* current position in uncompressed data */
1242     unsigned size;          /* buffer size, zero if not allocated yet */
1243     unsigned want;          /* requested buffer size, default is GZBUFSIZE */
1244     unsigned char *in;      /* input buffer */
1245     unsigned char *out;     /* output buffer (double-sized when reading) */
1246     unsigned char *next;    /* next output data to deliver or write */
1247     int level;              /* compression level */
1248     int strategy;           /* compression strategy */
1249     int err;                /* error code */
1250         /* zlib deflate stream */
1251     z_stream strm;          /* stream structure in-place (not a pointer) */
1252 };
1253
1254 GZWFILE_T
1255 gzwfile_open(const char *path)
1256 {
1257     int fd;
1258     GZWFILE_T state;
1259     int save_errno;
1260
1261     fd = ws_open(path, O_BINARY|O_WRONLY|O_CREAT|O_TRUNC, 0666);
1262     if (fd == -1)
1263         return NULL;
1264     state = gzwfile_fdopen(fd);
1265     if (state == NULL) {
1266         save_errno = errno;
1267         close(fd);
1268         errno = save_errno;
1269     }
1270     return state;
1271 }
1272
1273 GZWFILE_T
1274 gzwfile_fdopen(int fd)
1275 {
1276     GZWFILE_T state;
1277
1278     /* allocate wtap_writer structure to return */
1279     state = g_try_malloc(sizeof *state);
1280     if (state == NULL)
1281         return NULL;
1282     state->fd = fd;
1283     state->size = 0;            /* no buffers allocated yet */
1284     state->want = GZBUFSIZE;    /* requested buffer size */
1285
1286     state->level = Z_DEFAULT_COMPRESSION;
1287     state->strategy = Z_DEFAULT_STRATEGY;
1288
1289     /* initialize stream */
1290     state->err = Z_OK;              /* clear error */
1291     state->pos = 0;                 /* no uncompressed data yet */
1292     state->strm.avail_in = 0;       /* no input data yet */
1293
1294     /* return stream */
1295     return state;
1296 }
1297
1298 /* Initialize state for writing a gzip file.  Mark initialization by setting
1299    state->size to non-zero.  Return -1, and set state->err, on failure;
1300    return 0 on success. */
1301 static int
1302 gz_init(GZWFILE_T state)
1303 {
1304     int ret;
1305     z_streamp strm = &(state->strm);
1306
1307     /* allocate input and output buffers */
1308     state->in = g_try_malloc(state->want);
1309     state->out = g_try_malloc(state->want);
1310     if (state->in == NULL || state->out == NULL) {
1311         g_free(state->out);
1312         g_free(state->in);
1313         state->err = ENOMEM;
1314         return -1;
1315     }
1316
1317     /* allocate deflate memory, set up for gzip compression */
1318     strm->zalloc = Z_NULL;
1319     strm->zfree = Z_NULL;
1320     strm->opaque = Z_NULL;
1321     ret = deflateInit2(strm, state->level, Z_DEFLATED,
1322                        15 + 16, 8, state->strategy);
1323     if (ret != Z_OK) {
1324         g_free(state->out);
1325         g_free(state->in);
1326         if (ret == Z_MEM_ERROR) {
1327                 /* This means "not enough memory". */
1328                 state->err = ENOMEM;
1329         } else {
1330                 /* This "shouldn't happen". */
1331                 state->err = WTAP_ERR_INTERNAL;
1332         }
1333         return -1;
1334     }
1335
1336     /* mark state as initialized */
1337     state->size = state->want;
1338
1339     /* initialize write buffer */
1340     strm->avail_out = state->size;
1341     strm->next_out = state->out;
1342     state->next = strm->next_out;
1343     return 0;
1344 }
1345
1346 /* Compress whatever is at avail_in and next_in and write to the output file.
1347    Return -1, and set state->err, if there is an error writing to the output
1348    file; return 0 on success.
1349    flush is assumed to be a valid deflate() flush value.  If flush is Z_FINISH,
1350    then the deflate() state is reset to start a new gzip stream. */
1351 static int
1352 gz_comp(GZWFILE_T state, int flush)
1353 {
1354     int ret, got;
1355     unsigned have;
1356     z_streamp strm = &(state->strm);
1357
1358     /* allocate memory if this is the first time through */
1359     if (state->size == 0 && gz_init(state) == -1)
1360         return -1;
1361
1362     /* run deflate() on provided input until it produces no more output */
1363     ret = Z_OK;
1364     do {
1365         /* write out current buffer contents if full, or if flushing, but if
1366            doing Z_FINISH then don't write until we get to Z_STREAM_END */
1367         if (strm->avail_out == 0 || (flush != Z_NO_FLUSH &&
1368             (flush != Z_FINISH || ret == Z_STREAM_END))) {
1369             have = (unsigned)(strm->next_out - state->next);
1370             if (have) {
1371                 got = write(state->fd, state->next, have);
1372                 if (got < 0) {
1373                     state->err = errno;
1374                     return -1;
1375                 }
1376                 if ((unsigned)got != have) {
1377                     state->err = WTAP_ERR_SHORT_WRITE;
1378                     return -1;
1379                 }
1380             }
1381             if (strm->avail_out == 0) {
1382                 strm->avail_out = state->size;
1383                 strm->next_out = state->out;
1384             }
1385             state->next = strm->next_out;
1386         }
1387
1388         /* compress */
1389         have = strm->avail_out;
1390         ret = deflate(strm, flush);
1391         if (ret == Z_STREAM_ERROR) {
1392             /* This "shouldn't happen". */
1393             state->err = WTAP_ERR_INTERNAL;
1394             return -1;
1395         }
1396         have -= strm->avail_out;
1397     } while (have);
1398
1399     /* if that completed a deflate stream, allow another to start */
1400     if (flush == Z_FINISH)
1401         deflateReset(strm);
1402
1403     /* all done, no errors */
1404     return 0;
1405 }
1406
1407 /* Write out len bytes from buf.  Return 0, and set state->err, on
1408    failure or on an attempt to write 0 bytes (in which case state->err
1409    is Z_OK); return the number of bytes written on success. */
1410 unsigned
1411 gzwfile_write(GZWFILE_T state, const void *buf, unsigned len)
1412 {
1413     unsigned put = len;
1414     unsigned n;
1415     z_streamp strm;
1416
1417     strm = &(state->strm);
1418
1419     /* check that there's no error */
1420     if (state->err != Z_OK)
1421         return 0;
1422
1423     /* if len is zero, avoid unnecessary operations */
1424     if (len == 0)
1425         return 0;
1426
1427     /* allocate memory if this is the first time through */
1428     if (state->size == 0 && gz_init(state) == -1)
1429         return 0;
1430
1431     /* for small len, copy to input buffer, otherwise compress directly */
1432     if (len < state->size) {
1433         /* copy to input buffer, compress when full */
1434         do {
1435             if (strm->avail_in == 0)
1436                 strm->next_in = state->in;
1437             n = state->size - strm->avail_in;
1438             if (n > len)
1439                 n = len;
1440             memcpy(strm->next_in + strm->avail_in, buf, n);
1441             strm->avail_in += n;
1442             state->pos += n;
1443             buf = (char *)buf + n;
1444             len -= n;
1445             if (len && gz_comp(state, Z_NO_FLUSH) == -1)
1446                 return 0;
1447         } while (len);
1448     }
1449     else {
1450         /* consume whatever's left in the input buffer */
1451         if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
1452             return 0;
1453
1454         /* directly compress user buffer to file */
1455         strm->avail_in = len;
1456         strm->next_in = (voidp)buf;
1457         state->pos += len;
1458         if (gz_comp(state, Z_NO_FLUSH) == -1)
1459             return 0;
1460     }
1461
1462     /* input was all buffered or compressed (put will fit in int) */
1463     return (int)put;
1464 }
1465
1466 /* Flush out what we've written so far.  Returns -1, and sets state->err,
1467    on failure; returns 0 on success. */
1468 int
1469 gzwfile_flush(GZWFILE_T state)
1470 {
1471     /* check that there's no error */
1472     if (state->err != Z_OK)
1473         return -1;
1474
1475     /* compress remaining data with Z_SYNC_FLUSH */
1476     gz_comp(state, Z_SYNC_FLUSH);
1477     if (state->err != Z_OK)
1478         return -1;
1479     return 0;
1480 }
1481
1482 /* Flush out all data written, and close the file.  Returns a Wiretap
1483    error on failure; returns 0 on success. */
1484 int
1485 gzwfile_close(GZWFILE_T state)
1486 {
1487     int ret = 0;
1488
1489     /* flush, free memory, and close file */
1490     if (gz_comp(state, Z_FINISH) == -1 && ret == 0)
1491         ret = state->err;
1492     (void)deflateEnd(&(state->strm));
1493     g_free(state->out);
1494     g_free(state->in);
1495     state->err = Z_OK;
1496     if (close(state->fd) == -1 && ret == 0)
1497         ret = errno;
1498     g_free(state);
1499     return ret;
1500 }
1501
1502 int
1503 gzwfile_geterr(GZWFILE_T state)
1504 {
1505     return state->err;
1506 }
1507 #endif