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