afbed01a0e5396945ae81beae445ca0b1625fe3f
[metze/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 being 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                 return NULL;
673         } else
674                 return dump_open_table[filetype].name;
675 }
676
677 /* Name to use in, say, a command-line flag specifying the type. */
678 const char *wtap_file_type_short_string(int filetype)
679 {
680         if (filetype < 0 || filetype >= wtap_num_file_types)
681                 return NULL;
682         else
683                 return dump_open_table[filetype].short_name;
684 }
685
686 /* Translate a short name to a capture file type. */
687 int wtap_short_string_to_file_type(const char *short_name)
688 {
689         int filetype;
690
691         for (filetype = 0; filetype < wtap_num_file_types; filetype++) {
692                 if (dump_open_table[filetype].short_name != NULL &&
693                     strcmp(short_name, dump_open_table[filetype].short_name) == 0)
694                         return filetype;
695         }
696         return -1;      /* no such file type, or we can't write it */
697 }
698
699 /* file extensions to use. */
700 const char *wtap_file_extensions_string(int filetype)
701 {
702         if (filetype < 0 || filetype >= wtap_num_file_types)
703                 return NULL;
704         else
705                 return dump_open_table[filetype].file_extensions;
706 }
707
708 /* default file extension to use. */
709 const char *wtap_file_extension_default_string(int filetype)
710 {
711         if (filetype < 0 || filetype >= wtap_num_file_types)
712                 return NULL;
713         else
714                 return dump_open_table[filetype].file_extension_default;
715 }
716
717 gboolean wtap_dump_can_open(int filetype)
718 {
719         if (filetype < 0 || filetype >= wtap_num_file_types
720             || dump_open_table[filetype].dump_open == NULL)
721                 return FALSE;
722
723         return TRUE;
724 }
725
726 gboolean wtap_dump_can_write_encap(int filetype, int encap)
727 {
728         if (filetype < 0 || filetype >= wtap_num_file_types
729             || dump_open_table[filetype].can_write_encap == NULL)
730                 return FALSE;
731
732         if ((*dump_open_table[filetype].can_write_encap)(encap) != 0)
733                 return FALSE;
734
735         return TRUE;
736 }
737
738 #ifdef HAVE_LIBZ
739 gboolean wtap_dump_can_compress(int filetype)
740 {
741         if (filetype < 0 || filetype >= wtap_num_file_types
742             || dump_open_table[filetype].can_compress == FALSE)
743                 return FALSE;
744
745         return TRUE;
746 }
747 #else
748 gboolean wtap_dump_can_compress(int filetype _U_)
749 {
750         return FALSE;
751 }
752 #endif
753
754
755 static gboolean wtap_dump_open_check(int filetype, int encap, gboolean comressed, int *err);
756 static wtap_dumper* wtap_dump_alloc_wdh(int filetype, int encap, int snaplen,
757                                         gboolean compressed, int *err);
758 static gboolean wtap_dump_open_finish(wtap_dumper *wdh, int filetype, gboolean compressed, int *err);
759
760 static FILE_T wtap_dump_file_open(wtap_dumper *wdh, const char *filename);
761 static FILE_T wtap_dump_file_fdopen(wtap_dumper *wdh, int fd);
762 static int wtap_dump_file_close(wtap_dumper *wdh);
763
764 wtap_dumper* wtap_dump_open(const char *filename, int filetype, int encap,
765                                 int snaplen, gboolean compressed, int *err)
766 {
767         wtap_dumper *wdh;
768         FILE_T fh;
769
770         /* Check whether we can open a capture file with that file type
771            and that encapsulation. */
772         if (!wtap_dump_open_check(filetype, encap, compressed, err))
773                 return NULL;
774
775         /* Allocate a data structure for the output stream. */
776         wdh = wtap_dump_alloc_wdh(filetype, encap, snaplen, compressed, err);
777         if (wdh == NULL)
778                 return NULL;    /* couldn't allocate it */
779
780         /* "-" means stdout */
781         if (strcmp(filename, "-") == 0) {
782                 if(compressed) {
783                         g_free(wdh);
784                         return NULL;    /* compress won't work on stdout */
785                 }
786 #ifdef _WIN32
787                 setmode(fileno(stdout), O_BINARY);
788 #endif
789                 wdh->fh = stdout;
790         } else {
791                 /* In case "fopen()" fails but doesn't set "errno", set "errno"
792                    to a generic "the open failed" error. */
793                 errno = WTAP_ERR_CANT_OPEN;
794                 fh = wtap_dump_file_open(wdh, filename);
795                 if (fh == NULL) {
796                         *err = errno;
797                         g_free(wdh);
798                         return NULL;    /* can't create file */
799                 }
800                 wdh->fh = fh;
801         }
802
803         if (!wtap_dump_open_finish(wdh, filetype, compressed, err)) {
804                 /* Get rid of the file we created; we couldn't finish
805                    opening it. */
806                 if (wdh->fh != stdout) {
807                         wtap_dump_file_close(wdh);
808                         ws_unlink(filename);
809                 }
810                 g_free(wdh);
811                 return NULL;
812         }
813         return wdh;
814 }
815
816 wtap_dumper* wtap_dump_fdopen(int fd, int filetype, int encap, int snaplen,
817                                 gboolean compressed, int *err)
818 {
819         wtap_dumper *wdh;
820         FILE_T fh;
821
822         /* Check whether we can open a capture file with that file type
823            and that encapsulation. */
824         if (!wtap_dump_open_check(filetype, encap, compressed, err))
825                 return NULL;
826
827         /* Allocate a data structure for the output stream. */
828         wdh = wtap_dump_alloc_wdh(filetype, encap, snaplen, compressed, err);
829         if (wdh == NULL)
830                 return NULL;    /* couldn't allocate it */
831
832 #ifdef _WIN32
833         if(fd == 1) {
834                 setmode(fileno(stdout), O_BINARY);
835         }
836 #endif
837
838         /* In case "fopen()" fails but doesn't set "errno", set "errno"
839            to a generic "the open failed" error. */
840         errno = WTAP_ERR_CANT_OPEN;
841         fh = wtap_dump_file_fdopen(wdh, fd);
842         if (fh == NULL) {
843                 *err = errno;
844                 g_free(wdh);
845                 return NULL;    /* can't create standard I/O stream */
846         }
847         wdh->fh = fh;
848
849         if (!wtap_dump_open_finish(wdh, filetype, compressed, err)) {
850                 wtap_dump_file_close(wdh);
851                 g_free(wdh);
852                 return NULL;
853         }
854         return wdh;
855 }
856
857 static gboolean wtap_dump_open_check(int filetype, int encap, gboolean compressed, int *err)
858 {
859         if (!wtap_dump_can_open(filetype)) {
860                 /* Invalid type, or type we don't know how to write. */
861                 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
862                 return FALSE;
863         }
864
865         /* OK, we know how to write that type; can we write the specified
866            encapsulation type? */
867         *err = (*dump_open_table[filetype].can_write_encap)(encap);
868         if (*err != 0)
869                 return FALSE;
870
871         /* if compression is wanted, do we support this for this filetype? */
872         if(compressed && !wtap_dump_can_compress(filetype)) {
873                 *err = WTAP_ERR_COMPRESSION_NOT_SUPPORTED;
874                 return FALSE;
875         }
876
877         *err = (*dump_open_table[filetype].can_write_encap)(encap);
878         if (*err != 0)
879                 return FALSE;
880
881
882         /* All systems go! */
883         return TRUE;
884 }
885
886 static wtap_dumper* wtap_dump_alloc_wdh(int filetype, int encap, int snaplen,
887                                         gboolean compressed, int *err)
888 {
889         wtap_dumper *wdh;
890
891         wdh = (wtap_dumper *)g_malloc(sizeof (wtap_dumper));
892         if (wdh == NULL) {
893                 *err = errno;
894                 return NULL;
895         }
896         wdh->fh = NULL;
897         wdh->file_type = filetype;
898         wdh->snaplen = snaplen;
899         wdh->encap = encap;
900         wdh->compressed = compressed;
901         wdh->bytes_dumped = 0;
902         wdh->priv = NULL;
903         wdh->subtype_write = NULL;
904         wdh->subtype_close = NULL;
905         return wdh;
906 }
907
908 static gboolean wtap_dump_open_finish(wtap_dumper *wdh, int filetype, gboolean compressed, int *err)
909 {
910         int fd;
911         gboolean cant_seek;
912
913         /* Can we do a seek on the file descriptor?
914            If not, note that fact. */
915         if(compressed) {
916                 cant_seek = TRUE;
917         } else {
918                 fd = fileno(wdh->fh);
919                 if (lseek(fd, 1, SEEK_CUR) == -1)
920                         cant_seek = TRUE;
921                 else {
922                         /* Undo the seek. */
923                         lseek(fd, 0, SEEK_SET);
924                         cant_seek = FALSE;
925                 }
926         }
927
928         /* Now try to open the file for writing. */
929         if (!(*dump_open_table[filetype].dump_open)(wdh, cant_seek, err)) {
930                 return FALSE;
931         }
932
933         return TRUE;    /* success! */
934 }
935
936 gboolean wtap_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
937                    const union wtap_pseudo_header *pseudo_header, const guchar *pd, int *err)
938 {
939         return (wdh->subtype_write)(wdh, phdr, pseudo_header, pd, err);
940 }
941
942 void wtap_dump_flush(wtap_dumper *wdh)
943 {
944 #ifdef HAVE_LIBZ
945         if(wdh->compressed) {
946                 gzflush(wdh->fh, Z_SYNC_FLUSH); /* XXX - is Z_SYNC_FLUSH the right one? */
947         } else
948 #endif
949         {
950                 fflush(wdh->fh);
951         }
952 }
953
954 gboolean wtap_dump_close(wtap_dumper *wdh, int *err)
955 {
956         gboolean ret = TRUE;
957
958         if (wdh->subtype_close != NULL) {
959                 /* There's a close routine for this dump stream. */
960                 if (!(wdh->subtype_close)(wdh, err))
961                         ret = FALSE;
962         }
963         errno = WTAP_ERR_CANT_CLOSE;
964         /* Don't close stdout */
965         if (wdh->fh != stdout) {
966                 if (wtap_dump_file_close(wdh) == EOF) {
967                         if (ret) {
968                                 /* The per-format close function succeeded,
969                                    but the fclose didn't.  Save the reason
970                                    why, if our caller asked for it. */
971                                 if (err != NULL)
972                                         *err = errno;
973                         }
974                         ret = FALSE;
975                 }
976         } else {
977                 /* as we don't close stdout, at least try to flush it */
978                 wtap_dump_flush(wdh);
979         }
980         if (wdh->priv != NULL)
981                 g_free(wdh->priv);
982         g_free(wdh);
983         return ret;
984 }
985
986 gint64 wtap_get_bytes_dumped(wtap_dumper *wdh)
987 {
988         return wdh->bytes_dumped;
989 }
990
991 void wtap_set_bytes_dumped(wtap_dumper *wdh, gint64 bytes_dumped)
992 {
993         wdh->bytes_dumped = bytes_dumped;
994 }
995
996
997 /* internally open a file for writing (compressed or not) */
998 #ifdef HAVE_LIBZ
999 static FILE_T wtap_dump_file_open(wtap_dumper *wdh, const char *filename)
1000 {
1001         if(wdh->compressed) {
1002                 return gzopen(filename, "wb");
1003         } else {
1004                 return ws_fopen(filename, "wb");
1005         }
1006 }
1007 #else
1008 static FILE_T wtap_dump_file_open(wtap_dumper *wdh _U_, const char *filename)
1009 {
1010         return ws_fopen(filename, "wb");
1011 }
1012 #endif
1013
1014 /* internally open a file for writing (compressed or not) */
1015 #ifdef HAVE_LIBZ
1016 static FILE_T wtap_dump_file_fdopen(wtap_dumper *wdh, int fd)
1017 {
1018         if(wdh->compressed) {
1019                 return gzdopen(fd, "wb");
1020         } else {
1021                 return fdopen(fd, "wb");
1022         }
1023 }
1024 #else
1025 static FILE_T wtap_dump_file_fdopen(wtap_dumper *wdh _U_, int fd)
1026 {
1027         return fdopen(fd, "wb");
1028 }
1029 #endif
1030
1031 /* internally writing raw bytes (compressed or not) */
1032 gboolean wtap_dump_file_write(wtap_dumper *wdh, const void *buf, size_t bufsize,
1033                      int *err)
1034 {
1035         size_t nwritten;
1036 #ifdef HAVE_LIBZ
1037         int errnum;
1038 #endif
1039
1040 #ifdef HAVE_LIBZ
1041         if (wdh->compressed) {
1042                 nwritten = gzwrite(wdh->fh, buf, (unsigned) bufsize);
1043                 /*
1044                  * At least according to zlib.h, gzwrite returns 0
1045                  * on error; that appears to be the case in libz
1046                  * 1.2.5.
1047                  */
1048                 if (nwritten == 0) {
1049                         gzerror(wdh->fh, &errnum);
1050                         if (errnum == Z_ERRNO)
1051                                 *err = errno;
1052                         else {
1053                                 /*
1054                                  * XXX - what to do with this zlib-specific
1055                                  * number?
1056                                  */
1057                                 *err = errnum;
1058                         }
1059                         return FALSE;
1060                 }
1061         } else
1062 #endif
1063         {
1064                 nwritten = fwrite(buf, 1, bufsize, wdh->fh);
1065                 /*
1066                  * At least according to the Mac OS X man page,
1067                  * this can return a short count on an error.
1068                  */
1069                 if (nwritten != bufsize) {
1070                         if (ferror(wdh->fh))
1071                                 *err = errno;
1072                         else
1073                                 *err = WTAP_ERR_SHORT_WRITE;
1074                         return FALSE;
1075                 }
1076         }
1077         return TRUE;
1078 }
1079
1080 /* internally close a file for writing (compressed or not) */
1081 static int wtap_dump_file_close(wtap_dumper *wdh)
1082 {
1083 #ifdef HAVE_LIBZ
1084         if(wdh->compressed) {
1085                 return gzclose(wdh->fh);
1086         } else
1087 #endif
1088         {
1089                 return fclose(wdh->fh);
1090         }
1091 }