Allow the user to save either all of the current capture, or only the

packets that are currently being displayed from that capture.

Centralize the code to control whether "File:Save" and "File:Save As"
are enabled (and *always* have "File:Save As" enabled if you have a
capture; "File:Save" is enabled only if you have a live capture you've
not yet saved, although it does the same thing as "File:Save As").

Have the "save_file" member of a "capture_file" structure represent
*only* the file currently being *written* to by a capture, and, if there
is no capture currently in progress, have it be NULL; the name of the
file currently being *displayed" is in the "filename" member, and an
"is_tempfile" member indicates whether it's a temporary file for a live
capture or not.

Have "close_cap_file()" delete the current capture file if it's a
temporary capture file that hasn't been saved (in its entirety - saving
selected frames doesn't count).  Do the same (if there *is* a current
capture file) when exiting.

The "Ready to load or capture" message is the only statusbar message in
the "main" context; "close_cap_file()" should never pop it, it should
only pop whatever message exists in the "file" context, and thus has no
need to take, as an argument, the context for the message it should pop.

Update the man page to reflect the new behavior of "File:Save" and
"File:Save As", and to reflect recent changes to "Display:Match Selected".

svn path=/trunk/; revision=1170
This commit is contained in:
Guy Harris 1999-11-30 20:50:15 +00:00
parent 191f4cd467
commit dc548e7458
6 changed files with 465 additions and 184 deletions

View File

