Fix capinfo: ** ERROR **: Unknown capture file type 61
[obnox/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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdlib.h>
30
31 #ifdef HAVE_FCNTL_H
32 #include <fcntl.h>
33 #endif
34
35 #ifdef HAVE_UNISTD_H
36 #include <unistd.h>
37 #endif
38
39 #include <errno.h>
40
41 #include <wsutil/file_util.h>
42
43 #include "wtap-int.h"
44 #include "file_wrappers.h"
45 #include "buffer.h"
46 #include "lanalyzer.h"
47 #include "airopeek9.h"
48 #include "ngsniffer.h"
49 #include "radcom.h"
50 #include "ascendtext.h"
51 #include "nettl.h"
52 #include "libpcap.h"
53 #include "snoop.h"
54 #include "iptrace.h"
55 #include "iseries.h"
56 #include "netmon.h"
57 #include "netxray.h"
58 #include "toshiba.h"
59 #include "eyesdn.h"
60 #include "i4btrace.h"
61 #include "csids.h"
62 #include "pppdump.h"
63 #include "etherpeek.h"
64 #include "vms.h"
65 #include "dbs-etherwatch.h"
66 #include "visual.h"
67 #include "cosine.h"
68 #include "5views.h"
69 #include "erf.h"
70 #include "hcidump.h"
71 #include "network_instruments.h"
72 #include "k12.h"
73 #include "ber.h"
74 #include "catapult_dct2000.h"
75 #include "mpeg.h"
76 #include "netscreen.h"
77 #include "commview.h"
78 #include "pcapng.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
88
89 /* The open_file_* routines should return:
90  *
91  *      -1 on an I/O error;
92  *
93  *      1 if the file they're reading is one of the types it handles;
94  *
95  *      0 if the file they're reading isn't the type they're checking for.
96  *
97  * If the routine handles this type of file, it should set the "file_type"
98  * field in the "struct wtap" to the type of the file.
99  *
100  * Put the trace files that are merely saved telnet-sessions last, since it's
101  * possible that you could have captured someone a router telnet-session
102  * using another tool. So, a libpcap trace of an toshiba "snoop" session
103  * should be discovered as a libpcap file, not a toshiba file.
104  */
105
106
107 static wtap_open_routine_t open_routines_base[] = {
108         /* Files that have magic bytes in fixed locations. These
109          * are easy to identify.
110          */
111         libpcap_open,
112         lanalyzer_open,
113         ngsniffer_open,
114         snoop_open,
115         iptrace_open,
116         netmon_open,
117         netxray_open,
118         radcom_open,
119         nettl_open,
120         visual_open,
121         _5views_open,
122         network_instruments_open,
123         airopeek9_open,
124         dbs_etherwatch_open,
125         k12_open,
126         catapult_dct2000_open,
127         ber_open,
128         pcapng_open,
129         btsnoop_open,
130         packetlogger_open, /* This type does not have a magic number, but its
131                             * files are sometimes grabbed by mpeg_open. */
132         mpeg_open,
133         tnef_open,
134         dct3trace_open,
135         daintree_sna_open,
136         mime_file_open,
137         /* Files that don't have magic bytes at a fixed location,
138          * but that instead require a heuristic of some sort to
139          * identify them.  This includes the ASCII trace files that
140          * would be, for example, saved copies of a Telnet session
141          * to some box.
142          */
143
144         /* I put NetScreen *before* erf, because there were some
145          * false positives with my test-files (Sake Blok, July 2007)
146          */
147         netscreen_open,
148         erf_open,
149         ipfix_open,
150         k12text_open,
151         etherpeek_open,
152         pppdump_open,
153         iseries_open,
154         ascend_open,
155         eyesdn_open,
156         toshiba_open,
157         i4btrace_open,
158         csids_open,
159         vms_open,
160         cosine_open,
161         hcidump_open,
162         commview_open,
163         nstrace_open
164 };
165
166 #define N_FILE_TYPES    (sizeof open_routines_base / sizeof open_routines_base[0])
167
168 static wtap_open_routine_t* open_routines = NULL;
169
170 static GArray* open_routines_arr = NULL;
171
172
173 /* initialize the open routines array if it has not been initialized yet */
174 static void init_open_routines(void) {
175
176         if (open_routines_arr) return;
177
178         open_routines_arr = g_array_new(FALSE,TRUE,sizeof(wtap_open_routine_t));
179
180         g_array_append_vals(open_routines_arr,open_routines_base,N_FILE_TYPES);
181
182         open_routines = (wtap_open_routine_t*)(void *)open_routines_arr->data;
183 }
184
185 void wtap_register_open_routine(wtap_open_routine_t open_routine, gboolean has_magic) {
186         init_open_routines();
187
188         if (has_magic)
189                 g_array_prepend_val(open_routines_arr,open_routine);
190         else
191                 g_array_append_val(open_routines_arr,open_routine);
192
193         open_routines = (wtap_open_routine_t*)(void *)open_routines_arr->data;
194 }
195
196 /*
197  * Visual C++ on Win32 systems doesn't define these.  (Old UNIX systems don't
198  * define them either.)
199  *
200  * Visual C++ on Win32 systems doesn't define S_IFIFO, it defines _S_IFIFO.
201  */
202 #ifndef S_ISREG
203 #define S_ISREG(mode)   (((mode) & S_IFMT) == S_IFREG)
204 #endif
205 #ifndef S_IFIFO
206 #define S_IFIFO _S_IFIFO
207 #endif
208 #ifndef S_ISFIFO
209 #define S_ISFIFO(mode)  (((mode) & S_IFMT) == S_IFIFO)
210 #endif
211 #ifndef S_ISDIR
212 #define S_ISDIR(mode)   (((mode) & S_IFMT) == S_IFDIR)
213 #endif
214
215 /* Opens a file and prepares a wtap struct.
216    If "do_random" is TRUE, it opens the file twice; the second open
217    allows the application to do random-access I/O without moving
218    the seek offset for sequential I/O, which is used by Wireshark
219    so that it can do sequential I/O to a capture file that's being
220    written to as new packets arrive independently of random I/O done
221    to display protocol trees for packets when they're selected. */
222 wtap* wtap_open_offline(const char *filename, int *err, char **err_info,
223                         gboolean do_random)
224 {
225         int     fd;
226         ws_statb64 statb;
227         wtap    *wth;
228         unsigned int    i;
229         gboolean use_stdin = FALSE;
230
231         /* open standard input if filename is '-' */
232         if (strcmp(filename, "-") == 0)
233                 use_stdin = TRUE;
234
235         /* First, make sure the file is valid */
236         if (use_stdin) {
237                 if (ws_fstat64(0, &statb) < 0) {
238                         *err = errno;
239                         return NULL;
240                 }
241         } else {
242                 if (ws_stat64(filename, &statb) < 0) {
243                         *err = errno;
244                         return NULL;
245                 }
246         }
247         if (S_ISFIFO(statb.st_mode)) {
248                 /*
249                  * Opens of FIFOs are allowed only when not opening
250                  * for random access.
251                  *
252                  * XXX - currently, we do seeking when trying to find
253                  * out the file type, so we don't actually support
254                  * opening FIFOs.  However, we may eventually
255                  * do buffering that allows us to do at least some
256                  * file type determination even on pipes, so we
257                  * allow FIFO opens and let things fail later when
258                  * we try to seek.
259                  */
260                 if (do_random) {
261                         *err = WTAP_ERR_RANDOM_OPEN_PIPE;
262                         return NULL;
263                 }
264         } else if (S_ISDIR(statb.st_mode)) {
265                 /*
266                  * Return different errors for "this is a directory"
267                  * and "this is some random special file type", so
268                  * the user can get a potentially more helpful error.
269                  */
270                 *err = EISDIR;
271                 return NULL;
272         } else if (! S_ISREG(statb.st_mode)) {
273                 *err = WTAP_ERR_NOT_REGULAR_FILE;
274                 return NULL;
275         }
276
277         /*
278          * We need two independent descriptors for random access, so
279          * they have different file positions.  If we're opening the
280          * standard input, we can only dup it to get additional
281          * descriptors, so we can't have two independent descriptors,
282          * and thus can't do random access.
283          */
284         if (use_stdin && do_random) {
285                 *err = WTAP_ERR_RANDOM_OPEN_STDIN;
286                 return NULL;
287         }
288
289         errno = ENOMEM;
290         wth = (wtap *)g_malloc0(sizeof(wtap));
291
292         /* Open the file */
293         errno = WTAP_ERR_CANT_OPEN;
294         if (use_stdin) {
295                 /*
296                  * We dup FD 0, so that we don't have to worry about
297                  * a file_close of wth->fh closing the standard
298                  * input of the process.
299                  */
300                 fd = ws_dup(0);
301                 if (fd < 0) {
302                         *err = errno;
303                         g_free(wth);
304                         return NULL;
305                 }
306 #ifdef _WIN32
307                 if (_setmode(fd, O_BINARY) == -1) {
308                         /* "Shouldn't happen" */
309                         *err = errno;
310                         g_free(wth);
311                         return NULL;
312                 }
313 #endif
314                 if (!(wth->fh = filed_open(fd))) {
315                         *err = errno;
316                         ws_close(fd);
317                         g_free(wth);
318                         return NULL;
319                 }
320         } else {
321                 if (!(wth->fh = file_open(filename))) {
322                         *err = errno;
323                         g_free(wth);
324                         return NULL;
325                 }
326         }
327
328         if (do_random) {
329                 if (!(wth->random_fh = file_open(filename))) {
330                         *err = errno;
331                         file_close(wth->fh);
332                         g_free(wth);
333                         return NULL;
334                 }
335         } else
336                 wth->random_fh = NULL;
337
338         /* initialization */
339         wth->file_encap = WTAP_ENCAP_UNKNOWN;
340         wth->data_offset = 0;
341         wth->subtype_sequential_close = NULL;
342         wth->subtype_close = NULL;
343         wth->tsprecision = WTAP_FILE_TSPREC_USEC;
344         wth->priv = NULL;
345
346         init_open_routines();
347         if (wth->random_fh) {
348                 wth->fast_seek = g_ptr_array_new();
349
350                 file_set_random_access(wth->fh, FALSE, wth->fast_seek);
351                 file_set_random_access(wth->random_fh, TRUE, wth->fast_seek);
352         }
353
354         /* Try all file types */
355         for (i = 0; i < open_routines_arr->len; i++) {
356                 /* Seek back to the beginning of the file; the open routine
357                    for the previous file type may have left the file
358                    position somewhere other than the beginning, and the
359                    open routine for this file type will probably want
360                    to start reading at the beginning.
361
362                    Initialize the data offset while we're at it. */
363                 if (file_seek(wth->fh, 0, SEEK_SET, err) == -1) {
364                         /* I/O error - give up */
365                         if (wth->random_fh != NULL)
366                                 file_close(wth->random_fh);
367                         file_close(wth->fh);
368                         g_free(wth);
369                         return NULL;
370                 }
371                 wth->data_offset = 0;
372
373                 switch ((*open_routines[i])(wth, err, err_info)) {
374
375                 case -1:
376                         /* I/O error - give up */
377                         if (wth->random_fh != NULL)
378                                 file_close(wth->random_fh);
379                         file_close(wth->fh);
380                         g_free(wth);
381                         return NULL;
382
383                 case 0:
384                         /* No I/O error, but not that type of file */
385                         break;
386
387                 case 1:
388                         /* We found the file type */
389                         goto success;
390                 }
391         }
392
393         /* Well, it's not one of the types of file we know about. */
394         wtap_close(wth);
395         *err = WTAP_ERR_FILE_UNKNOWN_FORMAT;
396         return NULL;
397
398 success:
399         wth->frame_buffer = (struct Buffer *)g_malloc(sizeof(struct Buffer));
400         buffer_init(wth->frame_buffer, 1500);
401         return wth;
402 }
403
404 /* Table of the file types we know about. */
405 static const struct file_type_info dump_open_table_base[] = {
406         /* WTAP_FILE_UNKNOWN (only used internally for initialization) */
407         { NULL, NULL, NULL, NULL, FALSE, FALSE,
408           NULL, NULL },
409
410         /* WTAP_FILE_WTAP (only used internally while capturing) */
411         { NULL, NULL, NULL, NULL, FALSE, FALSE,
412           NULL, NULL },
413
414         /* WTAP_FILE_PCAP */
415         { "Wireshark/tcpdump/... - libpcap", "libpcap", "*.pcap;*.cap", ".pcap", FALSE, FALSE,
416           libpcap_dump_can_write_encap, libpcap_dump_open },
417
418         /* WTAP_FILE_PCAP_NSEC */
419         { "Wireshark - nanosecond libpcap", "nseclibpcap", "*.pcap;*.cap", ".pcap", FALSE, FALSE,
420           libpcap_dump_can_write_encap, libpcap_dump_open },
421
422         /* WTAP_FILE_PCAP_AIX */
423         { "AIX tcpdump - libpcap", "aixlibpcap", "*.pcap;*.cap", ".pcap", FALSE, FALSE,
424           NULL, NULL },
425
426         /* WTAP_FILE_PCAP_SS991029 */
427         { "Modified tcpdump - libpcap", "modlibpcap", "*.pcap;*.cap", ".pcap", FALSE, FALSE,
428           libpcap_dump_can_write_encap, libpcap_dump_open },
429
430         /* WTAP_FILE_PCAP_NOKIA */
431         { "Nokia tcpdump - libpcap ", "nokialibpcap", "*.pcap;*.cap", ".pcap", FALSE, FALSE,
432           libpcap_dump_can_write_encap, libpcap_dump_open },
433
434         /* WTAP_FILE_PCAP_SS990417 */
435         { "RedHat 6.1 tcpdump - libpcap", "rh6_1libpcap", "*.pcap;*.cap", ".pcap", FALSE, FALSE,
436           libpcap_dump_can_write_encap, libpcap_dump_open },
437
438         /* WTAP_FILE_PCAP_SS990915 */
439         { "SuSE 6.3 tcpdump - libpcap", "suse6_3libpcap", "*.pcap;*.cap", ".pcap", FALSE, FALSE,
440           libpcap_dump_can_write_encap, libpcap_dump_open },
441
442         /* WTAP_FILE_5VIEWS */
443         { "Accellent 5Views capture", "5views", "*.5vw", ".5vw", TRUE, FALSE,
444           _5views_dump_can_write_encap, _5views_dump_open },
445
446         /* WTAP_FILE_IPTRACE_1_0 */
447         { "AIX iptrace 1.0", "iptrace_1", "*.*", NULL, FALSE, FALSE,
448           NULL, NULL },
449
450         /* WTAP_FILE_IPTRACE_2_0 */
451         { "AIX iptrace 2.0", "iptrace_2", "*.*", NULL, FALSE, FALSE,
452           NULL, NULL },
453
454         /* WTAP_FILE_BER */
455         { "ASN.1 Basic Encoding Rules", "ber", "*.*", NULL, FALSE, FALSE,
456                 NULL, NULL },
457
458         /* WTAP_FILE_HCIDUMP */
459         { "Bluetooth HCI dump", "hcidump", "*.*", NULL, FALSE, FALSE,
460           NULL, NULL },
461
462         /* WTAP_FILE_CATAPULT_DCT2000 */
463         { "Catapult DCT2000 trace (.out format)", "dct2000", "*.out", ".out", FALSE, FALSE,
464           catapult_dct2000_dump_can_write_encap, catapult_dct2000_dump_open },
465
466         /* WTAP_FILE_NETXRAY_OLD */
467         { "Cinco Networks NetXRay 1.x", "netxray1", "*.cap", ".cap", TRUE, FALSE,
468           NULL, NULL },
469
470         /* WTAP_FILE_NETXRAY_1_0 */
471         { "Cinco Networks NetXRay 2.0 or later", "netxray2", "*.cap", ".cap", TRUE, FALSE,
472           NULL, NULL },
473
474         /* WTAP_FILE_COSINE */
475         { "CoSine IPSX L2 capture", "cosine", "*.*", NULL, FALSE, FALSE,
476           NULL, NULL },
477
478         /* WTAP_FILE_CSIDS */
479         { "CSIDS IPLog", "csids", "*.*", NULL, FALSE, FALSE,
480           NULL, NULL },
481
482         /* WTAP_FILE_DBS_ETHERWATCH */
483         { "DBS Etherwatch (VMS)", "etherwatch", "*.*", NULL, FALSE, FALSE,
484           NULL, NULL},
485
486         /* WTAP_FILE_ERF */
487         { "Endace ERF capture", "erf", "*.erf", ".erf", FALSE, FALSE,
488           NULL, NULL },
489
490         /* WTAP_FILE_EYESDN */
491         { "EyeSDN USB S0/E1 ISDN trace format", "eyesdn", "*.trc", ".trc", FALSE, FALSE,
492            eyesdn_dump_can_write_encap, eyesdn_dump_open },
493
494         /* WTAP_FILE_NETTL */
495         { "HP-UX nettl trace", "nettl", "*.TRC0;*.TRC1", ".TRC0", FALSE, FALSE,
496           nettl_dump_can_write_encap, nettl_dump_open },
497
498         /* WTAP_FILE_ISERIES */
499         { "IBM iSeries comm. trace (ASCII)", "iseries_ascii", "*.*", NULL, FALSE, FALSE,
500           NULL, NULL },
501
502         /* WTAP_FILE_ISERIES_UNICODE */
503         { "IBM iSeries comm. trace (UNICODE)", "iseries_unicode", "*.*", NULL, FALSE, FALSE,
504           NULL, NULL },
505
506         /* WTAP_FILE_I4BTRACE */
507         { "I4B ISDN trace", "i4btrace", "*.*", NULL, FALSE, FALSE,
508           NULL, NULL },
509
510         /* WTAP_FILE_ASCEND */
511         { "Lucent/Ascend access server trace", "ascend", "*.*", NULL, FALSE, FALSE,
512           NULL, NULL },
513
514         /* WTAP_FILE_NETMON_1_x */
515         { "Microsoft NetMon 1.x", "netmon1", "*.cap", ".cap", TRUE, FALSE,
516           netmon_dump_can_write_encap, netmon_dump_open },
517
518         /* WTAP_FILE_NETMON_2_x */
519         { "Microsoft NetMon 2.x", "netmon2", "*.cap", ".cap", TRUE, FALSE,
520           netmon_dump_can_write_encap, netmon_dump_open },
521
522         /* WTAP_FILE_NGSNIFFER_UNCOMPRESSED */
523         { "NA Sniffer (DOS)", "ngsniffer", "*.cap;*.enc;*.trc;*.fdc;*.syc", ".cap", FALSE, FALSE,
524           ngsniffer_dump_can_write_encap, ngsniffer_dump_open },
525
526         /* WTAP_FILE_NGSNIFFER_COMPRESSED */
527         { "NA Sniffer (DOS), compressed", "ngsniffer_comp", "*.caz", ".caz", FALSE, FALSE,
528           NULL, NULL },
529
530         /* WTAP_FILE_NETXRAY_1_1 */
531         { "NA Sniffer (Windows) 1.1", "ngwsniffer_1_1", "*.cap", ".cap", TRUE, FALSE,
532           netxray_dump_can_write_encap_1_1, netxray_dump_open_1_1 },
533
534         /* WTAP_FILE_NETXRAY_2_00x */
535         { "NA Sniffer (Windows) 2.00x", "ngwsniffer_2_0", "*.cap", ".cap", TRUE, FALSE,
536           netxray_dump_can_write_encap_2_0, netxray_dump_open_2_0 },
537
538         /* WTAP_FILE_NETWORK_INSTRUMENTS */
539         { "Network Instruments Observer", "niobserverv", "*.bfr", ".bfr", FALSE, FALSE,
540           network_instruments_dump_can_write_encap, network_instruments_dump_open },
541
542         /* WTAP_FILE_LANALYZER */
543         { "Novell LANalyzer","lanalyzer", "*.tr1", ".tr1", TRUE, FALSE,
544           lanalyzer_dump_can_write_encap, lanalyzer_dump_open },
545
546         /* WTAP_FILE_PPPDUMP */
547         { "pppd log (pppdump format)", "pppd", "*.*", NULL, FALSE, FALSE,
548           NULL, NULL },
549
550         /* WTAP_FILE_RADCOM */
551         { "RADCOM WAN/LAN analyzer", "radcom", "*.*", NULL, FALSE, FALSE,
552           NULL, NULL },
553
554         /* WTAP_FILE_SNOOP */
555         { "Sun snoop", "snoop", "*.snoop;*.cap", ".snoop", FALSE, FALSE,
556           snoop_dump_can_write_encap, snoop_dump_open },
557
558         /* WTAP_FILE_SHOMITI */
559         { "Shomiti/Finisar Surveyor", "shomiti", "*.cap", ".cap", FALSE, FALSE,
560           NULL, NULL },
561
562         /* WTAP_FILE_VMS */
563         { "TCPIPtrace (VMS)", "tcpiptrace", "*.*", NULL, FALSE, FALSE,
564           NULL, NULL},
565
566         /* WTAP_FILE_K12 */
567         { "Tektronix K12xx 32-bit .rf5 format", "rf5", "*.rf5", ".rf5", TRUE, FALSE,
568                 k12_dump_can_write_encap, k12_dump_open },
569
570         /* WTAP_FILE_TOSHIBA */
571         { "Toshiba Compact ISDN Router snoop", "toshiba", "*.*", NULL, FALSE, FALSE,
572           NULL, NULL },
573
574         /* WTAP_FILE_VISUAL_NETWORKS */
575         { "Visual Networks traffic capture", "visual", "*.*", NULL, TRUE, FALSE,
576           visual_dump_can_write_encap, visual_dump_open },
577
578         /* WTAP_FILE_ETHERPEEK_V56 */
579         { "WildPackets Ether/TokenPeek (V5 & V6)", "peek56", "*.tpc;*.apc;*.pkt;*.wpz", ".pkt", FALSE, FALSE,
580           NULL, NULL },
581
582         /* WTAP_FILE_ETHERPEEK_V7 */
583         { "WildPackets Ether/Token/AiroPeek (V7)", "peek7", "*.tpc;*.apc;*.pkt;*.wpz", ".pkt", FALSE, FALSE,
584           NULL, NULL },
585
586         /* WTAP_FILE_ETHERPEEK_V9 */
587         { "WildPackets Ether/AiroPeek (V9)", "peek9", "*.tpc;*.apc;*.pkt;*.wpz", ".pkt", FALSE, FALSE,
588           NULL, NULL },
589
590         /* WTAP_FILE_MPEG */
591         { "MPEG", "mpeg", "*.mpeg;*.mpg;*.mp3", ".mpeg", FALSE, FALSE,
592           NULL, NULL },
593
594         /* WTAP_FILE_K12TEXT  */
595         { "K12 text file", "k12text", "*.txt", ".txt", FALSE, FALSE,
596           k12text_dump_can_write_encap, k12text_dump_open },
597
598         /* WTAP_FILE_NETSCREEN */
599         { "NetScreen snoop text file", "netscreen", "*.*", NULL, FALSE, FALSE,
600           NULL, NULL },
601
602         /* WTAP_FILE_COMMVIEW */
603         { "TamoSoft CommView", "commview", "*.ncf", ".ncf", FALSE, FALSE,
604           commview_dump_can_write_encap, commview_dump_open },
605
606         /* WTAP_FILE_PCAPNG */
607         { "Wireshark - pcapng", "pcapng", "*.pcapng", NULL, FALSE, TRUE,
608           pcapng_dump_can_write_encap, pcapng_dump_open },
609
610         /* WTAP_FILE_BTSNOOP */
611         { "Symbian OS btsnoop", "btsnoop", "*.log", ".log", FALSE, FALSE,
612           btsnoop_dump_can_write_encap, btsnoop_dump_open_h4 },
613
614         /* WTAP_FILE_X2E_XORAYA */
615         { NULL, NULL, NULL, NULL, FALSE, FALSE,
616           NULL, NULL },
617
618         /* WTAP_FILE_TNEF */
619         { "Transport-Neutral Encapsulation Format", "tnef", "*.*", NULL, FALSE, FALSE,
620           NULL, NULL },
621
622         /* WTAP_FILE_DCT3TRACE */
623         { "Gammu DCT3 trace", "dct3trace", "*.xml", NULL, FALSE, FALSE,
624           NULL, NULL },
625
626         /* WTAP_FILE_PACKETLOGGER */
627         { "PacketLogger", "pklg", "*.pklg", NULL, FALSE, FALSE,
628           NULL, NULL },
629
630         /* WTAP_FILE_DAINTREE_SNA */
631         { "Daintree SNA", "dsna", "*.dcf", NULL, FALSE, FALSE,
632           NULL, NULL },
633
634         /* WTAP_FILE_NETSCALER_1_0 */
635         { "NetScaler Trace (Version 1.0)", "nstrace10", "*.*", "*.*", TRUE, FALSE,
636           nstrace_10_dump_can_write_encap, nstrace_dump_open },
637
638         /* WTAP_FILE_NETSCALER_2_0 */
639         { "NetScaler Trace (Version 2.0)", "nstrace20", "*.cap", "*.cap", TRUE, FALSE,
640           nstrace_20_dump_can_write_encap, nstrace_dump_open },
641
642         /* WTAP_FILE_JPEG_JFIF */
643         { "JPEG/JFIF", "jpeg", "*.jpg;*.jpeg;*.jfif", ".jpg", FALSE, FALSE,
644           NULL, NULL },
645
646         /* WTAP_FILE_IPFIX */
647         { "IPFIX File Format", "ipfix", "*.pfx;*.ipfix", NULL, FALSE, FALSE,
648           NULL, NULL },
649
650         /* WTAP_ENCAP_MIME */
651         { "MIME File Format", "mime", NULL, NULL, FALSE, FALSE, 
652            NULL, NULL }
653 };
654
655 gint wtap_num_file_types = sizeof(dump_open_table_base) / sizeof(struct file_type_info);
656
657 static GArray*  dump_open_table_arr = NULL;
658 static const struct file_type_info* dump_open_table = dump_open_table_base;
659
660 /* initialize the open routines array if it has not being initialized yet */
661 static void init_file_types(void) {
662
663         if (dump_open_table_arr) return;
664
665         dump_open_table_arr = g_array_new(FALSE,TRUE,sizeof(struct file_type_info));
666
667         g_array_append_vals(dump_open_table_arr,dump_open_table_base,wtap_num_file_types);
668
669         dump_open_table = (const struct file_type_info*)(void *)dump_open_table_arr->data;
670 }
671
672 int wtap_register_file_type(const struct file_type_info* fi) {
673         init_file_types();
674
675         g_array_append_val(dump_open_table_arr,*fi);
676
677         dump_open_table = (const struct file_type_info*)(void *)dump_open_table_arr->data;
678
679         return wtap_num_file_types++;
680 }
681
682 int wtap_get_num_file_types(void)
683 {
684         return wtap_num_file_types;
685 }
686
687 /* Name that should be somewhat descriptive. */
688 const char *wtap_file_type_string(int filetype)
689 {
690         if (filetype < 0 || filetype >= wtap_num_file_types) {
691                 g_error("Unknown capture file type %d", filetype);
692                 /** g_error() does an abort() and thus never returns **/
693                 return "";
694         } else
695                 return dump_open_table[filetype].name;
696 }
697
698 /* Name to use in, say, a command-line flag specifying the type. */
699 const char *wtap_file_type_short_string(int filetype)
700 {
701         if (filetype < 0 || filetype >= wtap_num_file_types)
702                 return NULL;
703         else
704                 return dump_open_table[filetype].short_name;
705 }
706
707 /* Translate a short name to a capture file type. */
708 int wtap_short_string_to_file_type(const char *short_name)
709 {
710         int filetype;
711
712         for (filetype = 0; filetype < wtap_num_file_types; filetype++) {
713                 if (dump_open_table[filetype].short_name != NULL &&
714                     strcmp(short_name, dump_open_table[filetype].short_name) == 0)
715                         return filetype;
716         }
717         return -1;      /* no such file type, or we can't write it */
718 }
719
720 /* file extensions to use. */
721 const char *wtap_file_extensions_string(int filetype)
722 {
723         if (filetype < 0 || filetype >= wtap_num_file_types)
724                 return NULL;
725         else
726                 return dump_open_table[filetype].file_extensions;
727 }
728
729 /* default file extension to use. */
730 const char *wtap_file_extension_default_string(int filetype)
731 {
732         if (filetype < 0 || filetype >= wtap_num_file_types)
733                 return NULL;
734         else
735                 return dump_open_table[filetype].file_extension_default;
736 }
737
738 gboolean wtap_dump_can_open(int filetype)
739 {
740         if (filetype < 0 || filetype >= wtap_num_file_types
741             || dump_open_table[filetype].dump_open == NULL)
742                 return FALSE;
743
744         return TRUE;
745 }
746
747 gboolean wtap_dump_can_write_encap(int filetype, int encap)
748 {
749         if (filetype < 0 || filetype >= wtap_num_file_types
750             || dump_open_table[filetype].can_write_encap == NULL)
751                 return FALSE;
752
753         if ((*dump_open_table[filetype].can_write_encap)(encap) != 0)
754                 return FALSE;
755
756         return TRUE;
757 }
758
759 #ifdef HAVE_LIBZ
760 gboolean wtap_dump_can_compress(int filetype)
761 {
762         /*
763          * If this is an unknown file type, or if we have to
764          * seek when writing out a file with this file type,
765          * return FALSE.
766          */
767         if (filetype < 0 || filetype >= wtap_num_file_types
768             || dump_open_table[filetype].writing_must_seek)
769                 return FALSE;
770
771         return TRUE;
772 }
773 #else
774 gboolean wtap_dump_can_compress(int filetype _U_)
775 {
776         return FALSE;
777 }
778 #endif
779
780 gboolean wtap_dump_has_name_resolution(int filetype)
781 {
782         if (filetype < 0 || filetype >= wtap_num_file_types
783             || dump_open_table[filetype].has_name_resolution == FALSE)
784                 return FALSE;
785
786         return TRUE;
787 }
788
789 static gboolean wtap_dump_open_check(int filetype, int encap, gboolean comressed, int *err);
790 static wtap_dumper* wtap_dump_alloc_wdh(int filetype, int encap, int snaplen,
791                                         gboolean compressed, int *err);
792 static gboolean wtap_dump_open_finish(wtap_dumper *wdh, int filetype, gboolean compressed, int *err);
793
794 static WFILE_T wtap_dump_file_open(wtap_dumper *wdh, const char *filename);
795 static WFILE_T wtap_dump_file_fdopen(wtap_dumper *wdh, int fd);
796 static int wtap_dump_file_close(wtap_dumper *wdh);
797
798 wtap_dumper* wtap_dump_open(const char *filename, int filetype, int encap,
799                                 int snaplen, gboolean compressed, int *err)
800 {
801         wtap_dumper *wdh;
802         WFILE_T fh;
803
804         /* Check whether we can open a capture file with that file type
805            and that encapsulation. */
806         if (!wtap_dump_open_check(filetype, encap, compressed, err))
807                 return NULL;
808
809         /* Allocate a data structure for the output stream. */
810         wdh = wtap_dump_alloc_wdh(filetype, encap, snaplen, compressed, err);
811         if (wdh == NULL)
812                 return NULL;    /* couldn't allocate it */
813
814         /* "-" means stdout */
815         if (strcmp(filename, "-") == 0) {
816                 if (compressed) {
817                         *err = EINVAL;  /* XXX - return a Wiretap error code for this */
818                         g_free(wdh);
819                         return NULL;    /* compress won't work on stdout */
820                 }
821 #ifdef _WIN32
822                 if (_setmode(fileno(stdout), O_BINARY) == -1) {
823                         /* "Should not happen" */
824                         *err = errno;
825                         g_free(wdh);
826                         return NULL;    /* couldn't put standard output in binary mode */
827                 }
828 #endif
829                 wdh->fh = stdout;
830         } else {
831                 /* In case "fopen()" fails but doesn't set "errno", set "errno"
832                    to a generic "the open failed" error. */
833                 errno = WTAP_ERR_CANT_OPEN;
834                 fh = wtap_dump_file_open(wdh, filename);
835                 if (fh == NULL) {
836                         *err = errno;
837                         g_free(wdh);
838                         return NULL;    /* can't create file */
839                 }
840                 wdh->fh = fh;
841         }
842
843         if (!wtap_dump_open_finish(wdh, filetype, compressed, err)) {
844                 /* Get rid of the file we created; we couldn't finish
845                    opening it. */
846                 if (wdh->fh != stdout) {
847                         wtap_dump_file_close(wdh);
848                         ws_unlink(filename);
849                 }
850                 g_free(wdh);
851                 return NULL;
852         }
853         return wdh;
854 }
855
856 wtap_dumper* wtap_dump_fdopen(int fd, int filetype, int encap, int snaplen,
857                                 gboolean compressed, int *err)
858 {
859         wtap_dumper *wdh;
860         WFILE_T fh;
861
862         /* Check whether we can open a capture file with that file type
863            and that encapsulation. */
864         if (!wtap_dump_open_check(filetype, encap, compressed, err))
865                 return NULL;
866
867         /* Allocate a data structure for the output stream. */
868         wdh = wtap_dump_alloc_wdh(filetype, encap, snaplen, compressed, err);
869         if (wdh == NULL)
870                 return NULL;    /* couldn't allocate it */
871
872 #ifdef _WIN32
873         if (fd == 1) {
874                 if (_setmode(fileno(stdout), O_BINARY) == -1) {
875                         /* "Should not happen" */
876                         *err = errno;
877                         g_free(wdh);
878                         return NULL;    /* couldn't put standard output in binary mode */
879                 }
880         }
881 #endif
882
883         /* In case "fopen()" fails but doesn't set "errno", set "errno"
884            to a generic "the open failed" error. */
885         errno = WTAP_ERR_CANT_OPEN;
886         fh = wtap_dump_file_fdopen(wdh, fd);
887         if (fh == NULL) {
888                 *err = errno;
889                 g_free(wdh);
890                 return NULL;    /* can't create standard I/O stream */
891         }
892         wdh->fh = fh;
893
894         if (!wtap_dump_open_finish(wdh, filetype, compressed, err)) {
895                 wtap_dump_file_close(wdh);
896                 g_free(wdh);
897                 return NULL;
898         }
899         return wdh;
900 }
901
902 static gboolean wtap_dump_open_check(int filetype, int encap, gboolean compressed, int *err)
903 {
904         if (!wtap_dump_can_open(filetype)) {
905                 /* Invalid type, or type we don't know how to write. */
906                 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
907                 return FALSE;
908         }
909
910         /* OK, we know how to write that type; can we write the specified
911            encapsulation type? */
912         *err = (*dump_open_table[filetype].can_write_encap)(encap);
913         if (*err != 0)
914                 return FALSE;
915
916         /* if compression is wanted, do we support this for this filetype? */
917         if(compressed && !wtap_dump_can_compress(filetype)) {
918                 *err = WTAP_ERR_COMPRESSION_NOT_SUPPORTED;
919                 return FALSE;
920         }
921
922         *err = (*dump_open_table[filetype].can_write_encap)(encap);
923         if (*err != 0)
924                 return FALSE;
925
926         /* All systems go! */
927         return TRUE;
928 }
929
930 static wtap_dumper* wtap_dump_alloc_wdh(int filetype, int encap, int snaplen,
931                                         gboolean compressed, int *err)
932 {
933         wtap_dumper *wdh;
934
935         wdh = (wtap_dumper *)g_malloc0(sizeof (wtap_dumper));
936         if (wdh == NULL) {
937                 *err = errno;
938                 return NULL;
939         }
940
941         wdh->file_type = filetype;
942         wdh->snaplen = snaplen;
943         wdh->encap = encap;
944         wdh->compressed = compressed;
945         return wdh;
946 }
947
948 static gboolean wtap_dump_open_finish(wtap_dumper *wdh, int filetype, gboolean compressed, int *err)
949 {
950         int fd;
951         gboolean cant_seek;
952
953         /* Can we do a seek on the file descriptor?
954            If not, note that fact. */
955         if(compressed) {
956                 cant_seek = TRUE;
957         } else {
958                 fd = fileno((FILE *)wdh->fh);
959                 if (lseek(fd, 1, SEEK_CUR) == -1)
960                         cant_seek = TRUE;
961                 else {
962                         /* Undo the seek. */
963                         lseek(fd, 0, SEEK_SET);
964                         cant_seek = FALSE;
965                 }
966         }
967
968         /* If this file type requires seeking, and we can't seek, fail. */
969         if (dump_open_table[filetype].writing_must_seek && cant_seek) {
970                 *err = WTAP_ERR_CANT_WRITE_TO_PIPE;
971                 return FALSE;
972         }
973
974         /* Now try to open the file for writing. */
975         if (!(*dump_open_table[filetype].dump_open)(wdh, err)) {
976                 return FALSE;
977         }
978
979         return TRUE;    /* success! */
980 }
981
982 gboolean wtap_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
983                    const union wtap_pseudo_header *pseudo_header, const guchar *pd, int *err)
984 {
985         return (wdh->subtype_write)(wdh, phdr, pseudo_header, pd, err);
986 }
987
988 void wtap_dump_flush(wtap_dumper *wdh)
989 {
990 #ifdef HAVE_LIBZ
991         if(wdh->compressed) {
992                 gzwfile_flush((GZWFILE_T)wdh->fh);
993         } else
994 #endif
995         {
996                 fflush((FILE *)wdh->fh);
997         }
998 }
999
1000 gboolean wtap_dump_close(wtap_dumper *wdh, int *err)
1001 {
1002         gboolean ret = TRUE;
1003
1004         if (wdh->subtype_close != NULL) {
1005                 /* There's a close routine for this dump stream. */
1006                 if (!(wdh->subtype_close)(wdh, err))
1007                         ret = FALSE;
1008         }
1009         errno = WTAP_ERR_CANT_CLOSE;
1010         /* Don't close stdout */
1011         if (wdh->fh != stdout) {
1012                 if (wtap_dump_file_close(wdh) == EOF) {
1013                         if (ret) {
1014                                 /* The per-format close function succeeded,
1015                                    but the fclose didn't.  Save the reason
1016                                    why, if our caller asked for it. */
1017                                 if (err != NULL)
1018                                         *err = errno;
1019                         }
1020                         ret = FALSE;
1021                 }
1022         } else {
1023                 /* as we don't close stdout, at least try to flush it */
1024                 wtap_dump_flush(wdh);
1025         }
1026         if (wdh->priv != NULL)
1027                 g_free(wdh->priv);
1028         g_free(wdh);
1029         return ret;
1030 }
1031
1032 gint64 wtap_get_bytes_dumped(wtap_dumper *wdh)
1033 {
1034         return wdh->bytes_dumped;
1035 }
1036
1037 void wtap_set_bytes_dumped(wtap_dumper *wdh, gint64 bytes_dumped)
1038 {
1039         wdh->bytes_dumped = bytes_dumped;
1040 }
1041
1042 gboolean wtap_dump_set_addrinfo_list(wtap_dumper *wdh, struct addrinfo *addrinfo_list)
1043 {
1044         if (!wdh || wdh->file_type < 0 || wdh->file_type >= wtap_num_file_types
1045                 || dump_open_table[wdh->file_type].has_name_resolution == FALSE)
1046                         return FALSE;
1047         wdh->addrinfo_list = addrinfo_list;
1048         return TRUE;
1049 }
1050
1051 /* internally open a file for writing (compressed or not) */
1052 #ifdef HAVE_LIBZ
1053 static WFILE_T wtap_dump_file_open(wtap_dumper *wdh, const char *filename)
1054 {
1055         if(wdh->compressed) {
1056                 return gzwfile_open(filename);
1057         } else {
1058                 return ws_fopen(filename, "wb");
1059         }
1060 }
1061 #else
1062 static WFILE_T wtap_dump_file_open(wtap_dumper *wdh _U_, const char *filename)
1063 {
1064         return ws_fopen(filename, "wb");
1065 }
1066 #endif
1067
1068 /* internally open a file for writing (compressed or not) */
1069 #ifdef HAVE_LIBZ
1070 static WFILE_T wtap_dump_file_fdopen(wtap_dumper *wdh, int fd)
1071 {
1072         if(wdh->compressed) {
1073                 return gzwfile_fdopen(fd);
1074         } else {
1075                 return fdopen(fd, "wb");
1076         }
1077 }
1078 #else
1079 static WFILE_T wtap_dump_file_fdopen(wtap_dumper *wdh _U_, int fd)
1080 {
1081         return fdopen(fd, "wb");
1082 }
1083 #endif
1084
1085 /* internally writing raw bytes (compressed or not) */
1086 gboolean wtap_dump_file_write(wtap_dumper *wdh, const void *buf, size_t bufsize,
1087                      int *err)
1088 {
1089         size_t nwritten;
1090
1091 #ifdef HAVE_LIBZ
1092         if (wdh->compressed) {
1093                 nwritten = gzwfile_write((GZWFILE_T)wdh->fh, buf, (unsigned) bufsize);
1094                 /*
1095                  * gzwfile_write() returns 0 on error.
1096                  */
1097                 if (nwritten == 0) {
1098                         *err = gzwfile_geterr((GZWFILE_T)wdh->fh);
1099                         return FALSE;
1100                 }
1101         } else
1102 #endif
1103         {
1104                 nwritten = fwrite(buf, 1, bufsize, (FILE *)wdh->fh);
1105                 /*
1106                  * At least according to the Mac OS X man page,
1107                  * this can return a short count on an error.
1108                  */
1109                 if (nwritten != bufsize) {
1110                         if (ferror((FILE *)wdh->fh))
1111                                 *err = errno;
1112                         else
1113                                 *err = WTAP_ERR_SHORT_WRITE;
1114                         return FALSE;
1115                 }
1116         }
1117         return TRUE;
1118 }
1119
1120 /* internally close a file for writing (compressed or not) */
1121 static int wtap_dump_file_close(wtap_dumper *wdh)
1122 {
1123 #ifdef HAVE_LIBZ
1124         if(wdh->compressed) {
1125                 return gzwfile_close((GZWFILE_T)wdh->fh);
1126         } else
1127 #endif
1128         {
1129                 return fclose((FILE *)wdh->fh);
1130         }
1131 }