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
This commit is contained in:
Ulf Lamping 2005-09-14 21:57:30 +00:00
parent 1d0e5b105c
commit 84cf7ce767
14 changed files with 272 additions and 123 deletions

View File

@ -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 */

View File

@ -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],

13
file.c
View File

@ -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.",

3
file.h
View File

@ -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.

View File

@ -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. */

View File

@ -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);

View File

@ -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();

View File

@ -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;
}

View File

@ -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. */

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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) \

View File

@ -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

View File

@ -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.