From Jakub Zawadzki: for file read progress bars, use the raw offset in
[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                         if (crc != strm->adler && !state->dont_check_crc) {
510                                 state->err = WTAP_ERR_DECOMPRESS;
511                                 state->err_info = "bad CRC";
512                         } else if (len != (strm->total_out & 0xffffffffL)) {
513                                 state->err = WTAP_ERR_DECOMPRESS;
514                                 state->err_info = "length field wrong";
515                         }
516                 }
517                 state->compression = UNKNOWN;      /* ready for next stream, once have is 0 */
518                 g_free(state->fast_seek_cur);
519                 state->fast_seek_cur = NULL;
520         }
521 }
522 #endif
523
524 static int
525 gz_head(FILE_T state)
526 {
527         /* get some data in the input buffer */
528         if (state->avail_in == 0) {
529                 if (fill_in_buffer(state) == -1)
530                         return -1;
531                 if (state->avail_in == 0)
532                         return 0;
533         }
534
535         /* look for the gzip magic header bytes 31 and 139 */
536 #ifdef HAVE_LIBZ
537         if (state->next_in[0] == 31) {
538                 state->avail_in--;
539                 state->next_in++;
540                 if (state->avail_in == 0 && fill_in_buffer(state) == -1)
541                         return -1;
542                 if (state->avail_in && state->next_in[0] == 139) {
543                         guint8 cm;
544                         guint8 flags;
545                         guint16 len;
546                         guint16 hcrc;
547
548                         /* we have a gzip header, woo hoo! */
549                         state->avail_in--;
550                         state->next_in++;
551
552                         /* read rest of header */
553
554                         /* compression method (CM) */
555                         if (gz_next1(state, &cm) == -1)
556                                 return -1;
557                         if (cm != 8) {
558                                 state->err = WTAP_ERR_DECOMPRESS;
559                                 state->err_info = "unknown compression method";
560                                 return -1;
561                         }
562
563                         /* flags (FLG) */
564                         if (gz_next1(state, &flags) == -1)
565                                 return -1;
566                         if (flags & 0xe0) {     /* reserved flag bits */
567                                 state->err = WTAP_ERR_DECOMPRESS;
568                                 state->err_info = "reserved flag bits set";
569                                 return -1;
570                         }
571
572                         /* modification time (MTIME) */
573                         if (gz_skipn(state, 4) == -1)
574                                 return -1;
575
576                         /* extra flags (XFL) */
577                         if (gz_skipn(state, 1) == -1)
578                                 return -1;
579
580                         /* operating system (OS) */
581                         if (gz_skipn(state, 1) == -1)
582                                 return -1;
583
584                         if (flags & 4) {
585                                 /* extra field - get XLEN */
586                                 if (gz_next2(state, &len) == -1)
587                                         return -1;
588
589                                 /* skip the extra field */
590                                 if (gz_skipn(state, len) == -1)
591                                         return -1;
592                         }
593                         if (flags & 8) {
594                                 /* file name */
595                                 if (gz_skipzstr(state) == -1)
596                                         return -1;
597                         }
598                         if (flags & 16) {
599                                 /* comment */
600                                 if (gz_skipzstr(state) == -1)
601                                         return -1;
602                         }
603                         if (flags & 2) {
604                                 /* header crc */
605                                 if (gz_next2(state, &hcrc) == -1)
606                                         return -1;
607                                 /* XXX - check the CRC? */
608                         }
609
610                         /* set up for decompression */
611                         inflateReset(&(state->strm));
612                         state->strm.adler = crc32(0L, Z_NULL, 0);
613                         state->compression = ZLIB;
614
615                         if (state->fast_seek) {
616                                 struct zlib_cur_seek_point *cur = g_malloc(sizeof(struct zlib_cur_seek_point));
617
618                                 cur->pos = cur->have = 0;
619                                 g_free(state->fast_seek_cur);
620                                 state->fast_seek_cur = cur;
621                                 fast_seek_header(state, state->raw_pos - state->avail_in, state->pos, GZIP_AFTER_HEADER);
622                         }
623                         return 0;
624                 }
625                 else {
626                         /* not a gzip file -- save first byte (31) and fall to raw i/o */
627                         state->out[0] = 31;
628                         state->have = 1;
629                 }
630         }
631 #endif
632 #ifdef HAVE_LIBXZ
633         /* { 0xFD, '7', 'z', 'X', 'Z', 0x00 } */
634         /* FD 37 7A 58 5A 00 */
635 #endif
636         if (state->fast_seek)
637                 fast_seek_header(state, state->raw_pos - state->avail_in - state->have, state->pos, UNCOMPRESSED);
638
639         /* doing raw i/o, save start of raw data for seeking, copy any leftover
640            input to output -- this assumes that the output buffer is larger than
641            the input buffer, which also assures space for gzungetc() */
642         state->raw = state->pos;
643         state->next = state->out;
644         if (state->avail_in) {
645                 memcpy(state->next + state->have, state->next_in, state->avail_in);
646                 state->have += state->avail_in;
647                 state->avail_in = 0;
648         }
649         state->compression = UNCOMPRESSED;
650         return 0;
651 }
652
653 static int /* gz_make */
654 fill_out_buffer(FILE_T state)
655 {
656         if (state->compression == UNKNOWN) {           /* look for gzip header */
657                 if (gz_head(state) == -1)
658                         return -1;
659                 if (state->have)                /* got some data from gz_head() */
660                         return 0;
661         }
662         if (state->compression == UNCOMPRESSED) {           /* straight copy */
663                 if (raw_read(state, state->out, state->size /* << 1 */, &(state->have)) == -1)
664                         return -1;
665                 state->next = state->out;
666         }
667 #ifdef HAVE_LIBZ
668         else if (state->compression == ZLIB) {      /* decompress */
669                 zlib_read(state, state->out, state->size << 1);
670         }
671 #endif
672         return 0;
673 }
674
675 static int
676 gz_skip(FILE_T state, gint64 len)
677 {
678         unsigned n;
679
680         /* skip over len bytes or reach end-of-file, whichever comes first */
681         while (len)
682                 if (state->have) {
683                         /* We have stuff in the output buffer; skip over
684                            it. */
685                         n = (gint64)state->have > len ? (unsigned)len : state->have;
686                         state->have -= n;
687                         state->next += n;
688                         state->pos += n;
689                         len -= n;
690                 } else if (state->err) {
691                         /* We have nothing in the output buffer, and
692                            we have an error that may not have been
693                            reported yet; that means we can't generate
694                            any more data into the output buffer, so
695                            return an error indication. */
696                         return -1;
697                 } else if (state->eof && state->avail_in == 0) {
698                         /* We have nothing in the output buffer, and
699                            we're at the end of the input; just return. */
700                         break;
701                 } else {
702                         /* We have nothing in the output buffer, and
703                            we can generate more data; get more output,
704                            looking for header if required. */
705                         if (fill_out_buffer(state) == -1)
706                                 return -1;
707                 }
708         return 0;
709 }
710
711 static void
712 gz_reset(FILE_T state)
713 {
714         state->have = 0;              /* no output data available */
715         state->eof = 0;               /* not at end of file */
716         state->compression = UNKNOWN; /* look for gzip header */
717
718         state->seek = 0;              /* no seek request pending */
719         state->err = 0;               /* clear error */
720         state->err_info = NULL;
721         state->pos = 0;               /* no uncompressed data yet */
722         state->avail_in = 0;          /* no input data yet */
723 }
724
725 FILE_T
726 filed_open(int fd)
727 {
728 #ifdef _STATBUF_ST_BLKSIZE      /* XXX, _STATBUF_ST_BLKSIZE portable? */
729         struct stat st;
730 #endif
731         int want = GZBUFSIZE;
732         FILE_T state;
733
734         if (fd == -1)
735                 return NULL;
736
737         /* allocate FILE_T structure to return */
738         state = g_try_malloc(sizeof *state);
739         if (state == NULL)
740                 return NULL;
741
742         state->fast_seek_cur = NULL;
743         state->fast_seek = NULL;
744
745         /* open the file with the appropriate mode (or just use fd) */
746         state->fd = fd;
747
748         /* save the current position for rewinding (only if reading) */
749         state->start = ws_lseek64(state->fd, 0, SEEK_CUR);
750         if (state->start == -1) state->start = 0;
751         state->raw_pos = state->start;
752
753         /* initialize stream */
754         gz_reset(state);
755
756 #ifdef _STATBUF_ST_BLKSIZE
757         if (fstat(fd, &st) >= 0) {
758                 want = st.st_blksize;
759                 /* XXX, verify result? */
760         }
761 #endif
762
763         /* allocate buffers */
764         state->in = g_try_malloc(want);
765         state->out = g_try_malloc(want << 1);
766         state->size = want;
767         if (state->in == NULL || state->out == NULL) {
768                 g_free(state->out);
769                 g_free(state->in);
770                 g_free(state);
771                 errno = ENOMEM;
772                 return NULL;
773         }
774
775 #ifdef HAVE_LIBZ
776         /* allocate inflate memory */
777         state->strm.zalloc = Z_NULL;
778         state->strm.zfree = Z_NULL;
779         state->strm.opaque = Z_NULL;
780         state->strm.avail_in = 0;
781         state->strm.next_in = Z_NULL;
782         if (inflateInit2(&(state->strm), -15) != Z_OK) {    /* raw inflate */
783                 g_free(state->out);
784                 g_free(state->in);
785                 g_free(state);
786                 errno = ENOMEM;
787                 return NULL;
788         }
789
790         /* for now, assume we should check the crc */
791         state->dont_check_crc = 0;
792 #endif
793         /* return stream */
794         return state;
795 }
796
797 FILE_T
798 file_open(const char *path)
799 {
800         int fd;
801         FILE_T ft;
802 #ifdef HAVE_LIBZ
803         const char *suffixp;
804 #endif
805
806         /* open file and do correct filename conversions.
807
808            XXX - do we need O_LARGEFILE?  On UN*X, if we need to do
809            something special to get large file support, the configure
810            script should have set us up with the appropriate #defines,
811            so we should be getting a large-file-enabled file descriptor
812            here.  Pre-Large File Summit UN*Xes, and possibly even some
813            post-LFS UN*Xes, might require O_LARGEFILE here, though.
814            If so, we should probably handle that in ws_open(). */
815         if ((fd = ws_open(path, O_RDONLY|O_BINARY, 0000)) == -1)
816                 return NULL;
817
818         /* open file handle */
819         ft = filed_open(fd);
820         if (ft == NULL) {
821                 ws_close(fd);
822                 return NULL;
823         }
824
825 #ifdef HAVE_LIBZ
826         /*
827          * If this file's name ends in ".caz", it's probably a compressed
828          * Windows Sniffer file.  The compression is gzip, but they don't
829          * bother filling in the CRC; we set a flag to ignore CRC errors.
830          */
831         suffixp = strrchr(path, '.');
832         if (suffixp != NULL) {
833                 if (g_ascii_strcasecmp(suffixp, ".caz") == 0)
834                         ft->dont_check_crc = 1;
835         }
836 #endif
837
838         return ft;
839 }
840
841 void 
842 file_set_random_access(FILE_T stream, gboolean random _U_, GPtrArray *seek)
843 {
844         stream->fast_seek = seek;
845 }
846
847 gint64
848 file_seek(FILE_T file, gint64 offset, int whence, int *err)
849 {
850         struct fast_seek_point *here;
851         unsigned n;
852
853         /* can only seek from start or relative to current position */
854         if (whence != SEEK_SET && whence != SEEK_CUR) {
855                 g_assert_not_reached();
856 /*
857                 *err = EINVAL;
858                 return -1;
859  */
860         }
861
862         /* normalize offset to a SEEK_CUR specification */
863         if (whence == SEEK_SET)
864                 offset -= file->pos;
865         else if (file->seek)
866                 offset += file->skip;
867         file->seek = 0;
868
869         /* XXX, profile */
870         if ((here = fast_seek_find(file, file->pos + offset)) && (offset < 0 || offset > SPAN || here->compression == UNCOMPRESSED)) {
871                 gint64 off, off2;
872
873 #ifdef HAVE_LIBZ
874                 if (here->compression == ZLIB) {
875 #ifdef HAVE_INFLATEPRIME
876                         off = here->in - (here->data.zlib.bits ? 1 : 0);
877 #else
878                         off = here->in;
879 #endif
880                         off2 = here->out;
881                 } else if (here->compression == GZIP_AFTER_HEADER) {
882                         off = here->in;
883                         off2 = here->out;
884                 } else
885 #endif
886                 {
887                         off2 = (file->pos + offset);
888                         off = here->in + (off2 - here->out);
889                 }
890
891                 if (ws_lseek64(file->fd, off, SEEK_SET) == -1) {
892                         *err = errno;
893                         return -1;
894                 }
895                 fast_seek_reset(file);
896
897                 file->raw_pos = off;
898                 file->have = 0;
899                 file->eof = 0;
900                 file->seek = 0;
901                 file->err = 0;
902                 file->err_info = NULL;
903                 file->avail_in = 0;
904
905 #ifdef HAVE_LIBZ
906                 if (here->compression == ZLIB) {
907                         z_stream *strm = &file->strm;
908
909                         inflateReset(strm);
910                         strm->adler = here->data.zlib.adler;
911                         strm->total_out = here->data.zlib.total_out;
912 #ifdef HAVE_INFLATEPRIME
913                         if (here->data.zlib.bits) {
914                                 FILE_T state = file;
915                                 int ret = GZ_GETC();
916
917                                 if (ret == -1) {
918                                         if (state->err == 0) {
919                                                 /* EOF */
920                                                 *err = WTAP_ERR_SHORT_READ;
921                                         } else
922                                                 *err = state->err;
923                                         return -1;
924                                 }
925                                 (void)inflatePrime(strm, here->data.zlib.bits, ret >> (8 - here->data.zlib.bits));
926                         }
927 #endif
928                         (void)inflateSetDictionary(strm, here->data.zlib.window, ZLIB_WINSIZE);
929                         file->compression = ZLIB;
930                 } else if (here->compression == GZIP_AFTER_HEADER) {
931                         z_stream *strm = &file->strm;
932
933                         inflateReset(strm);
934                         strm->adler = crc32(0L, Z_NULL, 0);
935                         file->compression = ZLIB;
936                 } else
937 #endif
938                         file->compression = here->compression;
939
940                 offset = (file->pos + offset) - off2;
941                 file->pos = off2;
942                 /* g_print("OK! %ld\n", offset); */
943
944                 if (offset) {
945                         file->seek = 1;
946                         file->skip = offset;
947                 }
948                 return file->pos + offset;
949         }
950
951         /* if within raw area while reading, just go there */
952         if (file->compression == UNCOMPRESSED && file->pos + offset >= file->raw) {
953                 if (ws_lseek64(file->fd, offset - file->have, SEEK_CUR) == -1) {
954                         *err = errno;
955                         return -1;
956                 }
957                 file->raw_pos += (offset - file->have);
958                 file->have = 0;
959                 file->eof = 0;
960                 file->seek = 0;
961                 file->err = 0;
962                 file->err_info = NULL;
963                 file->avail_in = 0;
964                 file->pos += offset;
965                 return file->pos;
966         }
967
968         /* calculate skip amount, rewinding if needed for back seek when reading */
969         if (offset < 0) {
970                 offset += file->pos;
971                 if (offset < 0) {                    /* before start of file! */
972                         /* *err = ???; */
973                         return -1;
974                 }
975                 /* rewind, then skip to offset */
976
977                 /* back up and start over */
978                 if (ws_lseek64(file->fd, file->start, SEEK_SET) == -1) {
979                         *err = errno;
980                         return -1;
981                 }
982                 fast_seek_reset(file);
983                 file->raw_pos = file->start;
984                 gz_reset(file);
985         }
986
987         /* skip what's in output buffer (one less gzgetc() check) */
988         n = (gint64)file->have > offset ? (unsigned)offset : file->have;
989         file->have -= n;
990         file->next += n;
991         file->pos += n;
992         offset -= n;
993
994         /* request skip (if not zero) */
995         if (offset) {
996                 file->seek = 1;
997                 file->skip = offset;
998         }
999         return file->pos + offset;
1000 }
1001
1002 gint64
1003 file_tell(FILE_T stream)
1004 {
1005         /* return position */
1006         return stream->pos + (stream->seek ? stream->skip : 0);
1007 }
1008
1009 gint64 file_tell_raw(FILE_T stream)
1010 {
1011         return stream->raw_pos;
1012 }
1013
1014 int 
1015 file_read(void *buf, unsigned int len, FILE_T file)
1016 {
1017         unsigned got, n;
1018
1019         /* if len is zero, avoid unnecessary operations */
1020         if (len == 0)
1021                 return 0;
1022
1023         /* process a skip request */
1024         if (file->seek) {
1025                 file->seek = 0;
1026                 if (gz_skip(file, file->skip) == -1)
1027                         return -1;
1028         }
1029
1030         /* get len bytes to buf, or less than len if at the end */
1031         got = 0;
1032         do {
1033                 if (file->have) {
1034                         /* We have stuff in the output buffer; copy
1035                            what we have. */
1036                         n = file->have > len ? len : file->have;
1037                         memcpy(buf, file->next, n);
1038                         file->next += n;
1039                         file->have -= n;
1040                 } else if (file->err) {
1041                         /* We have nothing in the output buffer, and
1042                            we have an error that may not have been
1043                            reported yet; that means we can't generate
1044                            any more data into the output buffer, so
1045                            return an error indication. */
1046                         return -1;
1047                 } else if (file->eof && file->avail_in == 0) {
1048                         /* We have nothing in the output buffer, and
1049                            we're at the end of the input; just return
1050                            with what we've gotten so far. */
1051                         break;
1052                 } else {
1053                         /* We have nothing in the output buffer, and
1054                            we can generate more data; get more output,
1055                            looking for header if required, and
1056                            keep looping to process the new stuff
1057                            in the output buffer. */
1058                         if (fill_out_buffer(file) == -1)
1059                                 return -1;
1060                         continue;       /* no progress yet -- go back to memcpy() above */
1061                 }
1062                 /* update progress */
1063                 len -= n;
1064                 buf = (char *)buf + n;
1065                 got += n;
1066                 file->pos += n;
1067         } while (len);
1068
1069         return (int)got;
1070 }
1071
1072 int
1073 file_getc(FILE_T file)
1074 {
1075         unsigned char buf[1];
1076         int ret;
1077
1078         /* check that we're reading and that there's no error */
1079         if (file->err)
1080                 return -1;
1081
1082         /* try output buffer (no need to check for skip request) */
1083         if (file->have) {
1084                 file->have--;
1085                 file->pos++;
1086                 return *(file->next)++;
1087         }
1088
1089         ret = file_read(buf, 1, file);
1090         return ret < 1 ? -1 : buf[0];
1091 }
1092
1093 char *
1094 file_gets(char *buf, int len, FILE_T file)
1095 {
1096         unsigned left, n;
1097         char *str;
1098         unsigned char *eol;
1099
1100         /* check parameters */
1101         if (buf == NULL || len < 1)
1102                 return NULL;
1103
1104         /* check that there's no error */
1105         if (file->err)
1106                 return NULL;
1107
1108         /* process a skip request */
1109         if (file->seek) {
1110                 file->seek = 0;
1111                 if (gz_skip(file, file->skip) == -1)
1112                         return NULL;
1113         }
1114
1115         /* copy output bytes up to new line or len - 1, whichever comes first --
1116            append a terminating zero to the string (we don't check for a zero in
1117            the contents, let the user worry about that) */
1118         str = buf;
1119         left = (unsigned)len - 1;
1120         if (left) do {
1121                 /* assure that something is in the output buffer */
1122                 if (file->have == 0) {
1123                         /* We have nothing in the output buffer. */
1124                         if (file->err) {
1125                                 /* We have an error that may not have
1126                                    been reported yet; that means we
1127                                    can't generate any more data into
1128                                    the output buffer, so return an
1129                                    error indication. */
1130                                 return NULL;
1131                         }
1132                         if (fill_out_buffer(file) == -1)
1133                                 return NULL;            /* error */
1134                         if (file->have == 0)  {     /* end of file */
1135                                 if (buf == str)         /* got bupkus */
1136                                         return NULL;
1137                                 break;                  /* got something -- return it */
1138                         }
1139                 }
1140
1141                 /* look for end-of-line in current output buffer */
1142                 n = file->have > left ? left : file->have;
1143                 eol = memchr(file->next, '\n', n);
1144                 if (eol != NULL)
1145                         n = (unsigned)(eol - file->next) + 1;
1146
1147                 /* copy through end-of-line, or remainder if not found */
1148                 memcpy(buf, file->next, n);
1149                 file->have -= n;
1150                 file->next += n;
1151                 file->pos += n;
1152                 left -= n;
1153                 buf += n;
1154         } while (left && eol == NULL);
1155
1156         /* found end-of-line or out of space -- terminate string and return it */
1157         buf[0] = 0;
1158         return str;
1159 }
1160
1161 int 
1162 file_eof(FILE_T file)
1163 {
1164         /* return end-of-file state */
1165         return (file->eof && file->avail_in == 0 && file->have == 0);
1166 }
1167
1168 /*
1169  * Routine to return a Wiretap error code (0 for no error, an errno
1170  * for a file error, or a WTAP_ERR_ code for other errors) for an
1171  * I/O stream.  Also returns an error string for some errors.
1172  */
1173 int
1174 file_error(FILE_T fh, gchar **err_info)
1175 {
1176         if (fh->err != 0) {
1177                 *err_info = (fh->err_info == NULL) ? NULL : g_strdup(fh->err_info);
1178                 return fh->err;
1179         }
1180         return 0;
1181 }
1182
1183 void
1184 file_clearerr(FILE_T stream)
1185 {
1186         /* clear error and end-of-file */
1187         stream->err = 0;
1188         stream->err_info = NULL;
1189         stream->eof = 0;
1190 }
1191
1192 int 
1193 file_close(FILE_T file)
1194 {
1195         int fd = file->fd;
1196
1197         /* free memory and close file */
1198         if (file->size) {
1199 #ifdef HAVE_LIBZ
1200                 inflateEnd(&(file->strm));
1201 #endif
1202                 g_free(file->out);
1203                 g_free(file->in);
1204         }
1205         g_free(file->fast_seek_cur);
1206         file->err = 0;
1207         file->err_info = NULL;
1208         g_free(file);
1209         return close(fd);
1210 }
1211
1212 #ifdef HAVE_LIBZ
1213 /* internal gzip file state data structure for writing */
1214 struct wtap_writer {
1215     int fd;                 /* file descriptor */
1216     gint64 pos;             /* current position in uncompressed data */
1217     unsigned size;          /* buffer size, zero if not allocated yet */
1218     unsigned want;          /* requested buffer size, default is GZBUFSIZE */
1219     unsigned char *in;      /* input buffer */
1220     unsigned char *out;     /* output buffer (double-sized when reading) */
1221     unsigned char *next;    /* next output data to deliver or write */
1222     int level;              /* compression level */
1223     int strategy;           /* compression strategy */
1224     int err;                /* error code */
1225         /* zlib deflate stream */
1226     z_stream strm;          /* stream structure in-place (not a pointer) */
1227 };
1228
1229 GZWFILE_T
1230 gzwfile_open(const char *path)
1231 {
1232     int fd;
1233     GZWFILE_T state;
1234     int save_errno;
1235
1236     fd = ws_open(path, O_BINARY|O_WRONLY|O_CREAT|O_TRUNC, 0666);
1237     if (fd == -1)
1238         return NULL;
1239     state = gzwfile_fdopen(fd);
1240     if (state == NULL) {
1241         save_errno = errno;
1242         close(fd);
1243         errno = save_errno;
1244     }
1245     return state;
1246 }
1247
1248 GZWFILE_T
1249 gzwfile_fdopen(int fd)
1250 {
1251     GZWFILE_T state;
1252
1253     /* allocate wtap_writer structure to return */
1254     state = g_try_malloc(sizeof *state);
1255     if (state == NULL)
1256         return NULL;
1257     state->fd = fd;
1258     state->size = 0;            /* no buffers allocated yet */
1259     state->want = GZBUFSIZE;    /* requested buffer size */
1260
1261     state->level = Z_DEFAULT_COMPRESSION;
1262     state->strategy = Z_DEFAULT_STRATEGY;
1263
1264     /* initialize stream */
1265     state->err = Z_OK;              /* clear error */
1266     state->pos = 0;                 /* no uncompressed data yet */
1267     state->strm.avail_in = 0;       /* no input data yet */
1268
1269     /* return stream */
1270     return state;
1271 }
1272
1273 /* Initialize state for writing a gzip file.  Mark initialization by setting
1274    state->size to non-zero.  Return -1, and set state->err, on failure;
1275    return 0 on success. */
1276 static int
1277 gz_init(GZWFILE_T state)
1278 {
1279     int ret;
1280     z_streamp strm = &(state->strm);
1281
1282     /* allocate input and output buffers */
1283     state->in = g_try_malloc(state->want);
1284     state->out = g_try_malloc(state->want);
1285     if (state->in == NULL || state->out == NULL) {
1286         g_free(state->out);
1287         g_free(state->in);
1288         state->err = ENOMEM;
1289         return -1;
1290     }
1291
1292     /* allocate deflate memory, set up for gzip compression */
1293     strm->zalloc = Z_NULL;
1294     strm->zfree = Z_NULL;
1295     strm->opaque = Z_NULL;
1296     ret = deflateInit2(strm, state->level, Z_DEFLATED,
1297                        15 + 16, 8, state->strategy);
1298     if (ret != Z_OK) {
1299         g_free(state->out);
1300         g_free(state->in);
1301         if (ret == Z_MEM_ERROR) {
1302                 /* This means "not enough memory". */
1303                 state->err = ENOMEM;
1304         } else {
1305                 /* This "shouldn't happen". */
1306                 state->err = WTAP_ERR_INTERNAL;
1307         }
1308         return -1;
1309     }
1310
1311     /* mark state as initialized */
1312     state->size = state->want;
1313
1314     /* initialize write buffer */
1315     strm->avail_out = state->size;
1316     strm->next_out = state->out;
1317     state->next = strm->next_out;
1318     return 0;
1319 }
1320
1321 /* Compress whatever is at avail_in and next_in and write to the output file.
1322    Return -1, and set state->err, if there is an error writing to the output
1323    file; return 0 on success.
1324    flush is assumed to be a valid deflate() flush value.  If flush is Z_FINISH,
1325    then the deflate() state is reset to start a new gzip stream. */
1326 static int
1327 gz_comp(GZWFILE_T state, int flush)
1328 {
1329     int ret, got;
1330     unsigned have;
1331     z_streamp strm = &(state->strm);
1332
1333     /* allocate memory if this is the first time through */
1334     if (state->size == 0 && gz_init(state) == -1)
1335         return -1;
1336
1337     /* run deflate() on provided input until it produces no more output */
1338     ret = Z_OK;
1339     do {
1340         /* write out current buffer contents if full, or if flushing, but if
1341            doing Z_FINISH then don't write until we get to Z_STREAM_END */
1342         if (strm->avail_out == 0 || (flush != Z_NO_FLUSH &&
1343             (flush != Z_FINISH || ret == Z_STREAM_END))) {
1344             have = (unsigned)(strm->next_out - state->next);
1345             if (have) {
1346                 got = write(state->fd, state->next, have);
1347                 if (got < 0) {
1348                     state->err = errno;
1349                     return -1;
1350                 }
1351                 if ((unsigned)got != have) {
1352                     state->err = WTAP_ERR_SHORT_WRITE;
1353                     return -1;
1354                 }
1355             }
1356             if (strm->avail_out == 0) {
1357                 strm->avail_out = state->size;
1358                 strm->next_out = state->out;
1359             }
1360             state->next = strm->next_out;
1361         }
1362
1363         /* compress */
1364         have = strm->avail_out;
1365         ret = deflate(strm, flush);
1366         if (ret == Z_STREAM_ERROR) {
1367             /* This "shouldn't happen". */
1368             state->err = WTAP_ERR_INTERNAL;
1369             return -1;
1370         }
1371         have -= strm->avail_out;
1372     } while (have);
1373
1374     /* if that completed a deflate stream, allow another to start */
1375     if (flush == Z_FINISH)
1376         deflateReset(strm);
1377
1378     /* all done, no errors */
1379     return 0;
1380 }
1381
1382 /* Write out len bytes from buf.  Return 0, and set state->err, on
1383    failure or on an attempt to write 0 bytes (in which case state->err
1384    is Z_OK); return the number of bytes written on success. */
1385 unsigned
1386 gzwfile_write(GZWFILE_T state, const void *buf, unsigned len)
1387 {
1388     unsigned put = len;
1389     unsigned n;
1390     z_streamp strm;
1391
1392     strm = &(state->strm);
1393
1394     /* check that there's no error */
1395     if (state->err != Z_OK)
1396         return 0;
1397
1398     /* if len is zero, avoid unnecessary operations */
1399     if (len == 0)
1400         return 0;
1401
1402     /* allocate memory if this is the first time through */
1403     if (state->size == 0 && gz_init(state) == -1)
1404         return 0;
1405
1406     /* for small len, copy to input buffer, otherwise compress directly */
1407     if (len < state->size) {
1408         /* copy to input buffer, compress when full */
1409         do {
1410             if (strm->avail_in == 0)
1411                 strm->next_in = state->in;
1412             n = state->size - strm->avail_in;
1413             if (n > len)
1414                 n = len;
1415             memcpy(strm->next_in + strm->avail_in, buf, n);
1416             strm->avail_in += n;
1417             state->pos += n;
1418             buf = (char *)buf + n;
1419             len -= n;
1420             if (len && gz_comp(state, Z_NO_FLUSH) == -1)
1421                 return 0;
1422         } while (len);
1423     }
1424     else {
1425         /* consume whatever's left in the input buffer */
1426         if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
1427             return 0;
1428
1429         /* directly compress user buffer to file */
1430         strm->avail_in = len;
1431         strm->next_in = (voidp)buf;
1432         state->pos += len;
1433         if (gz_comp(state, Z_NO_FLUSH) == -1)
1434             return 0;
1435     }
1436
1437     /* input was all buffered or compressed (put will fit in int) */
1438     return (int)put;
1439 }
1440
1441 /* Flush out what we've written so far.  Returns -1, and sets state->err,
1442    on failure; returns 0 on success. */
1443 int
1444 gzwfile_flush(GZWFILE_T state)
1445 {
1446     /* check that there's no error */
1447     if (state->err != Z_OK)
1448         return -1;
1449
1450     /* compress remaining data with Z_SYNC_FLUSH */
1451     gz_comp(state, Z_SYNC_FLUSH);
1452     if (state->err != Z_OK)
1453         return -1;
1454     return 0;
1455 }
1456
1457 /* Flush out all data written, and close the file.  Returns a Wiretap
1458    error on failure; returns 0 on success. */
1459 int
1460 gzwfile_close(GZWFILE_T state)
1461 {
1462     int ret = 0;
1463
1464     /* flush, free memory, and close file */
1465     if (gz_comp(state, Z_FINISH) == -1 && ret == 0)
1466         ret = state->err;
1467     (void)deflateEnd(&(state->strm));
1468     g_free(state->out);
1469     g_free(state->in);
1470     state->err = Z_OK;
1471     if (close(state->fd) == -1 && ret == 0)
1472         ret = errno;
1473     g_free(state);
1474     return ret;
1475 }
1476
1477 int
1478 gzwfile_geterr(GZWFILE_T state)
1479 {
1480     return state->err;
1481 }
1482 #endif