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