From 84cf7ce7675b450311dcec0b34b785974b2e85d0 Mon Sep 17 00:00:00 2001 From: Ulf Lamping Date: Wed, 14 Sep 2005 21:57:30 +0000 Subject: added compression support for capture file output. The Save/As dialog now has a checkbox "Compress with gzip" currently limited to Ethereal and all the variants of libpcap filetypes only. We might want to add output compression support to the other tools as well (tethereal, mergecap, ...). We might also want to add support for the other filetypes, but this is only possible if the filetype functions doesn't use special output operations like fseek. One bug is still left: if the input and output filetypes while saving are the same, Ethereal currently optimizes this by simply copy the binary file instead of using wiretap (so it will be faster but it will ignore the compress setting). Don't know a good workaround for this, as I don't know a way to find out if the input file is currently compressed or not. One idea might be to use a heuristic on the filesize (compared to the packet size summmary). Another workaround I see is to remove this optimization, which is of course not the way I like to do it ... svn path=/trunk/; revision=15804 --- capture_loop.c | 10 +- editcap.c | 2 +- file.c | 13 ++- file.h | 3 +- gtk/file_dlg.c | 18 +++- mergecap.c | 2 +- randpkt.c | 2 +- ringbuffer.c | 2 +- tethereal.c | 6 +- wiretap/file_access.c | 280 +++++++++++++++++++++++++++++++++++--------------- wiretap/libpcap.c | 42 ++++---- wiretap/wtap-int.h | 3 + wiretap/wtap.def | 3 +- wiretap/wtap.h | 9 +- 14 files changed, 272 insertions(+), 123 deletions(-) diff --git a/capture_loop.c b/capture_loop.c index 8421e73a32..8ed04636a6 100644 --- a/capture_loop.c +++ b/capture_loop.c @@ -832,7 +832,7 @@ static int capture_loop_init_wiretap_output(capture_options *capture_opts, int s file_snaplen, &err); } else { ld->wtap_pdh = wtap_dump_fdopen(save_file_fd, WTAP_FILE_PCAP, - ld->wtap_linktype, file_snaplen, &err); + ld->wtap_linktype, file_snaplen, FALSE /* compressed */, &err); } if (ld->wtap_pdh == NULL) { @@ -1242,7 +1242,7 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct message to our parent so that they'll open the capture file and update its windows to indicate that we have a live capture in progress. */ - fflush(wtap_dump_file(ld.wtap_pdh)); + wtap_dump_flush(ld.wtap_pdh); sync_pipe_filename_to_parent(capture_opts->save_file); /* initialize capture stop (and alike) conditions */ @@ -1328,7 +1328,7 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct if (cnd_file_duration) { cnd_reset(cnd_file_duration); } - fflush(wtap_dump_file(ld.wtap_pdh)); + wtap_dump_flush(ld.wtap_pdh); sync_pipe_filename_to_parent(capture_opts->save_file); } else { /* File switch failed: stop here */ @@ -1371,7 +1371,7 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct /* Let the parent process know. */ if (ld.packets_sync_pipe) { /* do sync here */ - fflush(wtap_dump_file(ld.wtap_pdh)); + wtap_dump_flush(ld.wtap_pdh); /* Send our parent a message saying we've written out "ld.sync_packets" packets to the capture file. */ @@ -1403,7 +1403,7 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct cnd_reset(cnd_file_duration); if(cnd_autostop_size) cnd_reset(cnd_autostop_size); - fflush(wtap_dump_file(ld.wtap_pdh)); + wtap_dump_flush(ld.wtap_pdh); sync_pipe_filename_to_parent(capture_opts->save_file); } else { /* File switch failed: stop here */ diff --git a/editcap.c b/editcap.c index 09269507e5..50592854a4 100644 --- a/editcap.c +++ b/editcap.c @@ -373,7 +373,7 @@ int main(int argc, char *argv[]) out_frame_type = wtap_file_encap(wth); pdh = wtap_dump_open(argv[optind + 1], out_file_type, - out_frame_type, wtap_snapshot_length(wth), &err); + out_frame_type, wtap_snapshot_length(wth), FALSE /* compressed */, &err); if (pdh == NULL) { fprintf(stderr, "editcap: Can't open or create %s: %s\n", argv[optind+1], diff --git a/file.c b/file.c index 53b7e6055f..9b4f9977e6 100644 --- a/file.c +++ b/file.c @@ -983,7 +983,8 @@ cf_merge_files(char **out_filenamep, int in_file_count, pdh = wtap_dump_fdopen(out_fd, file_type, merge_select_frame_type(in_file_count, in_files), - merge_max_snapshot_length(in_file_count, in_files), &open_err); + merge_max_snapshot_length(in_file_count, in_files), + FALSE /* compressed */, &open_err); if (pdh == NULL) { close(out_fd); merge_close_in_files(in_file_count, in_files); @@ -3081,7 +3082,7 @@ save_packet(capture_file *cf _U_, frame_data *fdata, } cf_status_t -cf_save(capture_file *cf, const char *fname, packet_range_t *range, guint save_format) +cf_save(capture_file *cf, const char *fname, packet_range_t *range, guint save_format, gboolean compressed) { gchar *from_filename; int err; @@ -3160,7 +3161,8 @@ cf_save(capture_file *cf, const char *fname, packet_range_t *range, guint save_f /* Either we're filtering packets, or we're saving in a different format; we can't do that by copying or moving the capture file, we have to do it by writing the packets out in Wiretap. */ - pdh = wtap_dump_open(fname, save_format, cf->lnk_t, cf->snap, &err); + pdh = wtap_dump_open(fname, save_format, cf->lnk_t, cf->snap, + compressed, &err); if (pdh == NULL) { cf_open_failure_alert_box(fname, err, NULL, TRUE, save_format); goto fail; @@ -3359,6 +3361,11 @@ cf_open_failure_alert_box(const char *filename, int err, gchar *err_info, filename); break; + case WTAP_ERR_COMPRESSION_NOT_SUPPORTED: + simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, + "Gzip compression not supported by this file type."); + break; + default: simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "The file \"%s\" could not be %s: %s.", diff --git a/file.h b/file.h index fd7ff33301..3eadec354d 100644 --- a/file.h +++ b/file.h @@ -157,9 +157,10 @@ cf_read_status_t cf_finish_tail(capture_file *cf, int *err); * @param fname the filename to save to * @param range the range of packets to save * @param save_format the format of the file to save (libpcap, ...) + * @param compressed wether to gzip compress the file * @return one of cf_status_t */ -cf_status_t cf_save(capture_file * cf, const char *fname, packet_range_t *range, guint save_format); +cf_status_t cf_save(capture_file * cf, const char *fname, packet_range_t *range, guint save_format, gboolean compressed); /** * Get a displayable name of the capture file. diff --git a/gtk/file_dlg.c b/gtk/file_dlg.c index 7288dc8396..100b5bf193 100644 --- a/gtk/file_dlg.c +++ b/gtk/file_dlg.c @@ -1217,6 +1217,7 @@ static void select_file_type_cb(GtkWidget *w _U_, gpointer data) { int new_filetype = GPOINTER_TO_INT(data); + GtkWidget *compressed_cb; if (filetype != new_filetype) { /* We can select only the filtered or marked packets to be saved if we can @@ -1225,6 +1226,8 @@ select_file_type_cb(GtkWidget *w _U_, gpointer data) range_set_displayed_sensitive(range_tb, can_save_with_wiretap(new_filetype)); filetype = new_filetype; file_set_save_marked_sensitive(); + compressed_cb = OBJECT_GET_DATA(file_save_as_w, "compressed"); + gtk_widget_set_sensitive(compressed_cb, wtap_dump_can_compress(new_filetype)); } } @@ -1267,7 +1270,7 @@ gpointer action_after_save_data_g; void file_save_as_cmd(action_after_save_e action_after_save, gpointer action_after_save_data) { - GtkWidget *main_vb, *ft_hb, *ft_lb, *range_fr; + GtkWidget *main_vb, *ft_hb, *ft_lb, *range_fr, *compressed_cb; GtkTooltips *tooltips; #if GTK_MAJOR_VERSION < 2 @@ -1352,6 +1355,13 @@ file_save_as_cmd(action_after_save_e action_after_save, gpointer action_after_sa /* dynamic values in the range frame */ range_update_dynamics(range_tb); + /* compressed */ + compressed_cb = gtk_check_button_new_with_label("Compress with gzip"); + gtk_container_add(GTK_CONTAINER(ft_hb), compressed_cb); + gtk_widget_show(compressed_cb); + OBJECT_SET_DATA(file_save_as_w, "compressed", compressed_cb); + gtk_widget_set_sensitive(compressed_cb, wtap_dump_can_compress(cfile.cd_t)); + SIGNAL_CONNECT(file_save_as_w, "destroy", file_save_as_destroy_cb, NULL); #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2 @@ -1389,6 +1399,7 @@ static void file_save_as_cb(GtkWidget *w _U_, gpointer fs) { gchar *cf_name; gchar *dirname; + GtkWidget *compressed_cb; #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2 @@ -1397,9 +1408,12 @@ file_save_as_cb(GtkWidget *w _U_, gpointer fs) { cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs))); #endif + compressed_cb = OBJECT_GET_DATA(file_save_as_w, "compressed"); + /* Write out the packets (all, or only the ones from the current range) to the file with the specified name. */ - if (cf_save(&cfile, cf_name, &range, filetype) != CF_OK) { + if (cf_save(&cfile, cf_name, &range, filetype, + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(compressed_cb))) != CF_OK) { /* The write failed; don't dismiss the open dialog box, just leave it around so that the user can, after they dismiss the alert box popped up for the error, try again. */ diff --git a/mergecap.c b/mergecap.c index 83777a7ebe..9136e64930 100644 --- a/mergecap.c +++ b/mergecap.c @@ -301,7 +301,7 @@ main(int argc, char *argv[]) } /* prepare the outfile */ - pdh = wtap_dump_fdopen(out_fd, file_type, frame_type, snaplen, &open_err); + pdh = wtap_dump_fdopen(out_fd, file_type, frame_type, snaplen, FALSE /* compressed */, &open_err); if (pdh == NULL) { merge_close_in_files(in_file_count, in_files); free(in_files); diff --git a/randpkt.c b/randpkt.c index 65873fa0e0..965189b06b 100644 --- a/randpkt.c +++ b/randpkt.c @@ -482,7 +482,7 @@ main(int argc, char **argv) pkthdr.pkt_encap = example->sample_wtap_encap; dump = wtap_dump_open(produce_filename, WTAP_FILE_PCAP, - example->sample_wtap_encap, produce_max_bytes, &err); + example->sample_wtap_encap, produce_max_bytes, FALSE /* compressed */, &err); seed(); diff --git a/ringbuffer.c b/ringbuffer.c index 84d2983d57..4f1d5fe0da 100644 --- a/ringbuffer.c +++ b/ringbuffer.c @@ -241,7 +241,7 @@ ringbuf_init_wtap_dump_fdopen(int filetype, int linktype, int snaplen, int *err) rb_data.linktype = linktype; rb_data.snaplen = snaplen; - rb_data.pdh = wtap_dump_fdopen(rb_data.fd, filetype, linktype, snaplen, err); + rb_data.pdh = wtap_dump_fdopen(rb_data.fd, filetype, linktype, snaplen, FALSE /* compressed */, err); return rb_data.pdh; } diff --git a/tethereal.c b/tethereal.c index 3fe4974140..7b60c68157 100644 --- a/tethereal.c +++ b/tethereal.c @@ -1681,7 +1681,7 @@ capture(char *save_file, int out_file_type) } } else { ld.pdh = wtap_dump_open(save_file, out_file_type, - ld.linktype, file_snaplen, &err); + ld.linktype, file_snaplen, FALSE /* compress */, &err); } if (ld.pdh == NULL) { @@ -1846,7 +1846,7 @@ capture(char *save_file, int out_file_type) } if (ld.output_to_pipe) { if (ld.packet_count > packet_count_prev) { - if (fflush(wtap_dump_file(ld.pdh))) { + if (wtap_dump_file_flush(ld.pdh)) { volatile_err = errno; ld.go = FALSE; } @@ -2121,7 +2121,7 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type) snapshot_length = WTAP_MAX_PACKET_SIZE; } pdh = wtap_dump_open(save_file, out_file_type, - linktype, snapshot_length, &err); + linktype, snapshot_length, FALSE /* compressed */, &err); if (pdh == NULL) { /* We couldn't set up to write to the capture file. */ diff --git a/wiretap/file_access.c b/wiretap/file_access.c index 84705e29fd..08b4d72384 100644 --- a/wiretap/file_access.c +++ b/wiretap/file_access.c @@ -338,175 +338,176 @@ success: static const struct file_type_info { const char *name; const char *short_name; + gboolean can_compress; int (*can_write_encap)(int); int (*dump_open)(wtap_dumper *, gboolean, int *); } dump_open_table[WTAP_NUM_FILE_TYPES] = { /* WTAP_FILE_UNKNOWN */ - { NULL, NULL, + { NULL, NULL, FALSE, NULL, NULL }, /* WTAP_FILE_WTAP */ - { "Wiretap (Ethereal)", NULL, + { "Wiretap (Ethereal)", NULL, FALSE, NULL, NULL }, /* WTAP_FILE_PCAP */ - { "libpcap (tcpdump, Ethereal, etc.)", "libpcap", + { "libpcap (tcpdump, Ethereal, etc.)", "libpcap", TRUE, libpcap_dump_can_write_encap, libpcap_dump_open }, /* WTAP_FILE_PCAP_SS990417 */ - { "RedHat Linux 6.1 libpcap (tcpdump)", "rh6_1libpcap", + { "RedHat Linux 6.1 libpcap (tcpdump)", "rh6_1libpcap", TRUE, libpcap_dump_can_write_encap, libpcap_dump_open }, /* WTAP_FILE_PCAP_SS990915 */ - { "SuSE Linux 6.3 libpcap (tcpdump)", "suse6_3libpcap", + { "SuSE Linux 6.3 libpcap (tcpdump)", "suse6_3libpcap", TRUE, libpcap_dump_can_write_encap, libpcap_dump_open }, /* WTAP_FILE_PCAP_SS991029 */ - { "modified libpcap (tcpdump)", "modlibpcap", + { "modified libpcap (tcpdump)", "modlibpcap", TRUE, libpcap_dump_can_write_encap, libpcap_dump_open }, /* WTAP_FILE_PCAP_NOKIA */ - { "Nokia libpcap (tcpdump)", "nokialibpcap", + { "Nokia libpcap (tcpdump)", "nokialibpcap", TRUE, libpcap_dump_can_write_encap, libpcap_dump_open }, /* WTAP_FILE_PCAP_AIX */ - { "AIX libpcap (tcpdump)", NULL, + { "AIX libpcap (tcpdump)", NULL, TRUE, NULL, NULL }, /* WTAP_FILE_PCAP_NSEC */ - { "Nanosecond libpcap (Ethereal)", "nseclibpcap", + { "Nanosecond libpcap (Ethereal)", "nseclibpcap", TRUE, libpcap_dump_can_write_encap, libpcap_dump_open }, /* WTAP_FILE_LANALYZER */ - { "Novell LANalyzer","lanalyzer", + { "Novell LANalyzer","lanalyzer", FALSE, lanalyzer_dump_can_write_encap, lanalyzer_dump_open }, /* WTAP_FILE_NGSNIFFER_UNCOMPRESSED */ - { "Network Associates Sniffer (DOS-based)", "ngsniffer", + { "Network Associates Sniffer (DOS-based)", "ngsniffer", FALSE, ngsniffer_dump_can_write_encap, ngsniffer_dump_open }, /* WTAP_FILE_NGSNIFFER_COMPRESSED */ - { "Network Associates Sniffer (DOS-based), compressed", "ngsniffer_comp", + { "Network Associates Sniffer (DOS-based), compressed", "ngsniffer_comp", FALSE, NULL, NULL }, /* WTAP_FILE_SNOOP */ - { "Sun snoop", "snoop", + { "Sun snoop", "snoop", FALSE, snoop_dump_can_write_encap, snoop_dump_open }, /* WTAP_FILE_SHOMITI */ - { "Shomiti/Finisar Surveyor", "shomiti", + { "Shomiti/Finisar Surveyor", "shomiti", FALSE, NULL, NULL }, /* WTAP_FILE_IPTRACE_1_0 */ - { "AIX iptrace 1.0", NULL, + { "AIX iptrace 1.0", NULL, FALSE, NULL, NULL }, /* WTAP_FILE_IPTRACE_2_0 */ - { "AIX iptrace 2.0", NULL, + { "AIX iptrace 2.0", NULL, FALSE, NULL, NULL }, /* WTAP_FILE_NETMON_1_x */ - { "Microsoft Network Monitor 1.x", "netmon1", + { "Microsoft Network Monitor 1.x", "netmon1", FALSE, netmon_dump_can_write_encap, netmon_dump_open }, /* WTAP_FILE_NETMON_2_x */ - { "Microsoft Network Monitor 2.x", "netmon2", + { "Microsoft Network Monitor 2.x", "netmon2", FALSE, netmon_dump_can_write_encap, netmon_dump_open }, /* WTAP_FILE_NETXRAY_OLD */ - { "Cinco Networks NetXRay 1.x", NULL, + { "Cinco Networks NetXRay 1.x", NULL, FALSE, NULL, NULL }, /* WTAP_FILE_NETXRAY_1_0 */ - { "Cinco Networks NetXRay 2.0 or later", NULL, + { "Cinco Networks NetXRay 2.0 or later", NULL, FALSE, NULL, NULL }, /* WTAP_FILE_NETXRAY_1_1 */ - { "Network Associates Sniffer (Windows-based) 1.1", "ngwsniffer_1_1", + { "Network Associates Sniffer (Windows-based) 1.1", "ngwsniffer_1_1", FALSE, netxray_dump_can_write_encap_1_1, netxray_dump_open_1_1 }, /* WTAP_FILE_NETXRAY_2_00x */ - { "Network Associates Sniffer (Windows-based) 2.00x", "ngwsniffer_2_0", + { "Network Associates Sniffer (Windows-based) 2.00x", "ngwsniffer_2_0", FALSE, netxray_dump_can_write_encap_2_0, netxray_dump_open_2_0 }, /* WTAP_FILE_RADCOM */ - { "RADCOM WAN/LAN analyzer", NULL, + { "RADCOM WAN/LAN analyzer", NULL, FALSE, NULL, NULL }, /* WTAP_FILE_ASCEND */ - { "Lucent/Ascend access server trace", NULL, + { "Lucent/Ascend access server trace", NULL, FALSE, NULL, NULL }, /* WTAP_FILE_NETTL */ - { "HP-UX nettl trace", "nettl", + { "HP-UX nettl trace", "nettl", FALSE, nettl_dump_can_write_encap, nettl_dump_open }, /* WTAP_FILE_TOSHIBA */ - { "Toshiba Compact ISDN Router snoop trace", NULL, + { "Toshiba Compact ISDN Router snoop trace", NULL, FALSE, NULL, NULL }, /* WTAP_FILE_I4BTRACE */ - { "I4B ISDN trace", NULL, + { "I4B ISDN trace", NULL, FALSE, NULL, NULL }, /* WTAP_FILE_CSIDS */ - { "CSIDS IPLog", NULL, + { "CSIDS IPLog", NULL, FALSE, NULL, NULL }, /* WTAP_FILE_PPPDUMP */ - { "pppd log (pppdump format)", NULL, + { "pppd log (pppdump format)", NULL, FALSE, NULL, NULL }, /* WTAP_FILE_ETHERPEEK_V56 */ - { "EtherPeek/TokenPeek trace (V5 & V6 file format)", NULL, + { "EtherPeek/TokenPeek trace (V5 & V6 file format)", NULL, FALSE, NULL, NULL }, /* WTAP_FILE_ETHERPEEK_V7 */ - { "EtherPeek/TokenPeek/AiroPeek trace (V7 file format)", NULL, + { "EtherPeek/TokenPeek/AiroPeek trace (V7 file format)", NULL, FALSE, NULL, NULL }, /* WTAP_FILE_VMS */ - { "TCPIPtrace (VMS)", NULL, + { "TCPIPtrace (VMS)", NULL, FALSE, NULL, NULL}, /* WTAP_FILE_DBS_ETHERWATCH */ - { "DBS Etherwatch (VMS)", NULL, + { "DBS Etherwatch (VMS)", NULL, FALSE, NULL, NULL}, /* WTAP_FILE_VISUAL_NETWORKS */ - { "Visual Networks traffic capture", "visual", + { "Visual Networks traffic capture", "visual", FALSE, visual_dump_can_write_encap, visual_dump_open }, /* WTAP_FILE_COSINE */ - { "CoSine IPSX L2 capture", "cosine", + { "CoSine IPSX L2 capture", "cosine", FALSE, NULL, NULL }, /* WTAP_FILE_5VIEWS */ - { "Accellent 5Views capture", "5views", + { "Accellent 5Views capture", "5views", FALSE, _5views_dump_can_write_encap, _5views_dump_open }, /* WTAP_FILE_ERF */ - { "Endace DAG capture", "erf", + { "Endace DAG capture", "erf", FALSE, NULL, NULL }, /* WTAP_FILE_HCIDUMP */ - { "Bluetooth HCI dump", "hcidump", + { "Bluetooth HCI dump", "hcidump", FALSE, NULL, NULL }, /* WTAP_FILE_NETWORK_INSTRUMENTS_V9 */ - { "Network Instruments Observer version 9", "niobserverv9", + { "Network Instruments Observer version 9", "niobserverv9", FALSE, network_instruments_dump_can_write_encap, network_instruments_dump_open }, /* WTAP_FILE_AIROPEEK_V9 */ - { "EtherPeek/AiroPeek trace (V9 file format)", NULL, + { "EtherPeek/AiroPeek trace (V9 file format)", NULL, FALSE, NULL, NULL }, /* WTAP_FILE_EYESDN */ - { "EyeSDN USB S0/E1 ISDN trace format", NULL, + { "EyeSDN USB S0/E1 ISDN trace format", NULL, FALSE, NULL, NULL }, /* WTAP_FILE_K12 */ - { "Tektronix K12xx 32-bit .rf5 format", "rf5", + { "Tektronix K12xx 32-bit .rf5 format", "rf5", FALSE, k12_dump_can_write_encap, k12_dump_open }, }; @@ -563,29 +564,51 @@ gboolean wtap_dump_can_write_encap(int filetype, int encap) return TRUE; } -static gboolean wtap_dump_open_check(int filetype, int encap, int *err); +gboolean wtap_dump_can_compress(int filetype) +{ +#ifdef HAVE_LIBZ + if (filetype < 0 || filetype >= WTAP_NUM_FILE_TYPES + || dump_open_table[filetype].can_compress == FALSE) + return FALSE; + + return TRUE; +#else + return FALSE; +#endif +} + + +static gboolean wtap_dump_open_check(int filetype, int encap, gboolean comressed, int *err); static wtap_dumper* wtap_dump_alloc_wdh(int filetype, int encap, int snaplen, - int *err); -static gboolean wtap_dump_open_finish(wtap_dumper *wdh, int filetype, int *err); + gboolean compressed, int *err); +static gboolean wtap_dump_open_finish(wtap_dumper *wdh, int filetype, gboolean compressed, int *err); + +static FILE *wtap_dump_file_open(wtap_dumper *wdh, const char *filename); +static FILE *wtap_dump_file_fdopen(wtap_dumper *wdh, int fd); +static int wtap_dump_file_close(wtap_dumper *wdh); wtap_dumper* wtap_dump_open(const char *filename, int filetype, int encap, - int snaplen, int *err) + int snaplen, gboolean compressed, int *err) { wtap_dumper *wdh; FILE *fh; /* Check whether we can open a capture file with that file type and that encapsulation. */ - if (!wtap_dump_open_check(filetype, encap, err)) + if (!wtap_dump_open_check(filetype, encap, compressed, err)) return NULL; /* Allocate a data structure for the output stream. */ - wdh = wtap_dump_alloc_wdh(filetype, encap, snaplen, err); + wdh = wtap_dump_alloc_wdh(filetype, encap, snaplen, compressed, err); if (wdh == NULL) return NULL; /* couldn't allocate it */ /* Empty filename means stdout */ if (*filename == '\0') { + if(compressed) { + g_free(wdh); + return NULL; /* compress won't work on stdout */ + } #ifdef _WIN32 setmode(fileno(stdout), O_BINARY); #endif @@ -594,56 +617,64 @@ wtap_dumper* wtap_dump_open(const char *filename, int filetype, int encap, /* In case "fopen()" fails but doesn't set "errno", set "errno" to a generic "the open failed" error. */ errno = WTAP_ERR_CANT_OPEN; - fh = fopen(filename, "wb"); + fh = wtap_dump_file_open(wdh, filename); if (fh == NULL) { *err = errno; + g_free(wdh); return NULL; /* can't create file */ } wdh->fh = fh; } - if (!wtap_dump_open_finish(wdh, filetype, err)) { + if (!wtap_dump_open_finish(wdh, filetype, compressed, err)) { /* Get rid of the file we created; we couldn't finish opening it. */ - if (wdh->fh != stdout) + if (wdh->fh != stdout) { + wtap_dump_file_close(wdh); unlink(filename); + } + g_free(wdh); return NULL; } return wdh; } wtap_dumper* wtap_dump_fdopen(int fd, int filetype, int encap, int snaplen, - int *err) + gboolean compressed, int *err) { wtap_dumper *wdh; FILE *fh; /* Check whether we can open a capture file with that file type and that encapsulation. */ - if (!wtap_dump_open_check(filetype, encap, err)) + if (!wtap_dump_open_check(filetype, encap, compressed, err)) return NULL; /* Allocate a data structure for the output stream. */ - wdh = wtap_dump_alloc_wdh(filetype, encap, snaplen, err); + wdh = wtap_dump_alloc_wdh(filetype, encap, snaplen, compressed, err); if (wdh == NULL) return NULL; /* couldn't allocate it */ /* In case "fopen()" fails but doesn't set "errno", set "errno" to a generic "the open failed" error. */ errno = WTAP_ERR_CANT_OPEN; - fh = fdopen(fd, "wb"); + fh = wtap_dump_file_fdopen(wdh, fd); if (fh == NULL) { *err = errno; + g_free(wdh); return NULL; /* can't create standard I/O stream */ } wdh->fh = fh; - if (!wtap_dump_open_finish(wdh, filetype, err)) + if (!wtap_dump_open_finish(wdh, filetype, compressed, err)) { + wtap_dump_file_close(wdh); + g_free(wdh); return NULL; + } return wdh; } -static gboolean wtap_dump_open_check(int filetype, int encap, int *err) +static gboolean wtap_dump_open_check(int filetype, int encap, gboolean compressed, int *err) { if (!wtap_dump_can_open(filetype)) { /* Invalid type, or type we don't know how to write. */ @@ -657,12 +688,23 @@ static gboolean wtap_dump_open_check(int filetype, int encap, int *err) if (*err != 0) return FALSE; + /* if compression is wanted, do we support this for this filetype? */ + if(compressed && !wtap_dump_can_compress(filetype)) { + *err = WTAP_ERR_COMPRESSION_NOT_SUPPORTED; + return FALSE; + } + + *err = (*dump_open_table[filetype].can_write_encap)(encap); + if (*err != 0) + return FALSE; + + /* All systems go! */ return TRUE; } static wtap_dumper* wtap_dump_alloc_wdh(int filetype, int encap, int snaplen, - int *err) + gboolean compressed, int *err) { wtap_dumper *wdh; @@ -675,6 +717,7 @@ static wtap_dumper* wtap_dump_alloc_wdh(int filetype, int encap, int snaplen, wdh->file_type = filetype; wdh->snaplen = snaplen; wdh->encap = encap; + wdh->compressed = compressed; wdh->bytes_dumped = 0; wdh->dump.opaque = NULL; wdh->subtype_write = NULL; @@ -682,49 +725,52 @@ static wtap_dumper* wtap_dump_alloc_wdh(int filetype, int encap, int snaplen, return wdh; } -static gboolean wtap_dump_open_finish(wtap_dumper *wdh, int filetype, int *err) +static gboolean wtap_dump_open_finish(wtap_dumper *wdh, int filetype, gboolean compressed, int *err) { int fd; gboolean cant_seek; /* Can we do a seek on the file descriptor? If not, note that fact. */ - fd = fileno(wdh->fh); - if (lseek(fd, 1, SEEK_CUR) == -1) - cant_seek = TRUE; - else { - /* Undo the seek. */ - lseek(fd, 0, SEEK_SET); - cant_seek = FALSE; + if(compressed) { + cant_seek = TRUE; + } else { + fd = fileno(wdh->fh); + if (lseek(fd, 1, SEEK_CUR) == -1) + cant_seek = TRUE; + else { + /* Undo the seek. */ + lseek(fd, 0, SEEK_SET); + cant_seek = FALSE; + } } /* Now try to open the file for writing. */ if (!(*dump_open_table[filetype].dump_open)(wdh, cant_seek, err)) { - /* The attempt failed. Close the stream for the file. - NOTE: this means the FD handed to "wtap_dump_fdopen()" - will be closed if the open fails. */ - if (wdh->fh != stdout) - fclose(wdh->fh); - - /* Now free up the dumper handle. */ - g_free(wdh); return FALSE; } return TRUE; /* success! */ } -FILE* wtap_dump_file(wtap_dumper *wdh) -{ - return wdh->fh; -} - gboolean wtap_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr, const union wtap_pseudo_header *pseudo_header, const guchar *pd, int *err) { return (wdh->subtype_write)(wdh, phdr, pseudo_header, pd, err); } +void wtap_dump_flush(wtap_dumper *wdh) +{ +#ifdef HAVE_LIBZ + if(wdh->compressed) { + gzflush(wdh->fh, Z_SYNC_FLUSH); /* XXX - is Z_SYNC_FLUSH the right one? */ + } else +#endif + { + fflush(wdh->fh); + } +} + gboolean wtap_dump_close(wtap_dumper *wdh, int *err) { gboolean ret = TRUE; @@ -737,7 +783,7 @@ gboolean wtap_dump_close(wtap_dumper *wdh, int *err) errno = WTAP_ERR_CANT_CLOSE; /* Don't close stdout */ if (wdh->fh != stdout) { - if (fclose(wdh->fh) == EOF) { + if (wtap_dump_file_close(wdh) == EOF) { if (ret) { /* The per-format close function succeeded, but the fclose didn't. Save the reason @@ -764,3 +810,77 @@ void wtap_set_bytes_dumped(wtap_dumper *wdh, long bytes_dumped) wdh->bytes_dumped = bytes_dumped; } + +/* internally open a file for writing (compressed or not) */ +static FILE *wtap_dump_file_open(wtap_dumper *wdh, const char *filename) +{ +#ifdef HAVE_LIBZ + if(wdh->compressed) { + return gzopen(filename, "wb"); + } else +#endif + { + return fopen(filename, "wb"); + } +} + +/* internally open a file for writing (compressed or not) */ +static FILE *wtap_dump_file_fdopen(wtap_dumper *wdh, int fd) +{ +#ifdef HAVE_LIBZ + if(wdh->compressed) { + return gzdopen(fd, "wb"); + } else +#endif + { + return fdopen(fd, "wb"); + } +} + +/* internally writing raw bytes (compressed or not) */ +size_t wtap_dump_file_write(wtap_dumper *wdh, const void *buf, unsigned bufsize) +{ +#ifdef HAVE_LIBZ + if(wdh->compressed) { + return gzwrite(wdh->fh, buf, bufsize); + } else +#endif + { + return fwrite(buf, 1, bufsize, wdh->fh); + } +} + +/* internally close a file for writing (compressed or not) */ +static int wtap_dump_file_close(wtap_dumper *wdh) +{ +#ifdef HAVE_LIBZ + if(wdh->compressed) { + return gzclose(wdh->fh); + } else +#endif + { + return fclose(wdh->fh); + } +} + +int wtap_dump_file_ferror(wtap_dumper *wdh) +{ +#ifdef HAVE_LIBZ + int errnum; + + if(wdh->compressed) { + gzerror(wdh->fh, &errnum); + + if(errnum == Z_ERRNO) { + return errno; + } else { + /* XXX - what to do with this zlib specific number? */ + return errnum; + } + } else +#endif + { + return ferror(wdh->fh); + } +} + diff --git a/wiretap/libpcap.c b/wiretap/libpcap.c index f3cbbe0f73..7226f78585 100644 --- a/wiretap/libpcap.c +++ b/wiretap/libpcap.c @@ -1991,10 +1991,10 @@ gboolean libpcap_dump_open(wtap_dumper *wdh, gboolean cant_seek _U_, int *err) return FALSE; } - nwritten = fwrite(&magic, 1, sizeof magic, wdh->fh); + nwritten = wtap_dump_file_write(wdh, &magic, sizeof magic); if (nwritten != sizeof magic) { - if (nwritten == 0 && ferror(wdh->fh)) - *err = errno; + if (nwritten == 0 && wtap_dump_file_ferror(wdh)) + *err = wtap_dump_file_ferror(wdh); else *err = WTAP_ERR_SHORT_WRITE; return FALSE; @@ -2020,10 +2020,10 @@ gboolean libpcap_dump_open(wtap_dumper *wdh, gboolean cant_seek _U_, int *err) file_hdr.snaplen = (wdh->snaplen != 0) ? wdh->snaplen : WTAP_MAX_PACKET_SIZE; file_hdr.network = wtap_wtap_encap_to_pcap_encap(wdh->encap); - nwritten = fwrite(&file_hdr, 1, sizeof file_hdr, wdh->fh); + nwritten = wtap_dump_file_write(wdh, &file_hdr, sizeof file_hdr); if (nwritten != sizeof file_hdr) { - if (nwritten == 0 && ferror(wdh->fh)) - *err = errno; + if (nwritten == 0 && wtap_dump_file_ferror(wdh)) + *err = wtap_dump_file_ferror(wdh); else *err = WTAP_ERR_SHORT_WRITE; return FALSE; @@ -2123,10 +2123,10 @@ static gboolean libpcap_dump(wtap_dumper *wdh, return FALSE; } - nwritten = fwrite(&rec_hdr, 1, hdr_size, wdh->fh); + nwritten = wtap_dump_file_write(wdh, &rec_hdr, hdr_size); if (nwritten != hdr_size) { - if (nwritten == 0 && ferror(wdh->fh)) - *err = errno; + if (nwritten == 0 && wtap_dump_file_ferror(wdh)) + *err = wtap_dump_file_ferror(wdh); else *err = WTAP_ERR_SHORT_WRITE; return FALSE; @@ -2168,10 +2168,10 @@ static gboolean libpcap_dump(wtap_dumper *wdh, } atm_hdr.vpi = (guint8) pseudo_header->atm.vpi; atm_hdr.vci = phtons(&pseudo_header->atm.vci); - nwritten = fwrite(&atm_hdr, 1, sizeof atm_hdr, wdh->fh); + nwritten = wtap_dump_file_write(wdh, &atm_hdr, sizeof atm_hdr); if (nwritten != sizeof atm_hdr) { - if (nwritten == 0 && ferror(wdh->fh)) - *err = errno; + if (nwritten == 0 && wtap_dump_file_ferror(wdh)) + *err = wtap_dump_file_ferror(wdh); else *err = WTAP_ERR_SHORT_WRITE; return FALSE; @@ -2185,10 +2185,10 @@ static gboolean libpcap_dump(wtap_dumper *wdh, memset(&irda_hdr, 0, sizeof(irda_hdr)); irda_hdr.sll_pkttype = phtons(&pseudo_header->irda.pkttype); irda_hdr.sll_protocol = g_htons(0x0017); - nwritten = fwrite(&irda_hdr, 1, sizeof(irda_hdr), wdh->fh); + nwritten = wtap_dump_file_write(wdh, &irda_hdr, sizeof(irda_hdr)); if (nwritten != sizeof(irda_hdr)) { - if (nwritten == 0 && ferror(wdh->fh)) - *err = errno; + if (nwritten == 0 && wtap_dump_file_ferror(wdh)) + *err = wtap_dump_file_ferror(wdh); else *err = WTAP_ERR_SHORT_WRITE; return FALSE; @@ -2203,10 +2203,10 @@ static gboolean libpcap_dump(wtap_dumper *wdh, mtp2_hdr.sent = pseudo_header->mtp2.sent; mtp2_hdr.annex_a_used = pseudo_header->mtp2.annex_a_used; mtp2_hdr.link_number = phtons(&pseudo_header->mtp2.link_number); - nwritten = fwrite(&mtp2_hdr, 1, sizeof(mtp2_hdr), wdh->fh); + nwritten = wtap_dump_file_write(wdh, &mtp2_hdr, sizeof(mtp2_hdr)); if (nwritten != sizeof(mtp2_hdr)) { - if (nwritten == 0 && ferror(wdh->fh)) - *err = errno; + if (nwritten == 0 && wtap_dump_file_ferror(wdh)) + *err = wtap_dump_file_ferror(wdh); else *err = WTAP_ERR_SHORT_WRITE; return FALSE; @@ -2214,10 +2214,10 @@ static gboolean libpcap_dump(wtap_dumper *wdh, wdh->bytes_dumped += sizeof(mtp2_hdr); } - nwritten = fwrite(pd, 1, phdr->caplen, wdh->fh); + nwritten = wtap_dump_file_write(wdh, pd, phdr->caplen); if (nwritten != phdr->caplen) { - if (nwritten == 0 && ferror(wdh->fh)) - *err = errno; + if (nwritten == 0 && wtap_dump_file_ferror(wdh)) + *err = wtap_dump_file_ferror(wdh); else *err = WTAP_ERR_SHORT_WRITE; return FALSE; diff --git a/wiretap/wtap-int.h b/wiretap/wtap-int.h index 79f3d072f0..52680d5fe7 100644 --- a/wiretap/wtap-int.h +++ b/wiretap/wtap-int.h @@ -230,6 +230,7 @@ struct wtap_dumper { int file_type; int snaplen; int encap; + gboolean compressed; long bytes_dumped; union { @@ -249,6 +250,8 @@ struct wtap_dumper { * e.g. WTAP_FILE_TSPREC_USEC */ }; +extern size_t wtap_dump_file_write(wtap_dumper *wdh, const void *buf, unsigned bufsize); +extern int wtap_dump_file_ferror(wtap_dumper *wdh); /* Macros to byte-swap 32-bit and 16-bit quantities. */ #define BSWAP32(x) \ diff --git a/wiretap/wtap.def b/wiretap/wtap.def index 74d11b8cb1..1470e46055 100644 --- a/wiretap/wtap.def +++ b/wiretap/wtap.def @@ -4,9 +4,10 @@ wtap_close wtap_dump wtap_dump_can_open wtap_dump_can_write_encap +wtap_dump_can_compress wtap_dump_close wtap_dump_fdopen -wtap_dump_file +wtap_dump_flush wtap_dump_open wtap_encap_short_string wtap_encap_string diff --git a/wiretap/wtap.h b/wiretap/wtap.h index 916a7f8b00..81774048bf 100644 --- a/wiretap/wtap.h +++ b/wiretap/wtap.h @@ -572,13 +572,14 @@ gboolean wtap_seek_read (wtap *wth, long seek_off, gboolean wtap_dump_can_open(int filetype); gboolean wtap_dump_can_write_encap(int filetype, int encap); +gboolean wtap_dump_can_compress(int filetype); wtap_dumper* wtap_dump_open(const char *filename, int filetype, int encap, - int snaplen, int *err); + int snaplen, gboolean compressed, int *err); wtap_dumper* wtap_dump_fdopen(int fd, int filetype, int encap, int snaplen, - int *err); + gboolean compressed, int *err); gboolean wtap_dump(wtap_dumper *, const struct wtap_pkthdr *, const union wtap_pseudo_header *pseudo_header, const guchar *, int *err); -FILE* wtap_dump_file(wtap_dumper *); +void wtap_dump_flush(wtap_dumper *); gboolean wtap_dump_close(wtap_dumper *, int *); long wtap_get_bytes_dumped(wtap_dumper *); void wtap_set_bytes_dumped(wtap_dumper *wdh, long bytes_dumped); @@ -624,6 +625,8 @@ void wtap_set_bytes_dumped(wtap_dumper *wdh, long bytes_dumped); /* LZ77 compressed data has bad offset to string */ #define WTAP_ERR_RANDOM_OPEN_STDIN -18 /* We're trying to open the standard input for random access */ +#define WTAP_ERR_COMPRESSION_NOT_SUPPORTED -19 + /* The filetype doesn't support output compression */ /* Errors from zlib; zlib error Z_xxx turns into Wiretap error WTAP_ERR_ZLIB + Z_xxx. -- cgit v1.2.3