@ -1,7 +1,7 @@
/* capture.c
* Routines for packet capture windows
*
* $Id: capture.c,v 1.83 1999/11/29 01:54:00 guy Exp $
* $Id: capture.c,v 1.84 1999/11/30 20:49:45 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@ -120,7 +120,7 @@ void
do_capture(char *capfile_name)
{
char tmpname[128+1];
gboolean is_temp_file;
gboolean is_tempfile;
u_char c;
int i;
guint byte_count;
@ -131,12 +131,12 @@ do_capture(char *capfile_name)
if (capfile_name != NULL) {
/* Try to open/create the specified file for use as a capture buffer. */
cf.save_file_fd = open(capfile_name, O_RDWR|O_TRUNC|O_CREAT, 0600);
is_temp_file = FALSE;
is_tempfile = FALSE;
} else {
/* Choose a random name for the capture buffer */
cf.save_file_fd = create_tempfile(tmpname, sizeof tmpname, "ether");
capfile_name = g_strdup(tmpname);
is_temp_file = TRUE;
is_tempfile = TRUE;
}
if (cf.save_file_fd == -1) {
simple_dialog(ESD_TYPE_WARN, NULL,
@ -144,15 +144,9 @@ do_capture(char *capfile_name)
"could not be opened: %s.", capfile_name, strerror(errno));
return;
}
close_cap_file(&cf, info_bar, file_ctx);
if (cf.save_file != NULL) {
/* If the current file is a temporary capture file, remove it. */
if (!cf.user_saved)
unlink(cf.save_file); /* silently ignore error */
g_free(cf.save_file);
}
close_cap_file(&cf, info_bar);
g_assert(cf.save_file == NULL);
cf.save_file = capfile_name;
cf.user_saved = !is_temp_file;
if (sync_mode) { /* use fork() for capture */
int fork_child;
@ -192,7 +186,6 @@ do_capture(char *capfile_name)
} else {
/* Parent process - read messages from the child process over the
sync pipe. */
cf.filename = cf.save_file;
close(sync_pipe[1]);
/* Read a byte count from "sync_pipe[0]", terminated with a
@ -210,6 +203,7 @@ do_capture(char *capfile_name)
XXX - reap the child process and report the status in detail. */
close(sync_pipe[0]);
unlink(cf.save_file);
g_free(cf.save_file);
cf.save_file = NULL;
simple_dialog(ESD_TYPE_WARN, NULL, "Capture child process died");
return;
@ -222,6 +216,7 @@ do_capture(char *capfile_name)
and report the failure. */
close(sync_pipe[0]);
unlink(cf.save_file);
g_free(cf.save_file);
cf.save_file = NULL;
simple_dialog(ESD_TYPE_WARN, NULL,
"Capture child process sent us a bad message");
@ -231,7 +226,7 @@ do_capture(char *capfile_name)
}
if (byte_count == 0) {
/* Success. Open the capture file, and set up to read it. */
err = start_tail_cap_file(cf.save_file, &cf);
err = start_tail_cap_file(cf.save_file, is_tempfile, &cf);
if (err == 0) {
/* We were able to open and set up to read the capture file;
arrange that our callback be called whenever it's possible
@ -254,6 +249,7 @@ do_capture(char *capfile_name)
/* Don't unlink the save file - leave it around, for debugging
purposes. */
g_free(cf.save_file);
cf.save_file = NULL;
}
} else {
@ -281,6 +277,7 @@ do_capture(char *capfile_name)
/* Get rid of the save file - the capture never started. */
unlink(cf.save_file);
g_free(cf.save_file);
cf.save_file = NULL;
}
}
@ -294,14 +291,16 @@ do_capture(char *capfile_name)
}
if (capture_succeeded) {
/* Capture succeeded; read in the capture file. */
if ((err = open_cap_file(cf.save_file, &cf)) == 0) {
if ((err = open_cap_file(cf.save_file, is_tempfile, &cf)) == 0) {
/* Set the read filter to NULL. */
cf.rfcode = NULL;
err = read_cap_file(&cf);
set_menu_sensitivity("/File/Save", TRUE);
set_menu_sensitivity("/File/Save As...", FALSE);
}
}
/* We're not doing a capture any more, so we don't have a save
file. */
g_free(cf.save_file);
cf.save_file = NULL;
}
}
@ -432,6 +431,12 @@ cap_file_input_cb(gpointer data, gint source, GdkInputCondition condition)
/* Read what remains of the capture file, and finish the capture.
XXX - do something if this fails? */
err = finish_tail_cap_file(cf);
/* We're not doing a capture any more, so we don't have a save
file. */
g_free(cf->save_file);
cf->save_file = NULL;
return;
}
@ -738,6 +743,8 @@ error:
/* We couldn't even start the capture, so get rid of the capture
file. */
unlink(cf.save_file); /* silently ignore error */
g_free(cf.save_file);
cf.save_file = NULL;
if (capture_child) {
/* This is the child process for a sync mode capture.
Send the error message to our parent, so they can display a

View File

@ -177,6 +177,12 @@ allows a filter to be specified; when the capture file is read, the
filter is applied to all packets read from the file, and packets not
matching the filter are discarded.
=item File:Save, File:Save As
Save the current capture, or the packets currently displayed from that
capture, to a file. A check box lets you select whether to save all
packets, or just those that have passed the current display filter.
=item File:Print
Prints, for all the packets in the current capture, the packet number,
@ -217,9 +223,12 @@ live capture is in progress.
=item Display:Match Selected
Creates and applies a display filter based on the data that is currently
highlighted in the protocol tree. The display filter is based on absolute
offset within the packet, so could be unreliable if the packet contains
protocols with variable-length headers, like source-routed token-ring.
highlighted in the protocol tree. If that data is a field that can be
tested in a display filter expression, the display filter will test that
field; otherwise, the display filter will be based on absolute offset
within the packet, and so could be unreliable if the packet contains
protocols with variable-length headers, such as a source-routed
token-ring packet.
=item Display:Colorize Display

424
file.c
View File

@ -1,7 +1,7 @@
/* file.c
* File I/O routines
*
* $Id: file.c,v 1.127 1999/11/30 07:27:36 guy Exp $
* $Id: file.c,v 1.128 1999/11/30 20:49:46 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@ -108,11 +108,15 @@ static void wtap_dispatch_cb(u_char *, const struct wtap_pkthdr *, int,
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;
@ -134,7 +138,7 @@ open_cap_file(char *fname, capture_file *cf) {
/* 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();
@ -147,11 +151,20 @@ open_cap_file(char *fname, capture_file *cf) {
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->first_packet = TRUE;
cf->count = 0;
cf->drops = 0;
cf->esec = 0;
@ -173,7 +186,8 @@ fail:
/* 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) {
@ -184,6 +198,17 @@ close_cap_file(capture_file *cf, void *w, guint context) {
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);
@ -196,10 +221,15 @@ close_cap_file(capture_file *cf, void *w, guint context) {
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);
/* Disable all menu items that make sense only if you have a capture. */
set_menu_sensitivity("/File/Save", FALSE);
@ -227,7 +257,7 @@ set_statusbar_filename(capture_file *cf)
gchar *done_fmt = " File: %s Drops: %u";
gchar *done_msg;
if (cf->user_saved || !cf->save_file) {
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)
@ -248,7 +278,8 @@ set_statusbar_filename(capture_file *cf)
}
int
read_cap_file(capture_file *cf) {
read_cap_file(capture_file *cf)
{
gchar *name_ptr, *load_msg, *load_fmt = " Loading: %s...";
int success;
int err;
@ -292,13 +323,17 @@ read_cap_file(capture_file *cf) {
gtk_progress_set_value(GTK_PROGRESS(prog_bar), 0);
gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
set_statusbar_filename(cf);
/* 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);
@ -343,13 +378,23 @@ read_cap_file(capture_file *cf) {
#ifdef HAVE_LIBPCAP
int
start_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);
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);
/* 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);
@ -358,7 +403,6 @@ start_tail_cap_file(char *fname, capture_file *cf) {
set_menu_sensitivity("/Tools/Follow TCP Stream", TRUE);
set_menu_sensitivity("/Tools/Graph", TRUE);
set_menu_sensitivity("/Tools/Summary", TRUE);
set_menu_sensitivity("/Capture/Start...", FALSE);
for (i = 0; i < cf->cinfo.num_cols; i++) {
if (get_column_resize_type(cf->cinfo.col_fmt[i]) == RESIZE_LIVE)
@ -417,6 +461,9 @@ finish_tail_cap_file(capture_file *cf)
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_statusbar_filename(cf);
/* Restore the "File/Open" menu item. */
@ -424,7 +471,8 @@ finish_tail_cap_file(capture_file *cf)
/* Enable menu items that make sense if you have a capture file
you've finished reading. */
set_menu_sensitivity("/File/Save", TRUE);
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);
@ -852,6 +900,19 @@ wtap_dispatch_cb(u_char *user, const struct wtap_pkthdr *phdr, int offset,
gtk_main_iteration();
}
if (cf->first_packet) {
/* Tentatively make the encapsulation type the type of the first
packet. */
cf->lnk_t = phdr->pkt_encap;
} else {
/* If this packet's encapsulation type isn't the same as the type
type we've chosen so far, make the type for this file
WTAP_ENCAP_PER_PACKET, because there is no single encapsulation
type for the entire file. */
if (cf->lnk_t != phdr->pkt_encap)
cf->lnk_t = WTAP_ENCAP_PER_PACKET;
}
/* Allocate the next list entry, and add it to the list. */
fdata = (frame_data *) g_malloc(sizeof(frame_data));
@ -1509,92 +1570,201 @@ thaw_clist(capture_file *cf)
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)
{
gchar *from_filename;
gchar *name_ptr, *save_msg, *save_fmt = " Saving: %s...";
gchar *err_fmt = " Error: Could not save to '%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];
#define COPY_BUFFER_SIZE 8192
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);
int retval;
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. */
#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
/* 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
}
} else {
/* It's a permanent file, so we should copy it, and not remove the
original. */
do_copy = TRUE;
from_filename = cf->filename;
}
unlink(from);
return 1;
}
/* 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;
}
/* Copies a file.
* Returns 0 on failure to do either, 1 on success of either
*/
int
file_cp(char *from, char *to)
{
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;
}
#define COPY_BUFFER_SIZE 8192
int from_fd, to_fd, nread, nwritten;
char *buffer;
buffer = g_malloc(COPY_BUFFER_SIZE);
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;
}
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;
}
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;
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;
}
return 1;
/* 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;
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;
}
}
}
if (!wtap_dump_close(pdh, &err)) {
simple_dialog(ESD_TYPE_WARN, NULL,
file_close_error_message(err), fname);
goto done;
}
}
done:
/* 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);
}
}
} else {
msg_len = strlen(name_ptr) + strlen(err_fmt) + 2;
save_msg = g_malloc(msg_len);
snprintf(save_msg, msg_len, err_fmt, name_ptr);
gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, save_msg);
g_free(save_msg);
}
return err;
}
char *
@ -1611,9 +1781,21 @@ file_open_error_message(int err, int for_writing)
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;
@ -1630,6 +1812,10 @@ file_open_error_message(int err, int for_writing)
" 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.";
@ -1653,6 +1839,31 @@ file_open_error_message(int err, int for_writing)
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)
{
@ -1689,3 +1900,42 @@ file_write_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;
}

14
file.h
View File

@ -1,7 +1,7 @@
/* file.h
* Definitions for file structures and routines
*
* $Id: file.h,v 1.57 1999/11/30 07:27:37 guy Exp $
* $Id: file.h,v 1.58 1999/11/30 20:49:47 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@ -77,9 +77,13 @@ typedef struct _capture_file {
FILE_T fh; /* File handle for capture file */
int filed; /* File descriptor of capture file */
gchar *filename; /* Name of capture file */
gboolean is_tempfile; /* Is capture file a temporary file? */
gboolean user_saved;/* If capture file is temporary, has it been saved by user yet? */
long f_len; /* Length of capture file */
guint16 cd_t; /* File type of capture file */
const gchar *cd_t_desc; /* Description of that file type */
gboolean first_packet; /* TRUE if we're looking at the first packet */
int lnk_t; /* Link-layer type with which to save capture */
guint32 vers; /* Version. For tcpdump minor is appended to major */
guint32 count; /* Packet count */
gfloat unfiltered_count; /* used for dfilter progress bar */
@ -93,7 +97,6 @@ typedef struct _capture_file {
gchar *iface; /* Interface */
gchar *save_file; /* File that user saved capture to */
int save_file_fd; /* File descriptor for saved file */
gint user_saved;/* Was capture file saved by user yet? */
wtap *wth; /* Wiretap session */
dfilter *rfcode; /* Compiled read filter program */
gchar *dfilter; /* Display filter string */
@ -118,13 +121,14 @@ typedef struct _capture_file {
FILE *print_fh; /* File we're printing to */
} capture_file;
int open_cap_file(char *, capture_file *);
void close_cap_file(capture_file *, void *, guint);
int open_cap_file(char *, gboolean, capture_file *);
void close_cap_file(capture_file *, void *);
int read_cap_file(capture_file *);
int start_tail_cap_file(char *, capture_file *);
int start_tail_cap_file(char *, gboolean, capture_file *);
int continue_tail_cap_file(capture_file *, int);
int finish_tail_cap_file(capture_file *);
/* size_t read_frame_header(capture_file *); */
int save_cap_file(char *, capture_file *, gboolean, guint);
int filter_packets(capture_file *cf, gchar *dfilter);
void colorize_packets(capture_file *);

View File

@ -1,7 +1,7 @@
/* file_dlg.c
* Dialog boxes for handling files
*
* $Id: file_dlg.c,v 1.11 1999/10/20 22:36:05 gram Exp $
* $Id: file_dlg.c,v 1.12 1999/11/30 20:50:14 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@ -64,8 +64,9 @@
#include "main.h"
#endif
#define FILTER_CB_KEY "filter_check_button"
static void file_open_ok_cb(GtkWidget *w, GtkFileSelection *fs);
static void file_save_ok_cb(GtkWidget *w, GtkFileSelection *fs);
static void file_save_as_ok_cb(GtkWidget *w, GtkFileSelection *fs);
/* Open a file */
@ -130,7 +131,7 @@ file_open_ok_cb(GtkWidget *w, GtkFileSelection *fs) {
}
/* Try to open the capture file. */
if ((err = open_cap_file(cf_name, &cf)) != 0) {
if ((err = open_cap_file(cf_name, FALSE, &cf)) != 0) {
/* We couldn't open it; don't dismiss the open dialog box,
just leave it around so that the user can, after they
dismiss the alert box popped up for the open error,
@ -166,44 +167,46 @@ file_open_ok_cb(GtkWidget *w, GtkFileSelection *fs) {
else {
last_open_dir = NULL;
}
set_menu_sensitivity("/File/Save", FALSE);
set_menu_sensitivity("/File/Save As...", TRUE);
g_free(cf_name);
}
/* Close a file */
void
file_close_cmd_cb(GtkWidget *widget, gpointer data) {
close_cap_file(&cf, info_bar, file_ctx);
close_cap_file(&cf, info_bar);
}
void
file_save_cmd_cb(GtkWidget *w, gpointer data) {
file_sel = gtk_file_selection_new ("Ethereal: Save Capture File");
/* Connect the ok_button to file_save_ok_cb function and pass along a
pointer to the file selection box widget */
gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button),
"clicked", (GtkSignalFunc) file_save_ok_cb, file_sel );
/* Connect the cancel_button to destroy the widget */
gtk_signal_connect_object(GTK_OBJECT (GTK_FILE_SELECTION
(file_sel)->cancel_button), "clicked", (GtkSignalFunc)
gtk_widget_destroy, GTK_OBJECT (file_sel));
/* If the file's already been saved, do nothing. */
if (cf.user_saved)
return;
gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_sel), "");
gtk_widget_show(file_sel);
/* Do a "Save As". */
file_save_as_cmd_cb(w, data);
}
void
file_save_as_cmd_cb(GtkWidget *w, gpointer data) {
GtkWidget *ok_bt, *filter_cb;
file_sel = gtk_file_selection_new ("Ethereal: Save Capture File As");
/* Connect the ok_button to file_save_as_ok_cb function and pass along a
pointer to the file selection box widget */
gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button),
"clicked", (GtkSignalFunc) file_save_as_ok_cb, file_sel );
ok_bt = GTK_FILE_SELECTION (file_sel)->ok_button;
gtk_signal_connect (GTK_OBJECT (ok_bt), "clicked",
(GtkSignalFunc) file_save_as_ok_cb, file_sel );
filter_cb = gtk_check_button_new_with_label("Save only packets currently being displayed");
gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(filter_cb), FALSE);
gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(file_sel)->action_area),
filter_cb, FALSE, FALSE, 0);
gtk_widget_show(filter_cb);
gtk_object_set_data(GTK_OBJECT(ok_bt), FILTER_CB_KEY, filter_cb);
/* Connect the cancel_button to destroy the widget */
gtk_signal_connect_object(GTK_OBJECT (GTK_FILE_SELECTION
@ -214,46 +217,27 @@ file_save_as_cmd_cb(GtkWidget *w, gpointer data) {
gtk_widget_show(file_sel);
}
static void
file_save_ok_cb(GtkWidget *w, GtkFileSelection *fs) {
gchar *cf_name;
int err;
cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
gtk_widget_hide(GTK_WIDGET (fs));
gtk_widget_destroy(GTK_WIDGET (fs));
if (!file_mv(cf.save_file, cf_name))
return;
g_free(cf.save_file);
cf.save_file = g_strdup(cf_name);
cf.user_saved = 1;
if ((err = open_cap_file(cf_name, &cf)) == 0) {
err = read_cap_file(&cf);
set_menu_sensitivity("/File/Save", FALSE);
set_menu_sensitivity("/File/Save As...", TRUE);
}
}
static void
file_save_as_ok_cb(GtkWidget *w, GtkFileSelection *fs) {
gchar *cf_name;
int err;
gchar *cf_name;
GtkWidget *button;
gboolean filtered;
cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
gtk_widget_hide(GTK_WIDGET (fs));
gtk_widget_destroy(GTK_WIDGET (fs));
if (!file_cp(cf.filename, cf_name))
return;
g_free(cf.filename);
cf.filename = g_strdup(cf_name);
cf.user_saved = 1;
if ((err = open_cap_file(cf.filename, &cf)) == 0) {
err = read_cap_file(&cf);
set_menu_sensitivity("/File/Save", FALSE);
set_menu_sensitivity("/File/Save As...", TRUE);
}
cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
gtk_widget_hide(GTK_WIDGET (fs));
gtk_widget_destroy(GTK_WIDGET (fs));
button = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(w),
FILTER_CB_KEY);
filtered = GTK_TOGGLE_BUTTON (button)->active;
/* Write out the packets (all, or only the ones that are currently
displayed) to the file with the specified name. */
save_cap_file(cf_name, &cf, filtered, WTAP_FILE_PCAP);
/* If "save_cap_file()" saved the file name we handed it, it saved
a copy, so we should free up our copy. */
g_free(cf_name);
}
/* Reload a file using the current read and display filters */
@ -261,13 +245,40 @@ void
file_reload_cmd_cb(GtkWidget *w, gpointer data) {
/*GtkWidget *filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);*/
GtkWidget *filter_te;
gchar *filename;
gboolean is_tempfile;
filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
if (cf.dfilter) g_free(cf.dfilter);
if (cf.dfilter)
g_free(cf.dfilter);
cf.dfilter = g_strdup(gtk_entry_get_text(GTK_ENTRY(filter_te)));
if (open_cap_file(cf.filename, &cf) == 0)
read_cap_file(&cf);
/* XXX - change the menu if the open fails? */
}
/* If the file could be opened, "open_cap_file()" calls "close_cap_file()"
to get rid of state for the old capture file before filling in state
for the new capture file. "close_cap_file()" 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, "close_cap_file()" will free "cf.filename", so we must make
a copy of it first. */
filename = strdup(cf.filename);
is_tempfile = cf.is_tempfile;
cf.is_tempfile = FALSE;
if (open_cap_file(filename, is_tempfile, &cf) == 0)
read_cap_file(&cf);
else {
/* The open failed, so "cf.is_tempfile" wasn't set to "is_tempfile".
Instead, the file was left open, so we should restore "cf.is_tempfile"
ourselves.
XXX - change the menu? Presumably "open_cap_file()" will do that;
make sure it does! */
cf.is_tempfile = is_tempfile;
}
/* "open_cap_file()" made a copy of the file name we handed it, so
we should free up our copy. */
g_free(filename);
}

