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