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