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