Export a wtap_dump_can_write_encaps() routine from Wiretap; it takes a
[metze/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 <wsutil/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 "ascendtext.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 #include "ber.h"
74 #include "catapult_dct2000.h"
75 #include "mp2t.h"
76 #include "mpeg.h"
77 #include "netscreen.h"
78 #include "commview.h"
79 #include "pcapng.h"
80 #include "aethra.h"
81 #include "btsnoop.h"
82 #include "tnef.h"
83 #include "dct3trace.h"
84 #include "packetlogger.h"
85 #include "daintree-sna.h"
86 #include "netscaler.h"
87 #include "mime_file.h"
88 #include "ipfix.h"
89 #include "vwr.h"
90 #include "pcap-encap.h"
91
92 /* The open_file_* routines should return:
93  *
94  *      -1 on an I/O error;
95  *
96  *      1 if the file they're reading is one of the types it handles;
97  *
98  *      0 if the file they're reading isn't the type they're checking for.
99  *
100  * If the routine handles this type of file, it should set the "file_type"
101  * field in the "struct wtap" to the type of the file.
102  *
103  * Put the trace files that are merely saved telnet-sessions last, since it's
104  * possible that you could have captured someone a router telnet-session
105  * using another tool. So, a libpcap trace of an toshiba "snoop" session
106  * should be discovered as a libpcap file, not a toshiba file.
107  */
108
109
110 static wtap_open_routine_t open_routines_base[] = {
111         /* Files that have magic bytes in fixed locations. These
112          * are easy to identify.
113          */
114         libpcap_open,
115         pcapng_open,
116         lanalyzer_open,
117         ngsniffer_open,
118         snoop_open,
119         iptrace_open,
120         netmon_open,
121         netxray_open,
122         radcom_open,
123         nettl_open,
124         visual_open,
125         _5views_open,
126         network_instruments_open,
127         airopeek9_open,
128         dbs_etherwatch_open,
129         k12_open,
130         catapult_dct2000_open,
131         ber_open,
132         aethra_open,
133         btsnoop_open,
134         eyesdn_open,
135         vwr_open,
136         packetlogger_open, /* This type does not have a magic number, but its
137                             * files are sometimes grabbed by mpeg_open. */
138         mpeg_open,
139         mp2t_open,
140         tnef_open,
141         dct3trace_open,
142         daintree_sna_open,
143         mime_file_open,
144         /* Files that don't have magic bytes at a fixed location,
145          * but that instead require a heuristic of some sort to
146          * identify them.  This includes the ASCII trace files that
147          * would be, for example, saved copies of a Telnet session
148          * to some box.
149          */
150
151         /* I put NetScreen *before* erf, because there were some
152          * false positives with my test-files (Sake Blok, July 2007)
153          */
154         netscreen_open,
155         erf_open,
156         ipfix_open,
157         k12text_open,
158         etherpeek_open,
159         pppdump_open,
160         iseries_open,
161         ascend_open,
162         toshiba_open,
163         i4btrace_open,
164         csids_open,
165         vms_open,
166         cosine_open,
167         hcidump_open,
168         commview_open,
169         nstrace_open
170 };
171
172 #define N_FILE_TYPES    (sizeof open_routines_base / sizeof open_routines_base[0])
173
174 static wtap_open_routine_t* open_routines = NULL;
175
176 static GArray* open_routines_arr = NULL;
177
178
179 /* initialize the open routines array if it has not been initialized yet */
180 static void init_open_routines(void) {
181
182         if (open_routines_arr) return;
183
184         open_routines_arr = g_array_new(FALSE,TRUE,sizeof(wtap_open_routine_t));
185
186         g_array_append_vals(open_routines_arr,open_routines_base,N_FILE_TYPES);
187
188         open_routines = (wtap_open_routine_t*)(void *)open_routines_arr->data;
189 }
190
191 void wtap_register_open_routine(wtap_open_routine_t open_routine, gboolean has_magic) {
192         init_open_routines();
193
194         if (has_magic)
195                 g_array_prepend_val(open_routines_arr,open_routine);
196         else
197                 g_array_append_val(open_routines_arr,open_routine);
198
199         open_routines = (wtap_open_routine_t*)(void *)open_routines_arr->data;
200 }
201
202 /*
203  * Visual C++ on Win32 systems doesn't define these.  (Old UNIX systems don't
204  * define them either.)
205  *
206  * Visual C++ on Win32 systems doesn't define S_IFIFO, it defines _S_IFIFO.
207  */
208 #ifndef S_ISREG
209 #define S_ISREG(mode)   (((mode) & S_IFMT) == S_IFREG)
210 #endif
211 #ifndef S_IFIFO
212 #define S_IFIFO _S_IFIFO
213 #endif
214 #ifndef S_ISFIFO
215 #define S_ISFIFO(mode)  (((mode) & S_IFMT) == S_IFIFO)
216 #endif
217 #ifndef S_ISDIR
218 #define S_ISDIR(mode)   (((mode) & S_IFMT) == S_IFDIR)
219 #endif
220
221 /* Opens a file and prepares a wtap struct.
222    If "do_random" is TRUE, it opens the file twice; the second open
223    allows the application to do random-access I/O without moving
224    the seek offset for sequential I/O, which is used by Wireshark
225    so that it can do sequential I/O to a capture file that's being
226    written to as new packets arrive independently of random I/O done
227    to display protocol trees for packets when they're selected. */
228 wtap* wtap_open_offline(const char *filename, int *err, char **err_info,
229                         gboolean do_random)
230 {
231         int     fd;
232         ws_statb64 statb;
233         wtap    *wth;
234         unsigned int    i;
235         gboolean use_stdin = FALSE;
236
237         /* open standard input if filename is '-' */
238         if (strcmp(filename, "-") == 0)
239                 use_stdin = TRUE;
240
241         /* First, make sure the file is valid */
242         if (use_stdin) {
243                 if (ws_fstat64(0, &statb) < 0) {
244                         *err = errno;
245                         return NULL;
246                 }
247         } else {
248                 if (ws_stat64(filename, &statb) < 0) {
249                         *err = errno;
250                         return NULL;
251                 }
252         }
253         if (S_ISFIFO(statb.st_mode)) {
254                 /*
255                  * Opens of FIFOs are allowed only when not opening
256                  * for random access.
257                  *
258                  * XXX - currently, we do seeking when trying to find
259                  * out the file type, so we don't actually support
260                  * opening FIFOs.  However, we may eventually
261                  * do buffering that allows us to do at least some
262                  * file type determination even on pipes, so we
263                  * allow FIFO opens and let things fail later when
264                  * we try to seek.
265                  */
266                 if (do_random) {
267                         *err = WTAP_ERR_RANDOM_OPEN_PIPE;
268                         return NULL;
269                 }
270         } else if (S_ISDIR(statb.st_mode)) {
271                 /*
272                  * Return different errors for "this is a directory"
273                  * and "this is some random special file type", so
274                  * the user can get a potentially more helpful error.
275                  */
276                 *err = EISDIR;
277                 return NULL;
278         } else if (! S_ISREG(statb.st_mode)) {
279                 *err = WTAP_ERR_NOT_REGULAR_FILE;
280                 return NULL;
281         }
282
283         /*
284          * We need two independent descriptors for random access, so
285          * they have different file positions.  If we're opening the
286          * standard input, we can only dup it to get additional
287          * descriptors, so we can't have two independent descriptors,
288          * and thus can't do random access.
289          */
290         if (use_stdin && do_random) {
291                 *err = WTAP_ERR_RANDOM_OPEN_STDIN;
292                 return NULL;
293         }
294
295         errno = ENOMEM;
296         wth = (wtap *)g_malloc0(sizeof(wtap));
297
298         /* Open the file */
299         errno = WTAP_ERR_CANT_OPEN;
300         if (use_stdin) {
301                 /*
302                  * We dup FD 0, so that we don't have to worry about
303                  * a file_close of wth->fh closing the standard
304                  * input of the process.
305                  */
306                 fd = ws_dup(0);
307                 if (fd < 0) {
308                         *err = errno;
309                         g_free(wth);
310                         return NULL;
311                 }
312 #ifdef _WIN32
313                 if (_setmode(fd, O_BINARY) == -1) {
314                         /* "Shouldn't happen" */
315                         *err = errno;
316                         g_free(wth);
317                         return NULL;
318                 }
319 #endif
320                 if (!(wth->fh = file_fdopen(fd))) {
321                         *err = errno;
322                         ws_close(fd);
323                         g_free(wth);
324                         return NULL;
325                 }
326         } else {
327                 if (!(wth->fh = file_open(filename))) {
328                         *err = errno;
329                         g_free(wth);
330                         return NULL;
331                 }
332         }
333
334         if (do_random) {
335                 if (!(wth->random_fh = file_open(filename))) {
336                         *err = errno;
337                         file_close(wth->fh);
338                         g_free(wth);
339                         return NULL;
340                 }
341         } else
342                 wth->random_fh = NULL;
343
344         /* initialization */
345         wth->file_encap = WTAP_ENCAP_UNKNOWN;
346         wth->subtype_sequential_close = NULL;
347         wth->subtype_close = NULL;
348         wth->tsprecision = WTAP_FILE_TSPREC_USEC;
349         wth->priv = NULL;
350
351         init_open_routines();
352         if (wth->random_fh) {
353                 wth->fast_seek = g_ptr_array_new();
354
355                 file_set_random_access(wth->fh, FALSE, wth->fast_seek);
356                 file_set_random_access(wth->random_fh, TRUE, wth->fast_seek);
357         }
358
359         /* Try all file types */
360         for (i = 0; i < open_routines_arr->len; i++) {
361                 /* Seek back to the beginning of the file; the open routine
362                    for the previous file type may have left the file
363                    position somewhere other than the beginning, and the
364                    open routine for this file type will probably want
365                    to start reading at the beginning.
366
367                    Initialize the data offset while we're at it. */
368                 if (file_seek(wth->fh, 0, SEEK_SET, err) == -1) {
369                         /* I/O error - give up */
370                         if (wth->random_fh != NULL)
371                                 file_close(wth->random_fh);
372                         file_close(wth->fh);
373                         g_free(wth);
374                         return NULL;
375                 }
376
377                 switch ((*open_routines[i])(wth, err, err_info)) {
378
379                 case -1:
380                         /* I/O error - give up */
381                         if (wth->random_fh != NULL)
382                                 file_close(wth->random_fh);
383                         file_close(wth->fh);
384                         g_free(wth);
385                         return NULL;
386
387                 case 0:
388                         /* No I/O error, but not that type of file */
389                         break;
390
391                 case 1:
392                         /* We found the file type */
393                         goto success;
394                 }
395         }
396
397         /* Well, it's not one of the types of file we know about. */
398         wtap_close(wth);
399         *err = WTAP_ERR_FILE_UNKNOWN_FORMAT;
400         return NULL;
401
402 success:
403         wth->frame_buffer = (struct Buffer *)g_malloc(sizeof(struct Buffer));
404         buffer_init(wth->frame_buffer, 1500);
405         return wth;
406 }
407
408 /*
409  * Given the pathname of the file we just closed with wtap_fdclose(), attempt
410  * to reopen that file and assign the new file descriptor(s) to the sequential
411  * stream and, if do_random is TRUE, to the random stream.  Used on Windows
412  * after the rename of a file we had open was done or if the rename of a
413  * file on top of a file we had open failed.
414  *
415  * This is only required by Wireshark, not TShark, and, at the point that
416  * Wireshark is doing this, the sequential stream is closed, and the
417  * random stream is open, so this refuses to open pipes, and only
418  * reopens the random stream.
419  */
420 gboolean
421 wtap_fdreopen(wtap *wth, const char *filename, int *err)
422 {
423         ws_statb64 statb;
424
425         /*
426          * We need two independent descriptors for random access, so
427          * they have different file positions.  If we're opening the
428          * standard input, we can only dup it to get additional
429          * descriptors, so we can't have two independent descriptors,
430          * and thus can't do random access.
431          */
432         if (strcmp(filename, "-") == 0) {
433                 *err = WTAP_ERR_RANDOM_OPEN_STDIN;
434                 return FALSE;
435         }
436
437         /* First, make sure the file is valid */
438         if (ws_stat64(filename, &statb) < 0) {
439                 *err = errno;
440                 return FALSE;
441         }
442         if (S_ISFIFO(statb.st_mode)) {
443                 /*
444                  * Opens of FIFOs are not allowed; see above.
445                  */
446                 *err = WTAP_ERR_RANDOM_OPEN_PIPE;
447                 return FALSE;
448         } else if (S_ISDIR(statb.st_mode)) {
449                 /*
450                  * Return different errors for "this is a directory"
451                  * and "this is some random special file type", so
452                  * the user can get a potentially more helpful error.
453                  */
454                 *err = EISDIR;
455                 return FALSE;
456         } else if (! S_ISREG(statb.st_mode)) {
457                 *err = WTAP_ERR_NOT_REGULAR_FILE;
458                 return FALSE;
459         }
460
461         /* Open the file */
462         errno = WTAP_ERR_CANT_OPEN;
463         if (!file_fdreopen(wth->random_fh, filename)) {
464                 *err = errno;
465                 return FALSE;
466         }
467         return TRUE;
468 }
469
470 /* Table of the file types we know about.
471    Entries must be sorted by WTAP_FILE_xxx values in ascending order */
472 static const struct file_type_info dump_open_table_base[] = {
473         /* WTAP_FILE_UNKNOWN (only used internally for initialization) */
474         { NULL, NULL, NULL, NULL, FALSE, FALSE,
475           NULL, NULL },
476
477         /* WTAP_FILE_PCAP */
478         /* Gianluca Varenni suggests that we add "deprecated" to the description. */
479         { "Wireshark/tcpdump/... - libpcap", "libpcap", "pcap", "cap;dmp", FALSE, FALSE,
480           libpcap_dump_can_write_encap, libpcap_dump_open },
481
482         /* WTAP_FILE_PCAPNG */
483         { "Wireshark - pcapng", "pcapng", "pcapng", "ntar", FALSE, TRUE,
484           pcapng_dump_can_write_encap, pcapng_dump_open },
485
486         /* WTAP_FILE_PCAP_NSEC */
487         { "Wireshark - nanosecond libpcap", "nseclibpcap", "pcap", "cap;dmp", FALSE, FALSE,
488           libpcap_dump_can_write_encap, libpcap_dump_open },
489
490         /* WTAP_FILE_PCAP_AIX */
491         { "AIX tcpdump - libpcap", "aixlibpcap", "pcap", "cap;dmp", FALSE, FALSE,
492           NULL, NULL },
493
494         /* WTAP_FILE_PCAP_SS991029 */
495         { "Modified tcpdump - libpcap", "modlibpcap", "pcap", "cap;dmp", FALSE, FALSE,
496           libpcap_dump_can_write_encap, libpcap_dump_open },
497
498         /* WTAP_FILE_PCAP_NOKIA */
499         { "Nokia tcpdump - libpcap ", "nokialibpcap", "pcap", "cap;dmp", FALSE, FALSE,
500           libpcap_dump_can_write_encap, libpcap_dump_open },
501
502         /* WTAP_FILE_PCAP_SS990417 */
503         { "RedHat 6.1 tcpdump - libpcap", "rh6_1libpcap", "pcap", "cap;dmp", FALSE, FALSE,
504           libpcap_dump_can_write_encap, libpcap_dump_open },
505
506         /* WTAP_FILE_PCAP_SS990915 */
507         { "SuSE 6.3 tcpdump - libpcap", "suse6_3libpcap", "pcap", "cap;dmp", FALSE, FALSE,
508           libpcap_dump_can_write_encap, libpcap_dump_open },
509
510         /* WTAP_FILE_5VIEWS */
511         { "InfoVista 5View capture", "5views", "5vw", NULL, TRUE, FALSE,
512           _5views_dump_can_write_encap, _5views_dump_open },
513
514         /* WTAP_FILE_IPTRACE_1_0 */
515         { "AIX iptrace 1.0", "iptrace_1", NULL, NULL, FALSE, FALSE,
516           NULL, NULL },
517
518         /* WTAP_FILE_IPTRACE_2_0 */
519         { "AIX iptrace 2.0", "iptrace_2", NULL, NULL, FALSE, FALSE,
520           NULL, NULL },
521
522         /* WTAP_FILE_BER */
523         { "ASN.1 Basic Encoding Rules", "ber", NULL, NULL, FALSE, FALSE,
524                 NULL, NULL },
525
526         /* WTAP_FILE_HCIDUMP */
527         { "Bluetooth HCI dump", "hcidump", NULL, NULL, FALSE, FALSE,
528           NULL, NULL },
529
530         /* WTAP_FILE_CATAPULT_DCT2000 */
531         { "Catapult DCT2000 trace (.out format)", "dct2000", "out", NULL, FALSE, FALSE,
532           catapult_dct2000_dump_can_write_encap, catapult_dct2000_dump_open },
533
534         /* WTAP_FILE_NETXRAY_OLD */
535         { "Cinco Networks NetXRay 1.x", "netxray1", "cap", NULL, TRUE, FALSE,
536           NULL, NULL },
537
538         /* WTAP_FILE_NETXRAY_1_0 */
539         { "Cinco Networks NetXRay 2.0 or later", "netxray2", "cap", NULL, TRUE, FALSE,
540           NULL, NULL },
541
542         /* WTAP_FILE_COSINE */
543         { "CoSine IPSX L2 capture", "cosine", "txt", NULL, FALSE, FALSE,
544           NULL, NULL },
545
546         /* WTAP_FILE_CSIDS */
547         { "CSIDS IPLog", "csids", NULL, NULL, FALSE, FALSE,
548           NULL, NULL },
549
550         /* WTAP_FILE_DBS_ETHERWATCH */
551         { "DBS Etherwatch (VMS)", "etherwatch", "txt", NULL, FALSE, FALSE,
552           NULL, NULL},
553
554         /* WTAP_FILE_ERF */
555         { "Endace ERF capture", "erf", "erf", NULL, FALSE, FALSE,
556           erf_dump_can_write_encap, erf_dump_open },
557
558         /* WTAP_FILE_EYESDN */
559         { "EyeSDN USB S0/E1 ISDN trace format", "eyesdn", "trc", NULL, FALSE, FALSE,
560            eyesdn_dump_can_write_encap, eyesdn_dump_open },
561
562         /* WTAP_FILE_NETTL */
563         { "HP-UX nettl trace", "nettl", "trc0", "trc1", FALSE, FALSE,
564           nettl_dump_can_write_encap, nettl_dump_open },
565
566         /* WTAP_FILE_ISERIES */
567         { "IBM iSeries comm. trace (ASCII)", "iseries_ascii", "txt", NULL, FALSE, FALSE,
568           NULL, NULL },
569
570         /* WTAP_FILE_ISERIES_UNICODE */
571         { "IBM iSeries comm. trace (UNICODE)", "iseries_unicode", "txt", NULL, FALSE, FALSE,
572           NULL, NULL },
573
574         /* WTAP_FILE_I4BTRACE */
575         { "I4B ISDN trace", "i4btrace", NULL, NULL, FALSE, FALSE,
576           NULL, NULL },
577
578         /* WTAP_FILE_ASCEND */
579         { "Lucent/Ascend access server trace", "ascend", "txt", NULL, FALSE, FALSE,
580           NULL, NULL },
581
582         /* WTAP_FILE_NETMON_1_x */
583         { "Microsoft NetMon 1.x", "netmon1", "cap", NULL, TRUE, FALSE,
584           netmon_dump_can_write_encap_1_x, netmon_dump_open },
585
586         /* WTAP_FILE_NETMON_2_x */
587         { "Microsoft NetMon 2.x", "netmon2", "cap", NULL, TRUE, FALSE,
588           netmon_dump_can_write_encap_2_x, netmon_dump_open },
589
590         /* WTAP_FILE_NGSNIFFER_UNCOMPRESSED */
591         { "NA Sniffer (DOS)", "ngsniffer", "cap", "enc;trc;fdc;syc", FALSE, FALSE,
592           ngsniffer_dump_can_write_encap, ngsniffer_dump_open },
593
594         /* WTAP_FILE_NGSNIFFER_COMPRESSED */
595         { "NA Sniffer (DOS), compressed", "ngsniffer_comp", "caz", NULL, FALSE, FALSE,
596           NULL, NULL },
597
598         /* WTAP_FILE_NETXRAY_1_1 */
599         { "NA Sniffer (Windows) 1.1", "ngwsniffer_1_1", "cap", NULL, TRUE, FALSE,
600           netxray_dump_can_write_encap_1_1, netxray_dump_open_1_1 },
601
602         /* WTAP_FILE_NETXRAY_2_00x */
603         { "NA Sniffer (Windows) 2.00x", "ngwsniffer_2_0", "cap", NULL, TRUE, FALSE,
604           netxray_dump_can_write_encap_2_0, netxray_dump_open_2_0 },
605
606         /* WTAP_FILE_NETWORK_INSTRUMENTS */
607         { "Network Instruments Observer", "niobserver", "bfr", NULL, FALSE, FALSE,
608           network_instruments_dump_can_write_encap, network_instruments_dump_open },
609
610         /* WTAP_FILE_LANALYZER */
611         { "Novell LANalyzer","lanalyzer", "tr1", NULL, TRUE, FALSE,
612           lanalyzer_dump_can_write_encap, lanalyzer_dump_open },
613
614         /* WTAP_FILE_PPPDUMP */
615         { "pppd log (pppdump format)", "pppd", NULL, NULL, FALSE, FALSE,
616           NULL, NULL },
617
618         /* WTAP_FILE_RADCOM */
619         { "RADCOM WAN/LAN analyzer", "radcom", NULL, NULL, FALSE, FALSE,
620           NULL, NULL },
621
622         /* WTAP_FILE_SNOOP */
623         { "Sun snoop", "snoop", "snoop", "cap", FALSE, FALSE,
624           snoop_dump_can_write_encap, snoop_dump_open },
625
626         /* WTAP_FILE_SHOMITI */
627         { "Shomiti/Finisar Surveyor", "shomiti", "cap", NULL, FALSE, FALSE,
628           NULL, NULL },
629
630         /* WTAP_FILE_VMS */
631         { "TCPIPtrace (VMS)", "tcpiptrace", "txt", NULL, FALSE, FALSE,
632           NULL, NULL},
633
634         /* WTAP_FILE_K12 */
635         { "Tektronix K12xx 32-bit .rf5 format", "rf5", "rf5", NULL, TRUE, FALSE,
636                 k12_dump_can_write_encap, k12_dump_open },
637
638         /* WTAP_FILE_TOSHIBA */
639         { "Toshiba Compact ISDN Router snoop", "toshiba", "txt", NULL, FALSE, FALSE,
640           NULL, NULL },
641
642         /* WTAP_FILE_VISUAL_NETWORKS */
643         { "Visual Networks traffic capture", "visual", NULL, NULL, TRUE, FALSE,
644           visual_dump_can_write_encap, visual_dump_open },
645
646         /* WTAP_FILE_ETHERPEEK_V56 */
647         { "WildPackets Ether/TokenPeek (V5 & V6)", "peek56", "pkt", "tpc;apc;wpz", FALSE, FALSE,
648           NULL, NULL },
649
650         /* WTAP_FILE_ETHERPEEK_V7 */
651         { "WildPackets Ether/Token/AiroPeek (V7)", "peek7", "pkt", "tpc;apc;wpz", FALSE, FALSE,
652           NULL, NULL },
653
654         /* WTAP_FILE_AIROPEEK_V9 */
655         { "WildPackets Ether/AiroPeek (V9)", "peek9", "pkt", "tpc;apc;wpz", FALSE, FALSE,
656           NULL, NULL },
657
658         /* WTAP_FILE_MPEG */
659         { "MPEG", "mpeg", "mpeg", "mpg;mp3", FALSE, FALSE,
660           NULL, NULL },
661
662         /* WTAP_FILE_K12TEXT  */
663         { "K12 text file", "k12text", "txt", NULL, FALSE, FALSE,
664           k12text_dump_can_write_encap, k12text_dump_open },
665
666         /* WTAP_FILE_NETSCREEN */
667         { "NetScreen snoop text file", "netscreen", "txt", NULL, FALSE, FALSE,
668           NULL, NULL },
669
670         /* WTAP_FILE_COMMVIEW */
671         { "TamoSoft CommView", "commview", "ncf", NULL, FALSE, FALSE,
672           commview_dump_can_write_encap, commview_dump_open },
673
674         /* WTAP_FILE_BTSNOOP */
675         { "Symbian OS btsnoop", "btsnoop", "log", NULL, FALSE, FALSE,
676           btsnoop_dump_can_write_encap, btsnoop_dump_open_h4 },
677
678         /* WTAP_FILE_TNEF */
679         { "Transport-Neutral Encapsulation Format", "tnef", NULL, NULL, FALSE, FALSE,
680           NULL, NULL },
681
682         /* WTAP_FILE_DCT3TRACE */
683         { "Gammu DCT3 trace", "dct3trace", "xml", NULL, FALSE, FALSE,
684           NULL, NULL },
685
686         /* WTAP_FILE_PACKETLOGGER */
687         { "PacketLogger", "pklg", "pklg", NULL, FALSE, FALSE,
688           NULL, NULL },
689
690         /* WTAP_FILE_DAINTREE_SNA */
691         { "Daintree SNA", "dsna", "dcf", NULL, FALSE, FALSE,
692           NULL, NULL },
693
694         /* WTAP_FILE_NETSCALER_1_0 */
695         { "NetScaler Trace (Version 1.0)", "nstrace10", NULL, NULL, TRUE, FALSE,
696           nstrace_10_dump_can_write_encap, nstrace_dump_open },
697
698         /* WTAP_FILE_NETSCALER_2_0 */
699         { "NetScaler Trace (Version 2.0)", "nstrace20", "cap", NULL, TRUE, FALSE,
700           nstrace_20_dump_can_write_encap, nstrace_dump_open },
701
702         /* WTAP_FILE_JPEG_JFIF */
703         { "JPEG/JFIF", "jpeg", "jpg", "jpeg;jfif", FALSE, FALSE,
704           NULL, NULL },
705
706         /* WTAP_FILE_IPFIX */
707         { "IPFIX File Format", "ipfix", "pfx", "ipfix", FALSE, FALSE,
708           NULL, NULL },
709
710         /* WTAP_ENCAP_MIME */
711         { "MIME File Format", "mime", NULL, NULL, FALSE, FALSE,
712            NULL, NULL },
713
714         /* WTAP_FILE_AETHRA */
715         { "Aethra .aps file", "aethra", "aps", NULL, FALSE, FALSE,
716           NULL, NULL },
717
718         /* WTAP_FILE_MPEG_2_TS */
719         { "MPEG2 transport stream", "mp2t", "mp2t", "ts;mpg", FALSE, FALSE,
720           NULL, NULL },
721   
722         /* WTAP_FILE_VWR_80211 */
723         { "Ixia IxVeriWave .vwr Raw 802.11 Capture", "vwr80211", "*.vwr", ".vwr", FALSE, FALSE,
724           NULL, NULL },
725  
726         /* WTAP_FILE_VWR_ETH */
727         { "Ixia IxVeriWave .vwr Raw Ethernet Capture", "vwreth", "*.vwr", ".vwr", FALSE, FALSE,
728           NULL, NULL }
729
730 };
731
732 gint wtap_num_file_types = sizeof(dump_open_table_base) / sizeof(struct file_type_info);
733
734 static GArray*  dump_open_table_arr = NULL;
735 static const struct file_type_info* dump_open_table = dump_open_table_base;
736
737 /* initialize the open routines array if it has not being initialized yet */
738 static void init_file_types(void) {
739
740         if (dump_open_table_arr) return;
741
742         dump_open_table_arr = g_array_new(FALSE,TRUE,sizeof(struct file_type_info));
743
744         g_array_append_vals(dump_open_table_arr,dump_open_table_base,wtap_num_file_types);
745
746         dump_open_table = (const struct file_type_info*)(void *)dump_open_table_arr->data;
747 }
748
749 int wtap_register_file_type(const struct file_type_info* fi) {
750         init_file_types();
751
752         g_array_append_val(dump_open_table_arr,*fi);
753
754         dump_open_table = (const struct file_type_info*)(void *)dump_open_table_arr->data;
755
756         return wtap_num_file_types++;
757 }
758
759 int wtap_get_num_file_types(void)
760 {
761         return wtap_num_file_types;
762 }
763
764 /*
765  * Return TRUE if a capture with a given GArray of WTAP_ENCAP_ types
766  * can be written in a specified format, and FALSE if it can't.
767  */
768 gboolean
769 wtap_dump_can_write_encaps(int ft, const GArray *file_encaps)
770 {
771         guint i;
772
773         /*
774          * Can we write in this format?
775          */
776         if (!wtap_dump_can_open(ft)) {
777                 /* No. */
778                 return FALSE;
779         }
780
781         /*
782          * OK, we can write in that format; can we write out all the
783          * specified encapsulation types in that format?
784          */
785         if (file_encaps->len > 1) {
786                 /*
787                  * We have more than one encapsulation type,
788                  * so that format needs to support
789                  * WTAP_ENCAP_PER_PACKET.
790                  */
791                 if (!wtap_dump_can_write_encap(ft, WTAP_ENCAP_PER_PACKET))
792                         return FALSE;
793         }
794
795         for (i = 0; i < file_encaps->len; i++) {
796                 if (!wtap_dump_can_write_encap(ft,
797                     g_array_index(file_encaps, int, i)))
798                         return FALSE;
799         }
800         return TRUE;
801 }
802
803 /*
804  * Get a GArray of WTAP_FILE_ values for file types that can be used
805  * to save a file of a given type with a given GArray of WTAP_ENCAP_
806  * types.
807  */
808 GArray *
809 wtap_get_savable_file_types(int file_type, const GArray *file_encaps)
810 {
811         GArray *savable_file_types;
812         int ft;
813         int default_file_type = -1;
814         int other_file_type = -1;
815
816         /* Can we save this file in its own file type? */
817         if (wtap_dump_can_write(file_type, file_encaps)) {
818                 /* Yes - make that the default file type. */
819                 default_file_type = file_type;
820         } else {
821                 /* No - can we save it as a pcap-NG file? */
822                 if (wtap_dump_can_write(WTAP_FILE_PCAPNG, file_encaps)) {
823                         /* Yes - default to pcap-NG, instead. */
824                         default_file_type = WTAP_FILE_PCAPNG;
825                 } else {
826                         /* OK, find the first file type we *can* save it as. */
827                         default_file_type = -1;
828                         for (ft = 0; ft < WTAP_NUM_FILE_TYPES; ft++) {
829                                 if (wtap_dump_can_write(ft, file_encaps)) {
830                                         /* OK, got it. */
831                                         default_file_type = ft;
832                                 }
833                         }
834                 }
835         }
836
837         if (default_file_type == -1) {
838                 /* We don't support writing this file as any file type. */
839                 return NULL;
840         }
841
842         /* Allocate the array. */
843         savable_file_types = g_array_new(FALSE, FALSE, (guint)sizeof (int));
844
845         /* Put the default file format first in the list. */
846         g_array_append_val(savable_file_types, default_file_type);
847
848         /* If it's pcap, put pcap-NG right after it; otherwise, if it's
849            pcap-NG, put pcap right after it. */
850         if (default_file_type == WTAP_FILE_PCAP) {
851                 if (wtap_dump_can_write(WTAP_FILE_PCAPNG, file_encaps))
852                         other_file_type = WTAP_FILE_PCAPNG;
853         } else if (default_file_type == WTAP_FILE_PCAPNG) {
854                 if (wtap_dump_can_write(WTAP_FILE_PCAP, file_encaps))
855                         other_file_type = WTAP_FILE_PCAP;
856         }
857         if (other_file_type != -1)
858                 g_array_append_val(savable_file_types, other_file_type);
859
860         /* Add all the other file types that work. */
861         for (ft = 0; ft < WTAP_NUM_FILE_TYPES; ft++) {
862                 if (ft == WTAP_FILE_UNKNOWN)
863                         continue;       /* not a real file type */
864                 if (ft == default_file_type || ft == other_file_type)
865                         continue;       /* we've already done this one */
866                 if (wtap_dump_can_write(ft, file_encaps)) {
867                         /* OK, we can write it out in this type. */
868                         g_array_append_val(savable_file_types, ft);
869                 }
870         }
871
872         return savable_file_types;
873 }
874
875 /* Name that should be somewhat descriptive. */
876 const char *wtap_file_type_string(int filetype)
877 {
878         if (filetype < 0 || filetype >= wtap_num_file_types) {
879                 g_error("Unknown capture file type %d", filetype);
880                 /** g_error() does an abort() and thus never returns **/
881                 return "";
882         } else
883                 return dump_open_table[filetype].name;
884 }
885
886 /* Name to use in, say, a command-line flag specifying the type. */
887 const char *wtap_file_type_short_string(int filetype)
888 {
889         if (filetype < 0 || filetype >= wtap_num_file_types)
890                 return NULL;
891         else
892                 return dump_open_table[filetype].short_name;
893 }
894
895 /* Translate a short name to a capture file type. */
896 int wtap_short_string_to_file_type(const char *short_name)
897 {
898         int filetype;
899
900         for (filetype = 0; filetype < wtap_num_file_types; filetype++) {
901                 if (dump_open_table[filetype].short_name != NULL &&
902                     strcmp(short_name, dump_open_table[filetype].short_name) == 0)
903                         return filetype;
904         }
905         return -1;      /* no such file type, or we can't write it */
906 }
907
908 static GSList *add_extensions(GSList *extensions, const gchar *extension,
909     GSList *compressed_file_extensions)
910 {
911         GSList *compressed_file_extension;
912
913         /*
914          * Add the specified extension.
915          */
916         extensions = g_slist_append(extensions, g_strdup(extension));
917
918         /*
919          * Now add the extensions for compressed-file versions of
920          * that extension.
921          */
922         for (compressed_file_extension = compressed_file_extensions;
923             compressed_file_extension != NULL;
924             compressed_file_extension = g_slist_next(compressed_file_extension)) {
925                 extensions = g_slist_append(extensions,
926                     g_strdup_printf("%s.%s", extension,
927                       (gchar *)compressed_file_extension->data));
928         }
929
930         return extensions;
931 }
932
933 /* Return a list of file extensions that are used by the specified file type.
934
935    If include_compressed is TRUE, the list will include compressed
936    extensions, e.g. not just "pcap" but also "pcap.gz" if we can read
937    gzipped files.
938
939    All strings in the list are allocated with g_malloc() and must be freed
940    with g_free(). */
941 GSList *wtap_get_file_extensions_list(int filetype, gboolean include_compressed)
942 {
943         gchar **extensions_set, **extensionp;
944         gchar *extension;
945         GSList *compressed_file_extensions;
946         GSList *extensions;
947
948         if (filetype < 0 || filetype >= wtap_num_file_types)
949                 return NULL;    /* not a valid file type */
950
951         if (dump_open_table[filetype].default_file_extension == NULL)
952                 return NULL;    /* valid, but no extensions known */
953
954         extensions = NULL;      /* empty list, to start with */
955
956         /*
957          * If include_compressions is true, get the list of compressed-file
958          * extensions.
959          */
960         if (include_compressed)
961                 compressed_file_extensions = wtap_get_compressed_file_extensions();
962         else
963                 compressed_file_extensions = NULL;
964
965         /*
966          * Add the default extension, and all compressed variants of
967          * it.
968          */
969         extensions = add_extensions(extensions,
970             dump_open_table[filetype].default_file_extension,
971             compressed_file_extensions);
972
973         if (dump_open_table[filetype].additional_file_extensions != NULL) {
974                 /*
975                  * We have additional extensions; add them.
976                  *
977                  * First, split the extension-list string into a set of
978                  * extensions.
979                  */
980                 extensions_set = g_strsplit(dump_open_table[filetype].additional_file_extensions,
981                     ";", 0);
982
983                 /*
984                  * Add each of those extensions to the list.
985                  */
986                 for (extensionp = extensions_set; *extensionp != NULL;
987                     extensionp++) {
988                         extension = *extensionp;
989
990                         /*
991                          * Add the extension, and all compressed variants
992                          * of it.
993                          */
994                         extensions = add_extensions(extensions, extension,
995                             compressed_file_extensions);
996                 }
997
998                 g_strfreev(extensions_set);
999         }
1000         g_slist_free(compressed_file_extensions);
1001         return extensions;
1002 }
1003
1004 /*
1005  * Free a list returned by wtap_file_extensions_list().
1006  */
1007 void wtap_free_file_extensions_list(GSList *extensions)
1008 {
1009         GSList *extension;
1010
1011         for (extension = extensions; extension != NULL;
1012             extension = g_slist_next(extension)) {
1013                 g_free(extension->data);
1014         }
1015         g_slist_free(extensions);
1016 }
1017
1018 /* Return the default file extension to use with the specified file type;
1019    that's just the extension, without any ".". */
1020 const char *wtap_default_file_extension(int filetype)
1021 {
1022         if (filetype < 0 || filetype >= wtap_num_file_types)
1023                 return NULL;
1024         else
1025                 return dump_open_table[filetype].default_file_extension;
1026 }
1027
1028 gboolean wtap_dump_can_open(int filetype)
1029 {
1030         if (filetype < 0 || filetype >= wtap_num_file_types
1031             || dump_open_table[filetype].dump_open == NULL)
1032                 return FALSE;
1033
1034         return TRUE;
1035 }
1036
1037 gboolean wtap_dump_can_write_encap(int filetype, int encap)
1038 {
1039         if (filetype < 0 || filetype >= wtap_num_file_types
1040             || dump_open_table[filetype].can_write_encap == NULL)
1041                 return FALSE;
1042
1043         if ((*dump_open_table[filetype].can_write_encap)(encap) != 0)
1044                 return FALSE;
1045
1046         return TRUE;
1047 }
1048
1049 #ifdef HAVE_LIBZ
1050 gboolean wtap_dump_can_compress(int filetype)
1051 {
1052         /*
1053          * If this is an unknown file type, or if we have to
1054          * seek when writing out a file with this file type,
1055          * return FALSE.
1056          */
1057         if (filetype < 0 || filetype >= wtap_num_file_types
1058             || dump_open_table[filetype].writing_must_seek)
1059                 return FALSE;
1060
1061         return TRUE;
1062 }
1063 #else
1064 gboolean wtap_dump_can_compress(int filetype _U_)
1065 {
1066         return FALSE;
1067 }
1068 #endif
1069
1070 gboolean wtap_dump_has_name_resolution(int filetype)
1071 {
1072         if (filetype < 0 || filetype >= wtap_num_file_types
1073             || dump_open_table[filetype].has_name_resolution == FALSE)
1074                 return FALSE;
1075
1076         return TRUE;
1077 }
1078
1079 static gboolean wtap_dump_open_check(int filetype, int encap, gboolean comressed, int *err);
1080 static wtap_dumper* wtap_dump_alloc_wdh(int filetype, int encap, int snaplen,
1081                                         gboolean compressed, int *err);
1082 static gboolean wtap_dump_open_finish(wtap_dumper *wdh, int filetype, gboolean compressed, int *err);
1083
1084 static WFILE_T wtap_dump_file_open(wtap_dumper *wdh, const char *filename);
1085 static WFILE_T wtap_dump_file_fdopen(wtap_dumper *wdh, int fd);
1086 static int wtap_dump_file_close(wtap_dumper *wdh);
1087
1088 wtap_dumper* wtap_dump_open(const char *filename, int filetype, int encap,
1089                                 int snaplen, gboolean compressed, int *err)
1090 {
1091         return wtap_dump_open_ng(filename, filetype, encap,snaplen, compressed, NULL, NULL, err);
1092 }
1093
1094 wtap_dumper* wtap_dump_open_ng(const char *filename, int filetype, int encap,
1095                                 int snaplen, gboolean compressed, wtapng_section_t *shb_hdr, wtapng_iface_descriptions_t *idb_inf, int *err)
1096 {
1097         wtap_dumper *wdh;
1098         WFILE_T fh;
1099
1100         /* Check whether we can open a capture file with that file type
1101            and that encapsulation. */
1102         if (!wtap_dump_open_check(filetype, encap, compressed, err))
1103                 return NULL;
1104
1105         /* Allocate a data structure for the output stream. */
1106         wdh = wtap_dump_alloc_wdh(filetype, encap, snaplen, compressed, err);
1107         if (wdh == NULL)
1108                 return NULL;    /* couldn't allocate it */
1109
1110         /* Set Section Header Block data */
1111         wdh->shb_hdr = shb_hdr;
1112         /* Set Interface Description Block data */
1113         if ((idb_inf != NULL) && (idb_inf->number_of_interfaces > 0)) {
1114                 wdh->number_of_interfaces = idb_inf->number_of_interfaces;
1115                 wdh->interface_data = idb_inf->interface_data;
1116         } else {
1117                 wtapng_if_descr_t descr;
1118
1119                 descr.wtap_encap = encap;
1120                 descr.time_units_per_second = 0;
1121                 descr.link_type = wtap_wtap_encap_to_pcap_encap(encap);
1122                 descr.snap_len = snaplen;
1123                 descr.opt_comment = NULL;
1124                 descr.if_name = NULL;
1125                 descr.if_description = NULL;
1126                 descr.if_speed = 0;
1127                 descr.if_tsresol = 6;
1128                 descr.if_filter_str= NULL;
1129                 descr.bpf_filter_len= 0;
1130                 descr.if_filter_bpf_bytes= NULL;
1131                 descr.if_os = NULL;
1132                 descr.if_fcslen = -1;
1133                 descr.num_stat_entries = 0;          /* Number of ISB:s */
1134                 descr.interface_statistics = NULL;
1135                 wdh->number_of_interfaces= 1;
1136                 wdh->interface_data= g_array_new(FALSE, FALSE, sizeof(wtapng_if_descr_t));
1137                 g_array_append_val(wdh->interface_data, descr);
1138         }
1139
1140         /* "-" means stdout */
1141         if (strcmp(filename, "-") == 0) {
1142                 if (compressed) {
1143                         *err = EINVAL;  /* XXX - return a Wiretap error code for this */
1144                         g_free(wdh);
1145                         return NULL;    /* compress won't work on stdout */
1146                 }
1147 #ifdef _WIN32
1148                 if (_setmode(fileno(stdout), O_BINARY) == -1) {
1149                         /* "Should not happen" */
1150                         *err = errno;
1151                         g_free(wdh);
1152                         return NULL;    /* couldn't put standard output in binary mode */
1153                 }
1154 #endif
1155                 wdh->fh = stdout;
1156         } else {
1157                 /* In case "fopen()" fails but doesn't set "errno", set "errno"
1158                    to a generic "the open failed" error. */
1159                 errno = WTAP_ERR_CANT_OPEN;
1160                 fh = wtap_dump_file_open(wdh, filename);
1161                 if (fh == NULL) {
1162                         *err = errno;
1163                         g_free(wdh);
1164                         return NULL;    /* can't create file */
1165                 }
1166                 wdh->fh = fh;
1167         }
1168
1169         if (!wtap_dump_open_finish(wdh, filetype, compressed, err)) {
1170                 /* Get rid of the file we created; we couldn't finish
1171                    opening it. */
1172                 if (wdh->fh != stdout) {
1173                         wtap_dump_file_close(wdh);
1174                         ws_unlink(filename);
1175                 }
1176                 g_free(wdh);
1177                 return NULL;
1178         }
1179         return wdh;
1180 }
1181
1182 wtap_dumper* wtap_dump_fdopen(int fd, int filetype, int encap, int snaplen,
1183                                 gboolean compressed, int *err)
1184 {
1185         return wtap_dump_fdopen_ng(fd, filetype, encap, snaplen, compressed, NULL, NULL, err);
1186 }
1187
1188 wtap_dumper* wtap_dump_fdopen_ng(int fd, int filetype, int encap, int snaplen,
1189                                 gboolean compressed, wtapng_section_t *shb_hdr, wtapng_iface_descriptions_t *idb_inf, int *err)
1190 {
1191         wtap_dumper *wdh;
1192         WFILE_T fh;
1193
1194         /* Check whether we can open a capture file with that file type
1195            and that encapsulation. */
1196         if (!wtap_dump_open_check(filetype, encap, compressed, err))
1197                 return NULL;
1198
1199         /* Allocate a data structure for the output stream. */
1200         wdh = wtap_dump_alloc_wdh(filetype, encap, snaplen, compressed, err);
1201         if (wdh == NULL)
1202                 return NULL;    /* couldn't allocate it */
1203
1204 #ifdef _WIN32
1205         if (fd == 1) {
1206                 if (_setmode(fileno(stdout), O_BINARY) == -1) {
1207                         /* "Should not happen" */
1208                         *err = errno;
1209                         g_free(wdh);
1210                         return NULL;    /* couldn't put standard output in binary mode */
1211                 }
1212         }
1213 #endif
1214
1215         /* Set Section Header Block data */
1216         wdh->shb_hdr = shb_hdr;
1217         /* Set Interface Description Block data */
1218         if ((idb_inf != NULL) && (idb_inf->number_of_interfaces > 0)) {
1219                 wdh->number_of_interfaces = idb_inf->number_of_interfaces;
1220                 wdh->interface_data = idb_inf->interface_data;
1221         } else {
1222                 wtapng_if_descr_t descr;
1223
1224                 descr.wtap_encap = encap;
1225                 descr.time_units_per_second = 0;
1226                 descr.link_type = wtap_wtap_encap_to_pcap_encap(encap);
1227                 descr.snap_len = snaplen;
1228                 descr.opt_comment = NULL;
1229                 descr.if_name = NULL;
1230                 descr.if_description = NULL;
1231                 descr.if_speed = 0;
1232                 descr.if_tsresol = 6;
1233                 descr.if_filter_str= NULL;
1234                 descr.bpf_filter_len= 0;
1235                 descr.if_filter_bpf_bytes= NULL;
1236                 descr.if_os = NULL;
1237                 descr.if_fcslen = -1;
1238                 descr.num_stat_entries = 0;          /* Number of ISB:s */
1239                 descr.interface_statistics = NULL;
1240                 wdh->number_of_interfaces= 1;
1241                 wdh->interface_data= g_array_new(FALSE, FALSE, sizeof(wtapng_if_descr_t));
1242                 g_array_append_val(wdh->interface_data, descr);
1243         }
1244
1245         /* In case "fopen()" fails but doesn't set "errno", set "errno"
1246            to a generic "the open failed" error. */
1247         errno = WTAP_ERR_CANT_OPEN;
1248         fh = wtap_dump_file_fdopen(wdh, fd);
1249         if (fh == NULL) {
1250                 *err = errno;
1251                 g_free(wdh);
1252                 return NULL;    /* can't create standard I/O stream */
1253         }
1254         wdh->fh = fh;
1255
1256         if (!wtap_dump_open_finish(wdh, filetype, compressed, err)) {
1257                 wtap_dump_file_close(wdh);
1258                 g_free(wdh);
1259                 return NULL;
1260         }
1261         return wdh;
1262 }
1263
1264 static gboolean wtap_dump_open_check(int filetype, int encap, gboolean compressed, int *err)
1265 {
1266         if (!wtap_dump_can_open(filetype)) {
1267                 /* Invalid type, or type we don't know how to write. */
1268                 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
1269                 return FALSE;
1270         }
1271
1272         /* OK, we know how to write that type; can we write the specified
1273            encapsulation type? */
1274         *err = (*dump_open_table[filetype].can_write_encap)(encap);
1275         if (*err != 0)
1276                 return FALSE;
1277
1278         /* if compression is wanted, do we support this for this filetype? */
1279         if(compressed && !wtap_dump_can_compress(filetype)) {
1280                 *err = WTAP_ERR_COMPRESSION_NOT_SUPPORTED;
1281                 return FALSE;
1282         }
1283
1284         *err = (*dump_open_table[filetype].can_write_encap)(encap);
1285         if (*err != 0)
1286                 return FALSE;
1287
1288         /* All systems go! */
1289         return TRUE;
1290 }
1291
1292 static wtap_dumper* wtap_dump_alloc_wdh(int filetype, int encap, int snaplen,
1293                                         gboolean compressed, int *err)
1294 {
1295         wtap_dumper *wdh;
1296
1297         wdh = (wtap_dumper *)g_malloc0(sizeof (wtap_dumper));
1298         if (wdh == NULL) {
1299                 *err = errno;
1300                 return NULL;
1301         }
1302
1303         wdh->file_type = filetype;
1304         wdh->snaplen = snaplen;
1305         wdh->encap = encap;
1306         wdh->compressed = compressed;
1307         return wdh;
1308 }
1309
1310 static gboolean wtap_dump_open_finish(wtap_dumper *wdh, int filetype, gboolean compressed, int *err)
1311 {
1312         int fd;
1313         gboolean cant_seek;
1314
1315         /* Can we do a seek on the file descriptor?
1316            If not, note that fact. */
1317         if(compressed) {
1318                 cant_seek = TRUE;
1319         } else {
1320                 fd = fileno((FILE *)wdh->fh);
1321                 if (lseek(fd, 1, SEEK_CUR) == -1)
1322                         cant_seek = TRUE;
1323                 else {
1324                         /* Undo the seek. */
1325                         lseek(fd, 0, SEEK_SET);
1326                         cant_seek = FALSE;
1327                 }
1328         }
1329
1330         /* If this file type requires seeking, and we can't seek, fail. */
1331         if (dump_open_table[filetype].writing_must_seek && cant_seek) {
1332                 *err = WTAP_ERR_CANT_WRITE_TO_PIPE;
1333                 return FALSE;
1334         }
1335
1336         /* Now try to open the file for writing. */
1337         if (!(*dump_open_table[filetype].dump_open)(wdh, err)) {
1338                 return FALSE;
1339         }
1340
1341         return TRUE;    /* success! */
1342 }
1343
1344 gboolean wtap_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
1345                    const union wtap_pseudo_header *pseudo_header, const guint8 *pd, int *err)
1346 {
1347         return (wdh->subtype_write)(wdh, phdr, pseudo_header, pd, err);
1348 }
1349
1350 void wtap_dump_flush(wtap_dumper *wdh)
1351 {
1352 #ifdef HAVE_LIBZ
1353         if(wdh->compressed) {
1354                 gzwfile_flush((GZWFILE_T)wdh->fh);
1355         } else
1356 #endif
1357         {
1358                 fflush((FILE *)wdh->fh);
1359         }
1360 }
1361
1362 gboolean wtap_dump_close(wtap_dumper *wdh, int *err)
1363 {
1364         gboolean ret = TRUE;
1365
1366         if (wdh->subtype_close != NULL) {
1367                 /* There's a close routine for this dump stream. */
1368                 if (!(wdh->subtype_close)(wdh, err))
1369                         ret = FALSE;
1370         }
1371         errno = WTAP_ERR_CANT_CLOSE;
1372         /* Don't close stdout */
1373         if (wdh->fh != stdout) {
1374                 if (wtap_dump_file_close(wdh) == EOF) {
1375                         if (ret) {
1376                                 /* The per-format close function succeeded,
1377                                    but the fclose didn't.  Save the reason
1378                                    why, if our caller asked for it. */
1379                                 if (err != NULL)
1380                                         *err = errno;
1381                         }
1382                         ret = FALSE;
1383                 }
1384         } else {
1385                 /* as we don't close stdout, at least try to flush it */
1386                 wtap_dump_flush(wdh);
1387         }
1388         if (wdh->priv != NULL)
1389                 g_free(wdh->priv);
1390         g_free(wdh);
1391         return ret;
1392 }
1393
1394 gint64 wtap_get_bytes_dumped(wtap_dumper *wdh)
1395 {
1396         return wdh->bytes_dumped;
1397 }
1398
1399 void wtap_set_bytes_dumped(wtap_dumper *wdh, gint64 bytes_dumped)
1400 {
1401         wdh->bytes_dumped = bytes_dumped;
1402 }
1403
1404 gboolean wtap_dump_set_addrinfo_list(wtap_dumper *wdh, struct addrinfo *addrinfo_list)
1405 {
1406         if (!wdh || wdh->file_type < 0 || wdh->file_type >= wtap_num_file_types
1407                 || dump_open_table[wdh->file_type].has_name_resolution == FALSE)
1408                         return FALSE;
1409         wdh->addrinfo_list = addrinfo_list;
1410         return TRUE;
1411 }
1412
1413 /* internally open a file for writing (compressed or not) */
1414 #ifdef HAVE_LIBZ
1415 static WFILE_T wtap_dump_file_open(wtap_dumper *wdh, const char *filename)
1416 {
1417         if(wdh->compressed) {
1418                 return gzwfile_open(filename);
1419         } else {
1420                 return ws_fopen(filename, "wb");
1421         }
1422 }
1423 #else
1424 static WFILE_T wtap_dump_file_open(wtap_dumper *wdh _U_, const char *filename)
1425 {
1426         return ws_fopen(filename, "wb");
1427 }
1428 #endif
1429
1430 /* internally open a file for writing (compressed or not) */
1431 #ifdef HAVE_LIBZ
1432 static WFILE_T wtap_dump_file_fdopen(wtap_dumper *wdh, int fd)
1433 {
1434         if(wdh->compressed) {
1435                 return gzwfile_fdopen(fd);
1436         } else {
1437                 return fdopen(fd, "wb");
1438         }
1439 }
1440 #else
1441 static WFILE_T wtap_dump_file_fdopen(wtap_dumper *wdh _U_, int fd)
1442 {
1443         return fdopen(fd, "wb");
1444 }
1445 #endif
1446
1447 /* internally writing raw bytes (compressed or not) */
1448 gboolean wtap_dump_file_write(wtap_dumper *wdh, const void *buf, size_t bufsize,
1449                      int *err)
1450 {
1451         size_t nwritten;
1452
1453 #ifdef HAVE_LIBZ
1454         if (wdh->compressed) {
1455                 nwritten = gzwfile_write((GZWFILE_T)wdh->fh, buf, (unsigned) bufsize);
1456                 /*
1457                  * gzwfile_write() returns 0 on error.
1458                  */
1459                 if (nwritten == 0) {
1460                         *err = gzwfile_geterr((GZWFILE_T)wdh->fh);
1461                         return FALSE;
1462                 }
1463         } else
1464 #endif
1465         {
1466                 nwritten = fwrite(buf, 1, bufsize, (FILE *)wdh->fh);
1467                 /*
1468                  * At least according to the Mac OS X man page,
1469                  * this can return a short count on an error.
1470                  */
1471                 if (nwritten != bufsize) {
1472                         if (ferror((FILE *)wdh->fh))
1473                                 *err = errno;
1474                         else
1475                                 *err = WTAP_ERR_SHORT_WRITE;
1476                         return FALSE;
1477                 }
1478         }
1479         return TRUE;
1480 }
1481
1482 /* internally close a file for writing (compressed or not) */
1483 static int wtap_dump_file_close(wtap_dumper *wdh)
1484 {
1485 #ifdef HAVE_LIBZ
1486         if(wdh->compressed) {
1487                 return gzwfile_close((GZWFILE_T)wdh->fh);
1488         } else
1489 #endif
1490         {
1491                 return fclose((FILE *)wdh->fh);
1492         }
1493 }