/* file.c
* File I/O routines
*
- * $Id: file.c,v 1.101 1999/09/30 07:15:19 guy Exp $
+ * $Id: file.c,v 1.137 1999/12/12 13:25:54 oabad Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
#include "print.h"
#include "file.h"
#include "util.h"
+#include "ui_util.h"
#include "gtk/proto_draw.h"
#include "dfilter.h"
#include "timestamp.h"
+#include "conversation.h"
+#include "globals.h"
-#include "packet-ncp.h"
+#ifdef HAVE_DLFCN_H
+#include "plugins.h"
+#endif
+
+#ifndef __RESOLV_H__
+#include "resolv.h"
+#endif
+
+#include "packet-atalk.h"
+
+#include "packet-ipv6.h"
+
+#include "packet-sna.h"
+
+#include "packet-vines.h"
extern GtkWidget *packet_list, *prog_bar, *info_bar, *byte_view, *tree_view;
extern guint file_ctx;
-extern int sync_pipe[];
-guint cap_input_id;
gboolean auto_scroll_live = FALSE;
static guint32 firstsec, firstusec;
static void freeze_clist(capture_file *cf);
static void thaw_clist(capture_file *cf);
+static char *file_rename_error_message(int err);
+static char *file_close_error_message(int err);
+
/* Update the progress bar this many times when reading a file. */
#define N_PROGBAR_UPDATES 100
int
-open_cap_file(char *fname, capture_file *cf) {
+open_cap_file(char *fname, gboolean is_tempfile, capture_file *cf)
+{
wtap *wth;
int err;
FILE_T fh;
/* The open succeeded. Close whatever capture file we had open,
and fill in the information for this file. */
- close_cap_file(cf, info_bar, file_ctx);
+ close_cap_file(cf, info_bar);
+
+ /* Initialize the table of conversations. */
+ conversation_init();
/* Initialize protocol-specific variables */
- ncp_init_protocol();
+ init_all_protocols();
cf->wth = wth;
cf->fh = fh;
cf->filed = fd;
cf->f_len = cf_stat.st_size;
- /* set the file name because we need it to set the follow stream filter */
+ /* Set the file name because we need it to set the follow stream filter.
+ XXX - is that still true? We need it for other reasons, though,
+ in any case. */
cf->filename = g_strdup(fname);
+ /* Indicate whether it's a permanent or temporary file. */
+ cf->is_tempfile = is_tempfile;
+
+ /* If it's a temporary capture buffer file, mark it as not saved. */
+ cf->user_saved = !is_tempfile;
+
cf->cd_t = wtap_file_type(cf->wth);
- cf->cd_t_desc = wtap_file_type_string(cf->wth);
cf->count = 0;
cf->drops = 0;
cf->esec = 0;
/* Reset everything to a pristine state */
void
-close_cap_file(capture_file *cf, void *w, guint context) {
+close_cap_file(capture_file *cf, void *w)
+{
frame_data *fd, *fd_next;
if (cf->fh) {
wtap_close(cf->wth);
cf->wth = NULL;
}
+ /* We have no file open... */
+ if (cf->filename != NULL) {
+ /* If it's a temporary file, remove it. */
+ if (cf->is_tempfile)
+ unlink(cf->filename);
+ g_free(cf->filename);
+ cf->filename = NULL;
+ }
+ /* ...which means we have nothing to save. */
+ cf->user_saved = FALSE;
+
for (fd = cf->plist; fd != NULL; fd = fd_next) {
fd_next = fd->next;
g_free(fd);
cf->plist_end = NULL;
unselect_packet(cf); /* nothing to select */
+ /* Clear the packet list. */
gtk_clist_freeze(GTK_CLIST(packet_list));
gtk_clist_clear(GTK_CLIST(packet_list));
gtk_clist_thaw(GTK_CLIST(packet_list));
- gtk_statusbar_pop(GTK_STATUSBAR(w), context);
+
+ /* 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? */
+ gtk_statusbar_pop(GTK_STATUSBAR(w), file_ctx);
+
+ /* Restore the standard title bar message. */
+ set_main_window_name("The Ethereal Network Analyzer");
/* Disable all menu items that make sense only if you have a capture. */
set_menu_sensitivity("/File/Save", FALSE);
set_menu_sensitivity("/File/Reload", FALSE);
set_menu_sensitivity("/File/Print...", FALSE);
set_menu_sensitivity("/Display/Options...", FALSE);
+ set_menu_sensitivity("/Display/Match Selected", FALSE);
+ set_menu_sensitivity("/Display/Colorize Display...", FALSE);
+ set_menu_sensitivity("/Display/Find Frame...", FALSE);
+ set_menu_sensitivity("/Display/Go To Frame...", FALSE);
+ set_menu_sensitivity("/Display/Collapse All", FALSE);
+ set_menu_sensitivity("/Display/Expand All", FALSE);
+ set_menu_sensitivity("/Tools/Follow TCP Stream", FALSE);
+ set_menu_sensitivity("/Tools/Graph", FALSE);
set_menu_sensitivity("/Tools/Summary", FALSE);
}
+/* Set the file name in the status line, in the name for the main window,
+ and in the name for the main window's icon. */
+static void
+set_display_filename(capture_file *cf)
+{
+ gchar *name_ptr;
+ size_t msg_len;
+ gchar *done_fmt = " File: %s Drops: %u";
+ gchar *done_msg;
+ gchar *win_name_fmt = "%s - Ethereal";
+ gchar *win_name;
+
+ if (!cf->is_tempfile) {
+ /* Get the last component of the file name, and put that in the
+ status bar. */
+ if ((name_ptr = (gchar *) strrchr(cf->filename, '/')) == NULL)
+ name_ptr = cf->filename;
+ else
+ name_ptr++;
+ } else {
+ /* The file we read is a temporary file from a live capture;
+ we don't mention its name in the status bar. */
+ 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);
+ gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, done_msg);
+ g_free(done_msg);
+
+ msg_len = strlen(name_ptr) + strlen(win_name_fmt) + 1;
+ win_name = g_malloc(msg_len);
+ snprintf(win_name, msg_len, win_name_fmt, name_ptr);
+ set_main_window_name(win_name);
+ g_free(win_name);
+}
+
int
-read_cap_file(capture_file *cf) {
+read_cap_file(capture_file *cf)
+{
gchar *name_ptr, *load_msg, *load_fmt = " Loading: %s...";
- gchar *done_fmt = " File: %s Drops: %d";
int success;
int err;
size_t msg_len;
else
name_ptr++;
- load_msg = g_malloc(strlen(name_ptr) + strlen(load_fmt) + 2);
- sprintf(load_msg, load_fmt, name_ptr);
+ msg_len = strlen(name_ptr) + strlen(load_fmt) + 2;
+ load_msg = g_malloc(msg_len);
+ snprintf(load_msg, msg_len, load_fmt, name_ptr);
gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, load_msg);
+ g_free(load_msg);
cf->update_progbar = TRUE;
/* Update the progress bar when it gets to this value. */
freeze_clist(cf);
proto_tree_is_visible = FALSE;
success = wtap_loop(cf->wth, 0, wtap_dispatch_cb, (u_char *) cf, &err);
+ /* Set the file encapsulation type now; we don't know what it is until
+ we've looked at all the packets, as we don't know until then whether
+ there's more than one type (and thus whether it's
+ WTAP_ENCAP_PER_PACKET). */
+ cf->lnk_t = wtap_file_encap(cf->wth);
wtap_close(cf->wth);
cf->wth = NULL;
cf->filed = open(cf->filename, O_RDONLY);
cf->fh = filed_open(cf->filed, "r");
cf->unfiltered_count = cf->count;
+ cf->current_frame = cf->first_displayed;
+ /* Make the first row the selected row. */
+ gtk_clist_select_row(GTK_CLIST(packet_list), 0, -1);
thaw_clist(cf);
gtk_progress_set_activity_mode(GTK_PROGRESS(prog_bar), FALSE);
gtk_progress_set_value(GTK_PROGRESS(prog_bar), 0);
gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
+ set_display_filename(cf);
- msg_len = strlen(name_ptr) + strlen(done_fmt) + 64;
- load_msg = g_realloc(load_msg, msg_len);
-
- if (cf->user_saved || !cf->save_file)
- snprintf(load_msg, msg_len, done_fmt, name_ptr, cf->drops);
- else
- snprintf(load_msg, msg_len, done_fmt, "<none>", cf->drops);
-
- gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, load_msg);
- g_free(load_msg);
-
- /* Enable menu items that make sense if you have a capture. */
+ /* Enable menu items that make sense if you have a capture file you've
+ finished reading. */
+ set_menu_sensitivity("/File/Save", !cf->user_saved);
+ set_menu_sensitivity("/File/Save As...", TRUE);
set_menu_sensitivity("/File/Close", TRUE);
set_menu_sensitivity("/File/Reload", TRUE);
set_menu_sensitivity("/File/Print...", TRUE);
+
+ /* Enable menu items that make sense if you have some captured packets. */
set_menu_sensitivity("/Display/Options...", TRUE);
+ set_menu_sensitivity("/Display/Match Selected", TRUE);
+ set_menu_sensitivity("/Display/Colorize Display...", TRUE);
+ set_menu_sensitivity("/Display/Find Frame...", TRUE);
+ set_menu_sensitivity("/Display/Go To Frame...", TRUE);
+ set_menu_sensitivity("/Tools/Graph", TRUE);
set_menu_sensitivity("/Tools/Summary", TRUE);
if (!success) {
}
#ifdef HAVE_LIBPCAP
-void
-cap_file_input_cb (gpointer data, gint source, GdkInputCondition condition) {
-
- capture_file *cf = (capture_file *)data;
- char buffer[256+1], *p = buffer, *q = buffer;
- int nread;
- int to_read = 0;
- gboolean exit_loop = FALSE;
- int err;
- int wstatus;
- int wsignal;
- char *msg;
- char *sigmsg;
- char sigmsg_buf[6+1+3+1];
- char *coredumped;
-
- /* avoid reentrancy problems and stack overflow */
- gtk_input_remove(cap_input_id);
-
- if ((nread = read(sync_pipe[0], buffer, 256)) <= 0) {
-
- /* The child has closed the sync pipe, meaning it's not going to be
- capturing any more packets. Pick up its exit status, and
- complain if it died of a signal. */
- if (wait(&wstatus) != -1) {
- /* XXX - are there any platforms on which we can run that *don't*
- support POSIX.1's <sys/wait.h> and macros therein? */
- wsignal = wstatus & 0177;
- coredumped = "";
- if (wstatus == 0177) {
- /* It stopped, rather than exiting. "Should not happen." */
- msg = "stopped";
- wsignal = (wstatus >> 8) & 0xFF;
- } else {
- msg = "terminated";
- if (wstatus & 0200)
- coredumped = " - core dumped";
- }
- if (wsignal != 0) {
- switch (wsignal) {
-
- case SIGHUP:
- sigmsg = "Hangup";
- break;
-
- case SIGINT:
- sigmsg = "Interrupted";
- break;
-
- case SIGQUIT:
- sigmsg = "Quit";
- break;
-
- case SIGILL:
- sigmsg = "Illegal instruction";
- break;
-
- case SIGTRAP:
- sigmsg = "Trace trap";
- break;
-
- case SIGABRT:
- sigmsg = "Abort";
- break;
-
- case SIGFPE:
- sigmsg = "Arithmetic exception";
- break;
-
- case SIGKILL:
- sigmsg = "Killed";
- break;
-
- case SIGBUS:
- sigmsg = "Bus error";
- break;
-
- case SIGSEGV:
- sigmsg = "Segmentation violation";
- break;
-
- case SIGSYS:
- sigmsg = "Bad system call";
- break;
-
- case SIGPIPE:
- sigmsg = "Broken pipe";
- break;
-
- case SIGALRM:
- sigmsg = "Alarm clock";
- break;
-
- case SIGTERM:
- sigmsg = "Terminated";
- break;
-
- default:
- sprintf(sigmsg_buf, "Signal %d", wsignal);
- sigmsg = sigmsg_buf;
- break;
- }
- simple_dialog(ESD_TYPE_WARN, NULL,
- "Child capture process %s: %s%s", msg, sigmsg, coredumped);
- }
- }
-
- /* Read what remains of the capture file, and stop capture (restore
- menu items) */
- gtk_clist_freeze(GTK_CLIST(packet_list));
-
- /* XXX - do something if this fails? */
- wtap_loop(cf->wth, 0, wtap_dispatch_cb, (u_char *) cf, &err);
-
- thaw_clist(cf);
- if (auto_scroll_live)
- gtk_clist_moveto(GTK_CLIST(packet_list),
- cf->plist_end->row, -1, 1.0, 1.0);
-
- wtap_close(cf->wth);
- cf->wth = NULL;
- set_menu_sensitivity("/File/Open...", TRUE);
- set_menu_sensitivity("/File/Close", TRUE);
- set_menu_sensitivity("/File/Save As...", TRUE);
- set_menu_sensitivity("/File/Print...", TRUE);
- set_menu_sensitivity("/File/Reload", TRUE);
- set_menu_sensitivity("/Capture/Start...", TRUE);
- set_menu_sensitivity("/Tools/Summary", TRUE);
- gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, " File: <none>");
- return;
- }
-
- buffer[nread] = '\0';
-
- while(!exit_loop) {
- /* look for (possibly multiple) '*' */
- switch (*q) {
- case '*' :
- to_read += atoi(p);
- p = q + 1;
- q++;
- break;
- case '\0' :
- /* XXX should handle the case of a pipe full (i.e. no star found) */
- exit_loop = TRUE;
- break;
- default :
- q++;
- break;
- }
- }
-
- gtk_clist_freeze(GTK_CLIST(packet_list));
- /* XXX - do something if this fails? */
- wtap_loop(cf->wth, to_read, wtap_dispatch_cb, (u_char *) cf, &err);
- gtk_clist_thaw(GTK_CLIST(packet_list));
- if (auto_scroll_live)
- gtk_clist_moveto(GTK_CLIST(packet_list), cf->plist_end->row, -1, 1.0, 1.0);
-
- /* restore pipe handler */
- cap_input_id = gtk_input_add_full (sync_pipe[0],
- GDK_INPUT_READ,
- cap_file_input_cb,
- NULL,
- (gpointer) cf,
- NULL);
-}
-
int
-tail_cap_file(char *fname, capture_file *cf) {
+start_tail_cap_file(char *fname, gboolean is_tempfile, capture_file *cf)
+{
int err;
int i;
- err = open_cap_file(fname, cf);
- if ((err == 0) && (cf->cd_t != WTAP_FILE_UNKNOWN)) {
-
+ err = open_cap_file(fname, is_tempfile, cf);
+ if (err == 0) {
+ /* Disable menu items that make sense only if you have a capture
+ file you've finished reading. */
set_menu_sensitivity("/File/Open...", FALSE);
- set_menu_sensitivity("/Display/Options...", TRUE);
+
+ /* Disable menu items that make sense only if you're not currently
+ running a capture. */
set_menu_sensitivity("/Capture/Start...", FALSE);
+ /* Enable menu items that make sense if you have some captured
+ packets (yes, I know, we don't have any *yet*). */
+ set_menu_sensitivity("/Display/Options...", TRUE);
+ set_menu_sensitivity("/Display/Match Selected", TRUE);
+ set_menu_sensitivity("/Display/Colorize Display...", TRUE);
+ set_menu_sensitivity("/Display/Find Frame...", TRUE);
+ set_menu_sensitivity("/Display/Go To Frame...", TRUE);
+ set_menu_sensitivity("/Tools/Graph", TRUE);
+ set_menu_sensitivity("/Tools/Summary", TRUE);
+
for (i = 0; i < cf->cinfo.num_cols; i++) {
if (get_column_resize_type(cf->cinfo.col_fmt[i]) == RESIZE_LIVE)
gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
}
}
+ /* Yes, "open_cap_file()" set this - but it set it to a file handle
+ from Wiretap, which will be closed when we close the file; we
+ want it to remain open even after that, so that we can read
+ packet data from it. */
cf->fh = file_open(fname, "r");
- cap_input_id = gtk_input_add_full (sync_pipe[0],
- GDK_INPUT_READ,
- cap_file_input_cb,
- NULL,
- (gpointer) cf,
- NULL);
gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx,
" <live capture in progress>");
}
- else {
- close(sync_pipe[0]);
- }
+ return err;
+}
+
+int
+continue_tail_cap_file(capture_file *cf, int to_read)
+{
+ int err;
+
+ gtk_clist_freeze(GTK_CLIST(packet_list));
+
+ wtap_loop(cf->wth, to_read, wtap_dispatch_cb, (u_char *) cf, &err);
+
+ gtk_clist_thaw(GTK_CLIST(packet_list));
+ if (auto_scroll_live && cf->plist_end != NULL)
+ gtk_clist_moveto(GTK_CLIST(packet_list),
+ cf->plist_end->row, -1, 1.0, 1.0);
+ return err;
+}
+
+int
+finish_tail_cap_file(capture_file *cf)
+{
+ int err;
+
+ gtk_clist_freeze(GTK_CLIST(packet_list));
+
+ wtap_loop(cf->wth, 0, wtap_dispatch_cb, (u_char *) cf, &err);
+
+ thaw_clist(cf);
+ if (auto_scroll_live && cf->plist_end != NULL)
+ gtk_clist_moveto(GTK_CLIST(packet_list),
+ cf->plist_end->row, -1, 1.0, 1.0);
+
+ /* Set the file encapsulation type now; we don't know what it is until
+ we've looked at all the packets, as we don't know until then whether
+ there's more than one type (and thus whether it's
+ WTAP_ENCAP_PER_PACKET). */
+ cf->lnk_t = wtap_file_encap(cf->wth);
+
+ /* There's nothing more to read from the capture file - close it. */
+ wtap_close(cf->wth);
+ cf->wth = NULL;
+
+ /* Pop the "<live capture in progress>" message off the status bar. */
+ gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
+
+ set_display_filename(cf);
+
+ /* Restore the "File/Open" menu item. */
+ set_menu_sensitivity("/File/Open...", TRUE);
+
+ /* Enable menu items that make sense if you have a capture file
+ you've finished reading. */
+ set_menu_sensitivity("/File/Save", !cf->user_saved);
+ set_menu_sensitivity("/File/Save As...", TRUE);
+ set_menu_sensitivity("/File/Close", TRUE);
+ set_menu_sensitivity("/File/Reload", TRUE);
+ set_menu_sensitivity("/File/Print...", TRUE);
+
+ /* Enable menu items that make sense if you're not currently running
+ a capture. */
+ set_menu_sensitivity("/Capture/Start...", TRUE);
+
return err;
}
#endif /* HAVE_LIBPCAP */
/* To do: Add check_col checks to the col_add* routines */
static void
-col_add_abs_time(frame_data *fd, gint el)
+col_set_abs_time(frame_data *fd, int col)
{
struct tm *tmp;
time_t then;
then = fd->abs_secs;
tmp = localtime(&then);
- col_add_fstr(fd, el, "%02d:%02d:%02d.%04ld",
+ snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%02d:%02d:%02d.%04ld",
tmp->tm_hour,
tmp->tm_min,
tmp->tm_sec,
}
static void
-col_add_rel_time(frame_data *fd, gint el)
+col_set_rel_time(frame_data *fd, int col)
{
- col_add_fstr(fd, el, "%d.%06d", fd->rel_secs, fd->rel_usecs);
+ snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%d.%06d", fd->rel_secs,
+ fd->rel_usecs);
}
static void
-col_add_delta_time(frame_data *fd, gint el)
+col_set_delta_time(frame_data *fd, int col)
{
- col_add_fstr(fd, el, "%d.%06d", fd->del_secs, fd->del_usecs);
+ snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%d.%06d", fd->del_secs,
+ fd->del_usecs);
}
/* Add "command-line-specified" time. */
static void
-col_add_cls_time(frame_data *fd)
+col_set_cls_time(frame_data *fd, int col)
{
switch (timestamp_type) {
case ABSOLUTE:
- col_add_abs_time(fd, COL_CLS_TIME);
+ col_set_abs_time(fd, col);
break;
case RELATIVE:
- col_add_rel_time(fd, COL_CLS_TIME);
+ col_set_rel_time(fd, col);
break;
case DELTA:
- col_add_delta_time(fd, COL_CLS_TIME);
+ col_set_delta_time(fd, col);
+ break;
+ }
+}
+
+static void
+col_set_addr(frame_data *fd, int col, address *addr, gboolean is_res)
+{
+ u_int ipv4_addr;
+ struct e_in6_addr ipv6_addr;
+ struct atalk_ddp_addr ddp_addr;
+ struct sna_fid_type_4_addr sna_fid_type_4_addr;
+
+ switch (addr->type) {
+
+ case AT_ETHER:
+ if (is_res)
+ strncpy(fd->cinfo->col_data[col], get_ether_name(addr->data), COL_MAX_LEN);
+ else
+ strncpy(fd->cinfo->col_data[col], ether_to_str(addr->data), COL_MAX_LEN);
+ break;
+
+ case AT_IPv4:
+ memcpy(&ipv4_addr, addr->data, sizeof ipv4_addr);
+ if (is_res)
+ strncpy(fd->cinfo->col_data[col], get_hostname(ipv4_addr), COL_MAX_LEN);
+ else
+ strncpy(fd->cinfo->col_data[col], ip_to_str(addr->data), COL_MAX_LEN);
+ break;
+
+ case AT_IPv6:
+ memcpy(&ipv6_addr.s6_addr, addr->data, sizeof ipv6_addr.s6_addr);
+ if (is_res)
+ strncpy(fd->cinfo->col_data[col], get_hostname6(&ipv6_addr), COL_MAX_LEN);
+ else
+ strncpy(fd->cinfo->col_data[col], ip6_to_str(&ipv6_addr), COL_MAX_LEN);
+ break;
+
+ case AT_IPX:
+ strncpy(fd->cinfo->col_data[col],
+ ipx_addr_to_str(pntohl(&addr->data[0]), &addr->data[4]), COL_MAX_LEN);
+ break;
+
+ case AT_SNA:
+ switch (addr->len) {
+
+ case 1:
+ snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%04X", addr->data[0]);
+ break;
+
+ case 2:
+ snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%04X",
+ pntohs(&addr->data[0]));
+ break;
+
+ case SNA_FID_TYPE_4_ADDR_LEN:
+ memcpy(&sna_fid_type_4_addr, addr->data, SNA_FID_TYPE_4_ADDR_LEN);
+ strncpy(fd->cinfo->col_data[col],
+ sna_fid_type_4_addr_to_str(&sna_fid_type_4_addr), COL_MAX_LEN);
break;
+ }
+ break;
+
+ case AT_ATALK:
+ memcpy(&ddp_addr, addr->data, sizeof ddp_addr);
+ strncpy(fd->cinfo->col_data[col], atalk_addr_to_str(&ddp_addr),
+ COL_MAX_LEN);
+ break;
+
+ case AT_VINES:
+ strncpy(fd->cinfo->col_data[col], vines_addr_to_str(&addr->data[0]),
+ COL_MAX_LEN);
+ break;
+
+ default:
+ break;
}
+ fd->cinfo->col_data[col][COL_MAX_LEN - 1] = '\0';
+}
+
+static void
+col_set_port(frame_data *fd, int col, port_type ptype, guint32 port,
+ gboolean is_res)
+{
+ switch (ptype) {
+
+ case PT_TCP:
+ if (is_res)
+ strncpy(fd->cinfo->col_data[col], get_tcp_port(port), COL_MAX_LEN);
+ else
+ snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%u", port);
+ break;
+
+ case PT_UDP:
+ if (is_res)
+ strncpy(fd->cinfo->col_data[col], get_udp_port(port), COL_MAX_LEN);
+ else
+ snprintf(fd->cinfo->col_data[col], COL_MAX_LEN, "%u", port);
+ break;
+
+ default:
+ break;
+ }
+ fd->cinfo->col_data[col][COL_MAX_LEN - 1] = '\0';
}
static void
fill_in_columns(frame_data *fd)
{
- if (check_col(fd, COL_NUMBER))
- col_add_fstr(fd, COL_NUMBER, "%u", fd->num);
-
- /* Set any time stamp columns. */
- if (check_col(fd, COL_CLS_TIME))
- col_add_cls_time(fd);
- if (check_col(fd, COL_ABS_TIME))
- col_add_abs_time(fd, COL_ABS_TIME);
- if (check_col(fd, COL_REL_TIME))
- col_add_rel_time(fd, COL_REL_TIME);
- if (check_col(fd, COL_DELTA_TIME))
- col_add_delta_time(fd, COL_DELTA_TIME);
-
- if (check_col(fd, COL_PACKET_LENGTH))
- col_add_fstr(fd, COL_PACKET_LENGTH, "%d", fd->pkt_len);
+ int i;
+
+ for (i = 0; i < fd->cinfo->num_cols; i++) {
+ switch (fd->cinfo->col_fmt[i]) {
+
+ case COL_NUMBER:
+ snprintf(fd->cinfo->col_data[i], COL_MAX_LEN, "%u", fd->num);
+ break;
+
+ case COL_CLS_TIME:
+ col_set_cls_time(fd, i);
+ break;
+
+ case COL_ABS_TIME:
+ col_set_abs_time(fd, i);
+ break;
+
+ case COL_REL_TIME:
+ col_set_rel_time(fd, i);
+ break;
+
+ case COL_DELTA_TIME:
+ col_set_delta_time(fd, i);
+ break;
+
+ case COL_DEF_SRC:
+ case COL_RES_SRC: /* COL_DEF_SRC is currently just like COL_RES_SRC */
+ col_set_addr(fd, i, &pi.src, TRUE);
+ break;
+
+ case COL_UNRES_SRC:
+ col_set_addr(fd, i, &pi.src, FALSE);
+ break;
+
+ case COL_DEF_DL_SRC:
+ case COL_RES_DL_SRC:
+ col_set_addr(fd, i, &pi.dl_src, TRUE);
+ break;
+
+ case COL_UNRES_DL_SRC:
+ col_set_addr(fd, i, &pi.dl_src, FALSE);
+ break;
+
+ case COL_DEF_NET_SRC:
+ case COL_RES_NET_SRC:
+ col_set_addr(fd, i, &pi.net_src, TRUE);
+ break;
+
+ case COL_UNRES_NET_SRC:
+ col_set_addr(fd, i, &pi.net_src, FALSE);
+ break;
+
+ case COL_DEF_DST:
+ case COL_RES_DST: /* COL_DEF_DST is currently just like COL_RES_DST */
+ col_set_addr(fd, i, &pi.dst, TRUE);
+ break;
+
+ case COL_UNRES_DST:
+ col_set_addr(fd, i, &pi.dst, FALSE);
+ break;
+
+ case COL_DEF_DL_DST:
+ case COL_RES_DL_DST:
+ col_set_addr(fd, i, &pi.dl_dst, TRUE);
+ break;
+
+ case COL_UNRES_DL_DST:
+ col_set_addr(fd, i, &pi.dl_dst, FALSE);
+ break;
+
+ case COL_DEF_NET_DST:
+ case COL_RES_NET_DST:
+ col_set_addr(fd, i, &pi.net_dst, TRUE);
+ break;
+
+ case COL_UNRES_NET_DST:
+ col_set_addr(fd, i, &pi.net_dst, FALSE);
+ break;
+
+ case COL_DEF_SRC_PORT:
+ case COL_RES_SRC_PORT: /* COL_DEF_SRC_PORT is currently just like COL_RES_SRC_PORT */
+ col_set_port(fd, i, pi.ptype, pi.srcport, TRUE);
+ break;
+
+ case COL_UNRES_SRC_PORT:
+ col_set_port(fd, i, pi.ptype, pi.srcport, FALSE);
+ break;
+
+ case COL_DEF_DST_PORT:
+ case COL_RES_DST_PORT: /* COL_DEF_DST_PORT is currently just like COL_RES_DST_PORT */
+ col_set_port(fd, i, pi.ptype, pi.destport, TRUE);
+ break;
+
+ case COL_UNRES_DST_PORT:
+ col_set_port(fd, i, pi.ptype, pi.destport, FALSE);
+ break;
+
+ case COL_PROTOCOL: /* currently done by dissectors */
+ case COL_INFO: /* currently done by dissectors */
+ break;
+
+ case COL_PACKET_LENGTH:
+ snprintf(fd->cinfo->col_data[i], COL_MAX_LEN, "%d", fd->pkt_len);
+ break;
+
+ case NUM_COL_FMTS: /* keep compiler happy - shouldn't get here */
+ break;
+ }
+ }
}
static void
gint i, row;
gint crow;
gint color;
- proto_tree *protocol_tree;
+ proto_tree *protocol_tree = NULL;
fdata->num = cf->count;
}
/* Apply the filters */
- if (DFILTER_CONTAINS_FILTER(cf->dfcode) ||
- CFILTERS_CONTAINS_FILTER(cf)) {
+ if (cf->dfcode != NULL || CFILTERS_CONTAINS_FILTER(cf->colors)) {
protocol_tree = proto_tree_create_root();
dissect_packet(buf, fdata, protocol_tree);
- if( DFILTER_CONTAINS_FILTER(cf->dfcode) )
+ if (cf->dfcode != NULL)
fdata->passed_dfilter = dfilter_apply(cf->dfcode, protocol_tree, cf->pd);
else
fdata->passed_dfilter = TRUE;
for(crow = 0; cf->colors->num_of_filters &&
crow < cf->colors->num_of_filters; crow++) {
- if(color_filter(cf,crow)->c_colorfilter == NULL) {
+ if(color_filter(cf->colors,crow)->c_colorfilter == NULL) {
continue;
}
- if(dfilter_apply(color_filter(cf,crow)->c_colorfilter, protocol_tree,
+ if(dfilter_apply(color_filter(cf->colors,crow)->c_colorfilter, protocol_tree,
cf->pd)){
color = crow;
break;
proto_tree_free(protocol_tree);
}
else {
- dissect_packet(buf, fdata, NULL);
+#ifdef HAVE_DLFCN_H
+ if (plugin_list)
+ protocol_tree = proto_tree_create_root();
+#endif
+ dissect_packet(buf, fdata, protocol_tree);
fdata->passed_dfilter = TRUE;
color = -1;
+#ifdef HAVE_DLFCN_H
+ if (protocol_tree)
+ proto_tree_free(protocol_tree);
+#endif
}
if (fdata->passed_dfilter) {
/* If we don't have the time stamp of the previous displayed packet,
if (cf->colors->color_filters && (color != -1)){
gtk_clist_set_background(GTK_CLIST(packet_list), row,
- &(color_filter(cf,color)->bg_color));
+ &(color_filter(cf->colors,color)->bg_color));
gtk_clist_set_foreground(GTK_CLIST(packet_list), row,
- &(color_filter(cf,color)->fg_color));
+ &(color_filter(cf->colors,color)->fg_color));
} else {
gtk_clist_set_background(GTK_CLIST(packet_list), row, &WHITE);
gtk_clist_set_foreground(GTK_CLIST(packet_list), row, &BLACK);
}
- /* If this was the selected packet, remember the row it's in, so
- we can re-select it. ("selected_packet" is 0-origin, as it's
- a GList index; "num", however, is 1-origin.) */
- if (cf->selected_packet == fdata->num - 1)
- cf->selected_row = row;
+ /* If we haven't yet seen the first frame, this is it. */
+ if (cf->first_displayed == NULL)
+ cf->first_displayed = fdata;
+
+ /* This is the last frame we've seen so far. */
+ cf->last_displayed = fdata;
+
+ /* If this was the current frame, remember the row it's in, so
+ we can arrange that it's on the screen when we're done. */
+ if (cf->current_frame == fdata)
+ cf->current_row = row;
} else
fdata->row = -1; /* not in the display */
fdata->cinfo = NULL;
fdata = (frame_data *) g_malloc(sizeof(frame_data));
fdata->next = NULL;
+ fdata->prev = NULL;
fdata->pkt_len = phdr->len;
fdata->cap_len = phdr->caplen;
fdata->file_off = offset;
fdata->lnk_t = phdr->pkt_encap;
fdata->abs_secs = phdr->ts.tv_sec;
fdata->abs_usecs = phdr->ts.tv_usec;
+ fdata->encoding = CHAR_ASCII;
fdata->pseudo_header = phdr->pseudo_header;
fdata->cinfo = NULL;
passed = TRUE;
if (cf->rfcode) {
- if (DFILTER_CONTAINS_FILTER(cf->rfcode)) {
- protocol_tree = proto_tree_create_root();
- dissect_packet(buf, fdata, protocol_tree);
- passed = dfilter_apply(cf->rfcode, protocol_tree, cf->pd);
- proto_tree_free(protocol_tree);
- }
+ protocol_tree = proto_tree_create_root();
+ dissect_packet(buf, fdata, protocol_tree);
+ passed = dfilter_apply(cf->rfcode, protocol_tree, cf->pd);
+ proto_tree_free(protocol_tree);
}
if (passed) {
plist_end = cf->plist_end;
+ fdata->prev = plist_end;
if (plist_end != NULL)
plist_end->next = fdata;
else
g_free(fdata);
}
-void
-filter_packets(capture_file *cf)
+int
+filter_packets(capture_file *cf, gchar *dftext)
{
- frame_data *fd;
- guint32 progbar_quantum;
- guint32 progbar_nextstep;
+ dfilter *dfcode;
- if (cf->dfilter == NULL) {
- dfilter_clear_filter(cf->dfcode);
- }
- else {
+ if (dftext == NULL) {
+ /* The new filter is an empty filter (i.e., display all packets). */
+ dfcode = NULL;
+ } else {
/*
- * Compile the filter.
+ * We have a filter; try to compile it.
*/
- if (dfilter_compile(cf->dfcode, cf->dfilter) != 0) {
+ if (dfilter_compile(dftext, &dfcode) != 0) {
+ /* The attempt failed; report an error. */
simple_dialog(ESD_TYPE_WARN, NULL, dfilter_error_msg);
- return;
+ return 0;
+ }
+
+ /* Was it empty? */
+ if (dfcode == NULL) {
+ /* Yes - free the filter text, and set it to null. */
+ g_free(dftext);
+ dftext = NULL;
}
}
+ /* We have a valid filter. Replace the current filter. */
+ if (cf->dfilter != NULL)
+ g_free(cf->dfilter);
+ cf->dfilter = dftext;
+ if (cf->dfcode != NULL)
+ dfilter_destroy(cf->dfcode);
+ cf->dfcode = dfcode;
+
+ /* Now go through the list of packets we've read from the capture file,
+ applying the current display filter, and, if the packet passes the
+ display filter, add it to the summary display, appropriately
+ colored. (That's how we colorize the display - it's like filtering
+ the display, only we don't install a new filter.) */
+ colorize_packets(cf);
+ return 1;
+}
+
+void
+colorize_packets(capture_file *cf)
+{
+ frame_data *fd;
+ guint32 progbar_quantum;
+ guint32 progbar_nextstep;
+
+ /* We need to re-initialize all the state information that protocols
+ keep, because we're making a fresh pass through all the packets. */
+
+ /* Initialize the table of conversations. */
+ conversation_init();
+
+ /* Initialize protocol-specific variables */
+ init_all_protocols();
+
gtk_progress_set_activity_mode(GTK_PROGRESS(prog_bar), FALSE);
/* Freeze the packet list while we redo it, so we don't get any
/* Clear it out. */
gtk_clist_clear(GTK_CLIST(packet_list));
+ /* We don't yet know which will be the first and last frames displayed. */
+ cf->first_displayed = NULL;
+ cf->last_displayed = NULL;
+
/* If a packet was selected, we don't know yet what row, if any, it'll
get. */
- cf->selected_row = -1;
+ cf->current_row = -1;
/* Iterate through the list of packets, calling a routine
to run the filter on the packet, see if it matches, and
cf->count++;
- wtap_seek_read (cf-> cd_t, cf->fh, fd->file_off, cf->pd, fd->cap_len);
+ wtap_seek_read (cf->cd_t, cf->fh, fd->file_off, cf->pd, fd->cap_len);
add_packet_to_packet_list(fd, cf, cf->pd);
}
gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), 0);
- if (cf->selected_row != -1) {
- /* We had a selected packet and it passed the filter. */
- gtk_clist_select_row(GTK_CLIST(packet_list), cf->selected_row, -1);
+ if (cf->current_row != -1) {
+ /* The current frame passed the filter; make sure it's visible. */
+ if (!gtk_clist_row_is_visible(GTK_CLIST(packet_list), cf->current_row))
+ gtk_clist_moveto(GTK_CLIST(packet_list), cf->current_row, -1, 0.0, 0.0);
+ if (cf->current_frame_is_selected) {
+ /* It was selected, so re-select it. */
+ gtk_clist_select_row(GTK_CLIST(packet_list), cf->current_row, -1);
+ }
+ finfo_selected = NULL;
} else {
- /* If we had one, it didn't pass the filter. */
+ /* The current frame didn't pass the filter; make the first frame
+ the current frame, and leave it unselected. */
unselect_packet(cf);
+ cf->current_frame = cf->first_displayed;
}
/* Unfreeze the packet list. */
if (print_args->print_hex) {
/* Print the full packet data as hex. */
- print_hex_data(cf->print_fh, cf->pd, fd->cap_len);
+ print_hex_data(cf->print_fh, cf->pd, fd->cap_len, fd->encoding);
}
/* Print a blank line if we print anything after this. */
if (check_col(fd, COL_CLS_TIME)) {
/* There are columns that show the time in the "command-line-specified"
format; update them. */
- for (i = 0; i < cf->cinfo.num_cols; i++) {
- cf->cinfo.col_data[i][0] = '\0';
- }
- col_add_cls_time(fd);
for (i = 0; i < cf->cinfo.num_cols; i++) {
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';
+ col_set_cls_time(fd, i);
gtk_clist_set_text(GTK_CLIST(packet_list), fd->row, i,
cf->cinfo.col_data[i]);
}
gtk_tree_clear_items(GTK_TREE(tree_view), 0, -1);
}
+gboolean
+find_packet(capture_file *cf, dfilter *sfcode)
+{
+ frame_data *start_fd;
+ frame_data *fd;
+ frame_data *new_fd = NULL;
+ guint32 progbar_quantum;
+ guint32 progbar_nextstep;
+ int count;
+ proto_tree *protocol_tree;
+
+ start_fd = cf->current_frame;
+ if (start_fd != NULL) {
+ gtk_progress_set_activity_mode(GTK_PROGRESS(prog_bar), FALSE);
+
+ /* Iterate through the list of packets, starting at the packet we've
+ picked, calling a routine to run the filter on the packet, see if
+ it matches, and stop if so. */
+ count = 0;
+ fd = start_fd;
+
+ proto_tree_is_visible = FALSE;
+
+ /* 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.
+
+ We base the progress bar on the extent to which we've gone through
+ the displayed packets, as those are the only ones for which we
+ have to do a significant amount of work. */
+ progbar_quantum = cf->count/N_PROGBAR_UPDATES;
+ gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(prog_bar), GTK_PROGRESS_LEFT_TO_RIGHT);
+
+ fd = start_fd;
+ for (;;) {
+ /* 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()"
+ to see if there's any pending input from an X server, and doing
+ that for every packet can be costly, especially on a big file. */
+ if (count >= progbar_nextstep) {
+ /* let's not divide by zero. I should never be started
+ * with count == 0, so let's assert that
+ */
+ g_assert(cf->count > 0);
+
+ gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar),
+ (gfloat) count / cf->count);
+
+ progbar_nextstep += progbar_quantum;
+ while (gtk_events_pending())
+ gtk_main_iteration();
+ }
+
+ /* Go past the current frame. */
+ if (cf->sbackward) {
+ /* Go on to the previous frame. */
+ fd = fd->prev;
+ if (fd == NULL)
+ fd = cf->plist_end; /* wrap around */
+ } else {
+ /* Go on to the next frame. */
+ fd = fd->next;
+ if (fd == NULL)
+ fd = cf->plist; /* wrap around */
+ }
+
+ if (fd == start_fd) {
+ /* We're back to the frame we were on originally. The search
+ failed. */
+ break;
+ }
+
+ /* Is this packet in the display? */
+ if (fd->passed_dfilter) {
+ count++;
+
+ /* Yes. Does it match the search filter? */
+ protocol_tree = proto_tree_create_root();
+ wtap_seek_read(cf->cd_t, cf->fh, fd->file_off, cf->pd, fd->cap_len);
+ dissect_packet(cf->pd, fd, protocol_tree);
+ if (dfilter_apply(sfcode, protocol_tree, cf->pd)) {
+ new_fd = fd;
+ break; /* found it! */
+ }
+ }
+ }
+
+ gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), 0);
+ }
+
+ if (new_fd != NULL) {
+ /* We found a frame. Make it visible, and select it. */
+ if (!gtk_clist_row_is_visible(GTK_CLIST(packet_list), new_fd->row))
+ gtk_clist_moveto(GTK_CLIST(packet_list), new_fd->row, -1, 0.0, 0.0);
+ gtk_clist_select_row(GTK_CLIST(packet_list), new_fd->row, -1);
+ return TRUE; /* success */
+ } else
+ return FALSE; /* failure */
+}
+
+goto_result_t
+goto_frame(capture_file *cf, guint fnumber)
+{
+ frame_data *fd;
+
+ for (fd = cf->plist; fd != NULL && fd->num < fnumber; fd = fd->next)
+ ;
+
+ if (fd == NULL)
+ return NO_SUCH_FRAME; /* we didn't find that frame */
+ if (!fd->passed_dfilter)
+ return FRAME_NOT_DISPLAYED; /* the frame with that number isn't displayed */
+
+ /* We found that frame, and it's currently being displayed.
+ Make it visible, and select it. */
+ if (!gtk_clist_row_is_visible(GTK_CLIST(packet_list), fd->row))
+ gtk_clist_moveto(GTK_CLIST(packet_list), fd->row, -1, 0.0, 0.0);
+ gtk_clist_select_row(GTK_CLIST(packet_list), fd->row, -1);
+ return FOUND_FRAME;
+}
/* Select the packet on a given row. */
void
if (fd->row == row)
break;
}
- cf->fd = fd;
- /* Remember the ordinal number of that frame. */
- cf->selected_packet = i;
+ g_assert(fd != NULL);
+
+ /* Record that this frame is the current frame, and that it's selected. */
+ cf->current_frame = fd;
+ cf->current_frame_is_selected = TRUE;
/* Get the data in that frame. */
- wtap_seek_read (cf-> cd_t, cf->fh, fd->file_off, cf->pd, fd->cap_len);
+ wtap_seek_read (cf->cd_t, cf->fh, fd->file_off, cf->pd, fd->cap_len);
/* Create the logical protocol tree. */
if (cf->protocol_tree)
proto_tree_free(cf->protocol_tree);
cf->protocol_tree = proto_tree_create_root();
proto_tree_is_visible = TRUE;
- dissect_packet(cf->pd, cf->fd, cf->protocol_tree);
+ dissect_packet(cf->pd, cf->current_frame, cf->protocol_tree);
/* Display the GUI protocol tree and hex dump. */
clear_tree_and_hex_views();
proto_tree_draw(cf->protocol_tree, tree_view);
- packet_hex_print(GTK_TEXT(byte_view), cf->pd, cf->fd->cap_len, -1, -1);
+ packet_hex_print(GTK_TEXT(byte_view), cf->pd, cf->current_frame->cap_len,
+ -1, -1, cf->current_frame->encoding);
gtk_text_thaw(GTK_TEXT(byte_view));
/* A packet is selected, so "File/Print Packet" has something to print. */
set_menu_sensitivity("/File/Print Packet", TRUE);
set_menu_sensitivity("/Display/Collapse All", TRUE);
set_menu_sensitivity("/Display/Expand All", TRUE);
+
+ if (pi.ipproto == 6) {
+ set_menu_sensitivity("/Tools/Follow TCP Stream", TRUE);
+ } else {
+ set_menu_sensitivity("/Tools/Follow TCP Stream", FALSE);
+ }
}
/* Unselect the selected packet, if any. */
void
unselect_packet(capture_file *cf)
{
- cf->selected_packet = -1; /* nothing there to be selected */
- cf->selected_row = -1;
+ cf->current_frame_is_selected = FALSE;
/* Destroy the protocol tree for that packet. */
if (cf->protocol_tree != NULL) {
cf->protocol_tree = NULL;
}
+ finfo_selected = NULL;
+
/* Clear out the display of that packet. */
clear_tree_and_hex_views();
set_menu_sensitivity("/File/Print Packet", FALSE);
set_menu_sensitivity("/Display/Collapse All", FALSE);
set_menu_sensitivity("/Display/Expand All", FALSE);
+ set_menu_sensitivity("/Tools/Follow TCP Stream", FALSE);
}
static void
gtk_clist_set_column_resizeable(GTK_CLIST(packet_list), i, TRUE);
}
-/* Tries to mv a file. If unsuccessful, tries to cp the file.
- * Returns 0 on failure to do either, 1 on success of either
- */
int
-file_mv(char *from, char *to)
+save_cap_file(char *fname, capture_file *cf, gboolean save_filtered,
+ guint save_format)
{
-
-#define COPY_BUFFER_SIZE 8192
-
- int retval;
-
-#ifndef WIN32
- /* try a hard link */
- retval = link(from, to);
-
- /* or try a copy */
- if (retval < 0) {
-#endif
- retval = file_cp(from, to);
- if (!retval) {
- return 0;
- }
-#ifndef WIN32
+ gchar *from_filename;
+ gchar *name_ptr, *save_msg, *save_fmt = " Saving: %s...";
+ size_t msg_len;
+ int err;
+ gboolean do_copy;
+ int from_fd, to_fd, nread, nwritten;
+ wtap_dumper *pdh;
+ frame_data *fd;
+ struct wtap_pkthdr hdr;
+ guint8 pd[65536];
+
+ if ((name_ptr = (gchar *) strrchr(fname, '/')) == NULL)
+ name_ptr = fname;
+ else
+ name_ptr++;
+ msg_len = strlen(name_ptr) + strlen(save_fmt) + 2;
+ save_msg = g_malloc(msg_len);
+ snprintf(save_msg, msg_len, save_fmt, name_ptr);
+ gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, save_msg);
+ g_free(save_msg);
+
+ if (!save_filtered && 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. */
+
+ /* In this branch, we set "err" only if we get an error, so we
+ must first clear it. */
+ err = 0;
+ if (cf->is_tempfile) {
+ /* 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. */
+ if (rename(cf->filename, fname) == 0) {
+ /* That succeeded - there's no need to copy the source file. */
+ from_filename = NULL;
+ do_copy = FALSE;
+ } else {
+ if (errno == EXDEV) {
+ /* They're on different file systems, so we have to copy the
+ file. */
+ do_copy = TRUE;
+ from_filename = cf->filename;
+ } else {
+ /* The rename failed, but not because they're on different
+ file systems - put up an error message. (Or should we
+ just punt and try to copy? The only reason why I'd
+ expect the rename to fail and the copy to succeed would
+ 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?) */
+ err = errno;
+ simple_dialog(ESD_TYPE_WARN, NULL,
+ file_rename_error_message(err), fname);
+ goto done;
}
-#endif
-
- unlink(from);
- return 1;
-}
-
-/* Copies a file.
- * Returns 0 on failure to do either, 1 on success of either
- */
-int
-file_cp(char *from, char *to)
-{
-
-#define COPY_BUFFER_SIZE 8192
+ }
+ } else {
+ /* It's a permanent file, so we should copy it, and not remove the
+ original. */
+ do_copy = TRUE;
+ from_filename = cf->filename;
+ }
- int from_fd, to_fd, nread, nwritten;
- char *buffer;
+ /* 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);
+ if (from_fd < 0) {
+ err = errno;
+ simple_dialog(ESD_TYPE_WARN, NULL,
+ file_open_error_message(err, TRUE), from_filename);
+ goto done;
+ }
- buffer = g_malloc(COPY_BUFFER_SIZE);
+ to_fd = creat(fname, 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;
+ }
- from_fd = open(from, O_RDONLY);
- if (from_fd < 0) {
- simple_dialog(ESD_TYPE_WARN, NULL,
- file_open_error_message(errno, TRUE), from);
- return 0;
+ 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;
+ }
+ }
+ } else {
+ /* 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);
+ if (pdh == NULL) {
+ simple_dialog(ESD_TYPE_WARN, NULL,
+ file_open_error_message(err, TRUE), fname);
+ goto done;
+ }
- to_fd = creat(to, 0644);
- if (to_fd < 0) {
- simple_dialog(ESD_TYPE_WARN, NULL,
- file_open_error_message(errno, TRUE), to);
- close(from_fd);
- return 0;
+ /* XXX - have a way to save only the packets currently selected by
+ the display filter.
+
+ 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 (fd = cf->plist; fd != NULL; fd = fd->next) {
+ /* XXX - do a progress bar */
+ if (!save_filtered || fd->passed_dfilter) {
+ /* Either we're saving all frames, or we're saving filtered frames
+ and this one passed the display filter - save it. */
+ hdr.ts.tv_sec = fd->abs_secs;
+ hdr.ts.tv_usec = fd->abs_usecs;
+ hdr.caplen = fd->cap_len;
+ hdr.len = fd->pkt_len;
+ hdr.pkt_encap = fd->lnk_t;
+ hdr.pseudo_header = fd->pseudo_header;
+ wtap_seek_read(cf->cd_t, cf->fh, fd->file_off, pd, fd->cap_len);
+
+ if (!wtap_dump(pdh, &hdr, pd, &err)) {
+ simple_dialog(ESD_TYPE_WARN, NULL,
+ file_write_error_message(err), fname);
+ wtap_dump_close(pdh, &err);
+ goto done;
}
+ }
+ }
- while( (nread = read(from_fd, buffer, COPY_BUFFER_SIZE)) > 0) {
- nwritten = write(to_fd, buffer, nread);
- if (nwritten < nread) {
- if (nwritten < 0) {
- simple_dialog(ESD_TYPE_WARN, NULL,
- file_write_error_message(errno), to);
- } else {
- simple_dialog(ESD_TYPE_WARN, NULL,
-"The file \"%s\" could not be saved: tried writing %d, wrote %d.\n",
- to, nread, nwritten);
- }
- close(from_fd);
- close(to_fd);
- return 0;
- }
- }
- if (nread < 0) {
- simple_dialog(ESD_TYPE_WARN, NULL,
- file_read_error_message(errno), from);
- close(from_fd);
- close(to_fd);
- return 0;
- }
- close(from_fd);
- close(to_fd);
+ if (!wtap_dump_close(pdh, &err)) {
+ simple_dialog(ESD_TYPE_WARN, NULL,
+ file_close_error_message(err), fname);
+ goto done;
+ }
+ }
+
+done:
- return 1;
+ /* Pop the "Saving:" message off the status bar. */
+ gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
+ if (err == 0) {
+ if (!save_filtered) {
+ /* We saved the entire capture, not just some packets from it.
+ Open and read the file we saved it to.
+
+ XXX - this is somewhat of a waste; we already have the
+ packets, all this gets us is updated file type information
+ (which we could just stuff into "cf"), and having the new
+ file be the one we have opened and from which we're reading
+ the data, and it means we have to spend time opening and
+ reading the file, which could be a significant amount of
+ time if the file is large. */
+ cf->user_saved = TRUE;
+
+ if ((err = open_cap_file(fname, FALSE, cf)) == 0) {
+ /* XXX - report errors if this fails? */
+ err = read_cap_file(cf);
+ set_menu_sensitivity("/File/Save", FALSE);
+ }
+ }
+ }
+ return err;
}
char *
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_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_ENCAP:
+ case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED:
+ /* Seen only when opening a capture file for writing. */
+ errmsg = "Ethereal cannot save this capture in that format.";
+ break;
+
case WTAP_ERR_BAD_RECORD:
errmsg = "The file \"%s\" appears to be damaged or corrupt.";
break;
" in the middle of a packet.";
break;
+ case WTAP_ERR_SHORT_WRITE:
+ errmsg = "A full header couldn't be written to the file \"%s\".";
+ break;
+
case ENOENT:
if (for_writing)
errmsg = "The path to the file \"%s\" does not exist.";
return errmsg;
}
+static char *
+file_rename_error_message(int err)
+{
+ char *errmsg;
+ static char errmsg_errno[1024+1];
+
+ switch (err) {
+
+ case ENOENT:
+ errmsg = "The path to the file \"%s\" does not exist.";
+ break;
+
+ case EACCES:
+ errmsg = "You do not have permission to move the capture file to \"%s\".";
+ break;
+
+ default:
+ sprintf(errmsg_errno, "The file \"%%s\" could not be moved: %s.",
+ wtap_strerror(err));
+ errmsg = errmsg_errno;
+ break;
+ }
+ return errmsg;
+}
+
char *
file_read_error_message(int err)
{
}
return errmsg;
}
+
+/* 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)
+{
+ char *errmsg;
+ static char errmsg_errno[1024+1];
+
+ switch (err) {
+
+ case WTAP_ERR_CANT_CLOSE:
+ errmsg = "The file \"%s\" couldn't be closed for some unknown reason.";
+ break;
+
+ case WTAP_ERR_SHORT_WRITE:
+ errmsg = "Not all the data could be written to the file \"%s\".";
+ break;
+
+ case ENOSPC:
+ errmsg = "The file \"%s\" could not be saved because there is no space left on the file system.";
+ 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
+
+ default:
+ sprintf(errmsg_errno, "An error occurred while closing the file \"%%s\": %s.",
+ wtap_strerror(err));
+ errmsg = errmsg_errno;
+ break;
+ }
+ return errmsg;
+}