6 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
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.
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.
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.
41 #include <wsutil/file_util.h>
44 #include "file_wrappers.h"
46 #include "lanalyzer.h"
47 #include "airopeek9.h"
48 #include "ngsniffer.h"
50 #include "ascendtext.h"
63 #include "etherpeek.h"
65 #include "dbs-etherwatch.h"
71 #include "network_instruments.h"
74 #include "catapult_dct2000.h"
76 #include "netscreen.h"
81 #include "dct3trace.h"
82 #include "packetlogger.h"
83 #include "daintree-sna.h"
84 #include "netscaler.h"
85 #include "jpeg_jfif.h"
89 /* The open_file_* routines should return:
93 * 1 if the file they're reading is one of the types it handles;
95 * 0 if the file they're reading isn't the type they're checking for.
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.
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.
107 static wtap_open_routine_t open_routines_base[] = {
108 /* Files that have magic bytes in fixed locations. These
109 * are easy to identify.
122 network_instruments_open,
126 catapult_dct2000_open,
130 packetlogger_open, /* This type does not have a magic number, but its
131 * files are sometimes grabbed by mpeg_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
144 /* I put NetScreen *before* erf, because there were some
145 * false positives with my test-files (Sake Blok, July 2007)
166 #define N_FILE_TYPES (sizeof open_routines_base / sizeof open_routines_base[0])
168 static wtap_open_routine_t* open_routines = NULL;
170 static GArray* open_routines_arr = NULL;
173 /* initialize the open routines array if it has not been initialized yet */
174 static void init_open_routines(void) {
176 if (open_routines_arr) return;
178 open_routines_arr = g_array_new(FALSE,TRUE,sizeof(wtap_open_routine_t));
180 g_array_append_vals(open_routines_arr,open_routines_base,N_FILE_TYPES);
182 open_routines = (wtap_open_routine_t*)(void *)open_routines_arr->data;
185 void wtap_register_open_routine(wtap_open_routine_t open_routine, gboolean has_magic) {
186 init_open_routines();
189 g_array_prepend_val(open_routines_arr,open_routine);
191 g_array_append_val(open_routines_arr,open_routine);
193 open_routines = (wtap_open_routine_t*)(void *)open_routines_arr->data;
197 * Visual C++ on Win32 systems doesn't define these. (Old UNIX systems don't
198 * define them either.)
200 * Visual C++ on Win32 systems doesn't define S_IFIFO, it defines _S_IFIFO.
203 #define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
206 #define S_IFIFO _S_IFIFO
209 #define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)
212 #define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
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,
228 gboolean use_stdin = FALSE;
230 /* open standard input if filename is '-' */
231 if (strcmp(filename, "-") == 0)
234 /* First, make sure the file is valid */
236 if (ws_fstat64(0, &statb) < 0) {
241 if (ws_stat64(filename, &statb) < 0) {
246 if (S_ISFIFO(statb.st_mode)) {
248 * Opens of FIFOs are allowed only when not opening
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
260 *err = WTAP_ERR_RANDOM_OPEN_PIPE;
263 } else if (S_ISDIR(statb.st_mode)) {
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.
271 } else if (! S_ISREG(statb.st_mode)) {
272 *err = WTAP_ERR_NOT_REGULAR_FILE;
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.
283 if (use_stdin && do_random) {
284 *err = WTAP_ERR_RANDOM_OPEN_STDIN;
289 wth = (wtap *)g_malloc0(sizeof(wtap));
292 errno = WTAP_ERR_CANT_OPEN;
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.
306 if (_setmode(wth->fd, O_BINARY) == -1) {
307 /* "Shouldn't happen" */
314 wth->fd = ws_open(filename, O_RDONLY|O_BINARY, 0000 /* no creation so don't matter */);
321 if (!(wth->fh = filed_open(wth->fd))) {
329 if (!(wth->random_fh = file_open(filename))) {
336 wth->random_fh = NULL;
339 wth->file_encap = WTAP_ENCAP_UNKNOWN;
340 wth->data_offset = 0;
341 wth->subtype_sequential_close = NULL;
342 wth->subtype_close = NULL;
343 wth->tsprecision = WTAP_FILE_TSPREC_USEC;
346 init_open_routines();
347 if (wth->random_fh) {
348 wth->fast_seek = g_ptr_array_new();
350 file_set_random_access(wth->fh, FALSE, wth->fast_seek);
351 file_set_random_access(wth->random_fh, TRUE, wth->fast_seek);
354 /* Try all file types */
355 for (i = 0; i < open_routines_arr->len; i++) {
356 /* Seek back to the beginning of the file; the open routine
357 for the previous file type may have left the file
358 position somewhere other than the beginning, and the
359 open routine for this file type will probably want
360 to start reading at the beginning.
362 Initialize the data offset while we're at it. */
363 if (file_seek(wth->fh, 0, SEEK_SET, err) == -1) {
364 /* I/O error - give up */
365 if (wth->random_fh != NULL)
366 file_close(wth->random_fh);
371 wth->data_offset = 0;
373 switch ((*open_routines[i])(wth, err, err_info)) {
376 /* I/O error - give up */
377 if (wth->random_fh != NULL)
378 file_close(wth->random_fh);
384 /* No I/O error, but not that type of file */
388 /* We found the file type */
393 /* Well, it's not one of the types of file we know about. */
395 *err = WTAP_ERR_FILE_UNKNOWN_FORMAT;
399 wth->frame_buffer = (struct Buffer *)g_malloc(sizeof(struct Buffer));
400 buffer_init(wth->frame_buffer, 1500);
404 /* Table of the file types we know about. */
405 static const struct file_type_info dump_open_table_base[] = {
406 /* WTAP_FILE_UNKNOWN (only used internally for initialization) */
407 { NULL, NULL, NULL, NULL, FALSE, FALSE,
410 /* WTAP_FILE_WTAP (only used internally while capturing) */
411 { NULL, NULL, NULL, NULL, FALSE, FALSE,
415 { "Wireshark/tcpdump/... - libpcap", "libpcap", "*.pcap;*.cap", ".pcap", FALSE, FALSE,
416 libpcap_dump_can_write_encap, libpcap_dump_open },
418 /* WTAP_FILE_PCAP_NSEC */
419 { "Wireshark - nanosecond libpcap", "nseclibpcap", "*.pcap;*.cap", ".pcap", FALSE, FALSE,
420 libpcap_dump_can_write_encap, libpcap_dump_open },
422 /* WTAP_FILE_PCAP_AIX */
423 { "AIX tcpdump - libpcap", "aixlibpcap", "*.pcap;*.cap", ".pcap", FALSE, FALSE,
426 /* WTAP_FILE_PCAP_SS991029 */
427 { "Modified tcpdump - libpcap", "modlibpcap", "*.pcap;*.cap", ".pcap", FALSE, FALSE,
428 libpcap_dump_can_write_encap, libpcap_dump_open },
430 /* WTAP_FILE_PCAP_NOKIA */
431 { "Nokia tcpdump - libpcap ", "nokialibpcap", "*.pcap;*.cap", ".pcap", FALSE, FALSE,
432 libpcap_dump_can_write_encap, libpcap_dump_open },
434 /* WTAP_FILE_PCAP_SS990417 */
435 { "RedHat 6.1 tcpdump - libpcap", "rh6_1libpcap", "*.pcap;*.cap", ".pcap", FALSE, FALSE,
436 libpcap_dump_can_write_encap, libpcap_dump_open },
438 /* WTAP_FILE_PCAP_SS990915 */
439 { "SuSE 6.3 tcpdump - libpcap", "suse6_3libpcap", "*.pcap;*.cap", ".pcap", FALSE, FALSE,
440 libpcap_dump_can_write_encap, libpcap_dump_open },
442 /* WTAP_FILE_5VIEWS */
443 { "Accellent 5Views capture", "5views", "*.5vw", ".5vw", TRUE, FALSE,
444 _5views_dump_can_write_encap, _5views_dump_open },
446 /* WTAP_FILE_IPTRACE_1_0 */
447 { "AIX iptrace 1.0", "iptrace_1", "*.*", NULL, FALSE, FALSE,
450 /* WTAP_FILE_IPTRACE_2_0 */
451 { "AIX iptrace 2.0", "iptrace_2", "*.*", NULL, FALSE, FALSE,
455 { "ASN.1 Basic Encoding Rules", "ber", "*.*", NULL, FALSE, FALSE,
458 /* WTAP_FILE_HCIDUMP */
459 { "Bluetooth HCI dump", "hcidump", "*.*", NULL, FALSE, FALSE,
462 /* WTAP_FILE_CATAPULT_DCT2000 */
463 { "Catapult DCT2000 trace (.out format)", "dct2000", "*.out", ".out", FALSE, FALSE,
464 catapult_dct2000_dump_can_write_encap, catapult_dct2000_dump_open },
466 /* WTAP_FILE_NETXRAY_OLD */
467 { "Cinco Networks NetXRay 1.x", "netxray1", "*.cap", ".cap", TRUE, FALSE,
470 /* WTAP_FILE_NETXRAY_1_0 */
471 { "Cinco Networks NetXRay 2.0 or later", "netxray2", "*.cap", ".cap", TRUE, FALSE,
474 /* WTAP_FILE_COSINE */
475 { "CoSine IPSX L2 capture", "cosine", "*.*", NULL, FALSE, FALSE,
478 /* WTAP_FILE_CSIDS */
479 { "CSIDS IPLog", "csids", "*.*", NULL, FALSE, FALSE,
482 /* WTAP_FILE_DBS_ETHERWATCH */
483 { "DBS Etherwatch (VMS)", "etherwatch", "*.*", NULL, FALSE, FALSE,
487 { "Endace ERF capture", "erf", "*.erf", ".erf", FALSE, FALSE,
490 /* WTAP_FILE_EYESDN */
491 { "EyeSDN USB S0/E1 ISDN trace format", "eyesdn", "*.trc", ".trc", FALSE, FALSE,
492 eyesdn_dump_can_write_encap, eyesdn_dump_open },
494 /* WTAP_FILE_NETTL */
495 { "HP-UX nettl trace", "nettl", "*.TRC0;*.TRC1", ".TRC0", FALSE, FALSE,
496 nettl_dump_can_write_encap, nettl_dump_open },
498 /* WTAP_FILE_ISERIES */
499 { "IBM iSeries comm. trace (ASCII)", "iseries_ascii", "*.*", NULL, FALSE, FALSE,
502 /* WTAP_FILE_ISERIES_UNICODE */
503 { "IBM iSeries comm. trace (UNICODE)", "iseries_unicode", "*.*", NULL, FALSE, FALSE,
506 /* WTAP_FILE_I4BTRACE */
507 { "I4B ISDN trace", "i4btrace", "*.*", NULL, FALSE, FALSE,
510 /* WTAP_FILE_ASCEND */
511 { "Lucent/Ascend access server trace", "ascend", "*.*", NULL, FALSE, FALSE,
514 /* WTAP_FILE_NETMON_1_x */
515 { "Microsoft NetMon 1.x", "netmon1", "*.cap", ".cap", TRUE, FALSE,
516 netmon_dump_can_write_encap, netmon_dump_open },
518 /* WTAP_FILE_NETMON_2_x */
519 { "Microsoft NetMon 2.x", "netmon2", "*.cap", ".cap", TRUE, FALSE,
520 netmon_dump_can_write_encap, netmon_dump_open },
522 /* WTAP_FILE_NGSNIFFER_UNCOMPRESSED */
523 { "NA Sniffer (DOS)", "ngsniffer", "*.cap;*.enc;*.trc;*.fdc;*.syc", ".cap", FALSE, FALSE,
524 ngsniffer_dump_can_write_encap, ngsniffer_dump_open },
526 /* WTAP_FILE_NGSNIFFER_COMPRESSED */
527 { "NA Sniffer (DOS), compressed", "ngsniffer_comp", "*.caz", ".caz", FALSE, FALSE,
530 /* WTAP_FILE_NETXRAY_1_1 */
531 { "NA Sniffer (Windows) 1.1", "ngwsniffer_1_1", "*.cap", ".cap", TRUE, FALSE,
532 netxray_dump_can_write_encap_1_1, netxray_dump_open_1_1 },
534 /* WTAP_FILE_NETXRAY_2_00x */
535 { "NA Sniffer (Windows) 2.00x", "ngwsniffer_2_0", "*.cap", ".cap", TRUE, FALSE,
536 netxray_dump_can_write_encap_2_0, netxray_dump_open_2_0 },
538 /* WTAP_FILE_NETWORK_INSTRUMENTS_V9 */
539 { "Network Instruments Observer (V9)", "niobserverv9", "*.bfr", ".bfr", FALSE, FALSE,
540 network_instruments_dump_can_write_encap, network_instruments_dump_open },
542 /* WTAP_FILE_LANALYZER */
543 { "Novell LANalyzer","lanalyzer", "*.tr1", ".tr1", TRUE, FALSE,
544 lanalyzer_dump_can_write_encap, lanalyzer_dump_open },
546 /* WTAP_FILE_PPPDUMP */
547 { "pppd log (pppdump format)", "pppd", "*.*", NULL, FALSE, FALSE,
550 /* WTAP_FILE_RADCOM */
551 { "RADCOM WAN/LAN analyzer", "radcom", "*.*", NULL, FALSE, FALSE,
554 /* WTAP_FILE_SNOOP */
555 { "Sun snoop", "snoop", "*.snoop;*.cap", ".snoop", FALSE, FALSE,
556 snoop_dump_can_write_encap, snoop_dump_open },
558 /* WTAP_FILE_SHOMITI */
559 { "Shomiti/Finisar Surveyor", "shomiti", "*.cap", ".cap", FALSE, FALSE,
563 { "TCPIPtrace (VMS)", "tcpiptrace", "*.*", NULL, FALSE, FALSE,
567 { "Tektronix K12xx 32-bit .rf5 format", "rf5", "*.rf5", ".rf5", TRUE, FALSE,
568 k12_dump_can_write_encap, k12_dump_open },
570 /* WTAP_FILE_TOSHIBA */
571 { "Toshiba Compact ISDN Router snoop", "toshiba", "*.*", NULL, FALSE, FALSE,
574 /* WTAP_FILE_VISUAL_NETWORKS */
575 { "Visual Networks traffic capture", "visual", "*.*", NULL, TRUE, FALSE,
576 visual_dump_can_write_encap, visual_dump_open },
578 /* WTAP_FILE_ETHERPEEK_V56 */
579 { "WildPackets Ether/TokenPeek (V5 & V6)", "peek56", "*.tpc;*.apc;*.pkt;*.wpz", ".pkt", FALSE, FALSE,
582 /* WTAP_FILE_ETHERPEEK_V7 */
583 { "WildPackets Ether/Token/AiroPeek (V7)", "peek7", "*.tpc;*.apc;*.pkt;*.wpz", ".pkt", FALSE, FALSE,
586 /* WTAP_FILE_ETHERPEEK_V9 */
587 { "WildPackets Ether/AiroPeek (V9)", "peek9", "*.tpc;*.apc;*.pkt;*.wpz", ".pkt", FALSE, FALSE,
591 { "MPEG", "mpeg", "*.mpeg;*.mpg;*.mp3", ".mpeg", FALSE, FALSE,
594 /* WTAP_FILE_K12TEXT */
595 { "K12 text file", "k12text", "*.txt", ".txt", FALSE, FALSE,
596 k12text_dump_can_write_encap, k12text_dump_open },
598 /* WTAP_FILE_NETSCREEN */
599 { "NetScreen snoop text file", "netscreen", "*.*", NULL, FALSE, FALSE,
602 /* WTAP_FILE_COMMVIEW */
603 { "TamoSoft CommView", "commview", "*.ncf", ".ncf", FALSE, FALSE,
604 commview_dump_can_write_encap, commview_dump_open },
606 /* WTAP_FILE_PCAPNG */
607 { "Wireshark - pcapng", "pcapng", "*.pcapng", NULL, FALSE, TRUE,
608 pcapng_dump_can_write_encap, pcapng_dump_open },
610 /* WTAP_FILE_BTSNOOP */
611 { "Symbian OS btsnoop", "btsnoop", "*.log", ".log", FALSE, FALSE,
612 btsnoop_dump_can_write_encap, btsnoop_dump_open_h4 },
614 /* WTAP_FILE_X2E_XORAYA */
615 { NULL, NULL, NULL, NULL, FALSE, FALSE,
619 { "Transport-Neutral Encapsulation Format", "tnef", "*.*", NULL, FALSE, FALSE,
622 /* WTAP_FILE_DCT3TRACE */
623 { "Gammu DCT3 trace", "dct3trace", "*.xml", NULL, FALSE, FALSE,
626 /* WTAP_FILE_PACKETLOGGER */
627 { "PacketLogger", "pklg", "*.pklg", NULL, FALSE, FALSE,
630 /* WTAP_FILE_DAINTREE_SNA */
631 { "Daintree SNA", "dsna", "*.dcf", NULL, FALSE, FALSE,
634 /* WTAP_FILE_NETSCALER_1_0 */
635 { "NetScaler Trace (Version 1.0)", "nstrace10", "*.*", "*.*", TRUE, FALSE,
636 nstrace_10_dump_can_write_encap, nstrace_dump_open },
638 /* WTAP_FILE_NETSCALER_2_0 */
639 { "NetScaler Trace (Version 2.0)", "nstrace20", "*.cap", "*.cap", TRUE, FALSE,
640 nstrace_20_dump_can_write_encap, nstrace_dump_open },
642 /* WTAP_FILE_JPEG_JFIF */
643 { "JPEG/JFIF", "jpeg", "*.jpg;*.jpeg;*.jfif", ".jpg", FALSE, FALSE,
646 /* WTAP_FILE_IPFIX */
647 { "IPFIX File Format", "ipfix", "*.pfx;*.ipfix", NULL, FALSE, FALSE,
651 gint wtap_num_file_types = sizeof(dump_open_table_base) / sizeof(struct file_type_info);
653 static GArray* dump_open_table_arr = NULL;
654 static const struct file_type_info* dump_open_table = dump_open_table_base;
656 /* initialize the open routines array if it has not being initialized yet */
657 static void init_file_types(void) {
659 if (dump_open_table_arr) return;
661 dump_open_table_arr = g_array_new(FALSE,TRUE,sizeof(struct file_type_info));
663 g_array_append_vals(dump_open_table_arr,dump_open_table_base,wtap_num_file_types);
665 dump_open_table = (const struct file_type_info*)(void *)dump_open_table_arr->data;
668 int wtap_register_file_type(const struct file_type_info* fi) {
671 g_array_append_val(dump_open_table_arr,*fi);
673 dump_open_table = (const struct file_type_info*)(void *)dump_open_table_arr->data;
675 return wtap_num_file_types++;
678 int wtap_get_num_file_types(void)
680 return wtap_num_file_types;
683 /* Name that should be somewhat descriptive. */
684 const char *wtap_file_type_string(int filetype)
686 if (filetype < 0 || filetype >= wtap_num_file_types) {
687 g_error("Unknown capture file type %d", filetype);
688 /** g_error() does an abort() and thus never returns **/
691 return dump_open_table[filetype].name;
694 /* Name to use in, say, a command-line flag specifying the type. */
695 const char *wtap_file_type_short_string(int filetype)
697 if (filetype < 0 || filetype >= wtap_num_file_types)
700 return dump_open_table[filetype].short_name;
703 /* Translate a short name to a capture file type. */
704 int wtap_short_string_to_file_type(const char *short_name)
708 for (filetype = 0; filetype < wtap_num_file_types; filetype++) {
709 if (dump_open_table[filetype].short_name != NULL &&
710 strcmp(short_name, dump_open_table[filetype].short_name) == 0)
713 return -1; /* no such file type, or we can't write it */
716 /* file extensions to use. */
717 const char *wtap_file_extensions_string(int filetype)
719 if (filetype < 0 || filetype >= wtap_num_file_types)
722 return dump_open_table[filetype].file_extensions;
725 /* default file extension to use. */
726 const char *wtap_file_extension_default_string(int filetype)
728 if (filetype < 0 || filetype >= wtap_num_file_types)
731 return dump_open_table[filetype].file_extension_default;
734 gboolean wtap_dump_can_open(int filetype)
736 if (filetype < 0 || filetype >= wtap_num_file_types
737 || dump_open_table[filetype].dump_open == NULL)
743 gboolean wtap_dump_can_write_encap(int filetype, int encap)
745 if (filetype < 0 || filetype >= wtap_num_file_types
746 || dump_open_table[filetype].can_write_encap == NULL)
749 if ((*dump_open_table[filetype].can_write_encap)(encap) != 0)
756 gboolean wtap_dump_can_compress(int filetype)
759 * If this is an unknown file type, or if we have to
760 * seek when writing out a file with this file type,
763 if (filetype < 0 || filetype >= wtap_num_file_types
764 || dump_open_table[filetype].writing_must_seek)
770 gboolean wtap_dump_can_compress(int filetype _U_)
776 gboolean wtap_dump_has_name_resolution(int filetype)
778 if (filetype < 0 || filetype >= wtap_num_file_types
779 || dump_open_table[filetype].has_name_resolution == FALSE)
785 static gboolean wtap_dump_open_check(int filetype, int encap, gboolean comressed, int *err);
786 static wtap_dumper* wtap_dump_alloc_wdh(int filetype, int encap, int snaplen,
787 gboolean compressed, int *err);
788 static gboolean wtap_dump_open_finish(wtap_dumper *wdh, int filetype, gboolean compressed, int *err);
790 static WFILE_T wtap_dump_file_open(wtap_dumper *wdh, const char *filename);
791 static WFILE_T wtap_dump_file_fdopen(wtap_dumper *wdh, int fd);
792 static int wtap_dump_file_close(wtap_dumper *wdh);
794 wtap_dumper* wtap_dump_open(const char *filename, int filetype, int encap,
795 int snaplen, gboolean compressed, int *err)
800 /* Check whether we can open a capture file with that file type
801 and that encapsulation. */
802 if (!wtap_dump_open_check(filetype, encap, compressed, err))
805 /* Allocate a data structure for the output stream. */
806 wdh = wtap_dump_alloc_wdh(filetype, encap, snaplen, compressed, err);
808 return NULL; /* couldn't allocate it */
810 /* "-" means stdout */
811 if (strcmp(filename, "-") == 0) {
813 *err = EINVAL; /* XXX - return a Wiretap error code for this */
815 return NULL; /* compress won't work on stdout */
818 if (_setmode(fileno(stdout), O_BINARY) == -1) {
819 /* "Should not happen" */
822 return NULL; /* couldn't put standard output in binary mode */
827 /* In case "fopen()" fails but doesn't set "errno", set "errno"
828 to a generic "the open failed" error. */
829 errno = WTAP_ERR_CANT_OPEN;
830 fh = wtap_dump_file_open(wdh, filename);
834 return NULL; /* can't create file */
839 if (!wtap_dump_open_finish(wdh, filetype, compressed, err)) {
840 /* Get rid of the file we created; we couldn't finish
842 if (wdh->fh != stdout) {
843 wtap_dump_file_close(wdh);
852 wtap_dumper* wtap_dump_fdopen(int fd, int filetype, int encap, int snaplen,
853 gboolean compressed, int *err)
858 /* Check whether we can open a capture file with that file type
859 and that encapsulation. */
860 if (!wtap_dump_open_check(filetype, encap, compressed, err))
863 /* Allocate a data structure for the output stream. */
864 wdh = wtap_dump_alloc_wdh(filetype, encap, snaplen, compressed, err);
866 return NULL; /* couldn't allocate it */
870 if (_setmode(fileno(stdout), O_BINARY) == -1) {
871 /* "Should not happen" */
874 return NULL; /* couldn't put standard output in binary mode */
879 /* In case "fopen()" fails but doesn't set "errno", set "errno"
880 to a generic "the open failed" error. */
881 errno = WTAP_ERR_CANT_OPEN;
882 fh = wtap_dump_file_fdopen(wdh, fd);
886 return NULL; /* can't create standard I/O stream */
890 if (!wtap_dump_open_finish(wdh, filetype, compressed, err)) {
891 wtap_dump_file_close(wdh);
898 static gboolean wtap_dump_open_check(int filetype, int encap, gboolean compressed, int *err)
900 if (!wtap_dump_can_open(filetype)) {
901 /* Invalid type, or type we don't know how to write. */
902 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
906 /* OK, we know how to write that type; can we write the specified
907 encapsulation type? */
908 *err = (*dump_open_table[filetype].can_write_encap)(encap);
912 /* if compression is wanted, do we support this for this filetype? */
913 if(compressed && !wtap_dump_can_compress(filetype)) {
914 *err = WTAP_ERR_COMPRESSION_NOT_SUPPORTED;
918 *err = (*dump_open_table[filetype].can_write_encap)(encap);
922 /* All systems go! */
926 static wtap_dumper* wtap_dump_alloc_wdh(int filetype, int encap, int snaplen,
927 gboolean compressed, int *err)
931 wdh = (wtap_dumper *)g_malloc0(sizeof (wtap_dumper));
937 wdh->file_type = filetype;
938 wdh->snaplen = snaplen;
940 wdh->compressed = compressed;
944 static gboolean wtap_dump_open_finish(wtap_dumper *wdh, int filetype, gboolean compressed, int *err)
949 /* Can we do a seek on the file descriptor?
950 If not, note that fact. */
954 fd = fileno((FILE *)wdh->fh);
955 if (lseek(fd, 1, SEEK_CUR) == -1)
959 lseek(fd, 0, SEEK_SET);
964 /* If this file type requires seeking, and we can't seek, fail. */
965 if (dump_open_table[filetype].writing_must_seek && cant_seek) {
966 *err = WTAP_ERR_CANT_WRITE_TO_PIPE;
970 /* Now try to open the file for writing. */
971 if (!(*dump_open_table[filetype].dump_open)(wdh, err)) {
975 return TRUE; /* success! */
978 gboolean wtap_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
979 const union wtap_pseudo_header *pseudo_header, const guchar *pd, int *err)
981 return (wdh->subtype_write)(wdh, phdr, pseudo_header, pd, err);
984 void wtap_dump_flush(wtap_dumper *wdh)
987 if(wdh->compressed) {
988 gzwfile_flush((GZWFILE_T)wdh->fh);
992 fflush((FILE *)wdh->fh);
996 gboolean wtap_dump_close(wtap_dumper *wdh, int *err)
1000 if (wdh->subtype_close != NULL) {
1001 /* There's a close routine for this dump stream. */
1002 if (!(wdh->subtype_close)(wdh, err))
1005 errno = WTAP_ERR_CANT_CLOSE;
1006 /* Don't close stdout */
1007 if (wdh->fh != stdout) {
1008 if (wtap_dump_file_close(wdh) == EOF) {
1010 /* The per-format close function succeeded,
1011 but the fclose didn't. Save the reason
1012 why, if our caller asked for it. */
1019 /* as we don't close stdout, at least try to flush it */
1020 wtap_dump_flush(wdh);
1022 if (wdh->priv != NULL)
1028 gint64 wtap_get_bytes_dumped(wtap_dumper *wdh)
1030 return wdh->bytes_dumped;
1033 void wtap_set_bytes_dumped(wtap_dumper *wdh, gint64 bytes_dumped)
1035 wdh->bytes_dumped = bytes_dumped;
1038 gboolean wtap_dump_set_addrinfo_list(wtap_dumper *wdh, struct addrinfo *addrinfo_list)
1040 if (!wdh || wdh->file_type < 0 || wdh->file_type >= wtap_num_file_types
1041 || dump_open_table[wdh->file_type].has_name_resolution == FALSE)
1043 wdh->addrinfo_list = addrinfo_list;
1047 /* internally open a file for writing (compressed or not) */
1049 static WFILE_T wtap_dump_file_open(wtap_dumper *wdh, const char *filename)
1051 if(wdh->compressed) {
1052 return gzwfile_open(filename);
1054 return ws_fopen(filename, "wb");
1058 static WFILE_T wtap_dump_file_open(wtap_dumper *wdh _U_, const char *filename)
1060 return ws_fopen(filename, "wb");
1064 /* internally open a file for writing (compressed or not) */
1066 static WFILE_T wtap_dump_file_fdopen(wtap_dumper *wdh, int fd)
1068 if(wdh->compressed) {
1069 return gzwfile_fdopen(fd);
1071 return fdopen(fd, "wb");
1075 static WFILE_T wtap_dump_file_fdopen(wtap_dumper *wdh _U_, int fd)
1077 return fdopen(fd, "wb");
1081 /* internally writing raw bytes (compressed or not) */
1082 gboolean wtap_dump_file_write(wtap_dumper *wdh, const void *buf, size_t bufsize,
1088 if (wdh->compressed) {
1089 nwritten = gzwfile_write((GZWFILE_T)wdh->fh, buf, (unsigned) bufsize);
1091 * gzwfile_write() returns 0 on error.
1093 if (nwritten == 0) {
1094 *err = gzwfile_geterr((GZWFILE_T)wdh->fh);
1100 nwritten = fwrite(buf, 1, bufsize, (FILE *)wdh->fh);
1102 * At least according to the Mac OS X man page,
1103 * this can return a short count on an error.
1105 if (nwritten != bufsize) {
1106 if (ferror((FILE *)wdh->fh))
1109 *err = WTAP_ERR_SHORT_WRITE;
1116 /* internally close a file for writing (compressed or not) */
1117 static int wtap_dump_file_close(wtap_dumper *wdh)
1120 if(wdh->compressed) {
1121 return gzwfile_close((GZWFILE_T)wdh->fh);
1125 return fclose((FILE *)wdh->fh);