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