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