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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
41 #include <wsutil/file_util.h>
44 #include "file_wrappers.h"
46 #include "lanalyzer.h"
47 #include "ngsniffer.h"
49 #include "ascendtext.h"
62 #include "peekclassic.h"
63 #include "peektagged.h"
65 #include "dbs-etherwatch.h"
71 #include "network_instruments.h"
74 #include "catapult_dct2000.h"
77 #include "netscreen.h"
83 #include "dct3trace.h"
84 #include "packetlogger.h"
85 #include "daintree-sna.h"
86 #include "netscaler.h"
87 #include "mime_file.h"
90 #include "pcap-encap.h"
92 /* The open_file_* routines should return:
96 * 1 if the file they're reading is one of the types it handles;
98 * 0 if the file they're reading isn't the type they're checking for.
100 * If the routine handles this type of file, it should set the "file_type"
101 * field in the "struct wtap" to the type of the file.
103 * Put the trace files that are merely saved telnet-sessions last, since it's
104 * possible that you could have captured someone a router telnet-session
105 * using another tool. So, a libpcap trace of an toshiba "snoop" session
106 * should be discovered as a libpcap file, not a toshiba file.
110 static wtap_open_routine_t open_routines_base[] = {
111 /* Files that have magic bytes in fixed locations. These
112 * are easy to identify.
126 network_instruments_open,
130 catapult_dct2000_open,
136 packetlogger_open, /* This type does not have a magic number, but its
137 * files are sometimes grabbed by mpeg_open. */
144 /* Files that don't have magic bytes at a fixed location,
145 * but that instead require a heuristic of some sort to
146 * identify them. This includes the ASCII trace files that
147 * would be, for example, saved copies of a Telnet session
151 /* I put NetScreen *before* erf, because there were some
152 * false positives with my test-files (Sake Blok, July 2007)
172 #define N_FILE_TYPES (sizeof open_routines_base / sizeof open_routines_base[0])
174 static wtap_open_routine_t* open_routines = NULL;
176 static GArray* open_routines_arr = NULL;
179 /* initialize the open routines array if it has not been initialized yet */
180 static void init_open_routines(void) {
182 if (open_routines_arr) return;
184 open_routines_arr = g_array_new(FALSE,TRUE,sizeof(wtap_open_routine_t));
186 g_array_append_vals(open_routines_arr,open_routines_base,N_FILE_TYPES);
188 open_routines = (wtap_open_routine_t*)(void *)open_routines_arr->data;
191 void wtap_register_open_routine(wtap_open_routine_t open_routine, gboolean has_magic) {
192 init_open_routines();
195 g_array_prepend_val(open_routines_arr,open_routine);
197 g_array_append_val(open_routines_arr,open_routine);
199 open_routines = (wtap_open_routine_t*)(void *)open_routines_arr->data;
203 * Visual C++ on Win32 systems doesn't define these. (Old UNIX systems don't
204 * define them either.)
206 * Visual C++ on Win32 systems doesn't define S_IFIFO, it defines _S_IFIFO.
209 #define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
212 #define S_IFIFO _S_IFIFO
215 #define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)
218 #define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
221 /* Opens a file and prepares a wtap struct.
222 If "do_random" is TRUE, it opens the file twice; the second open
223 allows the application to do random-access I/O without moving
224 the seek offset for sequential I/O, which is used by Wireshark
225 so that it can do sequential I/O to a capture file that's being
226 written to as new packets arrive independently of random I/O done
227 to display protocol trees for packets when they're selected. */
228 wtap* wtap_open_offline(const char *filename, int *err, char **err_info,
235 gboolean use_stdin = FALSE;
237 /* open standard input if filename is '-' */
238 if (strcmp(filename, "-") == 0)
241 /* First, make sure the file is valid */
243 if (ws_fstat64(0, &statb) < 0) {
248 if (ws_stat64(filename, &statb) < 0) {
253 if (S_ISFIFO(statb.st_mode)) {
255 * Opens of FIFOs are allowed only when not opening
258 * XXX - currently, we do seeking when trying to find
259 * out the file type, so we don't actually support
260 * opening FIFOs. However, we may eventually
261 * do buffering that allows us to do at least some
262 * file type determination even on pipes, so we
263 * allow FIFO opens and let things fail later when
267 *err = WTAP_ERR_RANDOM_OPEN_PIPE;
270 } else if (S_ISDIR(statb.st_mode)) {
272 * Return different errors for "this is a directory"
273 * and "this is some random special file type", so
274 * the user can get a potentially more helpful error.
278 } else if (! S_ISREG(statb.st_mode)) {
279 *err = WTAP_ERR_NOT_REGULAR_FILE;
284 * We need two independent descriptors for random access, so
285 * they have different file positions. If we're opening the
286 * standard input, we can only dup it to get additional
287 * descriptors, so we can't have two independent descriptors,
288 * and thus can't do random access.
290 if (use_stdin && do_random) {
291 *err = WTAP_ERR_RANDOM_OPEN_STDIN;
296 wth = (wtap *)g_malloc0(sizeof(wtap));
299 errno = WTAP_ERR_CANT_OPEN;
302 * We dup FD 0, so that we don't have to worry about
303 * a file_close of wth->fh closing the standard
304 * input of the process.
313 if (_setmode(fd, O_BINARY) == -1) {
314 /* "Shouldn't happen" */
320 if (!(wth->fh = file_fdopen(fd))) {
327 if (!(wth->fh = file_open(filename))) {
335 if (!(wth->random_fh = file_open(filename))) {
342 wth->random_fh = NULL;
345 wth->file_encap = WTAP_ENCAP_UNKNOWN;
346 wth->subtype_sequential_close = NULL;
347 wth->subtype_close = NULL;
348 wth->tsprecision = WTAP_FILE_TSPREC_USEC;
351 init_open_routines();
352 if (wth->random_fh) {
353 wth->fast_seek = g_ptr_array_new();
355 file_set_random_access(wth->fh, FALSE, wth->fast_seek);
356 file_set_random_access(wth->random_fh, TRUE, wth->fast_seek);
359 /* Try all file types */
360 for (i = 0; i < open_routines_arr->len; i++) {
361 /* Seek back to the beginning of the file; the open routine
362 for the previous file type may have left the file
363 position somewhere other than the beginning, and the
364 open routine for this file type will probably want
365 to start reading at the beginning.
367 Initialize the data offset while we're at it. */
368 if (file_seek(wth->fh, 0, SEEK_SET, err) == -1) {
369 /* I/O error - give up */
370 if (wth->random_fh != NULL)
371 file_close(wth->random_fh);
377 switch ((*open_routines[i])(wth, err, err_info)) {
380 /* I/O error - give up */
381 if (wth->random_fh != NULL)
382 file_close(wth->random_fh);
388 /* No I/O error, but not that type of file */
392 /* We found the file type */
397 /* Well, it's not one of the types of file we know about. */
399 *err = WTAP_ERR_FILE_UNKNOWN_FORMAT;
403 wth->frame_buffer = (struct Buffer *)g_malloc(sizeof(struct Buffer));
404 buffer_init(wth->frame_buffer, 1500);
409 * Given the pathname of the file we just closed with wtap_fdclose(), attempt
410 * to reopen that file and assign the new file descriptor(s) to the sequential
411 * stream and, if do_random is TRUE, to the random stream. Used on Windows
412 * after the rename of a file we had open was done or if the rename of a
413 * file on top of a file we had open failed.
415 * This is only required by Wireshark, not TShark, and, at the point that
416 * Wireshark is doing this, the sequential stream is closed, and the
417 * random stream is open, so this refuses to open pipes, and only
418 * reopens the random stream.
421 wtap_fdreopen(wtap *wth, const char *filename, int *err)
426 * We need two independent descriptors for random access, so
427 * they have different file positions. If we're opening the
428 * standard input, we can only dup it to get additional
429 * descriptors, so we can't have two independent descriptors,
430 * and thus can't do random access.
432 if (strcmp(filename, "-") == 0) {
433 *err = WTAP_ERR_RANDOM_OPEN_STDIN;
437 /* First, make sure the file is valid */
438 if (ws_stat64(filename, &statb) < 0) {
442 if (S_ISFIFO(statb.st_mode)) {
444 * Opens of FIFOs are not allowed; see above.
446 *err = WTAP_ERR_RANDOM_OPEN_PIPE;
448 } else if (S_ISDIR(statb.st_mode)) {
450 * Return different errors for "this is a directory"
451 * and "this is some random special file type", so
452 * the user can get a potentially more helpful error.
456 } else if (! S_ISREG(statb.st_mode)) {
457 *err = WTAP_ERR_NOT_REGULAR_FILE;
462 errno = WTAP_ERR_CANT_OPEN;
463 if (!file_fdreopen(wth->random_fh, filename)) {
470 /* Table of the file types we know about.
471 Entries must be sorted by WTAP_FILE_xxx values in ascending order */
472 static const struct file_type_info dump_open_table_base[] = {
473 /* WTAP_FILE_UNKNOWN (only used internally for initialization) */
474 { NULL, NULL, NULL, NULL, FALSE, FALSE,
478 /* Gianluca Varenni suggests that we add "deprecated" to the description. */
479 { "Wireshark/tcpdump/... - libpcap", "libpcap", "pcap", "cap;dmp", FALSE, FALSE,
480 libpcap_dump_can_write_encap, libpcap_dump_open },
482 /* WTAP_FILE_PCAPNG */
483 { "Wireshark - pcapng", "pcapng", "pcapng", "ntar", FALSE, TRUE,
484 pcapng_dump_can_write_encap, pcapng_dump_open },
486 /* WTAP_FILE_PCAP_NSEC */
487 { "Wireshark - nanosecond libpcap", "nseclibpcap", "pcap", "cap;dmp", FALSE, FALSE,
488 libpcap_dump_can_write_encap, libpcap_dump_open },
490 /* WTAP_FILE_PCAP_AIX */
491 { "AIX tcpdump - libpcap", "aixlibpcap", "pcap", "cap;dmp", FALSE, FALSE,
494 /* WTAP_FILE_PCAP_SS991029 */
495 { "Modified tcpdump - libpcap", "modlibpcap", "pcap", "cap;dmp", FALSE, FALSE,
496 libpcap_dump_can_write_encap, libpcap_dump_open },
498 /* WTAP_FILE_PCAP_NOKIA */
499 { "Nokia tcpdump - libpcap ", "nokialibpcap", "pcap", "cap;dmp", FALSE, FALSE,
500 libpcap_dump_can_write_encap, libpcap_dump_open },
502 /* WTAP_FILE_PCAP_SS990417 */
503 { "RedHat 6.1 tcpdump - libpcap", "rh6_1libpcap", "pcap", "cap;dmp", FALSE, FALSE,
504 libpcap_dump_can_write_encap, libpcap_dump_open },
506 /* WTAP_FILE_PCAP_SS990915 */
507 { "SuSE 6.3 tcpdump - libpcap", "suse6_3libpcap", "pcap", "cap;dmp", FALSE, FALSE,
508 libpcap_dump_can_write_encap, libpcap_dump_open },
510 /* WTAP_FILE_5VIEWS */
511 { "InfoVista 5View capture", "5views", "5vw", NULL, TRUE, FALSE,
512 _5views_dump_can_write_encap, _5views_dump_open },
514 /* WTAP_FILE_IPTRACE_1_0 */
515 { "AIX iptrace 1.0", "iptrace_1", NULL, NULL, FALSE, FALSE,
518 /* WTAP_FILE_IPTRACE_2_0 */
519 { "AIX iptrace 2.0", "iptrace_2", NULL, NULL, FALSE, FALSE,
523 { "ASN.1 Basic Encoding Rules", "ber", NULL, NULL, FALSE, FALSE,
526 /* WTAP_FILE_HCIDUMP */
527 { "Bluetooth HCI dump", "hcidump", NULL, NULL, FALSE, FALSE,
530 /* WTAP_FILE_CATAPULT_DCT2000 */
531 { "Catapult DCT2000 trace (.out format)", "dct2000", "out", NULL, FALSE, FALSE,
532 catapult_dct2000_dump_can_write_encap, catapult_dct2000_dump_open },
534 /* WTAP_FILE_NETXRAY_OLD */
535 { "Cinco Networks NetXRay 1.x", "netxray1", "cap", NULL, TRUE, FALSE,
538 /* WTAP_FILE_NETXRAY_1_0 */
539 { "Cinco Networks NetXRay 2.0 or later", "netxray2", "cap", NULL, TRUE, FALSE,
542 /* WTAP_FILE_COSINE */
543 { "CoSine IPSX L2 capture", "cosine", "txt", NULL, FALSE, FALSE,
546 /* WTAP_FILE_CSIDS */
547 { "CSIDS IPLog", "csids", NULL, NULL, FALSE, FALSE,
550 /* WTAP_FILE_DBS_ETHERWATCH */
551 { "DBS Etherwatch (VMS)", "etherwatch", "txt", NULL, FALSE, FALSE,
555 { "Endace ERF capture", "erf", "erf", NULL, FALSE, FALSE,
556 erf_dump_can_write_encap, erf_dump_open },
558 /* WTAP_FILE_EYESDN */
559 { "EyeSDN USB S0/E1 ISDN trace format", "eyesdn", "trc", NULL, FALSE, FALSE,
560 eyesdn_dump_can_write_encap, eyesdn_dump_open },
562 /* WTAP_FILE_NETTL */
563 { "HP-UX nettl trace", "nettl", "trc0", "trc1", FALSE, FALSE,
564 nettl_dump_can_write_encap, nettl_dump_open },
566 /* WTAP_FILE_ISERIES */
567 { "IBM iSeries comm. trace (ASCII)", "iseries_ascii", "txt", NULL, FALSE, FALSE,
570 /* WTAP_FILE_ISERIES_UNICODE */
571 { "IBM iSeries comm. trace (UNICODE)", "iseries_unicode", "txt", NULL, FALSE, FALSE,
574 /* WTAP_FILE_I4BTRACE */
575 { "I4B ISDN trace", "i4btrace", NULL, NULL, FALSE, FALSE,
578 /* WTAP_FILE_ASCEND */
579 { "Lucent/Ascend access server trace", "ascend", "txt", NULL, FALSE, FALSE,
582 /* WTAP_FILE_NETMON_1_x */
583 { "Microsoft NetMon 1.x", "netmon1", "cap", NULL, TRUE, FALSE,
584 netmon_dump_can_write_encap_1_x, netmon_dump_open },
586 /* WTAP_FILE_NETMON_2_x */
587 { "Microsoft NetMon 2.x", "netmon2", "cap", NULL, TRUE, FALSE,
588 netmon_dump_can_write_encap_2_x, netmon_dump_open },
590 /* WTAP_FILE_NGSNIFFER_UNCOMPRESSED */
591 { "NA Sniffer (DOS)", "ngsniffer", "cap", "enc;trc;fdc;syc", FALSE, FALSE,
592 ngsniffer_dump_can_write_encap, ngsniffer_dump_open },
594 /* WTAP_FILE_NGSNIFFER_COMPRESSED */
595 { "NA Sniffer (DOS), compressed", "ngsniffer_comp", "caz", NULL, FALSE, FALSE,
598 /* WTAP_FILE_NETXRAY_1_1 */
599 { "NA Sniffer (Windows) 1.1", "ngwsniffer_1_1", "cap", NULL, TRUE, FALSE,
600 netxray_dump_can_write_encap_1_1, netxray_dump_open_1_1 },
602 /* WTAP_FILE_NETXRAY_2_00x */
603 { "NA Sniffer (Windows) 2.00x", "ngwsniffer_2_0", "cap", NULL, TRUE, FALSE,
604 netxray_dump_can_write_encap_2_0, netxray_dump_open_2_0 },
606 /* WTAP_FILE_NETWORK_INSTRUMENTS */
607 { "Network Instruments Observer", "niobserver", "bfr", NULL, FALSE, FALSE,
608 network_instruments_dump_can_write_encap, network_instruments_dump_open },
610 /* WTAP_FILE_LANALYZER */
611 { "Novell LANalyzer","lanalyzer", "tr1", NULL, TRUE, FALSE,
612 lanalyzer_dump_can_write_encap, lanalyzer_dump_open },
614 /* WTAP_FILE_PPPDUMP */
615 { "pppd log (pppdump format)", "pppd", NULL, NULL, FALSE, FALSE,
618 /* WTAP_FILE_RADCOM */
619 { "RADCOM WAN/LAN analyzer", "radcom", NULL, NULL, FALSE, FALSE,
622 /* WTAP_FILE_SNOOP */
623 { "Sun snoop", "snoop", "snoop", "cap", FALSE, FALSE,
624 snoop_dump_can_write_encap, snoop_dump_open },
626 /* WTAP_FILE_SHOMITI */
627 { "Shomiti/Finisar Surveyor", "shomiti", "cap", NULL, FALSE, FALSE,
631 { "TCPIPtrace (VMS)", "tcpiptrace", "txt", NULL, FALSE, FALSE,
635 { "Tektronix K12xx 32-bit .rf5 format", "rf5", "rf5", NULL, TRUE, FALSE,
636 k12_dump_can_write_encap, k12_dump_open },
638 /* WTAP_FILE_TOSHIBA */
639 { "Toshiba Compact ISDN Router snoop", "toshiba", "txt", NULL, FALSE, FALSE,
642 /* WTAP_FILE_VISUAL_NETWORKS */
643 { "Visual Networks traffic capture", "visual", NULL, NULL, TRUE, FALSE,
644 visual_dump_can_write_encap, visual_dump_open },
646 /* WTAP_FILE_PEEKCLASSIC_V56 */
647 { "WildPackets classic (V5 and V6)", "peekclassic56", "pkt", "tpc;apc;wpz", FALSE, FALSE,
650 /* WTAP_FILE_PEEKCLASSIC_V7 */
651 { "WildPackets classic (V7)", "peekclassic7", "pkt", "tpc;apc;wpz", FALSE, FALSE,
654 /* WTAP_FILE_PEEKTAGGED */
655 { "WildPackets tagged", "peektagged", "pkt", "tpc;apc;wpz", FALSE, FALSE,
659 { "MPEG", "mpeg", "mpeg", "mpg;mp3", FALSE, FALSE,
662 /* WTAP_FILE_K12TEXT */
663 { "K12 text file", "k12text", "txt", NULL, FALSE, FALSE,
664 k12text_dump_can_write_encap, k12text_dump_open },
666 /* WTAP_FILE_NETSCREEN */
667 { "NetScreen snoop text file", "netscreen", "txt", NULL, FALSE, FALSE,
670 /* WTAP_FILE_COMMVIEW */
671 { "TamoSoft CommView", "commview", "ncf", NULL, FALSE, FALSE,
672 commview_dump_can_write_encap, commview_dump_open },
674 /* WTAP_FILE_BTSNOOP */
675 { "Symbian OS btsnoop", "btsnoop", "log", NULL, FALSE, FALSE,
676 btsnoop_dump_can_write_encap, btsnoop_dump_open_h4 },
679 { "Transport-Neutral Encapsulation Format", "tnef", NULL, NULL, FALSE, FALSE,
682 /* WTAP_FILE_DCT3TRACE */
683 { "Gammu DCT3 trace", "dct3trace", "xml", NULL, FALSE, FALSE,
686 /* WTAP_FILE_PACKETLOGGER */
687 { "PacketLogger", "pklg", "pklg", NULL, FALSE, FALSE,
690 /* WTAP_FILE_DAINTREE_SNA */
691 { "Daintree SNA", "dsna", "dcf", NULL, FALSE, FALSE,
694 /* WTAP_FILE_NETSCALER_1_0 */
695 { "NetScaler Trace (Version 1.0)", "nstrace10", NULL, NULL, TRUE, FALSE,
696 nstrace_10_dump_can_write_encap, nstrace_dump_open },
698 /* WTAP_FILE_NETSCALER_2_0 */
699 { "NetScaler Trace (Version 2.0)", "nstrace20", "cap", NULL, TRUE, FALSE,
700 nstrace_20_dump_can_write_encap, nstrace_dump_open },
702 /* WTAP_FILE_JPEG_JFIF */
703 { "JPEG/JFIF", "jpeg", "jpg", "jpeg;jfif", FALSE, FALSE,
706 /* WTAP_FILE_IPFIX */
707 { "IPFIX File Format", "ipfix", "pfx", "ipfix", FALSE, FALSE,
710 /* WTAP_ENCAP_MIME */
711 { "MIME File Format", "mime", NULL, NULL, FALSE, FALSE,
714 /* WTAP_FILE_AETHRA */
715 { "Aethra .aps file", "aethra", "aps", NULL, FALSE, FALSE,
718 /* WTAP_FILE_MPEG_2_TS */
719 { "MPEG2 transport stream", "mp2t", "mp2t", "ts;mpg", FALSE, FALSE,
722 /* WTAP_FILE_VWR_80211 */
723 { "Ixia IxVeriWave .vwr Raw 802.11 Capture", "vwr80211", "*.vwr", ".vwr", FALSE, FALSE,
726 /* WTAP_FILE_VWR_ETH */
727 { "Ixia IxVeriWave .vwr Raw Ethernet Capture", "vwreth", "*.vwr", ".vwr", FALSE, FALSE,
732 gint wtap_num_file_types = sizeof(dump_open_table_base) / sizeof(struct file_type_info);
734 static GArray* dump_open_table_arr = NULL;
735 static const struct file_type_info* dump_open_table = dump_open_table_base;
737 /* initialize the open routines array if it has not being initialized yet */
738 static void init_file_types(void) {
740 if (dump_open_table_arr) return;
742 dump_open_table_arr = g_array_new(FALSE,TRUE,sizeof(struct file_type_info));
744 g_array_append_vals(dump_open_table_arr,dump_open_table_base,wtap_num_file_types);
746 dump_open_table = (const struct file_type_info*)(void *)dump_open_table_arr->data;
749 int wtap_register_file_type(const struct file_type_info* fi) {
752 g_array_append_val(dump_open_table_arr,*fi);
754 dump_open_table = (const struct file_type_info*)(void *)dump_open_table_arr->data;
756 return wtap_num_file_types++;
759 int wtap_get_num_file_types(void)
761 return wtap_num_file_types;
765 * Return TRUE if a capture with a given GArray of WTAP_ENCAP_ types
766 * can be written in a specified format, and FALSE if it can't.
769 wtap_dump_can_write_encaps(int ft, const GArray *file_encaps)
774 * Can we write in this format?
776 if (!wtap_dump_can_open(ft)) {
782 * OK, we can write in that format; can we write out all the
783 * specified encapsulation types in that format?
785 if (file_encaps->len > 1) {
787 * We have more than one encapsulation type,
788 * so that format needs to support
789 * WTAP_ENCAP_PER_PACKET.
791 if (!wtap_dump_can_write_encap(ft, WTAP_ENCAP_PER_PACKET))
795 for (i = 0; i < file_encaps->len; i++) {
796 if (!wtap_dump_can_write_encap(ft,
797 g_array_index(file_encaps, int, i)))
804 * Get a GArray of WTAP_FILE_ values for file types that can be used
805 * to save a file of a given type with a given GArray of WTAP_ENCAP_
809 wtap_get_savable_file_types(int file_type, const GArray *file_encaps)
811 GArray *savable_file_types;
813 int default_file_type = -1;
814 int other_file_type = -1;
816 /* Can we save this file in its own file type? */
817 if (wtap_dump_can_write_encaps(file_type, file_encaps)) {
818 /* Yes - make that the default file type. */
819 default_file_type = file_type;
821 /* No - can we save it as a pcap-NG file? */
822 if (wtap_dump_can_write_encaps(WTAP_FILE_PCAPNG, file_encaps)) {
823 /* Yes - default to pcap-NG, instead. */
824 default_file_type = WTAP_FILE_PCAPNG;
826 /* OK, find the first file type we *can* save it as. */
827 default_file_type = -1;
828 for (ft = 0; ft < WTAP_NUM_FILE_TYPES; ft++) {
829 if (wtap_dump_can_write_encaps(ft, file_encaps)) {
831 default_file_type = ft;
837 if (default_file_type == -1) {
838 /* We don't support writing this file as any file type. */
842 /* Allocate the array. */
843 savable_file_types = g_array_new(FALSE, FALSE, (guint)sizeof (int));
845 /* Put the default file format first in the list. */
846 g_array_append_val(savable_file_types, default_file_type);
848 /* If it's pcap, put pcap-NG right after it; otherwise, if it's
849 pcap-NG, put pcap right after it. */
850 if (default_file_type == WTAP_FILE_PCAP) {
851 if (wtap_dump_can_write_encaps(WTAP_FILE_PCAPNG, file_encaps))
852 other_file_type = WTAP_FILE_PCAPNG;
853 } else if (default_file_type == WTAP_FILE_PCAPNG) {
854 if (wtap_dump_can_write_encaps(WTAP_FILE_PCAP, file_encaps))
855 other_file_type = WTAP_FILE_PCAP;
857 if (other_file_type != -1)
858 g_array_append_val(savable_file_types, other_file_type);
860 /* Add all the other file types that work. */
861 for (ft = 0; ft < WTAP_NUM_FILE_TYPES; ft++) {
862 if (ft == WTAP_FILE_UNKNOWN)
863 continue; /* not a real file type */
864 if (ft == default_file_type || ft == other_file_type)
865 continue; /* we've already done this one */
866 if (wtap_dump_can_write_encaps(ft, file_encaps)) {
867 /* OK, we can write it out in this type. */
868 g_array_append_val(savable_file_types, ft);
872 return savable_file_types;
875 /* Name that should be somewhat descriptive. */
876 const char *wtap_file_type_string(int filetype)
878 if (filetype < 0 || filetype >= wtap_num_file_types) {
879 g_error("Unknown capture file type %d", filetype);
880 /** g_error() does an abort() and thus never returns **/
883 return dump_open_table[filetype].name;
886 /* Name to use in, say, a command-line flag specifying the type. */
887 const char *wtap_file_type_short_string(int filetype)
889 if (filetype < 0 || filetype >= wtap_num_file_types)
892 return dump_open_table[filetype].short_name;
895 /* Translate a short name to a capture file type. */
896 int wtap_short_string_to_file_type(const char *short_name)
900 for (filetype = 0; filetype < wtap_num_file_types; filetype++) {
901 if (dump_open_table[filetype].short_name != NULL &&
902 strcmp(short_name, dump_open_table[filetype].short_name) == 0)
905 return -1; /* no such file type, or we can't write it */
908 static GSList *add_extensions(GSList *extensions, const gchar *extension,
909 GSList *compressed_file_extensions)
911 GSList *compressed_file_extension;
914 * Add the specified extension.
916 extensions = g_slist_append(extensions, g_strdup(extension));
919 * Now add the extensions for compressed-file versions of
922 for (compressed_file_extension = compressed_file_extensions;
923 compressed_file_extension != NULL;
924 compressed_file_extension = g_slist_next(compressed_file_extension)) {
925 extensions = g_slist_append(extensions,
926 g_strdup_printf("%s.%s", extension,
927 (gchar *)compressed_file_extension->data));
933 /* Return a list of file extensions that are used by the specified file type.
935 If include_compressed is TRUE, the list will include compressed
936 extensions, e.g. not just "pcap" but also "pcap.gz" if we can read
939 All strings in the list are allocated with g_malloc() and must be freed
941 GSList *wtap_get_file_extensions_list(int filetype, gboolean include_compressed)
943 gchar **extensions_set, **extensionp;
945 GSList *compressed_file_extensions;
948 if (filetype < 0 || filetype >= wtap_num_file_types)
949 return NULL; /* not a valid file type */
951 if (dump_open_table[filetype].default_file_extension == NULL)
952 return NULL; /* valid, but no extensions known */
954 extensions = NULL; /* empty list, to start with */
957 * If include_compressions is true, get the list of compressed-file
960 if (include_compressed)
961 compressed_file_extensions = wtap_get_compressed_file_extensions();
963 compressed_file_extensions = NULL;
966 * Add the default extension, and all compressed variants of
969 extensions = add_extensions(extensions,
970 dump_open_table[filetype].default_file_extension,
971 compressed_file_extensions);
973 if (dump_open_table[filetype].additional_file_extensions != NULL) {
975 * We have additional extensions; add them.
977 * First, split the extension-list string into a set of
980 extensions_set = g_strsplit(dump_open_table[filetype].additional_file_extensions,
984 * Add each of those extensions to the list.
986 for (extensionp = extensions_set; *extensionp != NULL;
988 extension = *extensionp;
991 * Add the extension, and all compressed variants
994 extensions = add_extensions(extensions, extension,
995 compressed_file_extensions);
998 g_strfreev(extensions_set);
1000 g_slist_free(compressed_file_extensions);
1005 * Free a list returned by wtap_file_extensions_list().
1007 void wtap_free_file_extensions_list(GSList *extensions)
1011 for (extension = extensions; extension != NULL;
1012 extension = g_slist_next(extension)) {
1013 g_free(extension->data);
1015 g_slist_free(extensions);
1018 /* Return the default file extension to use with the specified file type;
1019 that's just the extension, without any ".". */
1020 const char *wtap_default_file_extension(int filetype)
1022 if (filetype < 0 || filetype >= wtap_num_file_types)
1025 return dump_open_table[filetype].default_file_extension;
1028 gboolean wtap_dump_can_open(int filetype)
1030 if (filetype < 0 || filetype >= wtap_num_file_types
1031 || dump_open_table[filetype].dump_open == NULL)
1037 gboolean wtap_dump_can_write_encap(int filetype, int encap)
1039 if (filetype < 0 || filetype >= wtap_num_file_types
1040 || dump_open_table[filetype].can_write_encap == NULL)
1043 if ((*dump_open_table[filetype].can_write_encap)(encap) != 0)
1050 gboolean wtap_dump_can_compress(int filetype)
1053 * If this is an unknown file type, or if we have to
1054 * seek when writing out a file with this file type,
1057 if (filetype < 0 || filetype >= wtap_num_file_types
1058 || dump_open_table[filetype].writing_must_seek)
1064 gboolean wtap_dump_can_compress(int filetype _U_)
1070 gboolean wtap_dump_has_name_resolution(int filetype)
1072 if (filetype < 0 || filetype >= wtap_num_file_types
1073 || dump_open_table[filetype].has_name_resolution == FALSE)
1079 static gboolean wtap_dump_open_check(int filetype, int encap, gboolean comressed, int *err);
1080 static wtap_dumper* wtap_dump_alloc_wdh(int filetype, int encap, int snaplen,
1081 gboolean compressed, int *err);
1082 static gboolean wtap_dump_open_finish(wtap_dumper *wdh, int filetype, gboolean compressed, int *err);
1084 static WFILE_T wtap_dump_file_open(wtap_dumper *wdh, const char *filename);
1085 static WFILE_T wtap_dump_file_fdopen(wtap_dumper *wdh, int fd);
1086 static int wtap_dump_file_close(wtap_dumper *wdh);
1088 wtap_dumper* wtap_dump_open(const char *filename, int filetype, int encap,
1089 int snaplen, gboolean compressed, int *err)
1091 return wtap_dump_open_ng(filename, filetype, encap,snaplen, compressed, NULL, NULL, err);
1094 wtap_dumper* wtap_dump_open_ng(const char *filename, int filetype, int encap,
1095 int snaplen, gboolean compressed, wtapng_section_t *shb_hdr, wtapng_iface_descriptions_t *idb_inf, int *err)
1100 /* Check whether we can open a capture file with that file type
1101 and that encapsulation. */
1102 if (!wtap_dump_open_check(filetype, encap, compressed, err))
1105 /* Allocate a data structure for the output stream. */
1106 wdh = wtap_dump_alloc_wdh(filetype, encap, snaplen, compressed, err);
1108 return NULL; /* couldn't allocate it */
1110 /* Set Section Header Block data */
1111 wdh->shb_hdr = shb_hdr;
1112 /* Set Interface Description Block data */
1113 if ((idb_inf != NULL) && (idb_inf->number_of_interfaces > 0)) {
1114 wdh->number_of_interfaces = idb_inf->number_of_interfaces;
1115 wdh->interface_data = idb_inf->interface_data;
1117 wtapng_if_descr_t descr;
1119 descr.wtap_encap = encap;
1120 descr.time_units_per_second = 1000000; /* default microsecond resolution */
1121 descr.link_type = wtap_wtap_encap_to_pcap_encap(encap);
1122 descr.snap_len = snaplen;
1123 descr.opt_comment = NULL;
1124 descr.if_name = NULL;
1125 descr.if_description = NULL;
1127 descr.if_tsresol = 6;
1128 descr.if_filter_str= NULL;
1129 descr.bpf_filter_len= 0;
1130 descr.if_filter_bpf_bytes= NULL;
1132 descr.if_fcslen = -1;
1133 descr.num_stat_entries = 0; /* Number of ISB:s */
1134 descr.interface_statistics = NULL;
1135 wdh->number_of_interfaces= 1;
1136 wdh->interface_data= g_array_new(FALSE, FALSE, sizeof(wtapng_if_descr_t));
1137 g_array_append_val(wdh->interface_data, descr);
1140 /* "-" means stdout */
1141 if (strcmp(filename, "-") == 0) {
1143 *err = EINVAL; /* XXX - return a Wiretap error code for this */
1145 return NULL; /* compress won't work on stdout */
1148 if (_setmode(fileno(stdout), O_BINARY) == -1) {
1149 /* "Should not happen" */
1152 return NULL; /* couldn't put standard output in binary mode */
1157 /* In case "fopen()" fails but doesn't set "errno", set "errno"
1158 to a generic "the open failed" error. */
1159 errno = WTAP_ERR_CANT_OPEN;
1160 fh = wtap_dump_file_open(wdh, filename);
1164 return NULL; /* can't create file */
1169 if (!wtap_dump_open_finish(wdh, filetype, compressed, err)) {
1170 /* Get rid of the file we created; we couldn't finish
1172 if (wdh->fh != stdout) {
1173 wtap_dump_file_close(wdh);
1174 ws_unlink(filename);
1182 wtap_dumper* wtap_dump_fdopen(int fd, int filetype, int encap, int snaplen,
1183 gboolean compressed, int *err)
1185 return wtap_dump_fdopen_ng(fd, filetype, encap, snaplen, compressed, NULL, NULL, err);
1188 wtap_dumper* wtap_dump_fdopen_ng(int fd, int filetype, int encap, int snaplen,
1189 gboolean compressed, wtapng_section_t *shb_hdr, wtapng_iface_descriptions_t *idb_inf, int *err)
1194 /* Check whether we can open a capture file with that file type
1195 and that encapsulation. */
1196 if (!wtap_dump_open_check(filetype, encap, compressed, err))
1199 /* Allocate a data structure for the output stream. */
1200 wdh = wtap_dump_alloc_wdh(filetype, encap, snaplen, compressed, err);
1202 return NULL; /* couldn't allocate it */
1206 if (_setmode(fileno(stdout), O_BINARY) == -1) {
1207 /* "Should not happen" */
1210 return NULL; /* couldn't put standard output in binary mode */
1215 /* Set Section Header Block data */
1216 wdh->shb_hdr = shb_hdr;
1217 /* Set Interface Description Block data */
1218 if ((idb_inf != NULL) && (idb_inf->number_of_interfaces > 0)) {
1219 wdh->number_of_interfaces = idb_inf->number_of_interfaces;
1220 wdh->interface_data = idb_inf->interface_data;
1222 wtapng_if_descr_t descr;
1224 descr.wtap_encap = encap;
1225 descr.time_units_per_second = 0;
1226 descr.link_type = wtap_wtap_encap_to_pcap_encap(encap);
1227 descr.snap_len = snaplen;
1228 descr.opt_comment = NULL;
1229 descr.if_name = NULL;
1230 descr.if_description = NULL;
1232 descr.if_tsresol = 6;
1233 descr.if_filter_str= NULL;
1234 descr.bpf_filter_len= 0;
1235 descr.if_filter_bpf_bytes= NULL;
1237 descr.if_fcslen = -1;
1238 descr.num_stat_entries = 0; /* Number of ISB:s */
1239 descr.interface_statistics = NULL;
1240 wdh->number_of_interfaces= 1;
1241 wdh->interface_data= g_array_new(FALSE, FALSE, sizeof(wtapng_if_descr_t));
1242 g_array_append_val(wdh->interface_data, descr);
1245 /* In case "fopen()" fails but doesn't set "errno", set "errno"
1246 to a generic "the open failed" error. */
1247 errno = WTAP_ERR_CANT_OPEN;
1248 fh = wtap_dump_file_fdopen(wdh, fd);
1252 return NULL; /* can't create standard I/O stream */
1256 if (!wtap_dump_open_finish(wdh, filetype, compressed, err)) {
1257 wtap_dump_file_close(wdh);
1264 static gboolean wtap_dump_open_check(int filetype, int encap, gboolean compressed, int *err)
1266 if (!wtap_dump_can_open(filetype)) {
1267 /* Invalid type, or type we don't know how to write. */
1268 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
1272 /* OK, we know how to write that type; can we write the specified
1273 encapsulation type? */
1274 *err = (*dump_open_table[filetype].can_write_encap)(encap);
1278 /* if compression is wanted, do we support this for this filetype? */
1279 if(compressed && !wtap_dump_can_compress(filetype)) {
1280 *err = WTAP_ERR_COMPRESSION_NOT_SUPPORTED;
1284 *err = (*dump_open_table[filetype].can_write_encap)(encap);
1288 /* All systems go! */
1292 static wtap_dumper* wtap_dump_alloc_wdh(int filetype, int encap, int snaplen,
1293 gboolean compressed, int *err)
1297 wdh = (wtap_dumper *)g_malloc0(sizeof (wtap_dumper));
1303 wdh->file_type = filetype;
1304 wdh->snaplen = snaplen;
1306 wdh->compressed = compressed;
1310 static gboolean wtap_dump_open_finish(wtap_dumper *wdh, int filetype, gboolean compressed, int *err)
1315 /* Can we do a seek on the file descriptor?
1316 If not, note that fact. */
1320 fd = fileno((FILE *)wdh->fh);
1321 if (lseek(fd, 1, SEEK_CUR) == -1)
1324 /* Undo the seek. */
1325 lseek(fd, 0, SEEK_SET);
1330 /* If this file type requires seeking, and we can't seek, fail. */
1331 if (dump_open_table[filetype].writing_must_seek && cant_seek) {
1332 *err = WTAP_ERR_CANT_WRITE_TO_PIPE;
1336 /* Now try to open the file for writing. */
1337 if (!(*dump_open_table[filetype].dump_open)(wdh, err)) {
1341 return TRUE; /* success! */
1344 gboolean wtap_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
1345 const union wtap_pseudo_header *pseudo_header, const guint8 *pd, int *err)
1347 return (wdh->subtype_write)(wdh, phdr, pseudo_header, pd, err);
1350 void wtap_dump_flush(wtap_dumper *wdh)
1353 if(wdh->compressed) {
1354 gzwfile_flush((GZWFILE_T)wdh->fh);
1358 fflush((FILE *)wdh->fh);
1362 gboolean wtap_dump_close(wtap_dumper *wdh, int *err)
1364 gboolean ret = TRUE;
1366 if (wdh->subtype_close != NULL) {
1367 /* There's a close routine for this dump stream. */
1368 if (!(wdh->subtype_close)(wdh, err))
1371 errno = WTAP_ERR_CANT_CLOSE;
1372 /* Don't close stdout */
1373 if (wdh->fh != stdout) {
1374 if (wtap_dump_file_close(wdh) == EOF) {
1376 /* The per-format close function succeeded,
1377 but the fclose didn't. Save the reason
1378 why, if our caller asked for it. */
1385 /* as we don't close stdout, at least try to flush it */
1386 wtap_dump_flush(wdh);
1388 if (wdh->priv != NULL)
1394 gint64 wtap_get_bytes_dumped(wtap_dumper *wdh)
1396 return wdh->bytes_dumped;
1399 void wtap_set_bytes_dumped(wtap_dumper *wdh, gint64 bytes_dumped)
1401 wdh->bytes_dumped = bytes_dumped;
1404 gboolean wtap_dump_set_addrinfo_list(wtap_dumper *wdh, struct addrinfo *addrinfo_list)
1406 if (!wdh || wdh->file_type < 0 || wdh->file_type >= wtap_num_file_types
1407 || dump_open_table[wdh->file_type].has_name_resolution == FALSE)
1409 wdh->addrinfo_list = addrinfo_list;
1413 /* internally open a file for writing (compressed or not) */
1415 static WFILE_T wtap_dump_file_open(wtap_dumper *wdh, const char *filename)
1417 if(wdh->compressed) {
1418 return gzwfile_open(filename);
1420 return ws_fopen(filename, "wb");
1424 static WFILE_T wtap_dump_file_open(wtap_dumper *wdh _U_, const char *filename)
1426 return ws_fopen(filename, "wb");
1430 /* internally open a file for writing (compressed or not) */
1432 static WFILE_T wtap_dump_file_fdopen(wtap_dumper *wdh, int fd)
1434 if(wdh->compressed) {
1435 return gzwfile_fdopen(fd);
1437 return fdopen(fd, "wb");
1441 static WFILE_T wtap_dump_file_fdopen(wtap_dumper *wdh _U_, int fd)
1443 return fdopen(fd, "wb");
1447 /* internally writing raw bytes (compressed or not) */
1448 gboolean wtap_dump_file_write(wtap_dumper *wdh, const void *buf, size_t bufsize,
1454 if (wdh->compressed) {
1455 nwritten = gzwfile_write((GZWFILE_T)wdh->fh, buf, (unsigned) bufsize);
1457 * gzwfile_write() returns 0 on error.
1459 if (nwritten == 0) {
1460 *err = gzwfile_geterr((GZWFILE_T)wdh->fh);
1466 nwritten = fwrite(buf, 1, bufsize, (FILE *)wdh->fh);
1468 * At least according to the Mac OS X man page,
1469 * this can return a short count on an error.
1471 if (nwritten != bufsize) {
1472 if (ferror((FILE *)wdh->fh))
1475 *err = WTAP_ERR_SHORT_WRITE;
1482 /* internally close a file for writing (compressed or not) */
1483 static int wtap_dump_file_close(wtap_dumper *wdh)
1486 if(wdh->compressed) {
1487 return gzwfile_close((GZWFILE_T)wdh->fh);
1491 return fclose((FILE *)wdh->fh);