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