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