/* file.c
* File I/O routines
*
- * $Id: file.c,v 1.198 2000/07/09 23:22:18 guy Exp $
+ * $Id: file.c,v 1.235 2001/03/24 02:14:54 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
-#include <sys/stat.h>
#include <errno.h>
-#include <fcntl.h>
#include <signal.h>
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
#ifdef NEED_SNPRINTF_H
-# ifdef HAVE_STDARG_H
-# include <stdarg.h>
-# else
-# include <varargs.h>
-# endif
# include "snprintf.h"
#endif
# include <netinet/in.h>
#endif
+#include <epan.h>
+
#include "gtk/main.h"
+#include "color.h"
+#include "gtk/color_utils.h"
#include "column.h"
#include "packet.h"
#include "print.h"
#include "menu.h"
#include "util.h"
#include "simple_dialog.h"
+#include "progress_dlg.h"
#include "ui_util.h"
#include "prefs.h"
#include "gtk/proto_draw.h"
-#include "dfilter.h"
+#include "gtk/packet_win.h"
+#include "dfilter/dfilter.h"
#include "conversation.h"
#include "globals.h"
+#include "gtk/colors.h"
-#include "plugins.h"
-
-extern GtkWidget *packet_list, *info_bar, *byte_view, *tree_view;
+extern GtkWidget *packet_list, *info_bar, *byte_nb_ptr, *tree_view;
extern guint file_ctx;
gboolean auto_scroll_live = FALSE;
static void read_packet(capture_file *cf, int offset);
static void rescan_packets(capture_file *cf, const char *action,
- gboolean refilter);
+ gboolean refilter, gboolean redissect);
static void set_selected_row(int row);
static char *file_rename_error_message(int err);
static char *file_close_error_message(int err);
+static gboolean copy_binary_file(char *from_filename, char *to_filename);
/* Update the progress bar this many times when reading a file. */
#define N_PROGBAR_UPDATES 100
close_cap_file(cf, info_bar);
/* Initialize the table of conversations. */
- conversation_init();
+ epan_conversation_init();
/* Initialize protocol-specific variables */
init_all_protocols();
cf->cd_t = wtap_file_type(cf->wth);
cf->count = 0;
+ cf->drops_known = FALSE;
cf->drops = 0;
cf->esec = 0;
cf->eusec = 0;
return (0);
fail:
- simple_dialog(ESD_TYPE_WARN, NULL,
+ simple_dialog(ESD_TYPE_CRIT, NULL,
file_open_error_message(err, FALSE), fname);
return (err);
}
cf->plist_chunk = NULL;
}
if (cf->rfcode != NULL) {
- dfilter_destroy(cf->rfcode);
+ dfilter_free(cf->rfcode);
cf->rfcode = NULL;
}
cf->plist = NULL;
set_menus_for_captured_packets(FALSE);
set_menus_for_selected_packet(FALSE);
set_menus_for_capture_in_progress(FALSE);
+ set_menus_for_selected_tree_row(FALSE);
/* We have no file open. */
cf->state = FILE_CLOSED;
{
gchar *name_ptr;
size_t msg_len;
- gchar *done_fmt = " File: %s Drops: %u";
+ static const gchar done_fmt_nodrops[] = " File: %s";
+ static const gchar done_fmt_drops[] = " File: %s Drops: %u";
gchar *done_msg;
gchar *win_name_fmt = "%s - Ethereal";
gchar *win_name;
name_ptr = "<capture>";
}
- msg_len = strlen(name_ptr) + strlen(done_fmt) + 64;
- done_msg = g_malloc(msg_len);
- snprintf(done_msg, msg_len, done_fmt, name_ptr, cf->drops);
+ if (cf->drops_known) {
+ msg_len = strlen(name_ptr) + strlen(done_fmt_drops) + 64;
+ done_msg = g_malloc(msg_len);
+ snprintf(done_msg, msg_len, done_fmt_drops, name_ptr, cf->drops);
+ } else {
+ msg_len = strlen(name_ptr) + strlen(done_fmt_nodrops);
+ done_msg = g_malloc(msg_len);
+ snprintf(done_msg, msg_len, done_fmt_nodrops, name_ptr);
+ }
gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, done_msg);
g_free(done_msg);
progbar = create_progress_dlg(load_msg, "Stop", &stop_flag);
g_free(load_msg);
- while ((data_offset = wtap_read(cf->wth, err)) > 0) {
+ while ((wtap_read(cf->wth, err, &data_offset))) {
/* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
when we update it, we have to run the GTK+ main loop to get it
to repaint what's pending, and doing so may involve an "ioctl()"
if (cf->first_displayed != NULL)
gtk_signal_emit_by_name(GTK_OBJECT(packet_list), "select_row", 0);
- if (data_offset < 0) {
+ if (*err != 0) {
/* Put up a message box noting that the read failed somewhere along
the line. Don't throw out the stuff we managed to read, though,
if any. */
break;
default:
- sprintf(errmsg_errno, "An error occurred while reading the"
- " capture file: %s.", wtap_strerror(*err));
+ snprintf(errmsg_errno, sizeof(errmsg_errno),
+ "An error occurred while reading the"
+ " capture file: %s.", wtap_strerror(*err));
errmsg = errmsg_errno;
break;
}
snprintf(err_str, sizeof err_str, errmsg);
- simple_dialog(ESD_TYPE_WARN, NULL, err_str);
+ simple_dialog(ESD_TYPE_CRIT, NULL, err_str);
return (READ_ERROR);
} else
return (READ_SUCCESS);
gtk_clist_freeze(GTK_CLIST(packet_list));
- while (to_read != 0 && (data_offset = wtap_read(cf->wth, err)) > 0) {
+ while (to_read != 0 && (wtap_read(cf->wth, err, &data_offset))) {
if (cf->state == FILE_READ_ABORTED) {
/* Well, the user decided to exit Ethereal. Break out of the
loop, and let the code below (which is called even if there
"finish_tail_cap_file()" will be called, and it will clean up
and exit. */
return READ_ABORTED;
- } else if (data_offset < 0) {
+ } else if (*err != 0) {
/* We got an error reading the capture file.
XXX - pop up a dialog box? */
return (READ_ERROR);
gtk_clist_freeze(GTK_CLIST(packet_list));
- while ((data_offset = wtap_read(cf->wth, err)) > 0) {
+ while ((wtap_read(cf->wth, err, &data_offset))) {
if (cf->state == FILE_READ_ABORTED) {
/* Well, the user decided to abort the read. Break out of the
loop, and let the code below (which is called even if there
set_menus_for_capture_file(TRUE);
set_menus_for_unsaved_capture_file(!cf->user_saved);
- if (data_offset < 0) {
+ if (*err != 0) {
/* We got an error reading the capture file.
XXX - pop up a dialog box? */
return (READ_ERROR);
typedef struct {
color_filter_t *colorf;
- proto_tree *protocol_tree;
- const guint8 *pd;
- frame_data *fdata;
+ epan_dissect_t *edt;
} apply_color_filter_args;
/*
apply_color_filter_args *args = argp;
if (colorf->c_colorfilter != NULL && args->colorf == NULL) {
- if (dfilter_apply(colorf->c_colorfilter, args->protocol_tree, args->pd, args->fdata->cap_len))
+ if (dfilter_apply_edt(colorf->c_colorfilter, args->edt))
args->colorf = colorf;
}
}
apply_color_filter_args args;
gint i, row;
proto_tree *protocol_tree = NULL;
+ epan_dissect_t *edt;
+ GdkColor fg, bg;
/* We don't yet have a color filter to apply. */
args.colorf = NULL;
firstusec = fdata->abs_usecs;
}
- /* Get the time elapsed between the first packet and this packet. */
- cf->esec = fdata->abs_secs - firstsec;
- if (firstusec <= fdata->abs_usecs) {
- cf->eusec = fdata->abs_usecs - firstusec;
- } else {
- cf->eusec = (fdata->abs_usecs + 1000000) - firstusec;
- cf->esec--;
- }
-
fdata->cinfo = &cf->cinfo;
for (i = 0; i < fdata->cinfo->num_cols; i++) {
- fdata->cinfo->col_data[i][0] = '\0';
+ fdata->cinfo->col_buf[i][0] = '\0';
+ fdata->cinfo->col_data[i] = fdata->cinfo->col_buf[i];
}
/* If either
we have a list of color filters;
- we have plugins to apply;
-
allocate a protocol tree root node, so that we'll construct
a protocol tree against which a filter expression can be
evaluated. */
- if ((cf->dfcode != NULL && refilter) || filter_list != NULL
-#ifdef HAVE_PLUGINS
- || enabled_plugins_number > 0
-#endif
- )
+ if ((cf->dfcode != NULL && refilter) || filter_list != NULL)
protocol_tree = proto_tree_create_root();
/* Dissect the frame. */
- dissect_packet(pseudo_header, buf, fdata, protocol_tree);
+ edt = epan_dissect_new(pseudo_header, buf, fdata, protocol_tree);
/* If we have a display filter, apply it if we're refiltering, otherwise
leave the "passed_dfilter" flag alone.
if (cf->dfcode != NULL) {
if (refilter) {
if (cf->dfcode != NULL)
- fdata->flags.passed_dfilter = dfilter_apply(cf->dfcode, protocol_tree, buf, fdata->cap_len) ? 1 : 0;
+ fdata->flags.passed_dfilter = dfilter_apply_edt(cf->dfcode, edt) ? 1 : 0;
else
fdata->flags.passed_dfilter = 1;
}
the color filters. */
if (fdata->flags.passed_dfilter) {
if (filter_list != NULL) {
- args.protocol_tree = protocol_tree;
- args.pd = buf;
- args.fdata = fdata;
+ args.edt = edt;
g_slist_foreach(filter_list, apply_color_filter, &args);
}
}
if (protocol_tree != NULL)
proto_tree_free(protocol_tree);
+ epan_dissect_free(edt);
+
if (fdata->flags.passed_dfilter) {
/* This frame passed the display filter, so add it to the clist. */
}
/* Get the time elapsed between the first packet and this packet. */
- fdata->rel_secs = cf->esec;
- fdata->rel_usecs = cf->eusec;
+ compute_timestamp_diff(&fdata->rel_secs, &fdata->rel_usecs,
+ fdata->abs_secs, fdata->abs_usecs, firstsec, firstusec);
+
+ /* If it's greater than the current elapsed time, set the elapsed time
+ to it (we check for "greater than" so as not to be confused by
+ time moving backwards). */
+ if (cf->esec < fdata->rel_secs
+ || (cf->esec == fdata->rel_secs && cf->eusec < fdata->rel_usecs)) {
+ cf->esec = fdata->rel_secs;
+ cf->eusec = fdata->rel_usecs;
+ }
/* Get the time elapsed between the previous displayed packet and
this packet. */
- fdata->del_secs = fdata->abs_secs - prevsec;
- if (prevusec <= fdata->abs_usecs) {
- fdata->del_usecs = fdata->abs_usecs - prevusec;
- } else {
- fdata->del_usecs = (fdata->abs_usecs + 1000000) - prevusec;
- fdata->del_secs--;
- }
+ compute_timestamp_diff(&fdata->del_secs, &fdata->del_usecs,
+ fdata->abs_secs, fdata->abs_usecs, prevsec, prevusec);
prevsec = fdata->abs_secs;
prevusec = fdata->abs_usecs;
row = gtk_clist_append(GTK_CLIST(packet_list), fdata->cinfo->col_data);
gtk_clist_set_row_data(GTK_CLIST(packet_list), row, fdata);
- if (filter_list != NULL && (args.colorf != NULL)) {
- gtk_clist_set_background(GTK_CLIST(packet_list), row,
- &args.colorf->bg_color);
- gtk_clist_set_foreground(GTK_CLIST(packet_list), row,
- &args.colorf->fg_color);
+ if (fdata->flags.marked) {
+ color_t_to_gdkcolor(&bg, &prefs.gui_marked_bg);
+ color_t_to_gdkcolor(&fg, &prefs.gui_marked_fg);
+ } else if (filter_list != NULL && (args.colorf != NULL)) {
+ bg = args.colorf->bg_color;
+ fg = args.colorf->fg_color;
} else {
- gtk_clist_set_background(GTK_CLIST(packet_list), row, &WHITE);
- gtk_clist_set_foreground(GTK_CLIST(packet_list), row, &BLACK);
+ bg = WHITE;
+ fg = BLACK;
}
+ gtk_clist_set_background(GTK_CLIST(packet_list), row, &bg);
+ gtk_clist_set_foreground(GTK_CLIST(packet_list), row, &fg);
} else {
/* This frame didn't pass the display filter, so it's not being added
to the clist, and thus has no row. */
int passed;
proto_tree *protocol_tree;
frame_data *plist_end;
+ epan_dissect_t *edt;
/* Allocate the next list entry, and add it to the list. */
fdata = g_mem_chunk_alloc(cf->plist_chunk);
fdata->next = NULL;
fdata->prev = NULL;
fdata->pfd = NULL;
+ fdata->data_src = NULL;
fdata->pkt_len = phdr->len;
fdata->cap_len = phdr->caplen;
fdata->file_off = offset;
fdata->abs_usecs = phdr->ts.tv_usec;
fdata->flags.encoding = CHAR_ASCII;
fdata->flags.visited = 0;
+ fdata->flags.marked = 0;
fdata->cinfo = NULL;
passed = TRUE;
if (cf->rfcode) {
protocol_tree = proto_tree_create_root();
- dissect_packet(pseudo_header, buf, fdata, protocol_tree);
- passed = dfilter_apply(cf->rfcode, protocol_tree, buf, fdata->cap_len);
+ edt = epan_dissect_new(pseudo_header, buf, fdata, protocol_tree);
+ passed = dfilter_apply_edt(cf->rfcode, edt);
proto_tree_free(protocol_tree);
+ epan_dissect_free(edt);
}
if (passed) {
plist_end = cf->plist_end;
int
filter_packets(capture_file *cf, gchar *dftext)
{
- dfilter *dfcode;
+ dfilter_t *dfcode;
if (dftext == NULL) {
/* The new filter is an empty filter (i.e., display all packets). */
/*
* We have a filter; try to compile it.
*/
- if (dfilter_compile(dftext, &dfcode) != 0) {
+ if (!dfilter_compile(dftext, &dfcode)) {
/* The attempt failed; report an error. */
- simple_dialog(ESD_TYPE_WARN, NULL, dfilter_error_msg);
+ simple_dialog(ESD_TYPE_CRIT, NULL, dfilter_error_msg);
return 0;
}
g_free(cf->dfilter);
cf->dfilter = dftext;
if (cf->dfcode != NULL)
- dfilter_destroy(cf->dfcode);
+ dfilter_free(cf->dfcode);
cf->dfcode = dfcode;
- /* Now rescan the packet list, applying the new filter. */
- rescan_packets(cf, "Filtering", TRUE);
+ /* Now rescan the packet list, applying the new filter, but not
+ throwing away information constructed on a previous pass. */
+ rescan_packets(cf, "Filtering", TRUE, FALSE);
return 1;
}
void
colorize_packets(capture_file *cf)
{
- rescan_packets(cf, "Colorizing", FALSE);
+ rescan_packets(cf, "Colorizing", FALSE, FALSE);
}
void
redissect_packets(capture_file *cf)
{
- rescan_packets(cf, "Reprocessing", TRUE);
+ rescan_packets(cf, "Reprocessing", TRUE, TRUE);
}
/* Rescan the list of packets, reconstructing the CList.
"action" describes why we're doing this; it's used in the progress
dialog box.
- "refilter" is TRUE if we need to re-evaluate the filter expression. */
+ "refilter" is TRUE if we need to re-evaluate the filter expression.
+
+ "redissect" is TRUE if we need to make the dissectors reconstruct
+ any state information they have (because a preference that affects
+ some dissector has changed, meaning some dissector might construct
+ its state differently from the way it was constructed the last time). */
static void
-rescan_packets(capture_file *cf, const char *action, gboolean refilter)
+rescan_packets(capture_file *cf, const char *action, gboolean refilter,
+ gboolean redissect)
{
frame_data *fdata;
progdlg_t *progbar;
rebuild the clist, however. */
selected_row = -1;
- /* We need to re-initialize all the state information that protocols
- keep, because we're making a fresh pass through all the packets. */
+ if (redissect) {
+ /* We need to re-initialize all the state information that protocols
+ keep, because some preference that controls a dissector has changed,
+ which might cause the state information to be constructed differently
+ by that dissector. */
- /* Initialize the table of conversations. */
- conversation_init();
+ /* Initialize the table of conversations. */
+ epan_conversation_init();
- /* Initialize protocol-specific variables */
- init_all_protocols();
+ /* Initialize protocol-specific variables */
+ init_all_protocols();
+ }
/* Freeze the packet list while we redo it, so we don't get any
screen updates while it happens. */
count++;
+ if (redissect) {
+ /* Since all state for the frame was destroyed, mark the frame
+ * as not visited, free the GSList referring to the state
+ * data (the per-frame data itself was freed by
+ * "init_all_protocols()"), and null out the GSList pointer. */
+ fdata->flags.visited = 0;
+ if (fdata->pfd) {
+ g_slist_free(fdata->pfd);
+ }
+ fdata->pfd = NULL;
+ if (fdata->data_src) { /* release data source list */
+ g_slist_free(fdata->data_src);
+ }
+ fdata->data_src = NULL;
+ }
+
wtap_seek_read (cf->wth, fdata->file_off, &cf->pseudo_header,
cf->pd, fdata->cap_len);
selected_row = row;
}
+ if (redissect) {
+ /* Clear out what remains of the visited flags and per-frame data
+ pointers.
+
+ XXX - that may cause various forms of bogosity when dissecting
+ these frames, as they won't have been seen by this sequential
+ pass, but the only alternative I see is to keep scanning them
+ even though the user requested that the scan stop, and that
+ would leave the user stuck with an Ethereal grinding on
+ until it finishes. Should we just stick them with that? */
+ for (; fdata != NULL; fdata = fdata->next) {
+ fdata->flags.visited = 0;
+ if (fdata->pfd) {
+ g_slist_free(fdata->pfd);
+ }
+ fdata->pfd = NULL;
+ if (fdata->data_src) {
+ g_slist_free(fdata->data_src);
+ }
+ fdata->data_src = NULL;
+ }
+ }
+
/* We're done filtering the packets; destroy the progress bar. */
destroy_progress_dlg(progbar);
char *cp;
int column_len;
int line_len;
+ epan_dissect_t *edt = NULL;
cf->print_fh = open_print_dest(print_args->to_file, print_args->dest);
if (cf->print_fh == NULL)
the logical protocol tree. */
fdata->cinfo = &cf->cinfo;
for (i = 0; i < fdata->cinfo->num_cols; i++) {
- fdata->cinfo->col_data[i][0] = '\0';
+ fdata->cinfo->col_buf[i][0] = '\0';
+ fdata->cinfo->col_data[i] = fdata->cinfo->col_buf[i];
}
- dissect_packet(&cf->pseudo_header, cf->pd, fdata, NULL);
+ edt = epan_dissect_new(&cf->pseudo_header, cf->pd, fdata, NULL);
fill_in_columns(fdata);
cp = &line_buf[0];
line_len = 0;
/* Create the logical protocol tree. */
protocol_tree = proto_tree_create_root();
- dissect_packet(&cf->pseudo_header, cf->pd, fdata, protocol_tree);
+ edt = epan_dissect_new(&cf->pseudo_header, cf->pd, fdata, protocol_tree);
/* Print the information in that tree. */
proto_tree_print(FALSE, print_args, (GNode *)protocol_tree,
if (print_args->print_hex) {
/* Print the full packet data as hex. */
- print_hex_data(cf->print_fh, print_args->format, cf->pd,
- fdata->cap_len, fdata->flags.encoding);
+ print_hex_data(cf->print_fh, print_args->format, fdata);
}
/* Print a blank line if we print anything after this. */
print_separator = TRUE;
}
+ epan_dissect_free(edt);
}
}
if (cf->cinfo.fmt_matx[i][COL_CLS_TIME]) {
/* This is one of the columns that shows the time in
"command-line-specified" format; update it. */
- cf->cinfo.col_data[i][0] = '\0';
+ cf->cinfo.col_buf[i][0] = '\0';
col_set_cls_time(fdata, i);
gtk_clist_set_text(GTK_CLIST(packet_list), row, i,
cf->cinfo.col_data[i]);
clear_tree_and_hex_views(void)
{
/* Clear the hex dump. */
- gtk_text_freeze(GTK_TEXT(byte_view));
- gtk_text_set_point(GTK_TEXT(byte_view), 0);
- gtk_text_forward_delete(GTK_TEXT(byte_view),
- gtk_text_get_length(GTK_TEXT(byte_view)));
- gtk_text_thaw(GTK_TEXT(byte_view));
+ GtkWidget *byte_view;
+ int i;
+
+/* Get the current tab scroll window, then get the text widget */
+/* from the E_BYTE_VIEW_TEXT_INFO_KEY data field */
+
+ i = gtk_notebook_get_current_page( GTK_NOTEBOOK(byte_nb_ptr));
+
+ if ( i >= 0){
+ byte_view = gtk_notebook_get_nth_page( GTK_NOTEBOOK(byte_nb_ptr), i);
+ byte_view = gtk_object_get_data(GTK_OBJECT(byte_view), E_BYTE_VIEW_TEXT_INFO_KEY);
+
+ gtk_text_freeze(GTK_TEXT(byte_view));
+ gtk_text_set_point(GTK_TEXT(byte_view), 0);
+ gtk_text_forward_delete(GTK_TEXT(byte_view),
+ gtk_text_get_length(GTK_TEXT(byte_view)));
+ gtk_text_thaw(GTK_TEXT(byte_view));
+ }
/* Remove all nodes in ctree. This is how it's done in testgtk.c in GTK+ */
gtk_clist_clear ( GTK_CLIST(tree_view) );
}
gboolean
-find_packet(capture_file *cf, dfilter *sfcode)
+find_packet(capture_file *cf, dfilter_t *sfcode)
{
frame_data *start_fd;
frame_data *fdata;
proto_tree *protocol_tree;
gboolean frame_matched;
int row;
+ epan_dissect_t *edt;
start_fd = cf->current_frame;
if (start_fd != NULL) {
protocol_tree = proto_tree_create_root();
wtap_seek_read(cf->wth, fdata->file_off, &cf->pseudo_header,
cf->pd, fdata->cap_len);
- dissect_packet(&cf->pseudo_header, cf->pd, fdata, protocol_tree);
- frame_matched = dfilter_apply(sfcode, protocol_tree, cf->pd, fdata->cap_len);
+ edt = epan_dissect_new(&cf->pseudo_header, cf->pd, fdata, protocol_tree);
+ frame_matched = dfilter_apply_edt(sfcode, edt);
proto_tree_free(protocol_tree);
+ epan_dissect_free(edt);
if (frame_matched) {
new_fd = fdata;
break; /* found it! */
select_packet(capture_file *cf, int row)
{
frame_data *fdata;
+ tvbuff_t *bv_tvb;
+ int i;
/* Get the frame data struct pointer for this frame */
fdata = (frame_data *) gtk_clist_get_row_data(GTK_CLIST(packet_list), row);
proto_tree_free(cf->protocol_tree);
cf->protocol_tree = proto_tree_create_root();
proto_tree_is_visible = TRUE;
- dissect_packet(&cf->pseudo_header, cf->pd, cf->current_frame,
+ cf->edt = epan_dissect_new(&cf->pseudo_header, cf->pd, cf->current_frame,
cf->protocol_tree);
proto_tree_is_visible = FALSE;
/* Display the GUI protocol tree and hex dump. */
clear_tree_and_hex_views();
+
+ i = 0;
+ while((bv_tvb = g_slist_nth_data ( cf->current_frame->data_src, i++))){
+ add_byte_view( tvb_get_name( bv_tvb), tvb_get_ptr(bv_tvb, 0, -1), tvb_length(bv_tvb));
+ }
+
proto_tree_draw(cf->protocol_tree, tree_view);
- packet_hex_print(GTK_TEXT(byte_view), cf->pd, cf->current_frame->cap_len,
- -1, -1, cf->current_frame->flags.encoding);
+
+ set_notebook_page( byte_nb_ptr, 0);
/* A packet is selected. */
set_menus_for_selected_packet(TRUE);
if (cf->protocol_tree != NULL) {
proto_tree_free(cf->protocol_tree);
cf->protocol_tree = NULL;
+ epan_dissect_free(cf->edt);
}
finfo_selected = NULL;
}
int
-save_cap_file(char *fname, capture_file *cf, gboolean save_filtered,
+save_cap_file(char *fname, capture_file *cf, gboolean save_filtered, gboolean save_marked,
guint save_format)
{
gchar *from_filename;
size_t msg_len;
int err;
gboolean do_copy;
- int from_fd, to_fd, nread, nwritten;
wtap_dumper *pdh;
frame_data *fdata;
struct wtap_pkthdr hdr;
gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, save_msg);
g_free(save_msg);
- if (!save_filtered && save_format == cf->cd_t) {
+ if (!save_filtered && !save_marked && save_format == cf->cd_t) {
/* We're not filtering packets, and we're saving it in the format
it's already in, so we can just move or copy the raw data. */
the temporary directory, and that might be fixable - but
is it worth requiring the user to go off and fix it?) */
err = errno;
- simple_dialog(ESD_TYPE_WARN, NULL,
+ simple_dialog(ESD_TYPE_CRIT, NULL,
file_rename_error_message(err), fname);
goto done;
}
}
/* Copy the file, if we haven't moved it. */
if (do_copy) {
- /* Copy the raw bytes of the file. */
- from_fd = open(from_filename, O_RDONLY | O_BINARY);
- if (from_fd < 0) {
- err = errno;
- simple_dialog(ESD_TYPE_WARN, NULL,
- file_open_error_message(err, TRUE), from_filename);
- goto done;
- }
-
- /* Use open() instead of creat() so that we can pass the O_BINARY
- flag, which is relevant on Win32; it appears that "creat()"
- may open the file in text mode, not binary mode, but we want
- to copy the raw bytes of the file, so we need the output file
- to be open in binary mode. */
- to_fd = open(fname, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
- if (to_fd < 0) {
- err = errno;
- simple_dialog(ESD_TYPE_WARN, NULL,
- file_open_error_message(err, TRUE), fname);
- close(from_fd);
- goto done;
- }
-
- while ((nread = read(from_fd, pd, sizeof pd)) > 0) {
- nwritten = write(to_fd, pd, nread);
- if (nwritten < nread) {
- if (nwritten < 0)
- err = errno;
- else
- err = WTAP_ERR_SHORT_WRITE;
- simple_dialog(ESD_TYPE_WARN, NULL,
- file_write_error_message(err), fname);
- close(from_fd);
- close(to_fd);
- goto done;
- }
- }
- if (nread < 0) {
- err = errno;
- simple_dialog(ESD_TYPE_WARN, NULL,
- file_read_error_message(err), from_filename);
- close(from_fd);
- close(to_fd);
- goto done;
- }
- close(from_fd);
- if (close(to_fd) < 0) {
- err = errno;
- simple_dialog(ESD_TYPE_WARN, NULL,
- file_close_error_message(err), fname);
- goto done;
- }
+ if (!copy_binary_file(from_filename, fname)) {
+ goto done;
+ }
}
} else {
/* Either we're filtering packets, or we're saving in a different
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);
if (pdh == NULL) {
- simple_dialog(ESD_TYPE_WARN, NULL,
+ simple_dialog(ESD_TYPE_CRIT, NULL,
file_open_error_message(err, TRUE), fname);
goto done;
}
/* XXX - have a way to save only the packets currently selected by
- the display filter.
+ the display filter or the marked ones.
If we do that, should we make that file the current file? If so,
it means we can no longer get at the other packets. What does
NetMon do? */
for (fdata = cf->plist; fdata != NULL; fdata = fdata->next) {
/* XXX - do a progress bar */
- if (!save_filtered || fdata->flags.passed_dfilter) {
- /* Either we're saving all frames, or we're saving filtered frames
- and this one passed the display filter - save it. */
+ if ((!save_filtered && !save_marked) ||
+ (save_filtered && fdata->flags.passed_dfilter && !save_marked) ||
+ (save_marked && fdata->flags.marked && !save_filtered) ||
+ (save_filtered && save_marked && fdata->flags.passed_dfilter &&
+ fdata->flags.marked)) {
+ /* Either :
+ - we're saving all frames, or
+ - we're saving filtered frames and this one passed the display filter or
+ - we're saving marked frames (and it has been marked) or
+ - we're saving filtered _and_ marked frames,
+ save it. */
hdr.ts.tv_sec = fdata->abs_secs;
hdr.ts.tv_usec = fdata->abs_usecs;
hdr.caplen = fdata->cap_len;
pd, fdata->cap_len);
if (!wtap_dump(pdh, &hdr, &pseudo_header, pd, &err)) {
- simple_dialog(ESD_TYPE_WARN, NULL,
+ simple_dialog(ESD_TYPE_CRIT, NULL,
file_write_error_message(err), fname);
wtap_dump_close(pdh, &err);
goto done;
/* Pop the "Saving:" message off the status bar. */
gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
if (err == 0) {
- if (!save_filtered) {
+ if (!save_filtered && !save_marked) {
/* We saved the entire capture, not just some packets from it.
Open and read the file we saved it to.
}
char *
-file_open_error_message(int err, int for_writing)
+file_open_error_message(int err, gboolean for_writing)
{
char *errmsg;
static char errmsg_errno[1024+1];
switch (err) {
case WTAP_ERR_NOT_REGULAR_FILE:
- errmsg = "The file \"%s\" is invalid.";
+ errmsg = "The file \"%s\" is a \"special file\" or socket or other non-regular file.";
break;
case WTAP_ERR_FILE_UNKNOWN_FORMAT:
errmsg = "You do not have permission to read the file \"%s\".";
break;
+ case EISDIR:
+ errmsg = "\"%s\" is a directory (folder), not a file.";
+ break;
+
default:
- sprintf(errmsg_errno, "The file \"%%s\" could not be opened: %s.",
+ snprintf(errmsg_errno, sizeof(errmsg_errno),
+ "The file \"%%s\" could not be opened: %s.",
wtap_strerror(err));
errmsg = errmsg_errno;
break;
break;
default:
- sprintf(errmsg_errno, "The file \"%%s\" could not be moved: %s.",
+ snprintf(errmsg_errno, sizeof(errmsg_errno),
+ "The file \"%%s\" could not be moved: %s.",
wtap_strerror(err));
errmsg = errmsg_errno;
break;
{
static char errmsg_errno[1024+1];
- sprintf(errmsg_errno, "An error occurred while reading from the file \"%%s\": %s.",
+ snprintf(errmsg_errno, sizeof(errmsg_errno),
+ "An error occurred while reading from the file \"%%s\": %s.",
wtap_strerror(err));
return errmsg_errno;
}
#endif
default:
- sprintf(errmsg_errno, "An error occurred while writing to the file \"%%s\": %s.",
+ snprintf(errmsg_errno, sizeof(errmsg_errno),
+ "An error occurred while writing to the file \"%%s\": %s.",
wtap_strerror(err));
errmsg = errmsg_errno;
break;
break;
case WTAP_ERR_SHORT_WRITE:
- errmsg = "Not all the data could be written to the file \"%s\".";
+ errmsg = "Not all the packets could be written to the file \"%s\".";
break;
case ENOSPC:
#endif
default:
- sprintf(errmsg_errno, "An error occurred while closing the file \"%%s\": %s.",
+ snprintf(errmsg_errno, sizeof(errmsg_errno),
+ "An error occurred while closing the file \"%%s\": %s.",
wtap_strerror(err));
errmsg = errmsg_errno;
break;
}
return errmsg;
}
+
+
+/* Copies a file in binary mode, for those operating systems that care about
+ * such things.
+ * Returns TRUE on success, FALSE on failure. If a failure, it also
+ * displays a simple dialog window with the error message.
+ */
+static gboolean
+copy_binary_file(char *from_filename, char *to_filename)
+{
+ int from_fd, to_fd, nread, nwritten, err;
+ guint8 pd[65536]; /* XXX - Hmm, 64K here, 64K in save_cap_file(),
+ perhaps we should make just one 64K buffer. */
+
+ /* Copy the raw bytes of the file. */
+ from_fd = open(from_filename, O_RDONLY | O_BINARY);
+ if (from_fd < 0) {
+ err = errno;
+ simple_dialog(ESD_TYPE_CRIT, NULL,
+ file_open_error_message(err, TRUE), from_filename);
+ goto done;
+ }
+
+ /* Use open() instead of creat() so that we can pass the O_BINARY
+ flag, which is relevant on Win32; it appears that "creat()"
+ may open the file in text mode, not binary mode, but we want
+ to copy the raw bytes of the file, so we need the output file
+ to be open in binary mode. */
+ to_fd = open(to_filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
+ if (to_fd < 0) {
+ err = errno;
+ simple_dialog(ESD_TYPE_CRIT, NULL,
+ file_open_error_message(err, TRUE), to_filename);
+ close(from_fd);
+ goto done;
+ }
+
+ while ((nread = read(from_fd, pd, sizeof pd)) > 0) {
+ nwritten = write(to_fd, pd, nread);
+ if (nwritten < nread) {
+ if (nwritten < 0)
+ err = errno;
+ else
+ err = WTAP_ERR_SHORT_WRITE;
+ simple_dialog(ESD_TYPE_CRIT, NULL,
+ file_write_error_message(err), to_filename);
+ close(from_fd);
+ close(to_fd);
+ goto done;
+ }
+ }
+ if (nread < 0) {
+ err = errno;
+ simple_dialog(ESD_TYPE_CRIT, NULL,
+ file_read_error_message(err), from_filename);
+ close(from_fd);
+ close(to_fd);
+ goto done;
+ }
+ close(from_fd);
+ if (close(to_fd) < 0) {
+ err = errno;
+ simple_dialog(ESD_TYPE_CRIT, NULL,
+ file_close_error_message(err), to_filename);
+ goto done;
+ }
+
+ return TRUE;
+
+ done:
+ return FALSE;
+}