View File

@ -1,6 +1,6 @@
/* main.c
*
* $Id: main.c,v 1.56 1999/11/30 05:33:05 guy Exp $
* $Id: main.c,v 1.57 1999/11/30 20:50:15 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@ -796,11 +796,10 @@ void expand_all_cb(GtkWidget *widget, gpointer data) {
void
file_quit_cmd_cb (GtkWidget *widget, gpointer data) {
/* If we have a save file, and it's a temporary file (i.e., the user
hasn't explicitly saved it), delete it. */
if (cf.save_file && !cf.user_saved) {
unlink(cf.save_file);
}
/* If we have a capture file open, and it's a temporary file,
unlink it. */
if (cf.filename != NULL && cf.is_tempfile)
unlink(cf.filename);
gtk_exit(0);
}
@ -922,6 +921,9 @@ main(int argc, char *argv[])
cf.plist_end = NULL;
cf.wth = NULL;
cf.fh = NULL;
cf.filename = NULL;
cf.user_saved = FALSE;
cf.is_tempfile = FALSE;
cf.rfcode = NULL;
cf.dfilter = NULL;
cf.dfcode = NULL;
@ -931,7 +933,6 @@ main(int argc, char *argv[])
cf.iface = NULL;
cf.save_file = NULL;
cf.save_file_fd = -1;
cf.user_saved = 0;
cf.snap = WTAP_MAX_PACKET_SIZE;
cf.count = 0;
cf.cinfo.num_cols = prefs->num_cols;
@ -1029,7 +1030,7 @@ main(int argc, char *argv[])
break;
#endif
case 'r': /* Read capture file xxx */
cf_name = g_strdup(optarg);
cf_name = optarg;
break;
case 'R': /* Read file filter */
rfilter = optarg;
@ -1326,7 +1327,7 @@ main(int argc, char *argv[])
}
}
if (!rfilter_parse_failed) {
if ((err = open_cap_file(cf_name, &cf)) == 0) {
if ((err = open_cap_file(cf_name, FALSE, &cf)) == 0) {
/* "open_cap_file()" succeeded, so it closed the previous
capture file, and thus destroyed any previous read filter
attached to "cf". */
@ -1337,7 +1338,6 @@ main(int argc, char *argv[])
last_open_dir = cf_name;
*s = '\0';
}
set_menu_sensitivity("/File/Save As...", TRUE);
} else {
dfilter_destroy(rfcode);
cf.rfcode = NULL;