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