/* file.c
* File I/O routines
*
- * $Id: file.c,v 1.340 2004/01/10 17:29:26 ulfl Exp $
+ * $Id$
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+/* With MSVC and a libethereal.dll this file needs to import some variables
+ in a special way. Therefore _NEED_VAR_IMPORT_ is defined. */
+#define _NEED_VAR_IMPORT_
+
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <epan/filesystem.h>
#include "color.h"
-#include "column.h"
+#include "color_filters.h"
+#include <epan/column.h>
#include <epan/packet.h>
-#include "range.h"
+#include "packet-range.h"
#include "print.h"
#include "file.h"
#include "menu.h"
#include "util.h"
+#include "merge.h"
+#include "alert_box.h"
#include "simple_dialog.h"
#include "progress_dlg.h"
#include "ui_util.h"
#include "statusbar.h"
-#include "prefs.h"
+#include <epan/prefs.h>
#include <epan/dfilter/dfilter.h>
#include <epan/conversation.h>
#include "globals.h"
#include <epan/epan_dissect.h>
-#include "tap.h"
+#include <epan/tap.h>
#include "tap_dfilter_dlg.h"
-#include "packet-data.h"
+#include <epan/dissectors/packet-data.h>
+
+/* Win32 needs the O_BINARY flag for open() */
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
#ifdef HAVE_LIBPCAP
gboolean auto_scroll_live;
static guint32 firstsec, firstusec;
static guint32 prevsec, prevusec;
-static guint32 cul_bytes = 0;
+static guint32 cum_bytes = 0;
static void read_packet(capture_file *cf, long offset);
gboolean (*match_function)(capture_file *, frame_data *, void *),
void *criterion);
+static void cf_open_failure_alert_box(const char *filename, int err,
+ gchar *err_info, gboolean for_writing,
+ int file_type);
static char *file_rename_error_message(int err);
-static char *file_close_error_message(int err);
+static void cf_write_failure_alert_box(const char *filename, int err);
+static void cf_close_failure_alert_box(const char *filename, 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 FRAME_DATA_CHUNK_SIZE 1024
-typedef struct {
- int level;
- FILE *fh;
- GSList *src_list;
- gboolean print_all_levels;
- gboolean print_hex_for_data;
- char_enc encoding;
- gint format; /* text or PostScript */
-} print_data;
-
-
int
cf_open(char *fname, gboolean is_tempfile, capture_file *cf)
{
wtap *wth;
int err;
+ gchar *err_info;
int fd;
struct stat cf_stat;
- wth = wtap_open_offline(fname, &err, TRUE);
+ wth = wtap_open_offline(fname, &err, &err_info, TRUE);
if (wth == NULL)
goto fail;
cf->cd_t = wtap_file_type(cf->wth);
cf->count = 0;
+ cf->displayed_count = 0;
cf->marked_count = 0;
cf->drops_known = FALSE;
cf->drops = 0;
return (0);
fail:
- simple_dialog(ESD_TYPE_CRIT, NULL,
- file_open_error_message(err, FALSE, 0), fname);
+ cf_open_failure_alert_box(fname, err, err_info, FALSE, 0);
return (err);
}
packet_list_clear();
packet_list_thaw();
+ cf->f_len = 0;
+ cf->count = 0;
+ cf->esec = 0;
+ cf->eusec = 0;
+
/* Clear any file-related status bar messages.
XXX - should be "clear *ALL* file-related status bar messages;
will there ever be more than one on the stack? */
set_menus_for_capture_in_progress(FALSE);
set_menus_for_selected_tree_row(cf);
+ reset_tap_listeners();
+
/* We have no file open. */
cf->state = FILE_CLOSED;
}
{
gchar *name_ptr;
size_t msg_len;
- static const gchar done_fmt_nodrops[] = " File: %s";
- static const gchar done_fmt_drops[] = " File: %s Drops: %u";
+ static const gchar done_fmt_nodrops[] = " File: %s %s %02u:%02u:%02u";
+ static const gchar done_fmt_drops[] = " File: %s %s %02u:%02u:%02u Drops: %u";
gchar *done_msg;
gchar *win_name_fmt = "%s - Ethereal";
gchar *win_name;
+ gchar *size_str;
name_ptr = cf_get_display_name(cf);
add_menu_recent_capture_file(cf->filename);
}
+ if (cf->f_len/1024/1024 > 10) {
+ size_str = g_strdup_printf("%ld MB", cf->f_len/1024/1024);
+ } else if (cf->f_len/1024 > 10) {
+ size_str = g_strdup_printf("%ld KB", cf->f_len/1024);
+ } else {
+ size_str = g_strdup_printf("%ld bytes", cf->f_len);
+ }
+
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);
+ done_msg = g_strdup_printf(done_fmt_drops, name_ptr, size_str,
+ cf->esec/3600, cf->esec%3600/60, cf->esec%60, 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);
+ done_msg = g_strdup_printf(done_fmt_nodrops, name_ptr, size_str,
+ cf->esec/3600, cf->esec%3600/60, cf->esec%60);
}
statusbar_push_file_msg(done_msg);
g_free(done_msg);
}
read_status_t
-cf_read(capture_file *cf, int *err)
+cf_read(capture_file *cf)
{
+ int err;
+ gchar *err_info;
gchar *name_ptr, *load_msg, *load_fmt = "%s";
- size_t msg_len;
char *errmsg;
char errmsg_errno[1024+1];
gchar err_str[2048+1];
int progbar_nextstep;
int progbar_quantum;
- cul_bytes=0;
+ cum_bytes=0;
reset_tap_listeners();
tap_dfilter_dlg_update();
name_ptr = get_basename(cf->filename);
- msg_len = strlen(name_ptr) + strlen(load_fmt) + 2;
- load_msg = g_malloc(msg_len);
- snprintf(load_msg, msg_len, load_fmt, name_ptr);
+ load_msg = g_strdup_printf(" Loading: %s", name_ptr);
statusbar_push_file_msg(load_msg);
+ g_free(load_msg);
+
+ load_msg = g_strdup_printf(load_fmt, name_ptr);
/* Update the progress bar when it gets to this value. */
progbar_nextstep = 0;
bump that value by this amount. */
progbar_quantum = cf->f_len/N_PROGBAR_UPDATES;
-#ifndef O_BINARY
-#define O_BINARY 0
-#endif
-
packet_list_freeze();
stop_flag = FALSE;
g_get_current_time(&start_time);
- while ((wtap_read(cf->wth, err, &data_offset))) {
+ while ((wtap_read(cf->wth, &err, &err_info, &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 (progbar == NULL) {
/* Create the progress bar if necessary */
- progbar = delayed_create_progress_dlg("Loading", load_msg, "Stop",
+ progbar = delayed_create_progress_dlg("Loading", load_msg,
&stop_flag, &start_time, prog_val);
if (progbar != NULL)
g_free(load_msg);
if (cf->first_displayed != NULL)
packet_list_select_row(0);
- if (*err != 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. */
- switch (*err) {
+ switch (err) {
case WTAP_ERR_UNSUPPORTED_ENCAP:
- errmsg = "The capture file is for a network type that Ethereal doesn't support.";
+ snprintf(errmsg_errno, sizeof(errmsg_errno),
+ "The capture file has a packet with a network type that Ethereal doesn't support.\n(%s)",
+ err_info);
+ g_free(err_info);
+ errmsg = errmsg_errno;
break;
case WTAP_ERR_CANT_READ:
- errmsg = "An attempt to read from the file failed for"
+ errmsg = "An attempt to read from the capture file failed for"
" some unknown reason.";
break;
break;
case WTAP_ERR_BAD_RECORD:
- errmsg = "The capture file appears to be damaged or corrupt.";
+ snprintf(errmsg_errno, sizeof(errmsg_errno),
+ "The capture file appears to be damaged or corrupt.\n(%s)",
+ err_info);
+ g_free(err_info);
+ errmsg = errmsg_errno;
break;
default:
snprintf(errmsg_errno, sizeof(errmsg_errno),
"An error occurred while reading the"
- " capture file: %s.", wtap_strerror(*err));
+ " capture file: %s.", wtap_strerror(err));
errmsg = errmsg_errno;
break;
}
snprintf(err_str, sizeof err_str, errmsg);
- simple_dialog(ESD_TYPE_CRIT, NULL, err_str);
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, err_str);
return (READ_ERROR);
} else
return (READ_SUCCESS);
cf_start_tail(char *fname, gboolean is_tempfile, capture_file *cf)
{
int err;
+ gchar *capture_msg;
err = cf_open(fname, is_tempfile, cf);
if (err == 0) {
packets (yes, I know, we don't have any *yet*). */
set_menus_for_captured_packets(TRUE);
- statusbar_push_file_msg(" <live capture in progress>");
+ capture_msg = g_strdup_printf(" %s: <live capture in progress>", cf->iface);
+
+ statusbar_push_file_msg(capture_msg);
+
+ g_free(capture_msg);
}
return err;
}
cf_continue_tail(capture_file *cf, int to_read, int *err)
{
long data_offset = 0;
+ gchar *err_info;
*err = 0;
packet_list_freeze();
- while (to_read != 0 && (wtap_read(cf->wth, err, &data_offset))) {
+ while (to_read != 0 && (wtap_read(cf->wth, err, &err_info, &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
read_status_t
cf_finish_tail(capture_file *cf, int *err)
{
+ gchar *err_info;
long data_offset;
+ int fd;
+ struct stat cf_stat;
packet_list_freeze();
- while ((wtap_read(cf->wth, err, &data_offset))) {
+ while ((wtap_read(cf->wth, err, &err_info, &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
/* We're done reading sequentially through the file. */
cf->state = FILE_READ_DONE;
+ /* we have to update the f_len field */
+ /* Find the size of the file. */
+ fd = wtap_fd(cf->wth);
+ if (fstat(fd, &cf_stat) >= 0) {
+ cf->f_len = cf_stat.st_size;
+ }
+
/* We're done reading sequentially through the file; close the
sequential I/O side, to free up memory it requires. */
wtap_sequential_close(cf->wth);
/* We got an error reading the capture file.
XXX - pop up a dialog box? */
return (READ_ERROR);
- } else
+ } else {
return (READ_SUCCESS);
+ }
}
#endif /* HAVE_LIBPCAP */
/* Add this filename to the list of recent files in the "Recent Files" submenu */
add_menu_recent_capture_file(cf->filename);
} else {
- displayname="<no file>";
+ displayname="(No file)";
}
} else {
/* The file we read is a temporary file from a live capture;
we don't mention its name. */
- displayname = "<capture>";
+ displayname = "(Untitled)";
}
return displayname;
}
epan_dissect_t *edt;
/* just add some value here until we know if it is being displayed or not */
- fdata->cul_bytes = cul_bytes + fdata->pkt_len;
+ fdata->cum_bytes = cum_bytes + fdata->pkt_len;
/* We don't yet have a color filter to apply. */
args.colorf = NULL;
even if they dont pass the display filter */
/* if this was a TIME REF frame we should reset the cul bytes field */
if(edt->pi.fd->flags.ref_time){
- cul_bytes = fdata->pkt_len;
- fdata->cul_bytes = cul_bytes;
+ cum_bytes = fdata->pkt_len;
+ fdata->cum_bytes = cum_bytes;
}
- /* increase cul_bytes with this packets length */
- cul_bytes += fdata->pkt_len;
+ /* increase cum_bytes with this packets length */
+ cum_bytes += fdata->pkt_len;
epan_dissect_fill_in_columns(edt);
frame. */
prevsec = fdata->abs_secs;
prevusec = fdata->abs_usecs;
+
+ cf->displayed_count++;
} else {
/* This frame didn't pass the display filter, so it's not being added
to the clist, and thus has no row. */
}
}
-int
-filter_packets(capture_file *cf, gchar *dftext)
+gboolean
+cf_merge_files(const char *out_filename, int out_fd, int in_file_count,
+ char *const *in_filenames, int file_type, gboolean do_append)
+{
+ merge_in_file_t *in_files;
+ wtap *wth;
+ wtap_dumper *pdh;
+ int open_err, read_err, write_err, close_err;
+ gchar *err_info;
+ int err_fileno;
+ int i;
+ char errmsg_errno[1024+1];
+ gchar err_str[2048+1];
+ char *errmsg;
+ gboolean got_read_error = FALSE, got_write_error = FALSE;
+ long data_offset;
+ progdlg_t *progbar = NULL;
+ gboolean stop_flag;
+ /*
+ * XXX - should be "off_t", but Wiretap would need more work to handle
+ * the full size of "off_t" on platforms where it's more than a "long"
+ * as well.
+ */
+ long f_len, file_pos;
+ float prog_val;
+ GTimeVal start_time;
+ gchar status_str[100];
+ int progbar_nextstep;
+ int progbar_quantum;
+
+ /* open the input files */
+ if (!merge_open_in_files(in_file_count, in_filenames, &in_files,
+ &open_err, &err_info, &err_fileno)) {
+ free(in_files);
+ cf_open_failure_alert_box(in_filenames[err_fileno], open_err, err_info,
+ FALSE, 0);
+ return FALSE;
+ }
+
+ 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);
+ if (pdh == NULL) {
+ merge_close_in_files(in_file_count, in_files);
+ free(in_files);
+ cf_open_failure_alert_box(out_filename, open_err, err_info, TRUE,
+ file_type);
+ return FALSE;
+ }
+
+ /* Get the sum of the sizes of all the files. */
+ f_len = 0;
+ for (i = 0; i < in_file_count; i++)
+ f_len += in_files[i].size;
+
+ /* Update the progress bar when it gets to this value. */
+ progbar_nextstep = 0;
+ /* When we reach the value that triggers a progress bar update,
+ bump that value by this amount. */
+ progbar_quantum = f_len/N_PROGBAR_UPDATES;
+
+ stop_flag = FALSE;
+ g_get_current_time(&start_time);
+
+ /* do the merge (or append) */
+ for (;;) {
+ if (do_append)
+ wth = merge_append_read_packet(in_file_count, in_files, &read_err,
+ &err_info);
+ else
+ wth = merge_read_packet(in_file_count, in_files, &read_err,
+ &err_info);
+ if (wth == NULL) {
+ if (read_err != 0)
+ got_read_error = TRUE;
+ break;
+ }
+
+ /* Get the sum of the data offsets in all of the files. */
+ data_offset = 0;
+ for (i = 0; i < in_file_count; i++)
+ data_offset += in_files[i].data_offset;
+
+ if (data_offset >= progbar_nextstep) {
+ /* Get the sum of the seek positions in all of the files. */
+ file_pos = 0;
+ for (i = 0; i < in_file_count; i++)
+ file_pos += lseek(wtap_fd(in_files[i].wth), 0, SEEK_CUR);
+ prog_val = (gfloat) file_pos / (gfloat) f_len;
+ if (prog_val > 1.0) {
+ /* Some file probably grew while we were reading it.
+ That "shouldn't happen", so we'll just clip the progress
+ value at 1.0. */
+ prog_val = 1.0;
+ }
+ if (progbar == NULL) {
+ /* Create the progress bar if necessary */
+ progbar = delayed_create_progress_dlg("Merging", "files",
+ &stop_flag, &start_time, prog_val);
+ }
+ if (progbar != NULL) {
+ g_snprintf(status_str, sizeof(status_str),
+ "%luKB of %luKB", file_pos / 1024, f_len / 1024);
+ update_progress_dlg(progbar, prog_val, status_str);
+ }
+ progbar_nextstep += progbar_quantum;
+ }
+
+ if (!wtap_dump(pdh, wtap_phdr(wth), wtap_pseudoheader(wth),
+ wtap_buf_ptr(wth), &write_err)) {
+ got_write_error = TRUE;
+ break;
+ }
+ }
+
+ /* We're done merging the files; destroy the progress bar if it was created. */
+ if (progbar != NULL)
+ destroy_progress_dlg(progbar);
+
+ merge_close_in_files(in_file_count, in_files);
+ if (!got_read_error && !got_write_error) {
+ if (!wtap_dump_close(pdh, &write_err))
+ got_write_error = TRUE;
+ } else
+ wtap_dump_close(pdh, &close_err);
+
+ if (got_read_error) {
+ /*
+ * Find the file on which we got the error, and report the error.
+ */
+ for (i = 0; i < in_file_count; i++) {
+ if (in_files[i].state == GOT_ERROR) {
+ /* Put up a message box noting that a read failed somewhere along
+ the line. */
+ switch (read_err) {
+
+ case WTAP_ERR_UNSUPPORTED_ENCAP:
+ snprintf(errmsg_errno, sizeof(errmsg_errno),
+ "The capture file %%s has a packet with a network type that Ethereal doesn't support.\n(%s)",
+ err_info);
+ g_free(err_info);
+ errmsg = errmsg_errno;
+ break;
+
+ case WTAP_ERR_CANT_READ:
+ errmsg = "An attempt to read from the capture file %s failed for"
+ " some unknown reason.";
+ break;
+
+ case WTAP_ERR_SHORT_READ:
+ errmsg = "The capture file %s appears to have been cut short"
+ " in the middle of a packet.";
+ break;
+
+ case WTAP_ERR_BAD_RECORD:
+ snprintf(errmsg_errno, sizeof(errmsg_errno),
+ "The capture file %%s appears to be damaged or corrupt.\n(%s)",
+ err_info);
+ g_free(err_info);
+ errmsg = errmsg_errno;
+ break;
+
+ default:
+ snprintf(errmsg_errno, sizeof(errmsg_errno),
+ "An error occurred while reading the"
+ " capture file %%s: %s.", wtap_strerror(read_err));
+ errmsg = errmsg_errno;
+ break;
+ }
+ snprintf(err_str, sizeof err_str, errmsg, in_files[i].filename);
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, err_str);
+ }
+ }
+ }
+
+ if (got_write_error) {
+ /* Put up an alert box for the write error. */
+ cf_write_failure_alert_box(out_filename, write_err);
+ }
+
+ return (!got_read_error && !got_write_error);
+}
+
+gboolean
+filter_packets(capture_file *cf, gchar *dftext, gboolean force)
{
dfilter_t *dfcode;
+ char *filter_new = dftext ? dftext : "";
+ char *filter_old = cf->dfilter ? cf->dfilter : "";
+
+ /* if new filter equals old one, do nothing unless told to do so */
+ if (!force && strcmp(filter_new, filter_old) == 0) {
+ return TRUE;
+ }
if (dftext == NULL) {
/* The new filter is an empty filter (i.e., display all packets). */
dftext = g_strdup(dftext);
if (!dfilter_compile(dftext, &dfcode)) {
/* The attempt failed; report an error. */
- simple_dialog(ESD_TYPE_CRIT, NULL, dfilter_error_msg);
- return 0;
+ gchar *safe_dftext = simple_dialog_format_message(dftext);
+ gchar *safe_dfilter_error_msg = simple_dialog_format_message(
+ dfilter_error_msg);
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "%s%s%s\n"
+ "\n"
+ "The following display filter is not a valid display filter:\n%s\n"
+ "See the help for a description of the display filter syntax.",
+ simple_dialog_primary_start(), safe_dfilter_error_msg,
+ simple_dialog_primary_end(), safe_dftext);
+ g_free(safe_dfilter_error_msg);
+ g_free(safe_dftext);
+ g_free(dftext);
+ return FALSE;
}
/* Was it empty? */
} else {
rescan_packets(cf, "Filtering", dftext, TRUE, FALSE);
}
- return 1;
+ return TRUE;
}
void
gboolean stop_flag;
int count;
int err;
+ gchar *err_info;
frame_data *selected_frame, *preceding_frame, *following_frame, *prev_frame;
int selected_row, prev_row, preceding_row, following_row;
gboolean selected_frame_seen;
int progbar_nextstep;
int progbar_quantum;
- cul_bytes=0;
+ cum_bytes=0;
reset_tap_listeners();
/* Which frame, if any, is the currently selected frame?
XXX - should the selected frame or the focus frame be the "current"
cf->first_displayed = NULL;
cf->last_displayed = NULL;
+ /* We currently don't display any packets */
+ cf->displayed_count = 0;
+
/* Iterate through the list of frames. Call a routine for each frame
to check whether it should be displayed and, if so, add it to
the display list. */
if (progbar == NULL)
/* Create the progress bar if necessary */
- progbar = delayed_create_progress_dlg(action, action_item, "Stop", &stop_flag,
+ progbar = delayed_create_progress_dlg(action, action_item, &stop_flag,
&start_time, prog_val);
if (progbar != NULL) {
}
if (!wtap_seek_read (cf->wth, fdata->file_off, &cf->pseudo_header,
- cf->pd, fdata->cap_len, &err)) {
- simple_dialog(ESD_TYPE_CRIT, NULL,
- file_read_error_message(err), cf->filename);
+ cf->pd, fdata->cap_len, &err, &err_info)) {
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ cf_read_error_message(err, err_info), cf->filename);
break;
}
psp_return_t
process_specified_packets(capture_file *cf, packet_range_t *range,
- const char *string1, const char *string2, const char *stop_button_title,
+ const char *string1, const char *string2,
gboolean (*callback)(capture_file *, frame_data *,
union wtap_pseudo_header *, const guint8 *, void *),
void *callback_args)
{
frame_data *fdata;
int err;
+ gchar *err_info;
union wtap_pseudo_header pseudo_header;
guint8 pd[WTAP_MAX_PACKET_SIZE+1];
psp_return_t ret = PSP_FINISHED;
if (progbar == NULL)
/* Create the progress bar if necessary */
progbar = delayed_create_progress_dlg(string1, string2,
- stop_button_title,
&progbar_stop_flag,
&progbar_start_time,
progbar_val);
/* Get the packet */
if (!wtap_seek_read(cf->wth, fdata->file_off, &pseudo_header,
- pd, fdata->cap_len, &err)) {
+ pd, fdata->cap_len, &err, &err_info)) {
/* Attempt to get the packet failed. */
- simple_dialog(ESD_TYPE_CRIT, NULL, file_read_error_message(err),
- cf->filename);
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ cf_read_error_message(err, err_info), cf->filename);
ret = PSP_FAILED;
break;
}
+ /* Process the packet */
if (!callback(cf, fdata, &pseudo_header, pd, callback_args)) {
/* Callback failed. We assume it reported the error appropriately. */
ret = PSP_FAILED;
return ret;
}
+static gboolean
+retap_packet(capture_file *cf _U_, frame_data *fdata,
+ union wtap_pseudo_header *pseudo_header, const guint8 *pd,
+ void *argsp _U_)
+{
+ epan_dissect_t *edt;
+
+ /* If we have tap listeners, allocate a protocol tree root node, so that
+ we'll construct a protocol tree against which a filter expression can
+ be evaluated. */
+ edt = epan_dissect_new(num_tap_filters != 0, FALSE);
+ tap_queue_init(edt);
+ epan_dissect_run(edt, pseudo_header, pd, fdata, NULL);
+ tap_push_tapped_queue(edt);
+ epan_dissect_free(edt);
+
+ return TRUE;
+}
+
+int
+retap_packets(capture_file *cf)
+{
+ packet_range_t range;
+
+ /* Reset the tap listeners. */
+ reset_tap_listeners();
+
+ /* Iterate through the list of packets, dissecting all packets and
+ re-running the taps. */
+ packet_range_init(&range);
+ packet_range_process_init(&range);
+ switch (process_specified_packets(cf, &range, "Refiltering statistics on",
+ "all packets", retap_packet,
+ NULL)) {
+ case PSP_FINISHED:
+ /* Completed successfully. */
+ break;
+
+ case PSP_STOPPED:
+ /* Well, the user decided to abort the refiltering.
+ Return FALSE so our caller knows they did that. */
+ return FALSE;
+
+ case PSP_FAILED:
+ /* Error while retapping. */
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
typedef struct {
print_args_t *print_args;
+ gboolean print_header_line;
+ char *header_line_buf;
+ int header_line_buf_len;
+ gboolean print_formfeed;
gboolean print_separator;
char *line_buf;
int line_buf_len;
int line_len;
int column_len;
int cp_off;
-
+ gboolean proto_tree_needed;
+ char bookmark_name[9+10+1]; /* "__frameNNNNNNNNNN__\0" */
+ char bookmark_title[6+10+1]; /* "Frame NNNNNNNNNN__\0" */
+
+ /* Create the protocol tree, and make it visible, if we're printing
+ the dissection or the hex data.
+ XXX - do we need it if we're just printing the hex data? */
+ proto_tree_needed =
+ args->print_args->print_dissections != print_dissections_none || args->print_args->print_hex;
+ edt = epan_dissect_new(proto_tree_needed, proto_tree_needed);
+
+ /* Fill in the column information if we're printing the summary
+ information. */
if (args->print_args->print_summary) {
- /* Fill in the column information, but don't bother creating
- the logical protocol tree. */
- edt = epan_dissect_new(FALSE, FALSE);
epan_dissect_run(edt, pseudo_header, pd, fdata, &cf->cinfo);
epan_dissect_fill_in_columns(edt);
+ } else
+ epan_dissect_run(edt, pseudo_header, pd, fdata, NULL);
+
+ if (args->print_formfeed) {
+ if (!new_page(args->print_args->stream))
+ goto fail;
+ } else {
+ if (args->print_separator) {
+ if (!print_line(args->print_args->stream, 0, ""))
+ goto fail;
+ }
+ }
+
+ /*
+ * We generate bookmarks, if the output format supports them.
+ * The name is "__frameN__".
+ */
+ sprintf(bookmark_name, "__frame%u__", fdata->num);
+
+ if (args->print_args->print_summary) {
+ if (args->print_header_line) {
+ if (!print_line(args->print_args->stream, 0, args->header_line_buf))
+ goto fail;
+ args->print_header_line = FALSE; /* we might not need to print any more */
+ }
cp = &args->line_buf[0];
line_len = 0;
for (i = 0; i < cf->cinfo.num_cols; i++) {
*cp++ = ' ';
}
*cp = '\0';
- print_line(cf->print_fh, 0, args->print_args->format, args->line_buf);
+
+ /*
+ * Generate a bookmark, using the summary line as the title.
+ */
+ if (!print_bookmark(args->print_args->stream, bookmark_name,
+ args->line_buf))
+ goto fail;
+
+ if (!print_line(args->print_args->stream, 0, args->line_buf))
+ goto fail;
} else {
- if (args->print_separator)
- print_line(cf->print_fh, 0, args->print_args->format, "");
+ /*
+ * Generate a bookmark, using "Frame N" as the title, as we're not
+ * printing the summary line.
+ */
+ sprintf(bookmark_title, "Frame %u", fdata->num);
+ if (!print_bookmark(args->print_args->stream, bookmark_name,
+ bookmark_title))
+ goto fail;
+ } /* if (print_summary) */
- /* Create the logical protocol tree, complete with the display
- representation of the items; we don't need the columns here,
- however. */
- edt = epan_dissect_new(TRUE, TRUE);
- epan_dissect_run(edt, pseudo_header, pd, fdata, NULL);
+ if (args->print_args->print_dissections != print_dissections_none) {
+ if (args->print_args->print_summary) {
+ /* Separate the summary line from the tree with a blank line. */
+ if (!print_line(args->print_args->stream, 0, ""))
+ goto fail;
+ }
/* Print the information in that tree. */
- proto_tree_print(args->print_args, edt, cf->print_fh);
+ if (!proto_tree_print(args->print_args, edt, args->print_args->stream))
+ goto fail;
- if (args->print_args->print_hex) {
- /* Print the full packet data as hex. */
- print_hex_data(cf->print_fh, args->print_args->format, edt);
- }
+ /* Print a blank line if we print anything after this (aka more than one packet). */
+ args->print_separator = TRUE;
+
+ /* Print a header line if we print any more packet summaries */
+ args->print_header_line = TRUE;
+ }
- /* Print a blank line if we print anything after this. */
+ if (args->print_args->print_hex) {
+ /* Print the full packet data as hex. */
+ if (!print_hex_data(args->print_args->stream, edt))
+ goto fail;
+
+ /* Print a blank line if we print anything after this (aka more than one packet). */
args->print_separator = TRUE;
- } /* if (print_summary) */
+
+ /* Print a header line if we print any more packet summaries */
+ args->print_header_line = TRUE;
+ } /* if (args->print_args->print_dissections != print_dissections_none) */
+
epan_dissect_free(edt);
+ /* do we want to have a formfeed between each packet from now on? */
+ if(args->print_args->print_formfeed) {
+ args->print_formfeed = TRUE;
+ }
+
return TRUE;
+
+fail:
+ epan_dissect_free(edt);
+ return FALSE;
}
-int
+pp_return_t
print_packets(capture_file *cf, print_args_t *print_args)
{
int i;
int cp_off;
int column_len;
int line_len;
-
- cf->print_fh = open_print_dest(print_args->to_file, print_args->dest);
- if (cf->print_fh == NULL)
- return FALSE; /* attempt to open destination failed */
-
- print_preamble(cf->print_fh, print_args->format);
+ psp_return_t ret;
callback_args.print_args = print_args;
+ callback_args.print_header_line = TRUE;
+ callback_args.header_line_buf = NULL;
+ callback_args.header_line_buf_len = 256;
+ callback_args.print_formfeed = FALSE;
callback_args.print_separator = FALSE;
callback_args.line_buf = NULL;
callback_args.line_buf_len = 256;
callback_args.col_widths = NULL;
+
+ if (!print_preamble(print_args->stream, cf->filename)) {
+ destroy_print_stream(print_args->stream);
+ return PP_WRITE_ERROR;
+ }
+
if (print_args->print_summary) {
- /* We're printing packet summaries. Allocate the line buffer at
- its initial length. */
- callback_args.line_buf = g_malloc(callback_args.line_buf_len + 1);
+ /* We're printing packet summaries. Allocate the header line buffer
+ and get the column widths. */
+ callback_args.header_line_buf = g_malloc(callback_args.header_line_buf_len + 1);
/* Find the widths for each of the columns - maximum of the
- width of the title and the width of the data - and print
- the column titles. */
+ width of the title and the width of the data - and construct
+ a buffer with a line containing the column titles. */
callback_args.col_widths = (gint *) g_malloc(sizeof(gint) * cf->cinfo.num_cols);
- cp = &callback_args.line_buf[0];
+ cp = &callback_args.header_line_buf[0];
line_len = 0;
for (i = 0; i < cf->cinfo.num_cols; i++) {
/* Don't pad the last column. */
/* Make sure there's room in the line buffer for the column; if not,
double its length. */
line_len += column_len + 1; /* "+1" for space */
- if (line_len > callback_args.line_buf_len) {
- cp_off = cp - callback_args.line_buf;
- callback_args.line_buf_len = 2 * line_len;
- callback_args.line_buf = g_realloc(callback_args.line_buf,
- callback_args.line_buf_len + 1);
- cp = callback_args.line_buf + cp_off;
+ if (line_len > callback_args.header_line_buf_len) {
+ cp_off = cp - callback_args.header_line_buf;
+ callback_args.header_line_buf_len = 2 * line_len;
+ callback_args.header_line_buf = g_realloc(callback_args.header_line_buf,
+ callback_args.header_line_buf_len + 1);
+ cp = callback_args.header_line_buf + cp_off;
}
/* Right-justify the packet number column. */
- if (cf->cinfo.col_fmt[i] == COL_NUMBER)
+/* if (cf->cinfo.col_fmt[i] == COL_NUMBER)
sprintf(cp, "%*s", callback_args.col_widths[i], cf->cinfo.col_title[i]);
- else
+ else*/
sprintf(cp, "%-*s", callback_args.col_widths[i], cf->cinfo.col_title[i]);
cp += column_len;
if (i != cf->cinfo.num_cols - 1)
*cp++ = ' ';
}
*cp = '\0';
- print_line(cf->print_fh, 0, print_args->format, callback_args.line_buf);
+
+ /* Now start out the main line buffer with the same length as the
+ header line buffer. */
+ callback_args.line_buf_len = callback_args.header_line_buf_len;
+ callback_args.line_buf = g_malloc(callback_args.line_buf_len + 1);
} /* if (print_summary) */
/* Iterate through the list of packets, printing the packets we were
told to print. */
- switch (process_specified_packets(cf, &print_args->range, "Printing",
- "selected packets", "Stop", print_packet,
- &callback_args)) {
+ ret = process_specified_packets(cf, &print_args->range, "Printing",
+ "selected packets", print_packet,
+ &callback_args);
+
+ if (callback_args.header_line_buf != NULL)
+ g_free(callback_args.header_line_buf);
+ if (callback_args.line_buf != NULL)
+ g_free(callback_args.line_buf);
+ if (callback_args.col_widths != NULL)
+ g_free(callback_args.col_widths);
+
+ switch (ret) {
+
case PSP_FINISHED:
/* Completed successfully. */
break;
/* Well, the user decided to abort the printing.
XXX - note that what got generated before they did that
- will get printed, as we're piping to a print program; we'd
+ will get printed if we're piping to a print program; we'd
have to write to a file and then hand that to the print
program to make it actually not print anything. */
break;
case PSP_FAILED:
- /* Error while saving. */
+ /* Error while printing.
+
+ XXX - note that what got generated before they did that
+ will get printed if we're piping to a print program; we'd
+ have to write to a file and then hand that to the print
+ program to make it actually not print anything. */
+ destroy_print_stream(print_args->stream);
+ return PP_WRITE_ERROR;
+ }
+
+ if (!print_finale(print_args->stream)) {
+ destroy_print_stream(print_args->stream);
+ return PP_WRITE_ERROR;
+ }
+
+ if (!destroy_print_stream(print_args->stream))
+ return PP_WRITE_ERROR;
+
+ return PP_OK;
+}
+
+static gboolean
+write_pdml_packet(capture_file *cf _U_, frame_data *fdata,
+ union wtap_pseudo_header *pseudo_header, const guint8 *pd,
+ void *argsp)
+{
+ FILE *fh = argsp;
+ epan_dissect_t *edt;
+
+ /* Create the protocol tree, but don't fill in the column information. */
+ edt = epan_dissect_new(TRUE, TRUE);
+ epan_dissect_run(edt, pseudo_header, pd, fdata, NULL);
+
+ /* Write out the information in that tree. */
+ proto_tree_write_pdml(edt, fh);
+
+ epan_dissect_free(edt);
+
+ return !ferror(fh);
+}
+
+pp_return_t
+write_pdml_packets(capture_file *cf, print_args_t *print_args)
+{
+ FILE *fh;
+ psp_return_t ret;
+
+ fh = fopen(print_args->file, "w");
+ if (fh == NULL)
+ return PP_OPEN_ERROR; /* attempt to open destination failed */
+
+ write_pdml_preamble(fh);
+ if (ferror(fh)) {
+ fclose(fh);
+ return PP_WRITE_ERROR;
+ }
+
+ /* Iterate through the list of packets, printing the packets we were
+ told to print. */
+ ret = process_specified_packets(cf, &print_args->range, "Writing PDML",
+ "selected packets", write_pdml_packet,
+ fh);
+
+ switch (ret) {
+
+ case PSP_FINISHED:
+ /* Completed successfully. */
break;
+
+ case PSP_STOPPED:
+ /* Well, the user decided to abort the printing. */
+ break;
+
+ case PSP_FAILED:
+ /* Error while printing. */
+ fclose(fh);
+ return PP_WRITE_ERROR;
}
- if (callback_args.col_widths != NULL)
- g_free(callback_args.col_widths);
- if (callback_args.line_buf != NULL)
- g_free(callback_args.line_buf);
+ write_pdml_finale(fh);
+ if (ferror(fh)) {
+ fclose(fh);
+ return PP_WRITE_ERROR;
+ }
- print_finale(cf->print_fh, print_args->format);
+ /* XXX - check for an error */
+ fclose(fh);
- close_print_dest(print_args->to_file, cf->print_fh);
+ return PP_OK;
+}
- cf->print_fh = NULL;
+static gboolean
+write_psml_packet(capture_file *cf, frame_data *fdata,
+ union wtap_pseudo_header *pseudo_header, const guint8 *pd,
+ void *argsp)
+{
+ FILE *fh = argsp;
+ epan_dissect_t *edt;
- return TRUE;
+ /* Fill in the column information, but don't create the protocol tree. */
+ edt = epan_dissect_new(FALSE, FALSE);
+ epan_dissect_run(edt, pseudo_header, pd, fdata, &cf->cinfo);
+
+ /* Write out the information in that tree. */
+ proto_tree_write_psml(edt, fh);
+
+ epan_dissect_free(edt);
+
+ return !ferror(fh);
+}
+
+pp_return_t
+write_psml_packets(capture_file *cf, print_args_t *print_args)
+{
+ FILE *fh;
+ psp_return_t ret;
+
+ fh = fopen(print_args->file, "w");
+ if (fh == NULL)
+ return PP_OPEN_ERROR; /* attempt to open destination failed */
+
+ write_psml_preamble(fh);
+ if (ferror(fh)) {
+ fclose(fh);
+ return PP_WRITE_ERROR;
+ }
+
+ /* Iterate through the list of packets, printing the packets we were
+ told to print. */
+ ret = process_specified_packets(cf, &print_args->range, "Writing PSML",
+ "selected packets", write_psml_packet,
+ fh);
+
+ switch (ret) {
+
+ case PSP_FINISHED:
+ /* Completed successfully. */
+ break;
+
+ case PSP_STOPPED:
+ /* Well, the user decided to abort the printing. */
+ break;
+
+ case PSP_FAILED:
+ /* Error while printing. */
+ fclose(fh);
+ return PP_WRITE_ERROR;
+ }
+
+ write_psml_finale(fh);
+ if (ferror(fh)) {
+ fclose(fh);
+ return PP_WRITE_ERROR;
+ }
+
+ /* XXX - check for an error */
+ fclose(fh);
+
+ return PP_OK;
}
/* Scan through the packet list and change all columns that use the
if (progbar == NULL)
/* Create the progress bar if necessary */
- progbar = delayed_create_progress_dlg("Changing", "time display", "Stop",
+ progbar = delayed_create_progress_dlg("Changing", "time display",
&stop_flag, &start_time, prog_val);
if (progbar != NULL) {
}
/* Don't match invisible entries. */
- if (!fi->visible)
+ if (PROTO_ITEM_IS_HIDDEN(node))
return;
/* was a free format label produced? */
info.data_len = string_size;
/* String or hex search? */
- if (cf->ascii) {
+ if (cf->string) {
/* String search - what type of string? */
switch (cf->scs_type) {
gboolean stop_flag;
int count;
int err;
+ gchar *err_info;
int row;
float prog_val;
GTimeVal start_time;
/* Create the progress bar if necessary */
if (progbar == NULL)
- progbar = delayed_create_progress_dlg("Searching", cf->sfilter, "Cancel",
+ progbar = delayed_create_progress_dlg("Searching", cf->sfilter,
&stop_flag, &start_time, prog_val);
if (progbar != NULL) {
if (cf->sbackward) {
/* Go on to the previous frame. */
fdata = fdata->prev;
- if (fdata == NULL)
- fdata = cf->plist_end; /* wrap around */
+ if (fdata == NULL) {
+ /*
+ * XXX - other apps have a bit more of a detailed message
+ * for this, and instead of offering "OK" and "Cancel",
+ * they offer things such as "Continue" and "Cancel";
+ * we need an API for popping up alert boxes with
+ * {Verb} and "Cancel".
+ */
+
+ if (prefs.gui_find_wrap)
+ {
+ simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
+ "%sBeginning of capture exceeded!%s\n\n"
+ "Search is continued from the end of the capture.",
+ simple_dialog_primary_start(), simple_dialog_primary_end());
+ fdata = cf->plist_end; /* wrap around */
+ }
+ else
+ {
+ simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
+ "%sBeginning of capture exceeded!%s\n\n"
+ "Try searching forwards.",
+ simple_dialog_primary_start(), simple_dialog_primary_end());
+ fdata = start_fd; /* stay on previous packet */
+ }
+ }
} else {
/* Go on to the next frame. */
fdata = fdata->next;
- if (fdata == NULL)
- fdata = cf->plist; /* wrap around */
+ if (fdata == NULL) {
+ if (prefs.gui_find_wrap)
+ {
+ simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
+ "%sEnd of capture exceeded!%s\n\n"
+ "Search is continued from the start of the capture.",
+ simple_dialog_primary_start(), simple_dialog_primary_end());
+ fdata = cf->plist; /* wrap around */
+ }
+ else
+ {
+ simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
+ "%sEnd of capture exceeded!%s\n\n"
+ "Try searching backwards.",
+ simple_dialog_primary_start(), simple_dialog_primary_end());
+ fdata = start_fd; /* stay on previous packet */
+ }
+ }
}
count++;
if (fdata->flags.passed_dfilter) {
/* Yes. Load its data. */
if (!wtap_seek_read(cf->wth, fdata->file_off, &cf->pseudo_header,
- cf->pd, fdata->cap_len, &err)) {
+ cf->pd, fdata->cap_len, &err, &err_info)) {
/* Read error. Report the error, and go back to the frame
where we started. */
- simple_dialog(ESD_TYPE_CRIT, NULL,
- file_read_error_message(err), cf->filename);
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ cf_read_error_message(err, err_info), cf->filename);
new_fd = start_fd;
break;
}
if (fdata == NULL) {
/* we didn't find a packet with that packet number */
- simple_dialog(ESD_TYPE_CRIT, NULL,
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
"There is no packet with that packet number.");
return FALSE; /* we failed to go to that packet */
}
if (!fdata->flags.passed_dfilter) {
/* that packet currently isn't displayed */
/* XXX - add it to the set of displayed packets? */
- simple_dialog(ESD_TYPE_CRIT, NULL,
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
"That packet is not currently being displayed.");
return FALSE; /* we failed to go to that packet */
}
return TRUE; /* we got to that packet */
}
+gboolean
+goto_top_frame(capture_file *cf)
+{
+ frame_data *fdata;
+ int row;
+ frame_data *lowest_fdata = NULL;
+
+ for (fdata = cf->plist; fdata != NULL; fdata = fdata->next) {
+ if (fdata->flags.passed_dfilter) {
+ lowest_fdata = fdata;
+ break;
+ }
+ }
+
+ if (lowest_fdata == NULL) {
+ return FALSE;
+ }
+
+ /* We found that packet, and it's currently being displayed.
+ Find what row it's in. */
+ row = packet_list_find_row_from_data(lowest_fdata);
+ g_assert(row != -1);
+
+ /* Select that row, make it the focus row, and make it visible. */
+ packet_list_set_selected_row(row);
+ return TRUE; /* we got to that packet */
+}
+
+gboolean
+goto_bottom_frame(capture_file *cf)
+{
+ frame_data *fdata;
+ int row;
+ frame_data *highest_fdata = NULL;
+
+ for (fdata = cf->plist; fdata != NULL; fdata = fdata->next) {
+ if (fdata->flags.passed_dfilter) {
+ highest_fdata = fdata;
+ }
+ }
+
+ if (highest_fdata == NULL) {
+ return FALSE;
+ }
+
+ /* We found that packet, and it's currently being displayed.
+ Find what row it's in. */
+ row = packet_list_find_row_from_data(highest_fdata);
+ g_assert(row != -1);
+
+ /* Select that row, make it the focus row, and make it visible. */
+ packet_list_set_selected_row(row);
+ return TRUE; /* we got to that packet */
+}
+
+/*
+ * Go to frame specified by currently selected protocol tree item.
+ */
+void
+goto_framenum(capture_file *cf)
+{
+ header_field_info *hfinfo;
+ guint32 framenum;
+
+ if (cf->finfo_selected) {
+ hfinfo = cf->finfo_selected->hfinfo;
+ g_assert(hfinfo);
+ if (hfinfo->type == FT_FRAMENUM) {
+ framenum = fvalue_get_integer(&cf->finfo_selected->value);
+ if (framenum != 0)
+ goto_frame(cf, framenum);
+ }
+ }
+}
+
/* Select the packet on a given row. */
void
select_packet(capture_file *cf, int row)
{
frame_data *fdata;
int err;
+ gchar *err_info;
/* Get the frame data struct pointer for this frame */
fdata = (frame_data *)packet_list_get_row_data(row);
/* Get the data in that frame. */
if (!wtap_seek_read (cf->wth, fdata->file_off, &cf->pseudo_header,
- cf->pd, fdata->cap_len, &err)) {
- simple_dialog(ESD_TYPE_CRIT, NULL,
- file_read_error_message(err), cf->filename);
+ cf->pd, fdata->cap_len, &err, &err_info)) {
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ cf_read_error_message(err, err_info), cf->filename);
return;
}
void
mark_frame(capture_file *cf, frame_data *frame)
{
- frame->flags.marked = TRUE;
- cf->marked_count++;
+ if (! frame->flags.marked) {
+ frame->flags.marked = TRUE;
+ if (cf->count > cf->marked_count)
+ cf->marked_count++;
+ }
}
/*
void
unmark_frame(capture_file *cf, frame_data *frame)
{
- frame->flags.marked = FALSE;
- cf->marked_count--;
+ if (frame->flags.marked) {
+ frame->flags.marked = FALSE;
+ if (cf->marked_count > 0)
+ cf->marked_count--;
+ }
}
typedef struct {
/* and save the packet */
if (!wtap_dump(args->pdh, &hdr, pseudo_header, pd, &err)) {
- simple_dialog(ESD_TYPE_CRIT, NULL, file_write_error_message(err),
- args->fname);
+ cf_write_failure_alert_box(args->fname, err);
return FALSE;
}
return TRUE;
* Unfortunately, the file requester gives us an absolute file
* name and the read file name may be relative (if supplied on
* the command line). From Joerg Mayer.
+ *
+ * This is a bit tricky on win32. The st_ino field is documented as:
+ * "The inode, and therefore st_ino, has no meaning in the FAT, ..."
+ * but it *is* set to zero if stat() returns without an error,
+ * so this is working, but maybe not quite the way expected. ULFL
*/
infile.st_ino = 1; /* These prevent us from getting equality */
outfile.st_ino = 2; /* If one or other of the files is not accessible */
stat(cf->filename, &infile);
stat(fname, &outfile);
if (infile.st_ino == outfile.st_ino) {
- simple_dialog(ESD_TYPE_CRIT, NULL,
- "Can't save over current capture file: %s!",
- cf->filename);
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "%sCapture file: \"%s\" already exists!%s\n\n"
+ "Please choose a different filename.",
+ simple_dialog_primary_start(), fname, simple_dialog_primary_end());
goto fail;
}
/* The file being saved is a temporary file from a live
capture, so it doesn't need to stay around under that name;
first, try renaming the capture buffer file to the new name. */
-#ifndef WIN32
+#ifndef _WIN32
if (rename(cf->filename, fname) == 0) {
/* That succeeded - there's no need to copy the source file. */
from_filename = NULL;
be if we didn't have permission to remove the file from
the temporary directory, and that might be fixable - but
is it worth requiring the user to go off and fix it?) */
- simple_dialog(ESD_TYPE_CRIT, NULL,
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
file_rename_error_message(errno), fname);
goto fail;
}
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_CRIT, NULL,
- file_open_error_message(err, TRUE, save_format), fname);
+ cf_open_failure_alert_box(fname, err, NULL, TRUE, save_format);
goto fail;
}
it means we can no longer get at the other packets. What does
NetMon do? */
- /* Iterate through the list of packets, printing the packets we were
- told to print.
+ /* Iterate through the list of packets, processing the packets we were
+ told to process.
XXX - we've already called "packet_range_process_init(range)", but
"process_specified_packets()" will do it again. Fortunately,
callback_args.pdh = pdh;
callback_args.fname = fname;
switch (process_specified_packets(cf, range, "Saving",
- "selected packets", "Stop", save_packet,
+ "selected packets", save_packet,
&callback_args)) {
case PSP_FINISHED:
}
if (!wtap_dump_close(pdh, &err)) {
- simple_dialog(ESD_TYPE_WARN, NULL, file_close_error_message(err), fname);
+ cf_close_failure_alert_box(fname, err);
goto fail;
}
}
/* Pop the "Saving:" message off the status bar. */
statusbar_pop_file_msg();
- /* XXX: I'm not sure how this should look like! */
if (packet_range_process_all(range)) {
- /*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.
if ((err = cf_open(fname, FALSE, cf)) == 0) {
/* XXX - report errors if this fails?
What should we return if it fails or is aborted? */
- switch (cf_read(cf, &err)) {
+ switch (cf_read(cf)) {
case READ_SUCCESS:
case READ_ERROR:
return FALSE;
}
-char *
-file_open_error_message(int err, gboolean for_writing, int file_type)
+static void
+cf_open_failure_alert_box(const char *filename, int err, gchar *err_info,
+ gboolean for_writing, int file_type)
{
- char *errmsg;
- static char errmsg_errno[1024+1];
-
- switch (err) {
-
- case WTAP_ERR_NOT_REGULAR_FILE:
- errmsg = "The file \"%s\" is a \"special file\" or socket or other non-regular file.";
- break;
-
- case WTAP_ERR_RANDOM_OPEN_PIPE:
- /* Seen only when opening a capture file for reading. */
- errmsg = "The file \"%s\" is a pipe or FIFO; Ethereal cannot read pipe or FIFO files.";
- break;
+ if (err < 0) {
+ /* Wiretap error. */
+ switch (err) {
+
+ case WTAP_ERR_NOT_REGULAR_FILE:
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "The file \"%s\" is a \"special file\" or socket or other non-regular file.",
+ filename);
+ break;
- case WTAP_ERR_FILE_UNKNOWN_FORMAT:
- case WTAP_ERR_UNSUPPORTED:
- /* Seen only when opening a capture file for reading. */
- errmsg = "The file \"%s\" is not a capture file in a format Ethereal understands.";
- break;
+ case WTAP_ERR_RANDOM_OPEN_PIPE:
+ /* Seen only when opening a capture file for reading. */
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "The file \"%s\" is a pipe or FIFO; Ethereal cannot read pipe or FIFO files.",
+ filename);
+ break;
- case WTAP_ERR_CANT_WRITE_TO_PIPE:
- /* Seen only when opening a capture file for writing. */
- snprintf(errmsg_errno, sizeof(errmsg_errno),
- "The file \"%%s\" is a pipe, and %s capture files cannot be "
- "written to a pipe.", wtap_file_type_string(file_type));
- errmsg = errmsg_errno;
- break;
+ case WTAP_ERR_FILE_UNKNOWN_FORMAT:
+ /* Seen only when opening a capture file for reading. */
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "The file \"%s\" is not a capture file in a format Ethereal understands.",
+ filename);
+ break;
- case WTAP_ERR_UNSUPPORTED_FILE_TYPE:
- /* Seen only when opening a capture file for writing. */
- errmsg = "Ethereal does not support writing capture files in that format.";
- break;
+ case WTAP_ERR_UNSUPPORTED:
+ /* Seen only when opening a capture file for reading. */
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "The file \"%s\" is not a capture file in a format Ethereal understands.\n"
+ "(%s)",
+ filename, err_info);
+ g_free(err_info);
+ break;
- case WTAP_ERR_UNSUPPORTED_ENCAP:
- case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED:
- if (for_writing)
- errmsg = "Ethereal cannot save this capture in that format.";
- else
- errmsg = "The file \"%s\" is a capture for a network type that Ethereal doesn't support.";
- break;
+ case WTAP_ERR_CANT_WRITE_TO_PIPE:
+ /* Seen only when opening a capture file for writing. */
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "The file \"%s\" is a pipe, and %s capture files cannot be "
+ "written to a pipe.",
+ filename, wtap_file_type_string(file_type));
+ break;
- case WTAP_ERR_BAD_RECORD:
- errmsg = "The file \"%s\" appears to be damaged or corrupt.";
- break;
+ case WTAP_ERR_UNSUPPORTED_FILE_TYPE:
+ /* Seen only when opening a capture file for writing. */
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "Ethereal does not support writing capture files in that format.");
+ break;
- case WTAP_ERR_CANT_OPEN:
- if (for_writing)
- errmsg = "The file \"%s\" could not be created for some unknown reason.";
- else
- errmsg = "The file \"%s\" could not be opened for some unknown reason.";
- break;
+ case WTAP_ERR_UNSUPPORTED_ENCAP:
+ if (for_writing) {
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "Ethereal cannot save this capture in that format.");
+ } else {
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "The file \"%s\" is a capture for a network type that Ethereal doesn't support.\n"
+ "(%s)",
+ filename, err_info);
+ g_free(err_info);
+ }
+ break;
- case WTAP_ERR_SHORT_READ:
- errmsg = "The file \"%s\" appears to have been cut short"
- " in the middle of a packet or other data.";
- break;
+ case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED:
+ if (for_writing) {
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "Ethereal cannot save this capture in that format.");
+ } else {
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "The file \"%s\" is a capture for a network type that Ethereal doesn't support.",
+ filename);
+ }
+ break;
- case WTAP_ERR_SHORT_WRITE:
- errmsg = "A full header couldn't be written to the file \"%s\".";
- break;
+ case WTAP_ERR_BAD_RECORD:
+ /* Seen only when opening a capture file for reading. */
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "The file \"%s\" appears to be damaged or corrupt.\n"
+ "(%s)",
+ filename, err_info);
+ g_free(err_info);
+ break;
- case ENOENT:
- if (for_writing)
- errmsg = "The path to the file \"%s\" does not exist.";
- else
- errmsg = "The file \"%s\" does not exist.";
- break;
+ case WTAP_ERR_CANT_OPEN:
+ if (for_writing) {
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "The file \"%s\" could not be created for some unknown reason.",
+ filename);
+ } else {
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "The file \"%s\" could not be opened for some unknown reason.",
+ filename);
+ }
+ break;
- case EACCES:
- if (for_writing)
- errmsg = "You do not have permission to create or write to the file \"%s\".";
- else
- errmsg = "You do not have permission to read the file \"%s\".";
- break;
+ case WTAP_ERR_SHORT_READ:
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "The file \"%s\" appears to have been cut short"
+ " in the middle of a packet or other data.",
+ filename);
+ break;
- case EISDIR:
- errmsg = "\"%s\" is a directory (folder), not a file.";
- break;
+ case WTAP_ERR_SHORT_WRITE:
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "A full header couldn't be written to the file \"%s\".",
+ filename);
+ break;
- default:
- snprintf(errmsg_errno, sizeof(errmsg_errno),
- "The file \"%%s\" could not be %s: %s.",
- for_writing ? "created" : "opened",
- wtap_strerror(err));
- errmsg = errmsg_errno;
- break;
+ default:
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "The file \"%s\" could not be %s: %s.",
+ filename,
+ for_writing ? "created" : "opened",
+ wtap_strerror(err));
+ break;
+ }
+ } else {
+ /* OS error. */
+ open_failure_alert_box(filename, err, for_writing);
}
- return errmsg;
}
static char *
}
char *
-file_read_error_message(int err)
-{
- static char errmsg_errno[1024+1];
-
- snprintf(errmsg_errno, sizeof(errmsg_errno),
- "An error occurred while reading from the file \"%%s\": %s.",
- wtap_strerror(err));
- return errmsg_errno;
-}
-
-char *
-file_write_error_message(int err)
+cf_read_error_message(int err, gchar *err_info)
{
- char *errmsg;
static char errmsg_errno[1024+1];
switch (err) {
- case ENOSPC:
- errmsg = "The file \"%s\" could not be saved because there is no space left on the file system.";
- break;
+ case WTAP_ERR_UNSUPPORTED_ENCAP:
+ snprintf(errmsg_errno, sizeof(errmsg_errno),
+ "The file \"%%s\" has a packet with a network type that Ethereal doesn't support.\n(%s)",
+ err_info);
+ break;
-#ifdef EDQUOT
- case EDQUOT:
- errmsg = "The file \"%s\" could not be saved because you are too close to, or over, your disk quota.";
+ case WTAP_ERR_BAD_RECORD:
+ snprintf(errmsg_errno, sizeof(errmsg_errno),
+ "An error occurred while reading from the file \"%%s\": %s.\n(%s)",
+ wtap_strerror(err), err_info);
break;
-#endif
default:
snprintf(errmsg_errno, sizeof(errmsg_errno),
- "An error occurred while writing to the file \"%%s\": %s.",
- wtap_strerror(err));
- errmsg = errmsg_errno;
+ "An error occurred while reading from the file \"%%s\": %s.",
+ wtap_strerror(err));
break;
}
- return errmsg;
+ return errmsg_errno;
+}
+
+static void
+cf_write_failure_alert_box(const char *filename, int err)
+{
+ if (err < 0) {
+ /* Wiretap error. */
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "An error occurred while writing to the file \"%s\": %s.",
+ filename, wtap_strerror(err));
+ } else {
+ /* OS error. */
+ write_failure_alert_box(filename, err);
+ }
}
/* Check for write errors - if the file is being written to an NFS server,
a write error may not show up until the file is closed, as NFS clients
might not send writes to the server until the "write()" call finishes,
so that the write may fail on the server but the "write()" may succeed. */
-static char *
-file_close_error_message(int err)
+static void
+cf_close_failure_alert_box(const char *filename, int err)
{
- char *errmsg;
- static char errmsg_errno[1024+1];
-
- switch (err) {
+ if (err < 0) {
+ /* Wiretap error. */
+ switch (err) {
+
+ case WTAP_ERR_CANT_CLOSE:
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "The file \"%s\" couldn't be closed for some unknown reason.",
+ filename);
+ break;
- case WTAP_ERR_CANT_CLOSE:
- errmsg = "The file \"%s\" couldn't be closed for some unknown reason.";
- break;
+ case WTAP_ERR_SHORT_WRITE:
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "Not all the packets could be written to the file \"%s\".",
+ filename);
+ break;
- case WTAP_ERR_SHORT_WRITE:
- errmsg = "Not all the packets could be written to the file \"%s\".";
- break;
+ default:
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "An error occurred while closing the file \"%s\": %s.",
+ filename, wtap_strerror(err));
+ break;
+ }
+ } else {
+ /* OS error.
+ We assume that a close error from the OS is really a write error. */
+ write_failure_alert_box(filename, err);
+ }
+}
- case ENOSPC:
- errmsg = "The file \"%s\" could not be saved because there is no space left on the file system.";
- break;
+/* Reload the current capture file. */
+void
+cf_reload() {
+ gchar *filename;
+ gboolean is_tempfile;
+
+ /* If the file could be opened, "cf_open()" calls "cf_close()"
+ to get rid of state for the old capture file before filling in state
+ for the new capture file. "cf_close()" will remove the file if
+ it's a temporary file; we don't want that to happen (for one thing,
+ it'd prevent subsequent reopens from working). Remember whether it's
+ a temporary file, mark it as not being a temporary file, and then
+ reopen it as the type of file it was.
+
+ Also, "cf_close()" will free "cfile.filename", so we must make
+ a copy of it first. */
+ filename = g_strdup(cfile.filename);
+ is_tempfile = cfile.is_tempfile;
+ cfile.is_tempfile = FALSE;
+ if (cf_open(filename, is_tempfile, &cfile) == 0) {
+ switch (cf_read(&cfile)) {
+
+ case READ_SUCCESS:
+ case READ_ERROR:
+ /* Just because we got an error, that doesn't mean we were unable
+ to read any of the file; we handle what we could get from the
+ file. */
+ break;
-#ifdef EDQUOT
- case EDQUOT:
- errmsg = "The file \"%s\" could not be saved because you are too close to, or over, your disk quota.";
- break;
-#endif
+ case READ_ABORTED:
+ /* The user bailed out of re-reading the capture file; the
+ capture file has been closed - just free the capture file name
+ string and return (without changing the last containing
+ directory). */
+ g_free(filename);
+ return;
+ }
+ } else {
+ /* The open failed, so "cfile.is_tempfile" wasn't set to "is_tempfile".
+ Instead, the file was left open, so we should restore "cfile.is_tempfile"
+ ourselves.
- default:
- snprintf(errmsg_errno, sizeof(errmsg_errno),
- "An error occurred while closing the file \"%%s\": %s.",
- wtap_strerror(err));
- errmsg = errmsg_errno;
- break;
+ XXX - change the menu? Presumably "cf_open()" will do that;
+ make sure it does! */
+ cfile.is_tempfile = is_tempfile;
}
- return errmsg;
+ /* "cf_open()" made a copy of the file name we handed it, so
+ we should free up our copy. */
+ g_free(filename);
}
-
/* 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
/* 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, 0), from_filename);
+ open_failure_alert_box(from_filename, errno, FALSE);
goto done;
}
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, 0), to_filename);
+ open_failure_alert_box(to_filename, errno, TRUE);
close(from_fd);
goto done;
}
err = errno;
else
err = WTAP_ERR_SHORT_WRITE;
- simple_dialog(ESD_TYPE_CRIT, NULL,
- file_write_error_message(err), to_filename);
+ write_failure_alert_box(to_filename, err);
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);
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "An error occurred while reading from the file \"%s\": %s.",
+ from_filename, strerror(err));
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);
+ write_failure_alert_box(to_filename, errno);
goto done;
}