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