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