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"
82 #include "dct3trace.h"
83 #include "packetlogger.h"
84 #include "daintree-sna.h"
85 #include "netscaler.h"
86 #include "mime_file.h"
90 /* The open_file_* routines should return:
94 * 1 if the file they're reading is one of the types it handles;
96 * 0 if the file they're reading isn't the type they're checking for.
98 * If the routine handles this type of file, it should set the "file_type"
99 * field in the "struct wtap" to the type of the file.
101 * Put the trace files that are merely saved telnet-sessions last, since it's
102 * possible that you could have captured someone a router telnet-session
103 * using another tool. So, a libpcap trace of an toshiba "snoop" session
104 * should be discovered as a libpcap file, not a toshiba file.
108 static wtap_open_routine_t open_routines_base[] = {
109 /* Files that have magic bytes in fixed locations. These
110 * are easy to identify.
123 network_instruments_open,
127 catapult_dct2000_open,
132 packetlogger_open, /* This type does not have a magic number, but its
133 * files are sometimes grabbed by mpeg_open. */
139 /* Files that don't have magic bytes at a fixed location,
140 * but that instead require a heuristic of some sort to
141 * identify them. This includes the ASCII trace files that
142 * would be, for example, saved copies of a Telnet session
146 /* I put NetScreen *before* erf, because there were some
147 * false positives with my test-files (Sake Blok, July 2007)
168 #define N_FILE_TYPES (sizeof open_routines_base / sizeof open_routines_base[0])
170 static wtap_open_routine_t* open_routines = NULL;
172 static GArray* open_routines_arr = NULL;
175 /* initialize the open routines array if it has not been initialized yet */
176 static void init_open_routines(void) {
178 if (open_routines_arr) return;
180 open_routines_arr = g_array_new(FALSE,TRUE,sizeof(wtap_open_routine_t));
182 g_array_append_vals(open_routines_arr,open_routines_base,N_FILE_TYPES);
184 open_routines = (wtap_open_routine_t*)(void *)open_routines_arr->data;
187 void wtap_register_open_routine(wtap_open_routine_t open_routine, gboolean has_magic) {
188 init_open_routines();
191 g_array_prepend_val(open_routines_arr,open_routine);
193 g_array_append_val(open_routines_arr,open_routine);
195 open_routines = (wtap_open_routine_t*)(void *)open_routines_arr->data;
199 * Visual C++ on Win32 systems doesn't define these. (Old UNIX systems don't
200 * define them either.)
202 * Visual C++ on Win32 systems doesn't define S_IFIFO, it defines _S_IFIFO.
205 #define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
208 #define S_IFIFO _S_IFIFO
211 #define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)
214 #define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
217 /* Opens a file and prepares a wtap struct.
218 If "do_random" is TRUE, it opens the file twice; the second open
219 allows the application to do random-access I/O without moving
220 the seek offset for sequential I/O, which is used by Wireshark
221 so that it can do sequential I/O to a capture file that's being
222 written to as new packets arrive independently of random I/O done
223 to display protocol trees for packets when they're selected. */
224 wtap* wtap_open_offline(const char *filename, int *err, char **err_info,
231 gboolean use_stdin = FALSE;
233 /* open standard input if filename is '-' */
234 if (strcmp(filename, "-") == 0)
237 /* First, make sure the file is valid */
239 if (ws_fstat64(0, &statb) < 0) {
244 if (ws_stat64(filename, &statb) < 0) {
249 if (S_ISFIFO(statb.st_mode)) {
251 * Opens of FIFOs are allowed only when not opening
254 * XXX - currently, we do seeking when trying to find
255 * out the file type, so we don't actually support
256 * opening FIFOs. However, we may eventually
257 * do buffering that allows us to do at least some
258 * file type determination even on pipes, so we
259 * allow FIFO opens and let things fail later when
263 *err = WTAP_ERR_RANDOM_OPEN_PIPE;
266 } else if (S_ISDIR(statb.st_mode)) {
268 * Return different errors for "this is a directory"
269 * and "this is some random special file type", so
270 * the user can get a potentially more helpful error.
274 } else if (! S_ISREG(statb.st_mode)) {
275 *err = WTAP_ERR_NOT_REGULAR_FILE;
280 * We need two independent descriptors for random access, so
281 * they have different file positions. If we're opening the
282 * standard input, we can only dup it to get additional
283 * descriptors, so we can't have two independent descriptors,
284 * and thus can't do random access.
286 if (use_stdin && do_random) {
287 *err = WTAP_ERR_RANDOM_OPEN_STDIN;
292 wth = (wtap *)g_malloc0(sizeof(wtap));
295 errno = WTAP_ERR_CANT_OPEN;
298 * We dup FD 0, so that we don't have to worry about
299 * a file_close of wth->fh closing the standard
300 * input of the process.
309 if (_setmode(fd, O_BINARY) == -1) {
310 /* "Shouldn't happen" */
316 if (!(wth->fh = filed_open(fd))) {
323 if (!(wth->fh = file_open(filename))) {
331 if (!(wth->random_fh = file_open(filename))) {
338 wth->random_fh = NULL;
341 wth->file_encap = WTAP_ENCAP_UNKNOWN;
342 wth->data_offset = 0;
343 wth->subtype_sequential_close = NULL;
344 wth->subtype_close = NULL;
345 wth->tsprecision = WTAP_FILE_TSPREC_USEC;
348 init_open_routines();
349 if (wth->random_fh) {
350 wth->fast_seek = g_ptr_array_new();
352 file_set_random_access(wth->fh, FALSE, wth->fast_seek);
353 file_set_random_access(wth->random_fh, TRUE, wth->fast_seek);
356 /* Try all file types */
357 for (i = 0; i < open_routines_arr->len; i++) {
358 /* Seek back to the beginning of the file; the open routine
359 for the previous file type may have left the file
360 position somewhere other than the beginning, and the
361 open routine for this file type will probably want
362 to start reading at the beginning.
364 Initialize the data offset while we're at it. */
365 if (file_seek(wth->fh, 0, SEEK_SET, err) == -1) {
366 /* I/O error - give up */
367 if (wth->random_fh != NULL)
368 file_close(wth->random_fh);
373 wth->data_offset = 0;
375 switch ((*open_routines[i])(wth, err, err_info)) {
378 /* I/O error - give up */
379 if (wth->random_fh != NULL)
380 file_close(wth->random_fh);
386 /* No I/O error, but not that type of file */
390 /* We found the file type */
395 /* Well, it's not one of the types of file we know about. */
397 *err = WTAP_ERR_FILE_UNKNOWN_FORMAT;
401 wth->frame_buffer = (struct Buffer *)g_malloc(sizeof(struct Buffer));
402 buffer_init(wth->frame_buffer, 1500);
406 /* Table of the file types we know about. */
407 static const struct file_type_info dump_open_table_base[] = {
408 /* WTAP_FILE_UNKNOWN (only used internally for initialization) */
409 { NULL, NULL, NULL, NULL, FALSE, FALSE,
413 /* Gianluca Varenni suggests that we add "deprecated" to the description. */
414 { "Wireshark/tcpdump/... - libpcap", "libpcap", "*.pcap;*.cap", ".pcap", FALSE, FALSE,
415 libpcap_dump_can_write_encap, libpcap_dump_open },
417 /* WTAP_FILE_PCAPNG */
418 { "Wireshark - pcapng", "pcapng", "*.pcapng", ".pcapng", FALSE, TRUE,
419 pcapng_dump_can_write_encap, pcapng_dump_open },
421 /* WTAP_FILE_PCAP_NSEC */
422 { "Wireshark - nanosecond libpcap", "nseclibpcap", "*.pcap;*.cap", ".pcap", FALSE, FALSE,
423 libpcap_dump_can_write_encap, libpcap_dump_open },
425 /* WTAP_FILE_PCAP_AIX */
426 { "AIX tcpdump - libpcap", "aixlibpcap", "*.pcap;*.cap", ".pcap", FALSE, FALSE,
429 /* WTAP_FILE_PCAP_SS991029 */
430 { "Modified tcpdump - libpcap", "modlibpcap", "*.pcap;*.cap", ".pcap", FALSE, FALSE,
431 libpcap_dump_can_write_encap, libpcap_dump_open },
433 /* WTAP_FILE_PCAP_NOKIA */
434 { "Nokia tcpdump - libpcap ", "nokialibpcap", "*.pcap;*.cap", ".pcap", FALSE, FALSE,
435 libpcap_dump_can_write_encap, libpcap_dump_open },
437 /* WTAP_FILE_PCAP_SS990417 */
438 { "RedHat 6.1 tcpdump - libpcap", "rh6_1libpcap", "*.pcap;*.cap", ".pcap", FALSE, FALSE,
439 libpcap_dump_can_write_encap, libpcap_dump_open },
441 /* WTAP_FILE_PCAP_SS990915 */
442 { "SuSE 6.3 tcpdump - libpcap", "suse6_3libpcap", "*.pcap;*.cap", ".pcap", FALSE, FALSE,
443 libpcap_dump_can_write_encap, libpcap_dump_open },
445 /* WTAP_FILE_5VIEWS */
446 { "Accellent 5Views capture", "5views", "*.5vw", ".5vw", TRUE, FALSE,
447 _5views_dump_can_write_encap, _5views_dump_open },
449 /* WTAP_FILE_IPTRACE_1_0 */
450 { "AIX iptrace 1.0", "iptrace_1", NULL, NULL, FALSE, FALSE,
453 /* WTAP_FILE_IPTRACE_2_0 */
454 { "AIX iptrace 2.0", "iptrace_2", NULL, NULL, FALSE, FALSE,
458 { "ASN.1 Basic Encoding Rules", "ber", NULL, NULL, FALSE, FALSE,
461 /* WTAP_FILE_HCIDUMP */
462 { "Bluetooth HCI dump", "hcidump", NULL, NULL, FALSE, FALSE,
465 /* WTAP_FILE_CATAPULT_DCT2000 */
466 { "Catapult DCT2000 trace (.out format)", "dct2000", "*.out", ".out", FALSE, FALSE,
467 catapult_dct2000_dump_can_write_encap, catapult_dct2000_dump_open },
469 /* WTAP_FILE_NETXRAY_OLD */
470 { "Cinco Networks NetXRay 1.x", "netxray1", "*.cap", ".cap", TRUE, FALSE,
473 /* WTAP_FILE_NETXRAY_1_0 */
474 { "Cinco Networks NetXRay 2.0 or later", "netxray2", "*.cap", ".cap", TRUE, FALSE,
477 /* WTAP_FILE_COSINE */
478 { "CoSine IPSX L2 capture", "cosine", "*.txt", ".txt", FALSE, FALSE,
481 /* WTAP_FILE_CSIDS */
482 { "CSIDS IPLog", "csids", NULL, NULL, FALSE, FALSE,
485 /* WTAP_FILE_DBS_ETHERWATCH */
486 { "DBS Etherwatch (VMS)", "etherwatch", "*.txt", ".txt", FALSE, FALSE,
490 { "Endace ERF capture", "erf", "*.erf", ".erf", FALSE, FALSE,
491 erf_dump_can_write_encap, erf_dump_open },
493 /* WTAP_FILE_EYESDN */
494 { "EyeSDN USB S0/E1 ISDN trace format", "eyesdn", "*.trc", ".trc", FALSE, FALSE,
495 eyesdn_dump_can_write_encap, eyesdn_dump_open },
497 /* WTAP_FILE_NETTL */
498 { "HP-UX nettl trace", "nettl", "*.trc0;*.trc1", ".trc0", FALSE, FALSE,
499 nettl_dump_can_write_encap, nettl_dump_open },
501 /* WTAP_FILE_ISERIES */
502 { "IBM iSeries comm. trace (ASCII)", "iseries_ascii", "*.txt", ".txt", FALSE, FALSE,
505 /* WTAP_FILE_ISERIES_UNICODE */
506 { "IBM iSeries comm. trace (UNICODE)", "iseries_unicode", "*.txt", ".txt", FALSE, FALSE,
509 /* WTAP_FILE_I4BTRACE */
510 { "I4B ISDN trace", "i4btrace", NULL, NULL, FALSE, FALSE,
513 /* WTAP_FILE_ASCEND */
514 { "Lucent/Ascend access server trace", "ascend", "*.txt", ".txt", FALSE, FALSE,
517 /* WTAP_FILE_NETMON_1_x */
518 { "Microsoft NetMon 1.x", "netmon1", "*.cap", ".cap", TRUE, FALSE,
519 netmon_dump_can_write_encap_1_x, netmon_dump_open },
521 /* WTAP_FILE_NETMON_2_x */
522 { "Microsoft NetMon 2.x", "netmon2", "*.cap", ".cap", TRUE, FALSE,
523 netmon_dump_can_write_encap_2_x, netmon_dump_open },
525 /* WTAP_FILE_NGSNIFFER_UNCOMPRESSED */
526 { "NA Sniffer (DOS)", "ngsniffer", "*.cap;*.enc;*.trc;*.fdc;*.syc", ".cap", FALSE, FALSE,
527 ngsniffer_dump_can_write_encap, ngsniffer_dump_open },
529 /* WTAP_FILE_NGSNIFFER_COMPRESSED */
530 { "NA Sniffer (DOS), compressed", "ngsniffer_comp", "*.caz", ".caz", FALSE, FALSE,
533 /* WTAP_FILE_NETXRAY_1_1 */
534 { "NA Sniffer (Windows) 1.1", "ngwsniffer_1_1", "*.cap", ".cap", TRUE, FALSE,
535 netxray_dump_can_write_encap_1_1, netxray_dump_open_1_1 },
537 /* WTAP_FILE_NETXRAY_2_00x */
538 { "NA Sniffer (Windows) 2.00x", "ngwsniffer_2_0", "*.cap", ".cap", TRUE, FALSE,
539 netxray_dump_can_write_encap_2_0, netxray_dump_open_2_0 },
541 /* WTAP_FILE_NETWORK_INSTRUMENTS */
542 { "Network Instruments Observer", "niobserver", "*.bfr", ".bfr", FALSE, FALSE,
543 network_instruments_dump_can_write_encap, network_instruments_dump_open },
545 /* WTAP_FILE_LANALYZER */
546 { "Novell LANalyzer","lanalyzer", "*.tr1", ".tr1", TRUE, FALSE,
547 lanalyzer_dump_can_write_encap, lanalyzer_dump_open },
549 /* WTAP_FILE_PPPDUMP */
550 { "pppd log (pppdump format)", "pppd", NULL, NULL, FALSE, FALSE,
553 /* WTAP_FILE_RADCOM */
554 { "RADCOM WAN/LAN analyzer", "radcom", NULL, NULL, FALSE, FALSE,
557 /* WTAP_FILE_SNOOP */
558 { "Sun snoop", "snoop", "*.snoop;*.cap", ".snoop", FALSE, FALSE,
559 snoop_dump_can_write_encap, snoop_dump_open },
561 /* WTAP_FILE_SHOMITI */
562 { "Shomiti/Finisar Surveyor", "shomiti", "*.cap", ".cap", FALSE, FALSE,
566 { "TCPIPtrace (VMS)", "tcpiptrace", "*.txt", ".txt", FALSE, FALSE,
570 { "Tektronix K12xx 32-bit .rf5 format", "rf5", "*.rf5", ".rf5", TRUE, FALSE,
571 k12_dump_can_write_encap, k12_dump_open },
573 /* WTAP_FILE_TOSHIBA */
574 { "Toshiba Compact ISDN Router snoop", "toshiba", "*.txt", ".txt", FALSE, FALSE,
577 /* WTAP_FILE_VISUAL_NETWORKS */
578 { "Visual Networks traffic capture", "visual", NULL, NULL, TRUE, FALSE,
579 visual_dump_can_write_encap, visual_dump_open },
581 /* WTAP_FILE_ETHERPEEK_V56 */
582 { "WildPackets Ether/TokenPeek (V5 & V6)", "peek56", "*.tpc;*.apc;*.pkt;*.wpz", ".pkt", FALSE, FALSE,
585 /* WTAP_FILE_ETHERPEEK_V7 */
586 { "WildPackets Ether/Token/AiroPeek (V7)", "peek7", "*.tpc;*.apc;*.pkt;*.wpz", ".pkt", FALSE, FALSE,
589 /* WTAP_FILE_ETHERPEEK_V9 */
590 { "WildPackets Ether/AiroPeek (V9)", "peek9", "*.tpc;*.apc;*.pkt;*.wpz", ".pkt", FALSE, FALSE,
594 { "MPEG", "mpeg", "*.mpeg;*.mpg;*.mp3", ".mpeg", FALSE, FALSE,
597 /* WTAP_FILE_K12TEXT */
598 { "K12 text file", "k12text", "*.txt", ".txt", FALSE, FALSE,
599 k12text_dump_can_write_encap, k12text_dump_open },
601 /* WTAP_FILE_NETSCREEN */
602 { "NetScreen snoop text file", "netscreen", "*.txt", ".txt", FALSE, FALSE,
605 /* WTAP_FILE_COMMVIEW */
606 { "TamoSoft CommView", "commview", "*.ncf", ".ncf", FALSE, FALSE,
607 commview_dump_can_write_encap, commview_dump_open },
609 /* WTAP_FILE_BTSNOOP */
610 { "Symbian OS btsnoop", "btsnoop", "*.log", ".log", FALSE, FALSE,
611 btsnoop_dump_can_write_encap, btsnoop_dump_open_h4 },
614 { "Transport-Neutral Encapsulation Format", "tnef", NULL, NULL, FALSE, FALSE,
617 /* WTAP_FILE_DCT3TRACE */
618 { "Gammu DCT3 trace", "dct3trace", "*.xml", NULL, FALSE, FALSE,
621 /* WTAP_FILE_PACKETLOGGER */
622 { "PacketLogger", "pklg", "*.pklg", ".pklg", FALSE, FALSE,
625 /* WTAP_FILE_DAINTREE_SNA */
626 { "Daintree SNA", "dsna", "*.dcf", ".dcf", FALSE, FALSE,
629 /* WTAP_FILE_NETSCALER_1_0 */
630 { "NetScaler Trace (Version 1.0)", "nstrace10", NULL, NULL, TRUE, FALSE,
631 nstrace_10_dump_can_write_encap, nstrace_dump_open },
633 /* WTAP_FILE_NETSCALER_2_0 */
634 { "NetScaler Trace (Version 2.0)", "nstrace20", "*.cap", ".cap", TRUE, FALSE,
635 nstrace_20_dump_can_write_encap, nstrace_dump_open },
637 /* WTAP_FILE_JPEG_JFIF */
638 { "JPEG/JFIF", "jpeg", "*.jpg;*.jpeg;*.jfif", ".jpg", FALSE, FALSE,
641 /* WTAP_FILE_IPFIX */
642 { "IPFIX File Format", "ipfix", "*.pfx;*.ipfix", ".pfx", FALSE, FALSE,
645 /* WTAP_ENCAP_MIME */
646 { "MIME File Format", "mime", NULL, NULL, FALSE, FALSE,
649 /* WTAP_FILE_AETHRA */
650 { "Aethra .aps file", "aethra", "*.aps", ".aps", FALSE, FALSE,
654 gint wtap_num_file_types = sizeof(dump_open_table_base) / sizeof(struct file_type_info);
656 static GArray* dump_open_table_arr = NULL;
657 static const struct file_type_info* dump_open_table = dump_open_table_base;
659 /* initialize the open routines array if it has not being initialized yet */
660 static void init_file_types(void) {
662 if (dump_open_table_arr) return;
664 dump_open_table_arr = g_array_new(FALSE,TRUE,sizeof(struct file_type_info));
666 g_array_append_vals(dump_open_table_arr,dump_open_table_base,wtap_num_file_types);
668 dump_open_table = (const struct file_type_info*)(void *)dump_open_table_arr->data;
671 int wtap_register_file_type(const struct file_type_info* fi) {
674 g_array_append_val(dump_open_table_arr,*fi);
676 dump_open_table = (const struct file_type_info*)(void *)dump_open_table_arr->data;
678 return wtap_num_file_types++;
681 int wtap_get_num_file_types(void)
683 return wtap_num_file_types;
686 /* Name that should be somewhat descriptive. */
687 const char *wtap_file_type_string(int filetype)
689 if (filetype < 0 || filetype >= wtap_num_file_types) {
690 g_error("Unknown capture file type %d", filetype);
691 /** g_error() does an abort() and thus never returns **/
694 return dump_open_table[filetype].name;
697 /* Name to use in, say, a command-line flag specifying the type. */
698 const char *wtap_file_type_short_string(int filetype)
700 if (filetype < 0 || filetype >= wtap_num_file_types)
703 return dump_open_table[filetype].short_name;
706 /* Translate a short name to a capture file type. */
707 int wtap_short_string_to_file_type(const char *short_name)
711 for (filetype = 0; filetype < wtap_num_file_types; filetype++) {
712 if (dump_open_table[filetype].short_name != NULL &&
713 strcmp(short_name, dump_open_table[filetype].short_name) == 0)
716 return -1; /* no such file type, or we can't write it */
719 /* Return a list of file extensions that are used by the specified file type.
720 This includes compressed extensions, e.g. not just "pcap" but also
721 "pcap.gz" if we can read gzipped files.
723 All strings in the list are allocated with g_malloc() and must be freed
725 GSList *wtap_get_file_extensions_list(int filetype)
727 gchar **extensions_set, **extensionp;
729 GSList *compressed_file_extensions, *compressed_file_extension;
732 if (filetype < 0 || filetype >= wtap_num_file_types)
733 return NULL; /* not a valid file type */
735 if (dump_open_table[filetype].file_extensions == NULL)
736 return NULL; /* valid, but no extensions list */
739 * Split the extension-list string into a set of extensions.
741 extensions_set = g_strsplit(dump_open_table[filetype].file_extensions,
745 * Get the list of compressed-file extensions.
747 compressed_file_extensions = wtap_get_compressed_file_extensions();
750 * Add each of those extensions to the list.
752 extensions = NULL; /* empty list, to start with */
753 for (extensionp = extensions_set; *extensionp != NULL; extensionp++) {
754 extension = *extensionp;
757 * XXX - skip past the "*.".
762 * Now add the extension.
764 extensions = g_slist_append(extensions, g_strdup(extension));
767 * Now add the extensions for compressed-file versions of
770 for (compressed_file_extension = compressed_file_extensions;
771 compressed_file_extension != NULL;
772 compressed_file_extension = g_slist_next(compressed_file_extension)) {
773 extensions = g_slist_append(extensions,
774 g_strdup_printf("%s.%s", extension,
775 (gchar *)compressed_file_extension->data));
778 g_strfreev(extensions_set);
779 g_slist_free(compressed_file_extensions);
784 * Free a list returned by wtap_file_extensions_list().
786 void wtap_free_file_extensions_list(GSList *extensions)
790 for (extension = extensions; extension != NULL;
791 extension = g_slist_next(extension)) {
792 g_free(extension->data);
794 g_slist_free(extensions);
797 /* Return the default file extension to use with the specified file type;
798 that's just the extension, without any ".". */
799 const char *wtap_file_extension_default_string(int filetype)
801 if (filetype < 0 || filetype >= wtap_num_file_types)
805 * XXX - skip past the ".".
807 return dump_open_table[filetype].file_extension_default + 1;
811 gboolean wtap_dump_can_open(int filetype)
813 if (filetype < 0 || filetype >= wtap_num_file_types
814 || dump_open_table[filetype].dump_open == NULL)
820 gboolean wtap_dump_can_write_encap(int filetype, int encap)
822 if (filetype < 0 || filetype >= wtap_num_file_types
823 || dump_open_table[filetype].can_write_encap == NULL)
826 if ((*dump_open_table[filetype].can_write_encap)(encap) != 0)
833 gboolean wtap_dump_can_compress(int filetype)
836 * If this is an unknown file type, or if we have to
837 * seek when writing out a file with this file type,
840 if (filetype < 0 || filetype >= wtap_num_file_types
841 || dump_open_table[filetype].writing_must_seek)
847 gboolean wtap_dump_can_compress(int filetype _U_)
853 gboolean wtap_dump_has_name_resolution(int filetype)
855 if (filetype < 0 || filetype >= wtap_num_file_types
856 || dump_open_table[filetype].has_name_resolution == FALSE)
862 static gboolean wtap_dump_open_check(int filetype, int encap, gboolean comressed, int *err);
863 static wtap_dumper* wtap_dump_alloc_wdh(int filetype, int encap, int snaplen,
864 gboolean compressed, int *err);
865 static gboolean wtap_dump_open_finish(wtap_dumper *wdh, int filetype, gboolean compressed, int *err);
867 static WFILE_T wtap_dump_file_open(wtap_dumper *wdh, const char *filename);
868 static WFILE_T wtap_dump_file_fdopen(wtap_dumper *wdh, int fd);
869 static int wtap_dump_file_close(wtap_dumper *wdh);
871 wtap_dumper* wtap_dump_open(const char *filename, int filetype, int encap,
872 int snaplen, gboolean compressed, int *err)
877 /* Check whether we can open a capture file with that file type
878 and that encapsulation. */
879 if (!wtap_dump_open_check(filetype, encap, compressed, err))
882 /* Allocate a data structure for the output stream. */
883 wdh = wtap_dump_alloc_wdh(filetype, encap, snaplen, compressed, err);
885 return NULL; /* couldn't allocate it */
887 /* "-" means stdout */
888 if (strcmp(filename, "-") == 0) {
890 *err = EINVAL; /* XXX - return a Wiretap error code for this */
892 return NULL; /* compress won't work on stdout */
895 if (_setmode(fileno(stdout), O_BINARY) == -1) {
896 /* "Should not happen" */
899 return NULL; /* couldn't put standard output in binary mode */
904 /* In case "fopen()" fails but doesn't set "errno", set "errno"
905 to a generic "the open failed" error. */
906 errno = WTAP_ERR_CANT_OPEN;
907 fh = wtap_dump_file_open(wdh, filename);
911 return NULL; /* can't create file */
916 if (!wtap_dump_open_finish(wdh, filetype, compressed, err)) {
917 /* Get rid of the file we created; we couldn't finish
919 if (wdh->fh != stdout) {
920 wtap_dump_file_close(wdh);
929 wtap_dumper* wtap_dump_fdopen(int fd, int filetype, int encap, int snaplen,
930 gboolean compressed, int *err)
935 /* Check whether we can open a capture file with that file type
936 and that encapsulation. */
937 if (!wtap_dump_open_check(filetype, encap, compressed, err))
940 /* Allocate a data structure for the output stream. */
941 wdh = wtap_dump_alloc_wdh(filetype, encap, snaplen, compressed, err);
943 return NULL; /* couldn't allocate it */
947 if (_setmode(fileno(stdout), O_BINARY) == -1) {
948 /* "Should not happen" */
951 return NULL; /* couldn't put standard output in binary mode */
956 /* In case "fopen()" fails but doesn't set "errno", set "errno"
957 to a generic "the open failed" error. */
958 errno = WTAP_ERR_CANT_OPEN;
959 fh = wtap_dump_file_fdopen(wdh, fd);
963 return NULL; /* can't create standard I/O stream */
967 if (!wtap_dump_open_finish(wdh, filetype, compressed, err)) {
968 wtap_dump_file_close(wdh);
975 static gboolean wtap_dump_open_check(int filetype, int encap, gboolean compressed, int *err)
977 if (!wtap_dump_can_open(filetype)) {
978 /* Invalid type, or type we don't know how to write. */
979 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
983 /* OK, we know how to write that type; can we write the specified
984 encapsulation type? */
985 *err = (*dump_open_table[filetype].can_write_encap)(encap);
989 /* if compression is wanted, do we support this for this filetype? */
990 if(compressed && !wtap_dump_can_compress(filetype)) {
991 *err = WTAP_ERR_COMPRESSION_NOT_SUPPORTED;
995 *err = (*dump_open_table[filetype].can_write_encap)(encap);
999 /* All systems go! */
1003 static wtap_dumper* wtap_dump_alloc_wdh(int filetype, int encap, int snaplen,
1004 gboolean compressed, int *err)
1008 wdh = (wtap_dumper *)g_malloc0(sizeof (wtap_dumper));
1014 wdh->file_type = filetype;
1015 wdh->snaplen = snaplen;
1017 wdh->compressed = compressed;
1021 static gboolean wtap_dump_open_finish(wtap_dumper *wdh, int filetype, gboolean compressed, int *err)
1026 /* Can we do a seek on the file descriptor?
1027 If not, note that fact. */
1031 fd = fileno((FILE *)wdh->fh);
1032 if (lseek(fd, 1, SEEK_CUR) == -1)
1035 /* Undo the seek. */
1036 lseek(fd, 0, SEEK_SET);
1041 /* If this file type requires seeking, and we can't seek, fail. */
1042 if (dump_open_table[filetype].writing_must_seek && cant_seek) {
1043 *err = WTAP_ERR_CANT_WRITE_TO_PIPE;
1047 /* Now try to open the file for writing. */
1048 if (!(*dump_open_table[filetype].dump_open)(wdh, err)) {
1052 return TRUE; /* success! */
1055 gboolean wtap_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
1056 const union wtap_pseudo_header *pseudo_header, const guint8 *pd, int *err)
1058 return (wdh->subtype_write)(wdh, phdr, pseudo_header, pd, err);
1061 void wtap_dump_flush(wtap_dumper *wdh)
1064 if(wdh->compressed) {
1065 gzwfile_flush((GZWFILE_T)wdh->fh);
1069 fflush((FILE *)wdh->fh);
1073 gboolean wtap_dump_close(wtap_dumper *wdh, int *err)
1075 gboolean ret = TRUE;
1077 if (wdh->subtype_close != NULL) {
1078 /* There's a close routine for this dump stream. */
1079 if (!(wdh->subtype_close)(wdh, err))
1082 errno = WTAP_ERR_CANT_CLOSE;
1083 /* Don't close stdout */
1084 if (wdh->fh != stdout) {
1085 if (wtap_dump_file_close(wdh) == EOF) {
1087 /* The per-format close function succeeded,
1088 but the fclose didn't. Save the reason
1089 why, if our caller asked for it. */
1096 /* as we don't close stdout, at least try to flush it */
1097 wtap_dump_flush(wdh);
1099 if (wdh->priv != NULL)
1105 gint64 wtap_get_bytes_dumped(wtap_dumper *wdh)
1107 return wdh->bytes_dumped;
1110 void wtap_set_bytes_dumped(wtap_dumper *wdh, gint64 bytes_dumped)
1112 wdh->bytes_dumped = bytes_dumped;
1115 gboolean wtap_dump_set_addrinfo_list(wtap_dumper *wdh, struct addrinfo *addrinfo_list)
1117 if (!wdh || wdh->file_type < 0 || wdh->file_type >= wtap_num_file_types
1118 || dump_open_table[wdh->file_type].has_name_resolution == FALSE)
1120 wdh->addrinfo_list = addrinfo_list;
1124 /* internally open a file for writing (compressed or not) */
1126 static WFILE_T wtap_dump_file_open(wtap_dumper *wdh, const char *filename)
1128 if(wdh->compressed) {
1129 return gzwfile_open(filename);
1131 return ws_fopen(filename, "wb");
1135 static WFILE_T wtap_dump_file_open(wtap_dumper *wdh _U_, const char *filename)
1137 return ws_fopen(filename, "wb");
1141 /* internally open a file for writing (compressed or not) */
1143 static WFILE_T wtap_dump_file_fdopen(wtap_dumper *wdh, int fd)
1145 if(wdh->compressed) {
1146 return gzwfile_fdopen(fd);
1148 return fdopen(fd, "wb");
1152 static WFILE_T wtap_dump_file_fdopen(wtap_dumper *wdh _U_, int fd)
1154 return fdopen(fd, "wb");
1158 /* internally writing raw bytes (compressed or not) */
1159 gboolean wtap_dump_file_write(wtap_dumper *wdh, const void *buf, size_t bufsize,
1165 if (wdh->compressed) {
1166 nwritten = gzwfile_write((GZWFILE_T)wdh->fh, buf, (unsigned) bufsize);
1168 * gzwfile_write() returns 0 on error.
1170 if (nwritten == 0) {
1171 *err = gzwfile_geterr((GZWFILE_T)wdh->fh);
1177 nwritten = fwrite(buf, 1, bufsize, (FILE *)wdh->fh);
1179 * At least according to the Mac OS X man page,
1180 * this can return a short count on an error.
1182 if (nwritten != bufsize) {
1183 if (ferror((FILE *)wdh->fh))
1186 *err = WTAP_ERR_SHORT_WRITE;
1193 /* internally close a file for writing (compressed or not) */
1194 static int wtap_dump_file_close(wtap_dumper *wdh)
1197 if(wdh->compressed) {
1198 return gzwfile_close((GZWFILE_T)wdh->fh);
1202 return fclose((FILE *)wdh->fh);