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