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