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