From Martin Warnes:
[obnox/wireshark/wip.git] / wiretap / file_access.c
1 /* file_access.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 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdlib.h>
30
31 #ifdef HAVE_FCNTL_H
32 #include <fcntl.h>
33 #endif
34
35 #ifdef HAVE_UNISTD_H
36 #include <unistd.h>
37 #endif
38
39 #include <errno.h>
40
41 #include "file_util.h"
42
43 #include "wtap-int.h"
44 #include "file_wrappers.h"
45 #include "buffer.h"
46 #include "lanalyzer.h"
47 #include "airopeek9.h"
48 #include "ngsniffer.h"
49 #include "radcom.h"
50 #include "ascend.h"
51 #include "nettl.h"
52 #include "libpcap.h"
53 #include "snoop.h"
54 #include "iptrace.h"
55 #include "iseries.h"
56 #include "netmon.h"
57 #include "netxray.h"
58 #include "toshiba.h"
59 #include "eyesdn.h"
60 #include "i4btrace.h"
61 #include "csids.h"
62 #include "pppdump.h"
63 #include "etherpeek.h"
64 #include "vms.h"
65 #include "dbs-etherwatch.h"
66 #include "visual.h"
67 #include "cosine.h"
68 #include "5views.h"
69 #include "erf.h"
70 #include "hcidump.h"
71 #include "network_instruments.h"
72 #include "k12.h"
73
74 /* The open_file_* routines should return:
75  *
76  *      -1 on an I/O error;
77  *
78  *      1 if the file they're reading is one of the types it handles;
79  *
80  *      0 if the file they're reading isn't the type they're checking for.
81  *
82  * If the routine handles this type of file, it should set the "file_type"
83  * field in the "struct wtap" to the type of the file.
84  *
85  * Put the trace files that are merely saved telnet-sessions last, since it's
86  * possible that you could have captured someone a router telnet-session
87  * using another tool. So, a libpcap trace of an toshiba "snoop" session
88  * should be discovered as a libpcap file, not a toshiba file.
89  */
90
91 static int (*const open_routines[])(wtap *, int *, char **) = {
92         /* Files that have magic bytes in fixed locations. These
93          * are easy to identify.
94          */
95         libpcap_open,
96         lanalyzer_open,
97         ngsniffer_open,
98         snoop_open,
99         iptrace_open,
100         netmon_open,
101         netxray_open,
102         radcom_open,
103         nettl_open,
104         visual_open,
105         _5views_open,
106         network_instruments_open,
107         airopeek9_open,
108         dbs_etherwatch_open,
109         k12_open,
110         
111         /* Files that don't have magic bytes at a fixed location,
112          * but that instead require a heuristic of some sort to
113          * identify them.  This includes the ASCII trace files that
114          * would be, for example, saved copies of a Telnet session
115          * to some box.
116          */
117         etherpeek_open,
118         pppdump_open,
119         iseries_open,
120         ascend_open,
121         eyesdn_open,
122         toshiba_open,
123         i4btrace_open,
124         csids_open,
125         vms_open,
126         cosine_open,
127         erf_open,
128         hcidump_open,
129 };
130
131 #define N_FILE_TYPES    (sizeof open_routines / sizeof open_routines[0])
132
133 /*
134  * Visual C++ on Win32 systems doesn't define these.  (Old UNIX systems don't
135  * define them either.)
136  *
137  * Visual C++ on Win32 systems doesn't define S_IFIFO, it defines _S_IFIFO.
138  */
139 #ifndef S_ISREG
140 #define S_ISREG(mode)   (((mode) & S_IFMT) == S_IFREG)
141 #endif
142 #ifndef S_IFIFO
143 #define S_IFIFO _S_IFIFO
144 #endif
145 #ifndef S_ISFIFO
146 #define S_ISFIFO(mode)  (((mode) & S_IFMT) == S_IFIFO)
147 #endif
148 #ifndef S_ISDIR
149 #define S_ISDIR(mode)   (((mode) & S_IFMT) == S_IFDIR)
150 #endif
151
152 /* Opens a file and prepares a wtap struct.
153    If "do_random" is TRUE, it opens the file twice; the second open
154    allows the application to do random-access I/O without moving
155    the seek offset for sequential I/O, which is used by Ethereal
156    so that it can do sequential I/O to a capture file that's being
157    written to as new packets arrive independently of random I/O done
158    to display protocol trees for packets when they're selected. */
159 wtap* wtap_open_offline(const char *filename, int *err, char **err_info,
160     gboolean do_random)
161 {
162         struct stat statb;
163         wtap    *wth;
164         unsigned int    i;
165         gboolean use_stdin = FALSE;
166
167         /* open standard input if filename is '-' */
168         if (strcmp(filename, "-") == 0)
169                 use_stdin = TRUE;
170
171         /* First, make sure the file is valid */
172         if (use_stdin) {
173                 if (fstat(0, &statb) < 0) {
174                         *err = errno;
175                         return NULL;
176                 }
177         } else {
178                 if (eth_stat(filename, &statb) < 0) {
179                         *err = errno;
180                         return NULL;
181                 }
182         }
183         if (S_ISFIFO(statb.st_mode)) {
184                 /*
185                  * Opens of FIFOs are allowed only when not opening
186                  * for random access.
187                  *
188                  * XXX - currently, we do seeking when trying to find
189                  * out the file type, so we don't actually support
190                  * opening FIFOs.  However, we may eventually
191                  * do buffering that allows us to do at least some
192                  * file type determination even on pipes, so we
193                  * allow FIFO opens and let things fail later when
194                  * we try to seek.
195                  */
196                 if (do_random) {
197                         *err = WTAP_ERR_RANDOM_OPEN_PIPE;
198                         return NULL;
199                 }
200         } else if (S_ISDIR(statb.st_mode)) {
201                 /*
202                  * Return different errors for "this is a directory"
203                  * and "this is some random special file type", so
204                  * the user can get a potentially more helpful error.
205                  */
206                 *err = EISDIR;
207                 return NULL;
208         } else if (! S_ISREG(statb.st_mode)) {
209                 *err = WTAP_ERR_NOT_REGULAR_FILE;
210                 return NULL;
211         }
212
213         /*
214          * We need two independent descriptors for random access, so
215          * they have different file positions.  If we're opening the
216          * standard input, we can only dup it to get additional
217          * descriptors, so we can't have two independent descriptors,
218          * and thus can't do random access.
219          */
220         if (use_stdin && do_random) {
221                 *err = WTAP_ERR_RANDOM_OPEN_STDIN;
222                 return NULL;
223         }
224
225         errno = ENOMEM;
226         wth = g_malloc(sizeof(wtap));
227         if (wth == NULL) {
228                 *err = errno;
229                 return NULL;
230         }
231
232         /* Open the file */
233         errno = WTAP_ERR_CANT_OPEN;
234         if (use_stdin) {
235                 /*
236                  * We dup FD 0, so that we don't have to worry about
237                  * an fclose or gzclose of wth->fh closing the standard
238                  * input of the process.
239                  */
240                 wth->fd = eth_dup(0);
241 #ifdef _WIN32
242                 _setmode(wth->fd, O_BINARY);
243 #endif
244         } else
245                 wth->fd = eth_open(filename, O_RDONLY|O_BINARY, 0000 /* no creation so don't matter */);
246         if (wth->fd < 0) {
247                 *err = errno;
248                 g_free(wth);
249                 return NULL;
250         }
251         if (!(wth->fh = filed_open(wth->fd, "rb"))) {
252                 *err = errno;
253                 eth_close(wth->fd);
254                 g_free(wth);
255                 return NULL;
256         }
257
258         if (do_random) {
259                 if (!(wth->random_fh = file_open(filename, "rb"))) {
260                         *err = errno;
261                         file_close(wth->fh);
262                         g_free(wth);
263                         return NULL;
264                 }
265         } else
266                 wth->random_fh = NULL;
267
268         /* initialization */
269         wth->file_encap = WTAP_ENCAP_UNKNOWN;
270         wth->data_offset = 0;
271         wth->subtype_sequential_close = NULL;
272         wth->subtype_close = NULL;
273         wth->tsprecision = WTAP_FILE_TSPREC_USEC;
274
275         /* Try all file types */
276         for (i = 0; i < N_FILE_TYPES; i++) {
277                 /* Seek back to the beginning of the file; the open routine
278                    for the previous file type may have left the file
279                    position somewhere other than the beginning, and the
280                    open routine for this file type will probably want
281                    to start reading at the beginning.
282
283                    Initialize the data offset while we're at it. */
284                 if (file_seek(wth->fh, 0, SEEK_SET, err) == -1) {
285                         /* I/O error - give up */
286                         if (wth->random_fh != NULL)
287                                 file_close(wth->random_fh);
288                         file_close(wth->fh);
289                         g_free(wth);
290                         return NULL;
291                 }
292                 wth->data_offset = 0;
293                 
294                 switch ((*open_routines[i])(wth, err, err_info)) {
295
296                 case -1:
297                         /* I/O error - give up */
298                         if (wth->random_fh != NULL)
299                                 file_close(wth->random_fh);
300                         file_close(wth->fh);
301                         g_free(wth);
302                         return NULL;
303
304                 case 0:
305                         /* No I/O error, but not that type of file */
306                         break;
307
308                 case 1:
309                         /* We found the file type */
310                         goto success;
311                 }
312         }
313
314         /* Well, it's not one of the types of file we know about. */
315         if (wth->random_fh != NULL)
316                 file_close(wth->random_fh);
317         file_close(wth->fh);
318         g_free(wth);
319         *err = WTAP_ERR_FILE_UNKNOWN_FORMAT;
320         return NULL;
321
322 success:
323         wth->frame_buffer = g_malloc(sizeof(struct Buffer));
324         buffer_init(wth->frame_buffer, 1500);
325         return wth;
326 }
327
328 /* Table of the file types we know about. */
329 static const struct file_type_info {
330         const char *name;
331         const char *short_name;
332         gboolean        can_compress;
333         int     (*can_write_encap)(int);
334         int     (*dump_open)(wtap_dumper *, gboolean, int *);
335 } dump_open_table[WTAP_NUM_FILE_TYPES] = {
336         /* WTAP_FILE_UNKNOWN */
337         { NULL, NULL, FALSE,
338           NULL, NULL },
339
340         /* WTAP_FILE_WTAP */
341         { "Wiretap (Ethereal)", NULL, FALSE,
342           NULL, NULL },
343
344         /* WTAP_FILE_PCAP */
345         { "libpcap (tcpdump, Ethereal, etc.)", "libpcap", TRUE,
346           libpcap_dump_can_write_encap, libpcap_dump_open },
347
348         /* WTAP_FILE_PCAP_SS990417 */
349         { "RedHat Linux 6.1 libpcap (tcpdump)", "rh6_1libpcap", TRUE,
350           libpcap_dump_can_write_encap, libpcap_dump_open },
351
352         /* WTAP_FILE_PCAP_SS990915 */
353         { "SuSE Linux 6.3 libpcap (tcpdump)", "suse6_3libpcap", TRUE,
354           libpcap_dump_can_write_encap, libpcap_dump_open },
355
356         /* WTAP_FILE_PCAP_SS991029 */
357         { "modified libpcap (tcpdump)", "modlibpcap", TRUE,
358           libpcap_dump_can_write_encap, libpcap_dump_open },
359
360         /* WTAP_FILE_PCAP_NOKIA */
361         { "Nokia libpcap (tcpdump)", "nokialibpcap", TRUE,
362           libpcap_dump_can_write_encap, libpcap_dump_open },
363
364         /* WTAP_FILE_PCAP_AIX */
365         { "AIX libpcap (tcpdump)", NULL, TRUE,
366           NULL, NULL },
367
368         /* WTAP_FILE_PCAP_NSEC */
369         { "Nanosecond libpcap (Ethereal)", "nseclibpcap", TRUE,
370           libpcap_dump_can_write_encap, libpcap_dump_open },
371
372         /* WTAP_FILE_LANALYZER */
373         { "Novell LANalyzer","lanalyzer", FALSE,
374           lanalyzer_dump_can_write_encap, lanalyzer_dump_open },
375
376         /* WTAP_FILE_NGSNIFFER_UNCOMPRESSED */
377         { "Network Associates Sniffer (DOS-based)", "ngsniffer", FALSE,
378           ngsniffer_dump_can_write_encap, ngsniffer_dump_open },
379
380         /* WTAP_FILE_NGSNIFFER_COMPRESSED */
381         { "Network Associates Sniffer (DOS-based), compressed", "ngsniffer_comp", FALSE,
382           NULL, NULL },
383
384         /* WTAP_FILE_SNOOP */
385         { "Sun snoop", "snoop", FALSE,
386           snoop_dump_can_write_encap, snoop_dump_open },
387
388         /* WTAP_FILE_SHOMITI */
389         { "Shomiti/Finisar Surveyor", "shomiti", FALSE,
390           NULL, NULL },
391
392         /* WTAP_FILE_IPTRACE_1_0 */
393         { "AIX iptrace 1.0", NULL, FALSE,
394           NULL, NULL },
395
396         /* WTAP_FILE_IPTRACE_2_0 */
397         { "AIX iptrace 2.0", NULL, FALSE,
398           NULL, NULL },
399
400         /* WTAP_FILE_NETMON_1_x */
401         { "Microsoft Network Monitor 1.x", "netmon1", FALSE,
402           netmon_dump_can_write_encap, netmon_dump_open },
403
404         /* WTAP_FILE_NETMON_2_x */
405         { "Microsoft Network Monitor 2.x", "netmon2", FALSE,
406           netmon_dump_can_write_encap, netmon_dump_open },
407
408         /* WTAP_FILE_NETXRAY_OLD */
409         { "Cinco Networks NetXRay 1.x", NULL, FALSE,
410           NULL, NULL },
411
412         /* WTAP_FILE_NETXRAY_1_0 */
413         { "Cinco Networks NetXRay 2.0 or later", NULL, FALSE,
414           NULL, NULL },
415
416         /* WTAP_FILE_NETXRAY_1_1 */
417         { "Network Associates Sniffer (Windows-based) 1.1", "ngwsniffer_1_1", FALSE,
418           netxray_dump_can_write_encap_1_1, netxray_dump_open_1_1 },
419
420         /* WTAP_FILE_NETXRAY_2_00x */
421         { "Network Associates Sniffer (Windows-based) 2.00x", "ngwsniffer_2_0", FALSE,
422           netxray_dump_can_write_encap_2_0, netxray_dump_open_2_0 },
423
424         /* WTAP_FILE_RADCOM */
425         { "RADCOM WAN/LAN analyzer", NULL, FALSE,
426           NULL, NULL },
427
428         /* WTAP_FILE_ASCEND */
429         { "Lucent/Ascend access server trace", NULL, FALSE,
430           NULL, NULL },
431
432         /* WTAP_FILE_NETTL */
433         { "HP-UX nettl trace", "nettl", FALSE,
434           nettl_dump_can_write_encap, nettl_dump_open },
435
436         /* WTAP_FILE_TOSHIBA */
437         { "Toshiba Compact ISDN Router snoop trace", NULL, FALSE,
438           NULL, NULL },
439
440         /* WTAP_FILE_I4BTRACE */
441         { "I4B ISDN trace", NULL, FALSE,
442           NULL, NULL },
443
444         /* WTAP_FILE_CSIDS */
445         { "CSIDS IPLog", NULL, FALSE,
446           NULL, NULL },
447
448         /* WTAP_FILE_PPPDUMP */
449         { "pppd log (pppdump format)", NULL, FALSE,
450           NULL, NULL },
451
452         /* WTAP_FILE_ETHERPEEK_V56 */
453         { "EtherPeek/TokenPeek trace (V5 & V6 file format)", NULL, FALSE,
454           NULL, NULL },
455
456         /* WTAP_FILE_ETHERPEEK_V7 */
457         { "EtherPeek/TokenPeek/AiroPeek trace (V7 file format)", NULL, FALSE,
458           NULL, NULL },
459
460         /* WTAP_FILE_VMS */
461         { "TCPIPtrace (VMS)", NULL, FALSE,
462           NULL, NULL},
463
464         /* WTAP_FILE_DBS_ETHERWATCH */
465         { "DBS Etherwatch (VMS)", NULL, FALSE,
466           NULL, NULL},
467
468         /* WTAP_FILE_VISUAL_NETWORKS */
469         { "Visual Networks traffic capture", "visual", FALSE,
470           visual_dump_can_write_encap, visual_dump_open },
471
472         /* WTAP_FILE_COSINE */
473         { "CoSine IPSX L2 capture", "cosine", FALSE,
474           NULL, NULL },
475
476         /* WTAP_FILE_5VIEWS */
477         { "Accellent 5Views capture", "5views", FALSE,
478           _5views_dump_can_write_encap, _5views_dump_open },
479
480         /* WTAP_FILE_ERF */
481         { "Endace DAG capture", "erf", FALSE,
482           NULL, NULL },
483
484         /* WTAP_FILE_HCIDUMP */
485         { "Bluetooth HCI dump", "hcidump", FALSE,
486           NULL, NULL },
487
488         /* WTAP_FILE_NETWORK_INSTRUMENTS_V9 */
489         { "Network Instruments Observer version 9", "niobserverv9", FALSE,
490           network_instruments_dump_can_write_encap, network_instruments_dump_open },
491
492         /* WTAP_FILE_AIROPEEK_V9 */
493         { "EtherPeek/AiroPeek trace (V9 file format)", NULL, FALSE,
494           NULL, NULL },
495     
496         /* WTAP_FILE_EYESDN */
497         { "EyeSDN USB S0/E1 ISDN trace format", NULL, FALSE,
498                 NULL, NULL },
499     
500         /* WTAP_FILE_K12 */
501         { "Tektronix K12xx 32-bit .rf5 format", "rf5", FALSE,
502                 k12_dump_can_write_encap, k12_dump_open },
503
504         /* WTAP_FILE_ISERIES */
505         { "IBM iSeries communications trace (ASCII)", NULL, FALSE,
506           NULL, NULL },
507
508         /* WTAP_FILE_ISERIES_UNICODE */
509         { "IBM iSeries communications trace (UNICODE)", NULL, FALSE,
510           NULL, NULL },
511
512 };
513
514 /* Name that should be somewhat descriptive. */
515 const char *wtap_file_type_string(int filetype)
516 {
517         if (filetype < 0 || filetype >= WTAP_NUM_FILE_TYPES) {
518                 g_error("Unknown capture file type %d", filetype);
519                 return NULL;
520         } else
521                 return dump_open_table[filetype].name;
522 }
523
524 /* Name to use in, say, a command-line flag specifying the type. */
525 const char *wtap_file_type_short_string(int filetype)
526 {
527         if (filetype < 0 || filetype >= WTAP_NUM_FILE_TYPES)
528                 return NULL;
529         else
530                 return dump_open_table[filetype].short_name;
531 }
532
533 /* Translate a short name to a capture file type. */
534 int wtap_short_string_to_file_type(const char *short_name)
535 {
536         int filetype;
537
538         for (filetype = 0; filetype < WTAP_NUM_FILE_TYPES; filetype++) {
539                 if (dump_open_table[filetype].short_name != NULL &&
540                     strcmp(short_name, dump_open_table[filetype].short_name) == 0)
541                         return filetype;
542         }
543         return -1;      /* no such file type, or we can't write it */
544 }
545
546 gboolean wtap_dump_can_open(int filetype)
547 {
548         if (filetype < 0 || filetype >= WTAP_NUM_FILE_TYPES
549             || dump_open_table[filetype].dump_open == NULL)
550                 return FALSE;
551
552         return TRUE;
553 }
554
555 gboolean wtap_dump_can_write_encap(int filetype, int encap)
556 {
557         if (filetype < 0 || filetype >= WTAP_NUM_FILE_TYPES
558             || dump_open_table[filetype].can_write_encap == NULL)
559                 return FALSE;
560
561         if ((*dump_open_table[filetype].can_write_encap)(encap) != 0)
562                 return FALSE;
563
564         return TRUE;
565 }
566
567 gboolean wtap_dump_can_compress(int filetype)
568 {
569 #ifdef HAVE_LIBZ
570         if (filetype < 0 || filetype >= WTAP_NUM_FILE_TYPES
571             || dump_open_table[filetype].can_compress == FALSE)
572                 return FALSE;
573
574         return TRUE;
575 #else
576         return FALSE;
577 #endif
578 }
579
580
581 static gboolean wtap_dump_open_check(int filetype, int encap, gboolean comressed, int *err);
582 static wtap_dumper* wtap_dump_alloc_wdh(int filetype, int encap, int snaplen,
583     gboolean compressed, int *err);
584 static gboolean wtap_dump_open_finish(wtap_dumper *wdh, int filetype, gboolean compressed, int *err);
585
586 static FILE *wtap_dump_file_open(wtap_dumper *wdh, const char *filename);
587 static FILE *wtap_dump_file_fdopen(wtap_dumper *wdh, int fd);
588 static int wtap_dump_file_close(wtap_dumper *wdh);
589
590 wtap_dumper* wtap_dump_open(const char *filename, int filetype, int encap,
591                                 int snaplen, gboolean compressed, int *err)
592 {
593         wtap_dumper *wdh;
594         FILE *fh;
595
596         /* Check whether we can open a capture file with that file type
597            and that encapsulation. */
598         if (!wtap_dump_open_check(filetype, encap, compressed, err))
599                 return NULL;
600
601         /* Allocate a data structure for the output stream. */
602         wdh = wtap_dump_alloc_wdh(filetype, encap, snaplen, compressed, err);
603         if (wdh == NULL)
604                 return NULL;    /* couldn't allocate it */
605
606         /* Empty filename means stdout */
607         if (*filename == '\0') {
608                 if(compressed) {
609                         g_free(wdh);
610                         return NULL;    /* compress won't work on stdout */
611                 }
612 #ifdef _WIN32
613                 setmode(fileno(stdout), O_BINARY);
614 #endif
615                 wdh->fh = stdout;
616         } else {
617                 /* In case "fopen()" fails but doesn't set "errno", set "errno"
618                    to a generic "the open failed" error. */
619                 errno = WTAP_ERR_CANT_OPEN;
620                 fh = wtap_dump_file_open(wdh, filename);
621                 if (fh == NULL) {
622                         *err = errno;
623                         g_free(wdh);
624                         return NULL;    /* can't create file */
625                 }
626                 wdh->fh = fh;
627         }
628
629         if (!wtap_dump_open_finish(wdh, filetype, compressed, err)) {
630                 /* Get rid of the file we created; we couldn't finish
631                    opening it. */
632                 if (wdh->fh != stdout) {
633                         wtap_dump_file_close(wdh);
634                         eth_unlink(filename);
635                 }
636                 g_free(wdh);
637                 return NULL;
638         }
639         return wdh;
640 }
641
642 wtap_dumper* wtap_dump_fdopen(int fd, int filetype, int encap, int snaplen,
643                                 gboolean compressed, int *err)
644 {
645         wtap_dumper *wdh;
646         FILE *fh;
647
648         /* Check whether we can open a capture file with that file type
649            and that encapsulation. */
650         if (!wtap_dump_open_check(filetype, encap, compressed, err))
651                 return NULL;
652
653         /* Allocate a data structure for the output stream. */
654         wdh = wtap_dump_alloc_wdh(filetype, encap, snaplen, compressed, err);
655         if (wdh == NULL)
656                 return NULL;    /* couldn't allocate it */
657
658         /* In case "fopen()" fails but doesn't set "errno", set "errno"
659            to a generic "the open failed" error. */
660         errno = WTAP_ERR_CANT_OPEN;
661         fh = wtap_dump_file_fdopen(wdh, fd);
662         if (fh == NULL) {
663                 *err = errno;
664                 g_free(wdh);
665                 return NULL;    /* can't create standard I/O stream */
666         }
667         wdh->fh = fh;
668
669         if (!wtap_dump_open_finish(wdh, filetype, compressed, err)) {
670                 wtap_dump_file_close(wdh);
671                 g_free(wdh);
672                 return NULL;
673         }
674         return wdh;
675 }
676
677 static gboolean wtap_dump_open_check(int filetype, int encap, gboolean compressed, int *err)
678 {
679         if (!wtap_dump_can_open(filetype)) {
680                 /* Invalid type, or type we don't know how to write. */
681                 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
682                 return FALSE;
683         }
684
685         /* OK, we know how to write that type; can we write the specified
686            encapsulation type? */
687         *err = (*dump_open_table[filetype].can_write_encap)(encap);
688         if (*err != 0)
689                 return FALSE;
690
691         /* if compression is wanted, do we support this for this filetype? */
692         if(compressed && !wtap_dump_can_compress(filetype)) {
693                 *err = WTAP_ERR_COMPRESSION_NOT_SUPPORTED;
694                 return FALSE;
695         }
696
697         *err = (*dump_open_table[filetype].can_write_encap)(encap);
698         if (*err != 0)
699                 return FALSE;
700
701
702         /* All systems go! */
703         return TRUE;
704 }
705
706 static wtap_dumper* wtap_dump_alloc_wdh(int filetype, int encap, int snaplen,
707                                         gboolean compressed, int *err)
708 {
709         wtap_dumper *wdh;
710
711         wdh = g_malloc(sizeof (wtap_dumper));
712         if (wdh == NULL) {
713                 *err = errno;
714                 return NULL;
715         }
716         wdh->fh = NULL;
717         wdh->file_type = filetype;
718         wdh->snaplen = snaplen;
719         wdh->encap = encap;
720         wdh->compressed = compressed;
721         wdh->bytes_dumped = 0;
722         wdh->dump.opaque = NULL;
723         wdh->subtype_write = NULL;
724         wdh->subtype_close = NULL;
725         return wdh;
726 }
727
728 static gboolean wtap_dump_open_finish(wtap_dumper *wdh, int filetype, gboolean compressed, int *err)
729 {
730         int fd;
731         gboolean cant_seek;
732
733         /* Can we do a seek on the file descriptor?
734            If not, note that fact. */
735         if(compressed) {
736                 cant_seek = TRUE;
737         } else {
738                 fd = fileno(wdh->fh);
739                 if (lseek(fd, 1, SEEK_CUR) == -1)
740                   cant_seek = TRUE;
741                 else {
742                   /* Undo the seek. */
743                   lseek(fd, 0, SEEK_SET);
744                   cant_seek = FALSE;
745                 }
746         }
747
748         /* Now try to open the file for writing. */
749         if (!(*dump_open_table[filetype].dump_open)(wdh, cant_seek, err)) {
750                 return FALSE;
751         }
752
753         return TRUE;    /* success! */
754 }
755
756 gboolean wtap_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
757     const union wtap_pseudo_header *pseudo_header, const guchar *pd, int *err)
758 {
759         return (wdh->subtype_write)(wdh, phdr, pseudo_header, pd, err);
760 }
761
762 void wtap_dump_flush(wtap_dumper *wdh)
763 {
764 #ifdef HAVE_LIBZ
765         if(wdh->compressed) {
766                 gzflush(wdh->fh, Z_SYNC_FLUSH); /* XXX - is Z_SYNC_FLUSH the right one? */
767         } else 
768 #endif
769         {
770                 fflush(wdh->fh);
771         }
772 }
773
774 gboolean wtap_dump_close(wtap_dumper *wdh, int *err)
775 {
776         gboolean ret = TRUE;
777
778         if (wdh->subtype_close != NULL) {
779                 /* There's a close routine for this dump stream. */
780                 if (!(wdh->subtype_close)(wdh, err))
781                         ret = FALSE;
782         }
783         errno = WTAP_ERR_CANT_CLOSE;
784         /* Don't close stdout */
785         if (wdh->fh != stdout) {
786                 if (wtap_dump_file_close(wdh) == EOF) {
787                         if (ret) {
788                                 /* The per-format close function succeeded,
789                                    but the fclose didn't.  Save the reason
790                                    why, if our caller asked for it. */
791                                 if (err != NULL)
792                                         *err = errno;
793                         }
794                         ret = FALSE;
795                 }
796         }
797         if (wdh->dump.opaque != NULL)
798                 g_free(wdh->dump.opaque);
799         g_free(wdh);
800         return ret;
801 }
802
803 long wtap_get_bytes_dumped(wtap_dumper *wdh)
804 {
805         return wdh->bytes_dumped;
806 }
807
808 void wtap_set_bytes_dumped(wtap_dumper *wdh, long bytes_dumped)
809 {
810         wdh->bytes_dumped = bytes_dumped;
811 }
812
813
814 /* internally open a file for writing (compressed or not) */
815 static FILE *wtap_dump_file_open(wtap_dumper *wdh, const char *filename)
816 {
817 #ifdef HAVE_LIBZ
818         if(wdh->compressed) {
819                 return gzopen(filename, "wb");
820         } else 
821 #endif
822         {
823                 return eth_fopen(filename, "wb");
824         }
825 }
826
827 /* internally open a file for writing (compressed or not) */
828 static FILE *wtap_dump_file_fdopen(wtap_dumper *wdh, int fd)
829 {
830 #ifdef HAVE_LIBZ
831         if(wdh->compressed) {
832                 return gzdopen(fd, "wb");
833         } else 
834 #endif
835         {
836                 return fdopen(fd, "wb");
837         }
838 }
839
840 /* internally writing raw bytes (compressed or not) */
841 size_t wtap_dump_file_write(wtap_dumper *wdh, const void *buf, unsigned bufsize)
842 {
843 #ifdef HAVE_LIBZ
844         if(wdh->compressed) {
845                 return gzwrite(wdh->fh, buf, bufsize);
846         } else 
847 #endif
848         {
849                 return fwrite(buf, 1, bufsize, wdh->fh);
850         }
851 }
852
853 /* internally close a file for writing (compressed or not) */
854 static int wtap_dump_file_close(wtap_dumper *wdh)
855 {
856 #ifdef HAVE_LIBZ
857         if(wdh->compressed) {
858                 return gzclose(wdh->fh);
859         } else 
860 #endif
861         {
862                 return fclose(wdh->fh);
863         }
864 }
865
866 int wtap_dump_file_ferror(wtap_dumper *wdh)
867 {
868 #ifdef HAVE_LIBZ
869         int errnum;
870
871         if(wdh->compressed) {
872                 gzerror(wdh->fh, &errnum);
873
874                 if(errnum == Z_ERRNO) {
875                         return errno;
876                 } else {
877                         /* XXX - what to do with this zlib specific number? */
878                         return errnum;
879                 }
880         } else 
881 #endif
882         {
883                 return ferror(wdh->fh);
884         }
885 }
886