9a2f469096620eaa625aff673455df35bec133db
[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_malloc0(sizeof(wtap));
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))) {
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))) {
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         wth->priv = NULL;
334
335         init_open_routines();
336
337         /* Try all file types */
338         for (i = 0; i < open_routines_arr->len; i++) {
339                 /* Seek back to the beginning of the file; the open routine
340                    for the previous file type may have left the file
341                    position somewhere other than the beginning, and the
342                    open routine for this file type will probably want
343                    to start reading at the beginning.
344
345                    Initialize the data offset while we're at it. */
346                 if (file_seek(wth->fh, 0, SEEK_SET, err) == -1) {
347                         /* I/O error - give up */
348                         if (wth->random_fh != NULL)
349                                 file_close(wth->random_fh);
350                         file_close(wth->fh);
351                         g_free(wth);
352                         return NULL;
353                 }
354                 wth->data_offset = 0;
355
356                 switch ((*open_routines[i])(wth, err, err_info)) {
357
358                 case -1:
359                         /* I/O error - give up */
360                         if (wth->random_fh != NULL)
361                                 file_close(wth->random_fh);
362                         file_close(wth->fh);
363                         g_free(wth);
364                         return NULL;
365
366                 case 0:
367                         /* No I/O error, but not that type of file */
368                         break;
369
370                 case 1:
371                         /* We found the file type */
372                         goto success;
373                 }
374         }
375
376         /* Well, it's not one of the types of file we know about. */
377         if (wth->random_fh != NULL)
378                 file_close(wth->random_fh);
379         file_close(wth->fh);
380         g_free(wth);
381         *err = WTAP_ERR_FILE_UNKNOWN_FORMAT;
382         return NULL;
383
384 success:
385         wth->frame_buffer = (struct Buffer *)g_malloc(sizeof(struct Buffer));
386         buffer_init(wth->frame_buffer, 1500);
387         return wth;
388 }
389
390 /* Table of the file types we know about. */
391 static const struct file_type_info dump_open_table_base[] = {
392         /* WTAP_FILE_UNKNOWN (only used internally for initialization) */
393         { NULL, NULL, NULL, NULL, FALSE, FALSE,
394           NULL, NULL },
395
396         /* WTAP_FILE_WTAP (only used internally while capturing) */
397         { NULL, NULL, NULL, NULL, FALSE, FALSE,
398           NULL, NULL },
399
400         /* WTAP_FILE_PCAP */
401         { "Wireshark/tcpdump/... - libpcap", "libpcap", "*.pcap;*.cap", ".pcap", TRUE, FALSE,
402           libpcap_dump_can_write_encap, libpcap_dump_open },
403
404         /* WTAP_FILE_PCAP_NSEC */
405         { "Wireshark - nanosecond libpcap", "nseclibpcap", "*.pcap;*.cap", ".pcap", TRUE, FALSE,
406           libpcap_dump_can_write_encap, libpcap_dump_open },
407
408         /* WTAP_FILE_PCAP_AIX */
409         { "AIX tcpdump - libpcap", "aixlibpcap", "*.pcap;*.cap", ".pcap", TRUE, FALSE,
410           NULL, NULL },
411
412         /* WTAP_FILE_PCAP_SS991029 */
413         { "Modified tcpdump - libpcap", "modlibpcap", "*.pcap;*.cap", ".pcap", TRUE, FALSE,
414           libpcap_dump_can_write_encap, libpcap_dump_open },
415
416         /* WTAP_FILE_PCAP_NOKIA */
417         { "Nokia tcpdump - libpcap ", "nokialibpcap", "*.pcap;*.cap", ".pcap", TRUE, FALSE,
418           libpcap_dump_can_write_encap, libpcap_dump_open },
419
420         /* WTAP_FILE_PCAP_SS990417 */
421         { "RedHat 6.1 tcpdump - libpcap", "rh6_1libpcap", "*.pcap;*.cap", ".pcap", TRUE, FALSE,
422           libpcap_dump_can_write_encap, libpcap_dump_open },
423
424         /* WTAP_FILE_PCAP_SS990915 */
425         { "SuSE 6.3 tcpdump - libpcap", "suse6_3libpcap", "*.pcap;*.cap", ".pcap", TRUE, FALSE,
426           libpcap_dump_can_write_encap, libpcap_dump_open },
427
428         /* WTAP_FILE_5VIEWS */
429         { "Accellent 5Views capture", "5views", "*.5vw", ".5vw", FALSE, FALSE,
430           _5views_dump_can_write_encap, _5views_dump_open },
431
432         /* WTAP_FILE_IPTRACE_1_0 */
433         { "AIX iptrace 1.0", "iptrace_1", "*.*", NULL, FALSE, FALSE,
434           NULL, NULL },
435
436         /* WTAP_FILE_IPTRACE_2_0 */
437         { "AIX iptrace 2.0", "iptrace_2", "*.*", NULL, FALSE, FALSE,
438           NULL, NULL },
439
440         /* WTAP_FILE_BER */
441         { "ASN.1 Basic Encoding Rules", "ber", "*.*", NULL, FALSE, FALSE,
442                 NULL, NULL },
443
444         /* WTAP_FILE_HCIDUMP */
445         { "Bluetooth HCI dump", "hcidump", "*.*", NULL, FALSE, FALSE,
446           NULL, NULL },
447
448         /* WTAP_FILE_CATAPULT_DCT2000 */
449         { "Catapult DCT2000 trace (.out format)", "dct2000", "*.out", ".out", FALSE, FALSE,
450           catapult_dct2000_dump_can_write_encap, catapult_dct2000_dump_open },
451
452         /* WTAP_FILE_NETXRAY_OLD */
453         { "Cinco Networks NetXRay 1.x", "netxray1", "*.cap", ".cap", FALSE, FALSE,
454           NULL, NULL },
455
456         /* WTAP_FILE_NETXRAY_1_0 */
457         { "Cinco Networks NetXRay 2.0 or later", "netxray2", "*.cap", ".cap", FALSE, FALSE,
458           NULL, NULL },
459
460         /* WTAP_FILE_COSINE */
461         { "CoSine IPSX L2 capture", "cosine", "*.*", NULL, FALSE, FALSE,
462           NULL, NULL },
463
464         /* WTAP_FILE_CSIDS */
465         { "CSIDS IPLog", "csids", "*.*", NULL, FALSE, FALSE,
466           NULL, NULL },
467
468         /* WTAP_FILE_DBS_ETHERWATCH */
469         { "DBS Etherwatch (VMS)", "etherwatch", "*.*", NULL, FALSE, FALSE,
470           NULL, NULL},
471
472         /* WTAP_FILE_ERF */
473         { "Endace ERF capture", "erf", "*.erf", ".erf", FALSE, FALSE,
474           NULL, NULL },
475
476         /* WTAP_FILE_EYESDN */
477         { "EyeSDN USB S0/E1 ISDN trace format", "eyesdn", "*.trc", ".trc", FALSE, FALSE,
478            eyesdn_dump_can_write_encap, eyesdn_dump_open },
479
480         /* WTAP_FILE_NETTL */
481         { "HP-UX nettl trace", "nettl", "*.TRC0;*.TRC1", ".TRC0", FALSE, FALSE,
482           nettl_dump_can_write_encap, nettl_dump_open },
483
484         /* WTAP_FILE_ISERIES */
485         { "IBM iSeries comm. trace (ASCII)", "iseries_ascii", "*.*", NULL, FALSE, FALSE,
486           NULL, NULL },
487
488         /* WTAP_FILE_ISERIES_UNICODE */
489         { "IBM iSeries comm. trace (UNICODE)", "iseries_unicode", "*.*", NULL, FALSE, FALSE,
490           NULL, NULL },
491
492         /* WTAP_FILE_I4BTRACE */
493         { "I4B ISDN trace", "i4btrace", "*.*", NULL, FALSE, FALSE,
494           NULL, NULL },
495
496         /* WTAP_FILE_ASCEND */
497         { "Lucent/Ascend access server trace", "ascend", "*.*", NULL, FALSE, FALSE,
498           NULL, NULL },
499
500         /* WTAP_FILE_NETMON_1_x */
501         { "Microsoft NetMon 1.x", "netmon1", "*.cap", ".cap", FALSE, FALSE,
502           netmon_dump_can_write_encap, netmon_dump_open },
503
504         /* WTAP_FILE_NETMON_2_x */
505         { "Microsoft NetMon 2.x", "netmon2", "*.cap", ".cap", FALSE, FALSE,
506           netmon_dump_can_write_encap, netmon_dump_open },
507
508         /* WTAP_FILE_NGSNIFFER_UNCOMPRESSED */
509         { "NA Sniffer (DOS)", "ngsniffer", "*.cap;*.enc;*.trc;*.fdc;*.syc", ".cap", FALSE, FALSE,
510           ngsniffer_dump_can_write_encap, ngsniffer_dump_open },
511
512         /* WTAP_FILE_NGSNIFFER_COMPRESSED */
513         { "NA Sniffer (DOS), compressed", "ngsniffer_comp", "*.caz", ".caz", FALSE, FALSE,
514           NULL, NULL },
515
516         /* WTAP_FILE_NETXRAY_1_1 */
517         { "NA Sniffer (Windows) 1.1", "ngwsniffer_1_1", "*.cap", ".cap", FALSE, FALSE,
518           netxray_dump_can_write_encap_1_1, netxray_dump_open_1_1 },
519
520         /* WTAP_FILE_NETXRAY_2_00x */
521         { "NA Sniffer (Windows) 2.00x", "ngwsniffer_2_0", "*.cap", ".cap", FALSE, FALSE,
522           netxray_dump_can_write_encap_2_0, netxray_dump_open_2_0 },
523
524         /* WTAP_FILE_NETWORK_INSTRUMENTS_V9 */
525         { "Network Instruments Observer (V9)", "niobserverv9", "*.bfr", ".bfr", FALSE, FALSE,
526           network_instruments_dump_can_write_encap, network_instruments_dump_open },
527
528         /* WTAP_FILE_LANALYZER */
529         { "Novell LANalyzer","lanalyzer", "*.tr1", ".tr1", FALSE, FALSE,
530           lanalyzer_dump_can_write_encap, lanalyzer_dump_open },
531
532         /* WTAP_FILE_PPPDUMP */
533         { "pppd log (pppdump format)", "pppd", "*.*", NULL, FALSE, FALSE,
534           NULL, NULL },
535
536         /* WTAP_FILE_RADCOM */
537         { "RADCOM WAN/LAN analyzer", "radcom", "*.*", NULL, FALSE, FALSE,
538           NULL, NULL },
539
540         /* WTAP_FILE_SNOOP */
541         { "Sun snoop", "snoop", "*.snoop;*.cap", ".snoop", FALSE, FALSE,
542           snoop_dump_can_write_encap, snoop_dump_open },
543
544         /* WTAP_FILE_SHOMITI */
545         { "Shomiti/Finisar Surveyor", "shomiti", "*.cap", ".cap", FALSE, FALSE,
546           NULL, NULL },
547
548         /* WTAP_FILE_VMS */
549         { "TCPIPtrace (VMS)", "tcpiptrace", "*.*", NULL, FALSE, FALSE,
550           NULL, NULL},
551
552         /* WTAP_FILE_K12 */
553         { "Tektronix K12xx 32-bit .rf5 format", "rf5", "*.rf5", ".rf5", TRUE, FALSE,
554                 k12_dump_can_write_encap, k12_dump_open },
555
556         /* WTAP_FILE_TOSHIBA */
557         { "Toshiba Compact ISDN Router snoop", "toshiba", "*.*", NULL, FALSE, FALSE,
558           NULL, NULL },
559
560         /* WTAP_FILE_VISUAL_NETWORKS */
561         { "Visual Networks traffic capture", "visual", "*.*", NULL, FALSE, FALSE,
562           visual_dump_can_write_encap, visual_dump_open },
563
564         /* WTAP_FILE_ETHERPEEK_V56 */
565         { "WildPackets Ether/TokenPeek (V5 & V6)", "peek56", "*.tpc;*.apc;*.pkt;*.wpz", ".pkt", FALSE, FALSE,
566           NULL, NULL },
567
568         /* WTAP_FILE_ETHERPEEK_V7 */
569         { "WildPackets Ether/Token/AiroPeek (V7)", "peek7", "*.tpc;*.apc;*.pkt;*.wpz", ".pkt", FALSE, FALSE,
570           NULL, NULL },
571
572         /* WTAP_FILE_ETHERPEEK_V9 */
573         { "WildPackets Ether/AiroPeek (V9)", "peek9", "*.tpc;*.apc;*.pkt;*.wpz", ".pkt", FALSE, FALSE,
574           NULL, NULL },
575
576         /* WTAP_FILE_MPEG */
577         { "MPEG", "mpeg", "*.mpeg;*.mpg;*.mp3", ".mpeg", FALSE, FALSE,
578           NULL, NULL },
579
580         /* WTAP_FILE_K12TEXT  */
581         { "K12 text file", "k12text", "*.txt", ".txt", TRUE, FALSE,
582           k12text_dump_can_write_encap, k12text_dump_open },
583
584         /* WTAP_FILE_NETSCREEN */
585         { "NetScreen snoop text file", "netscreen", "*.*", NULL, FALSE, FALSE,
586           NULL, NULL },
587
588         /* WTAP_FILE_COMMVIEW */
589         { "TamoSoft CommView", "commview", "*.ncf", ".ncf", TRUE, FALSE,
590           commview_dump_can_write_encap, commview_dump_open },
591
592         /* WTAP_FILE_PCAPNG */
593         { "Wireshark - pcapng", "pcapng", "*.pcapng", NULL, FALSE, TRUE,
594           pcapng_dump_can_write_encap, pcapng_dump_open },
595
596         /* WTAP_FILE_BTSNOOP */
597         { "Symbian OS btsnoop", "btsnoop", "*.log", ".log", FALSE, FALSE,
598           btsnoop_dump_can_write_encap, btsnoop_dump_open_h4 },
599
600         /* WTAP_FILE_X2E_XORAYA */
601         { NULL, NULL, NULL, NULL, FALSE, FALSE,
602           NULL, NULL },
603
604         /* WTAP_FILE_TNEF */
605         { "Transport-Neutral Encapsulation Format", "tnef", "*.*", NULL, FALSE, FALSE,
606           NULL, NULL },
607
608         /* WTAP_FILE_DCT3TRACE */
609         { "Gammu DCT3 trace", "dct3trace", "*.xml", NULL, FALSE, FALSE,
610           NULL, NULL },
611
612         /* WTAP_FILE_PACKETLOGGER */
613         { "PacketLogger", "pklg", "*.pklg", NULL, FALSE, FALSE,
614           NULL, NULL },
615
616         /* WTAP_FILE_DAINTREE_SNA */
617         { "Daintree SNA", "dsna", "*.dcf", NULL, FALSE, FALSE,
618           NULL, NULL },
619
620         /* WTAP_FILE_NETSCALER_1_0 */
621         { "NetScaler Trace (Version 1.0)", "nstrace10", "*.*", "*.*", FALSE, FALSE,
622           nstrace_10_dump_can_write_encap, nstrace_dump_open },
623
624         /* WTAP_FILE_NETSCALER_2_0 */
625         { "NetScaler Trace (Version 2.0)", "nstrace20", "*.cap", "*.cap", FALSE, FALSE,
626           nstrace_20_dump_can_write_encap, nstrace_dump_open },
627
628         /* WTAP_FILE_JPEG_JFIF */
629         { "JPEG/JFIF", "jpeg", "*.jpg;*.jpeg;*.jfif", ".jpg", FALSE, FALSE,
630           NULL, NULL },
631
632         /* WTAP_FILE_IPFIX */
633         { "IPFIX File Format", "ipfix", "*.pfx;*.ipfix", NULL, FALSE, FALSE,
634           NULL, NULL }
635 };
636
637 gint wtap_num_file_types = sizeof(dump_open_table_base) / sizeof(struct file_type_info);
638
639 static GArray*  dump_open_table_arr = NULL;
640 static const struct file_type_info* dump_open_table = dump_open_table_base;
641
642 /* initialize the open routines array if it has not being initialized yet */
643 static void init_file_types(void) {
644
645         if (dump_open_table_arr) return;
646
647         dump_open_table_arr = g_array_new(FALSE,TRUE,sizeof(struct file_type_info));
648
649         g_array_append_vals(dump_open_table_arr,dump_open_table_base,wtap_num_file_types);
650
651         dump_open_table = (const struct file_type_info*)dump_open_table_arr->data;
652 }
653
654 int wtap_register_file_type(const struct file_type_info* fi) {
655         init_file_types();
656
657         g_array_append_val(dump_open_table_arr,*fi);
658
659         dump_open_table = (const struct file_type_info*)dump_open_table_arr->data;
660
661         return wtap_num_file_types++;
662 }
663
664 int wtap_get_num_file_types(void)
665 {
666         return wtap_num_file_types;
667 }
668
669 /* Name that should be somewhat descriptive. */
670 const char *wtap_file_type_string(int filetype)
671 {
672         if (filetype < 0 || filetype >= wtap_num_file_types) {
673                 g_error("Unknown capture file type %d", filetype);
674                 /** g_error() does an abort() and thus never returns **/
675                 return "";
676         } else
677                 return dump_open_table[filetype].name;
678 }
679
680 /* Name to use in, say, a command-line flag specifying the type. */
681 const char *wtap_file_type_short_string(int filetype)
682 {
683         if (filetype < 0 || filetype >= wtap_num_file_types)
684                 return NULL;
685         else
686                 return dump_open_table[filetype].short_name;
687 }
688
689 /* Translate a short name to a capture file type. */
690 int wtap_short_string_to_file_type(const char *short_name)
691 {
692         int filetype;
693
694         for (filetype = 0; filetype < wtap_num_file_types; filetype++) {
695                 if (dump_open_table[filetype].short_name != NULL &&
696                     strcmp(short_name, dump_open_table[filetype].short_name) == 0)
697                         return filetype;
698         }
699         return -1;      /* no such file type, or we can't write it */
700 }
701
702 /* file extensions to use. */
703 const char *wtap_file_extensions_string(int filetype)
704 {
705         if (filetype < 0 || filetype >= wtap_num_file_types)
706                 return NULL;
707         else
708                 return dump_open_table[filetype].file_extensions;
709 }
710
711 /* default file extension to use. */
712 const char *wtap_file_extension_default_string(int filetype)
713 {
714         if (filetype < 0 || filetype >= wtap_num_file_types)
715                 return NULL;
716         else
717                 return dump_open_table[filetype].file_extension_default;
718 }
719
720 gboolean wtap_dump_can_open(int filetype)
721 {
722         if (filetype < 0 || filetype >= wtap_num_file_types
723             || dump_open_table[filetype].dump_open == NULL)
724                 return FALSE;
725
726         return TRUE;
727 }
728
729 gboolean wtap_dump_can_write_encap(int filetype, int encap)
730 {
731         if (filetype < 0 || filetype >= wtap_num_file_types
732             || dump_open_table[filetype].can_write_encap == NULL)
733                 return FALSE;
734
735         if ((*dump_open_table[filetype].can_write_encap)(encap) != 0)
736                 return FALSE;
737
738         return TRUE;
739 }
740
741 #ifdef HAVE_LIBZ
742 gboolean wtap_dump_can_compress(int filetype)
743 {
744         if (filetype < 0 || filetype >= wtap_num_file_types
745             || dump_open_table[filetype].can_compress == FALSE)
746                 return FALSE;
747
748         return TRUE;
749 }
750 #else
751 gboolean wtap_dump_can_compress(int filetype _U_)
752 {
753         return FALSE;
754 }
755 #endif
756
757 gboolean wtap_dump_has_name_resolution(int filetype)
758 {
759         if (filetype < 0 || filetype >= wtap_num_file_types
760             || dump_open_table[filetype].has_name_resolution == FALSE)
761                 return FALSE;
762
763         return TRUE;
764 }
765
766 static gboolean wtap_dump_open_check(int filetype, int encap, gboolean comressed, int *err);
767 static wtap_dumper* wtap_dump_alloc_wdh(int filetype, int encap, int snaplen,
768                                         gboolean compressed, int *err);
769 static gboolean wtap_dump_open_finish(wtap_dumper *wdh, int filetype, gboolean compressed, int *err);
770
771 static WFILE_T wtap_dump_file_open(wtap_dumper *wdh, const char *filename);
772 static WFILE_T wtap_dump_file_fdopen(wtap_dumper *wdh, int fd);
773 static int wtap_dump_file_close(wtap_dumper *wdh);
774
775 wtap_dumper* wtap_dump_open(const char *filename, int filetype, int encap,
776                                 int snaplen, gboolean compressed, int *err)
777 {
778         wtap_dumper *wdh;
779         WFILE_T fh;
780
781         /* Check whether we can open a capture file with that file type
782            and that encapsulation. */
783         if (!wtap_dump_open_check(filetype, encap, compressed, err))
784                 return NULL;
785
786         /* Allocate a data structure for the output stream. */
787         wdh = wtap_dump_alloc_wdh(filetype, encap, snaplen, compressed, err);
788         if (wdh == NULL)
789                 return NULL;    /* couldn't allocate it */
790
791         /* "-" means stdout */
792         if (strcmp(filename, "-") == 0) {
793                 if(compressed) {
794                         g_free(wdh);
795                         return NULL;    /* compress won't work on stdout */
796                 }
797 #ifdef _WIN32
798                 _setmode(fileno(stdout), O_BINARY);
799 #endif
800                 wdh->fh = stdout;
801         } else {
802                 /* In case "fopen()" fails but doesn't set "errno", set "errno"
803                    to a generic "the open failed" error. */
804                 errno = WTAP_ERR_CANT_OPEN;
805                 fh = wtap_dump_file_open(wdh, filename);
806                 if (fh == NULL) {
807                         *err = errno;
808                         g_free(wdh);
809                         return NULL;    /* can't create file */
810                 }
811                 wdh->fh = fh;
812         }
813
814         if (!wtap_dump_open_finish(wdh, filetype, compressed, err)) {
815                 /* Get rid of the file we created; we couldn't finish
816                    opening it. */
817                 if (wdh->fh != stdout) {
818                         wtap_dump_file_close(wdh);
819                         ws_unlink(filename);
820                 }
821                 g_free(wdh);
822                 return NULL;
823         }
824         return wdh;
825 }
826
827 wtap_dumper* wtap_dump_fdopen(int fd, int filetype, int encap, int snaplen,
828                                 gboolean compressed, int *err)
829 {
830         wtap_dumper *wdh;
831         WFILE_T fh;
832
833         /* Check whether we can open a capture file with that file type
834            and that encapsulation. */
835         if (!wtap_dump_open_check(filetype, encap, compressed, err))
836                 return NULL;
837
838         /* Allocate a data structure for the output stream. */
839         wdh = wtap_dump_alloc_wdh(filetype, encap, snaplen, compressed, err);
840         if (wdh == NULL)
841                 return NULL;    /* couldn't allocate it */
842
843 #ifdef _WIN32
844         if(fd == 1) {
845                 _setmode(fileno(stdout), O_BINARY);
846         }
847 #endif
848
849         /* In case "fopen()" fails but doesn't set "errno", set "errno"
850            to a generic "the open failed" error. */
851         errno = WTAP_ERR_CANT_OPEN;
852         fh = wtap_dump_file_fdopen(wdh, fd);
853         if (fh == NULL) {
854                 *err = errno;
855                 g_free(wdh);
856                 return NULL;    /* can't create standard I/O stream */
857         }
858         wdh->fh = fh;
859
860         if (!wtap_dump_open_finish(wdh, filetype, compressed, err)) {
861                 wtap_dump_file_close(wdh);
862                 g_free(wdh);
863                 return NULL;
864         }
865         return wdh;
866 }
867
868 static gboolean wtap_dump_open_check(int filetype, int encap, gboolean compressed, int *err)
869 {
870         if (!wtap_dump_can_open(filetype)) {
871                 /* Invalid type, or type we don't know how to write. */
872                 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
873                 return FALSE;
874         }
875
876         /* OK, we know how to write that type; can we write the specified
877            encapsulation type? */
878         *err = (*dump_open_table[filetype].can_write_encap)(encap);
879         if (*err != 0)
880                 return FALSE;
881
882         /* if compression is wanted, do we support this for this filetype? */
883         if(compressed && !wtap_dump_can_compress(filetype)) {
884                 *err = WTAP_ERR_COMPRESSION_NOT_SUPPORTED;
885                 return FALSE;
886         }
887
888         *err = (*dump_open_table[filetype].can_write_encap)(encap);
889         if (*err != 0)
890                 return FALSE;
891
892         /* All systems go! */
893         return TRUE;
894 }
895
896 static wtap_dumper* wtap_dump_alloc_wdh(int filetype, int encap, int snaplen,
897                                         gboolean compressed, int *err)
898 {
899         wtap_dumper *wdh;
900
901         wdh = (wtap_dumper *)g_malloc0(sizeof (wtap_dumper));
902         if (wdh == NULL) {
903                 *err = errno;
904                 return NULL;
905         }
906
907         wdh->file_type = filetype;
908         wdh->snaplen = snaplen;
909         wdh->encap = encap;
910         wdh->compressed = compressed;
911         return wdh;
912 }
913
914 static gboolean wtap_dump_open_finish(wtap_dumper *wdh, int filetype, gboolean compressed, int *err)
915 {
916         int fd;
917         gboolean cant_seek;
918
919         /* Can we do a seek on the file descriptor?
920            If not, note that fact. */
921         if(compressed) {
922                 cant_seek = TRUE;
923         } else {
924                 fd = fileno((FILE *)wdh->fh);
925                 if (lseek(fd, 1, SEEK_CUR) == -1)
926                         cant_seek = TRUE;
927                 else {
928                         /* Undo the seek. */
929                         lseek(fd, 0, SEEK_SET);
930                         cant_seek = FALSE;
931                 }
932         }
933
934         /* Now try to open the file for writing. */
935         if (!(*dump_open_table[filetype].dump_open)(wdh, cant_seek, err)) {
936                 return FALSE;
937         }
938
939         return TRUE;    /* success! */
940 }
941
942 gboolean wtap_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
943                    const union wtap_pseudo_header *pseudo_header, const guchar *pd, int *err)
944 {
945         return (wdh->subtype_write)(wdh, phdr, pseudo_header, pd, err);
946 }
947
948 void wtap_dump_flush(wtap_dumper *wdh)
949 {
950 #ifdef HAVE_LIBZ
951         if(wdh->compressed) {
952                 gzflush((gzFile)wdh->fh, Z_SYNC_FLUSH); /* XXX - is Z_SYNC_FLUSH the right one? */
953         } else
954 #endif
955         {
956                 fflush((FILE *)wdh->fh);
957         }
958 }
959
960 gboolean wtap_dump_close(wtap_dumper *wdh, int *err)
961 {
962         gboolean ret = TRUE;
963
964         if (wdh->subtype_close != NULL) {
965                 /* There's a close routine for this dump stream. */
966                 if (!(wdh->subtype_close)(wdh, err))
967                         ret = FALSE;
968         }
969         errno = WTAP_ERR_CANT_CLOSE;
970         /* Don't close stdout */
971         if (wdh->fh != stdout) {
972                 if (wtap_dump_file_close(wdh) == EOF) {
973                         if (ret) {
974                                 /* The per-format close function succeeded,
975                                    but the fclose didn't.  Save the reason
976                                    why, if our caller asked for it. */
977                                 if (err != NULL)
978                                         *err = errno;
979                         }
980                         ret = FALSE;
981                 }
982         } else {
983                 /* as we don't close stdout, at least try to flush it */
984                 wtap_dump_flush(wdh);
985         }
986         if (wdh->priv != NULL)
987                 g_free(wdh->priv);
988         g_free(wdh);
989         return ret;
990 }
991
992 gint64 wtap_get_bytes_dumped(wtap_dumper *wdh)
993 {
994         return wdh->bytes_dumped;
995 }
996
997 void wtap_set_bytes_dumped(wtap_dumper *wdh, gint64 bytes_dumped)
998 {
999         wdh->bytes_dumped = bytes_dumped;
1000 }
1001
1002 gboolean wtap_dump_set_addrinfo_list(wtap_dumper *wdh, struct addrinfo *addrinfo_list)
1003 {
1004         if (!wdh || wdh->file_type < 0 || wdh->file_type >= wtap_num_file_types
1005                 || dump_open_table[wdh->file_type].has_name_resolution == FALSE)
1006                         return FALSE;
1007         wdh->addrinfo_list = addrinfo_list;
1008         return TRUE;
1009 }
1010
1011 /* internally open a file for writing (compressed or not) */
1012 #ifdef HAVE_LIBZ
1013 static WFILE_T wtap_dump_file_open(wtap_dumper *wdh, const char *filename)
1014 {
1015         if(wdh->compressed) {
1016                 return gzopen(filename, "wb");
1017         } else {
1018                 return ws_fopen(filename, "wb");
1019         }
1020 }
1021 #else
1022 static WFILE_T wtap_dump_file_open(wtap_dumper *wdh _U_, const char *filename)
1023 {
1024         return ws_fopen(filename, "wb");
1025 }
1026 #endif
1027
1028 /* internally open a file for writing (compressed or not) */
1029 #ifdef HAVE_LIBZ
1030 static WFILE_T wtap_dump_file_fdopen(wtap_dumper *wdh, int fd)
1031 {
1032         if(wdh->compressed) {
1033                 return gzdopen(fd, "wb");
1034         } else {
1035                 return fdopen(fd, "wb");
1036         }
1037 }
1038 #else
1039 static WFILE_T wtap_dump_file_fdopen(wtap_dumper *wdh _U_, int fd)
1040 {
1041         return fdopen(fd, "wb");
1042 }
1043 #endif
1044
1045 /* internally writing raw bytes (compressed or not) */
1046 gboolean wtap_dump_file_write(wtap_dumper *wdh, const void *buf, size_t bufsize,
1047                      int *err)
1048 {
1049         size_t nwritten;
1050 #ifdef HAVE_LIBZ
1051         int errnum;
1052 #endif
1053
1054 #ifdef HAVE_LIBZ
1055         if (wdh->compressed) {
1056                 nwritten = gzwrite((gzFile)wdh->fh, buf, (unsigned) bufsize);
1057                 /*
1058                  * At least according to zlib.h, gzwrite returns 0
1059                  * on error; that appears to be the case in libz
1060                  * 1.2.5.
1061                  */
1062                 if (nwritten == 0) {
1063                         gzerror((gzFile)wdh->fh, &errnum);
1064                         if (errnum == Z_ERRNO)
1065                                 *err = errno;
1066                         else {
1067                                 /*
1068                                  * XXX - what to do with this zlib-specific
1069                                  * number?
1070                                  */
1071                                 *err = errnum;
1072                         }
1073                         return FALSE;
1074                 }
1075         } else
1076 #endif
1077         {
1078                 nwritten = fwrite(buf, 1, bufsize, (FILE *)wdh->fh);
1079                 /*
1080                  * At least according to the Mac OS X man page,
1081                  * this can return a short count on an error.
1082                  */
1083                 if (nwritten != bufsize) {
1084                         if (ferror((FILE *)wdh->fh))
1085                                 *err = errno;
1086                         else
1087                                 *err = WTAP_ERR_SHORT_WRITE;
1088                         return FALSE;
1089                 }
1090         }
1091         return TRUE;
1092 }
1093
1094 /* internally close a file for writing (compressed or not) */
1095 static int wtap_dump_file_close(wtap_dumper *wdh)
1096 {
1097 #ifdef HAVE_LIBZ
1098         if(wdh->compressed) {
1099                 return gzclose((gzFile)wdh->fh);
1100         } else
1101 #endif
1102         {
1103                 return fclose((FILE *)wdh->fh);
1104         }
1105 }