aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2012-06-05 02:46:54 +0000
committerGuy Harris <guy@alum.mit.edu>2012-06-05 02:46:54 +0000
commit99536cc8da7a484a30863880c475f2e3dd09fd38 (patch)
treec370be6d3442a63888d486f241b0cf5dd754a9ac
parent7186d034f074cb32ad633762db09784ded1dd262 (diff)
Distinguish between "failed" and "user stopped it" for "save as" and
"export specified packets". For "failed", let the user try again with a different file, in case it failed due to, for example, running out of space or quota (probably the most likely failure mode for writing, and trying to a different volume might be the best workaround). For "user stopped it", presumably they don't want to try again (the most likely reason is "it was taking too damn long"). Put "Exporting to: ...", not "Saving: ..." in the statusbar if we're doing "export specified packets". In process_specified_packets(), allow a null range pointer to be specified, meaning "save 'em all"; that avoids the possibly-expensive (with a large capture) operation of initializing the range. If a "safe save" atop an existing file fails or is stopped, get rid of the temporary file we created. svn path=/trunk/; revision=43095
-rw-r--r--file.c69
-rw-r--r--file.h33
-rw-r--r--ui/gtk/capture_file_dlg.c139
-rw-r--r--ui/gtk/main.c15
-rw-r--r--ui/gtk/main_statusbar.c50
5 files changed, 223 insertions, 83 deletions
diff --git a/file.c b/file.c
index 6646e3abc8..325a21a189 100644
--- a/file.c
+++ b/file.c
@@ -2087,7 +2087,8 @@ process_specified_packets(capture_file *cf, packet_range_t *range,
progbar_stop_flag = FALSE;
g_get_current_time(&progbar_start_time);
- packet_range_process_init(range);
+ if (range != NULL)
+ packet_range_process_init(range);
/* Iterate through all the packets, printing the packets that
were selected by the current display filter. */
@@ -2137,14 +2138,16 @@ process_specified_packets(capture_file *cf, packet_range_t *range,
progbar_count++;
- /* do we have to process this packet? */
- process_this = packet_range_process_packet(range, fdata);
- if (process_this == range_process_next) {
+ if (range != NULL) {
+ /* do we have to process this packet? */
+ process_this = packet_range_process_packet(range, fdata);
+ if (process_this == range_process_next) {
/* this packet uninteresting, continue with next one */
continue;
- } else if (process_this == range_processing_finished) {
+ } else if (process_this == range_processing_finished) {
/* all interesting packets processed, stop the loop */
break;
+ }
}
/* Get the packet */
@@ -3817,7 +3820,7 @@ cf_can_save_as(capture_file *cf)
return FALSE;
}
-cf_status_t
+cf_write_status_t
cf_save_packets(capture_file *cf, const char *fname, guint save_format,
gboolean compressed, gboolean dont_reopen)
{
@@ -3825,7 +3828,6 @@ cf_save_packets(capture_file *cf, const char *fname, guint save_format,
int err;
gboolean do_copy;
wtap_dumper *pdh;
- packet_range_t range;
save_callback_args_t callback_args;
cf_callback_invoke(cf_cb_file_save_started, (gpointer)fname);
@@ -3943,15 +3945,11 @@ cf_save_packets(capture_file *cf, const char *fname, guint save_format,
/* Add address resolution */
wtap_dump_set_addrinfo_list(pdh, get_addrinfo_list());
- /* Create a packet range that's set to the default "save everything"
- state. */
- packet_range_init(&range);
-
/* Iterate through the list of packets, processing all the packets. */
callback_args.pdh = pdh;
callback_args.fname = fname;
callback_args.file_type = save_format;
- switch (process_specified_packets(cf, &range, "Saving", "selected packets",
+ switch (process_specified_packets(cf, NULL, "Saving", "packets",
TRUE, save_packet, &callback_args)) {
case PSP_FINISHED:
@@ -3960,11 +3958,20 @@ cf_save_packets(capture_file *cf, const char *fname, guint save_format,
case PSP_STOPPED:
/* The user decided to abort the saving.
- XXX - remove the output file? */
- break;
+ If we're writing to a temporary file, remove it.
+ XXX - should we do so even if we're not writing to a
+ temporary file? */
+ wtap_dump_close(pdh, &err);
+ if (fname_new != NULL)
+ ws_unlink(fname_new);
+ cf_callback_invoke(cf_cb_file_save_stopped, NULL);
+ return CF_WRITE_ABORTED;
case PSP_FAILED:
- /* Error while saving. */
+ /* Error while saving.
+ If we're writing to a temporary file, remove it. */
+ if (fname_new != NULL)
+ ws_unlink(fname_new);
wtap_dump_close(pdh, &err);
goto fail;
}
@@ -4043,7 +4050,7 @@ cf_save_packets(capture_file *cf, const char *fname, guint save_format,
}
}
}
- return CF_OK;
+ return CF_WRITE_OK;
fail:
if (fname_new != NULL) {
@@ -4057,10 +4064,10 @@ fail:
g_free(fname_new);
}
cf_callback_invoke(cf_cb_file_save_failed, NULL);
- return CF_ERROR;
+ return CF_WRITE_ERROR;
}
-cf_status_t
+cf_write_status_t
cf_export_specified_packets(capture_file *cf, const char *fname,
packet_range_t *range, guint save_format,
gboolean compressed)
@@ -4072,7 +4079,7 @@ cf_export_specified_packets(capture_file *cf, const char *fname,
wtapng_section_t *shb_hdr = NULL;
wtapng_iface_descriptions_t *idb_inf = NULL;
- cf_callback_invoke(cf_cb_file_save_started, (gpointer)fname);
+ cf_callback_invoke(cf_cb_file_export_specified_packets_started, (gpointer)fname);
packet_range_process_init(range);
@@ -4128,12 +4135,22 @@ cf_export_specified_packets(capture_file *cf, const char *fname,
break;
case PSP_STOPPED:
- /* The user decided to abort the writing.
- XXX - remove the output file? */
+ /* The user decided to abort the saving.
+ If we're writing to a temporary file, remove it.
+ XXX - should we do so even if we're not writing to a
+ temporary file? */
+ wtap_dump_close(pdh, &err);
+ if (fname_new != NULL)
+ ws_unlink(fname_new);
+ cf_callback_invoke(cf_cb_file_export_specified_packets_stopped, NULL);
+ return CF_WRITE_ABORTED;
break;
case PSP_FAILED:
- /* Error while writing. */
+ /* Error while saving.
+ If we're writing to a temporary file, remove it. */
+ if (fname_new != NULL)
+ ws_unlink(fname_new);
wtap_dump_close(pdh, &err);
goto fail;
}
@@ -4155,8 +4172,8 @@ cf_export_specified_packets(capture_file *cf, const char *fname,
}
}
- cf_callback_invoke(cf_cb_file_save_finished, NULL);
- return CF_OK;
+ cf_callback_invoke(cf_cb_file_export_specified_packets_finished, NULL);
+ return CF_WRITE_OK;
fail:
if (fname_new != NULL) {
@@ -4169,8 +4186,8 @@ fail:
ws_unlink(fname_new);
g_free(fname_new);
}
- cf_callback_invoke(cf_cb_file_save_failed, NULL);
- return CF_ERROR;
+ cf_callback_invoke(cf_cb_file_export_specified_packets_failed, NULL);
+ return CF_WRITE_ERROR;
}
static void
diff --git a/file.h b/file.h
index e3b9acff0e..b40a642d91 100644
--- a/file.h
+++ b/file.h
@@ -51,6 +51,13 @@ typedef enum {
CF_READ_ABORTED /**< operation aborted by user */
} cf_read_status_t;
+/** Return values from functions that write out packets. */
+typedef enum {
+ CF_WRITE_OK, /**< operation succeeded */
+ CF_WRITE_ERROR, /**< operation got an error (function may provide err with details) */
+ CF_WRITE_ABORTED, /**< operation aborted by user */
+} cf_write_status_t;
+
/** Return values from functions that print sets of packets. */
typedef enum {
CF_PRINT_OK, /**< print operation succeeded */
@@ -70,7 +77,12 @@ typedef enum {
cf_cb_field_unselected,
cf_cb_file_save_started,
cf_cb_file_save_finished,
- cf_cb_file_save_failed
+ cf_cb_file_save_failed,
+ cf_cb_file_save_stopped,
+ cf_cb_file_export_specified_packets_started,
+ cf_cb_file_export_specified_packets_finished,
+ cf_cb_file_export_specified_packets_failed,
+ cf_cb_file_export_specified_packets_stopped
} cf_cbs;
typedef void (*cf_callback_t) (gint event, gpointer data, gpointer user_data);
@@ -208,11 +220,11 @@ gboolean cf_can_save_as(capture_file *cf);
* @param compressed whether to gzip compress the file
* @param dont_reopen TRUE if it shouldn't reopen and make that file the
* current capture file
- * @return one of cf_status_t
+ * @return one of cf_write_status_t
*/
-cf_status_t cf_save_packets(capture_file * cf, const char *fname,
- guint save_format, gboolean compressed,
- gboolean dont_reopen);
+cf_write_status_t cf_save_packets(capture_file * cf, const char *fname,
+ guint save_format, gboolean compressed,
+ gboolean dont_reopen);
/**
* Export some or all packets from a capture file to a new file. If there's
@@ -226,12 +238,13 @@ cf_status_t cf_save_packets(capture_file * cf, const char *fname,
* @param range the range of packets to write
* @param save_format the format of the file to write (libpcap, ...)
* @param compressed whether to gzip compress the file
- * @return one of cf_status_t
+ * @return one of cf_write_status_t
*/
-cf_status_t cf_export_specified_packets(capture_file *cf, const char *fname,
- packet_range_t *range,
- guint save_format,
- gboolean compressed);
+cf_write_status_t cf_export_specified_packets(capture_file *cf,
+ const char *fname,
+ packet_range_t *range,
+ guint save_format,
+ gboolean compressed);
/**
* Get a displayable name of the capture file.
diff --git a/ui/gtk/capture_file_dlg.c b/ui/gtk/capture_file_dlg.c
index 0ab1ae7dea..6392412c56 100644
--- a/ui/gtk/capture_file_dlg.c
+++ b/ui/gtk/capture_file_dlg.c
@@ -78,9 +78,9 @@
static void do_file_save(capture_file *cf, gboolean dont_reopen);
static void do_file_save_as(capture_file *cf);
-static void file_save_as_cb(GtkWidget *fs);
+static cf_write_status_t file_save_as_cb(GtkWidget *fs);
static void file_select_file_type_cb(GtkWidget *w, gpointer data);
-static void file_export_specified_packets_cb(GtkWidget *fs, packet_range_t *range);
+static cf_write_status_t file_export_specified_packets_cb(GtkWidget *fs, packet_range_t *range);
static void set_file_type_list(GtkWidget *combo_box, capture_file *cf);
#define E_FILE_TYPE_COMBO_BOX_KEY "file_type_combo_box"
@@ -1312,10 +1312,22 @@ do_file_save_as(capture_file *cf)
continue;
}
- /* save file */
+ /* Attempt to save the file */
g_free(cf_name);
- file_save_as_cb(file_save_as_w);
- return;
+ switch (file_save_as_cb(file_save_as_w)) {
+
+ case CF_WRITE_OK:
+ /* The save succeeded; we're done. */
+ return;
+
+ case CF_WRITE_ERROR:
+ /* The save failed; let the user try again */
+ continue;
+
+ case CF_WRITE_ABORTED:
+ /* The user aborted the save; just return. */
+ return;
+ }
}
#endif /* _WIN32 */
}
@@ -1328,8 +1340,9 @@ file_save_as_cmd_cb(GtkWidget *w _U_, gpointer data _U_)
/* all tests ok, we only have to save the file */
/* (and probably continue with a pending operation) */
-static void
-file_save_as_cb(GtkWidget *fs) {
+static cf_write_status_t
+file_save_as_cb(GtkWidget *fs)
+{
GtkWidget *ft_combo_box;
GtkWidget *compressed_cb;
gchar *cf_name;
@@ -1337,6 +1350,7 @@ file_save_as_cb(GtkWidget *fs) {
gpointer ptr;
int file_type;
gboolean compressed;
+ cf_write_status_t status;
/* Hide the file chooser while doing the save. */
gtk_widget_hide(fs);
@@ -1353,26 +1367,34 @@ file_save_as_cb(GtkWidget *fs) {
compressed = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(compressed_cb));
/* Write out all the packets to the file with the specified name. */
- if (cf_save_packets(&cfile, cf_name, file_type, compressed, FALSE) != CF_OK) {
- /* The write failed; don't dismiss the open dialog box,
- just leave it around so that the user can, after they
- dismiss the alert box popped up for the error, try again. */
- g_free(cf_name);
- /* XXX - as we cannot start a new event loop (using gtk_dialog_run()),
- * as this will prevent the user from closing the now existing error
- * message, simply close the dialog (this is the best we can do here). */
+ status = cf_save_packets(&cfile, cf_name, file_type, compressed, FALSE);
+ switch (status) {
+
+ case CF_WRITE_OK:
+ /* The write succeeded; get rid of the file selection box. */
+ /* cf_save_packets() might already closed our dialog! */
window_destroy(fs);
- return;
- }
- /* The write succeeded; get rid of the file selection box. */
- /* cf_save_packets() might already closed our dialog! */
- window_destroy(fs);
+ /* Save the directory name for future file dialogs. */
+ dirname = get_dirname(cf_name); /* Overwrites cf_name */
+ set_last_open_dir(dirname);
+ break;
+
+ case CF_WRITE_ERROR:
+ /* The write failed.
+ just leave the file selection box around so that the user can,
+ after they dismiss the alert box popped up for the error, try
+ again. */
+ break;
- /* Save the directory name for future file dialogs. */
- dirname = get_dirname(cf_name); /* Overwrites cf_name */
- set_last_open_dir(dirname);
+ case CF_WRITE_ABORTED:
+ /* The write was aborted; just get rid of the file selection
+ box and return. */
+ window_destroy(fs);
+ break;
+ }
g_free(cf_name);
+ return status;
}
void
@@ -1514,18 +1536,32 @@ file_export_specified_packets_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
continue;
}
- /* export packets */
+ /* attempt to export the packets */
g_free(cf_name);
- file_export_specified_packets_cb(file_export_specified_packets_w, &range);
- return;
+ switch (file_export_specified_packets_cb(file_export_specified_packets_w,
+ &range)) {
+
+ case CF_WRITE_OK:
+ /* The save succeeded; we're done. */
+ return;
+
+ case CF_WRITE_ERROR:
+ /* The save failed; let the user try again */
+ continue;
+
+ case CF_WRITE_ABORTED:
+ /* The user aborted the save; just return. */
+ return;
+ }
}
#endif /* _WIN32 */
}
/* all tests ok, we only have to write out the packets */
/* (and probably continue with a pending operation) */
-static void
-file_export_specified_packets_cb(GtkWidget *fs, packet_range_t *range) {
+static cf_write_status_t
+file_export_specified_packets_cb(GtkWidget *fs, packet_range_t *range)
+{
GtkWidget *ft_combo_box;
GtkWidget *compressed_cb;
gchar *cf_name;
@@ -1533,6 +1569,7 @@ file_export_specified_packets_cb(GtkWidget *fs, packet_range_t *range) {
gpointer ptr;
int file_type;
gboolean compressed;
+ cf_write_status_t status;
/* Hide the file chooser while we're doing the export. */
gtk_widget_hide(fs);
@@ -1549,29 +1586,37 @@ file_export_specified_packets_cb(GtkWidget *fs, packet_range_t *range) {
compressed = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(compressed_cb));
/* Write out the specified packets to the file with the specified name. */
- if (cf_export_specified_packets(&cfile, cf_name, range, file_type,
- compressed) != CF_OK) {
- /* The write failed; don't dismiss the open dialog box,
- just leave it around so that the user can, after they
- dismiss the alert box popped up for the error, try again. */
- g_free(cf_name);
- /* XXX - as we cannot start a new event loop (using gtk_dialog_run()),
- * as this will prevent the user from closing the now existing error
- * message, simply close the dialog (this is the best we can do here). */
+ status = cf_export_specified_packets(&cfile, cf_name, range, file_type,
+ compressed);
+ switch (status) {
+
+ case CF_WRITE_OK:
+ /* The write succeeded; get rid of the file selection box. */
+ /* cf_export_specified_packets() might already closed our dialog! */
window_destroy(GTK_WIDGET(fs));
- return;
- }
- /* The write succeeded; get rid of the file selection box. */
- /* cf_export_specified_packets() might already closed our dialog! */
- window_destroy(GTK_WIDGET(fs));
+ /* Save the directory name for future file dialogs.
+ XXX - should there be separate ones for "Save As" and
+ "Export Specified Packets"? */
+ dirname = get_dirname(cf_name); /* Overwrites cf_name */
+ set_last_open_dir(dirname);
+ break;
- /* Save the directory name for future file dialogs.
- XXX - should there be separate ones for "Save As" and
- "Export Specified Packets"? */
- dirname = get_dirname(cf_name); /* Overwrites cf_name */
- set_last_open_dir(dirname);
+ case CF_WRITE_ERROR:
+ /* The write failed.
+ just leave the file selection box around so that the user can,
+ after they dismiss the alert box popped up for the error, try
+ again. */
+ break;
+
+ case CF_WRITE_ABORTED:
+ /* The write was aborted; just get rid of the file selection
+ box and return. */
+ window_destroy(fs);
+ break;
+ }
g_free(cf_name);
+ return status;
}
/* Reload a file using the current read and display filters */
diff --git a/ui/gtk/main.c b/ui/gtk/main.c
index e40b91eb39..2c38529ab1 100644
--- a/ui/gtk/main.c
+++ b/ui/gtk/main.c
@@ -1765,6 +1765,21 @@ main_cf_callback(gint event, gpointer data, gpointer user_data _U_)
case(cf_cb_file_save_failed):
g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Save failed");
break;
+ case(cf_cb_file_save_stopped):
+ g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Save stopped");
+ break;
+ case(cf_cb_file_export_specified_packets_started):
+ g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Export specified packets started");
+ break;
+ case(cf_cb_file_export_specified_packets_finished):
+ g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Export specified packets finished");
+ break;
+ case(cf_cb_file_export_specified_packets_failed):
+ g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Export specified packets failed");
+ break;
+ case(cf_cb_file_export_specified_packets_stopped):
+ g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Export specified packets stopped");
+ break;
default:
g_warning("main_cf_callback: event %u unknown", event);
g_assert_not_reached();
diff --git a/ui/gtk/main_statusbar.c b/ui/gtk/main_statusbar.c
index 937aaf8581..1d3ffbc6e9 100644
--- a/ui/gtk/main_statusbar.c
+++ b/ui/gtk/main_statusbar.c
@@ -943,6 +943,41 @@ statusbar_cf_file_save_failed_cb(gpointer data _U_)
statusbar_pop_file_msg();
}
+static void
+statusbar_cf_file_save_stopped_cb(gpointer data _U_)
+{
+ /* Pop the "Saving:" message off the status bar. */
+ statusbar_pop_file_msg();
+}
+
+static void
+statusbar_cf_file_export_specified_packets_started_cb(gchar *filename)
+{
+ statusbar_pop_file_msg();
+ statusbar_push_file_msg(" Exporting to: %s...", g_filename_display_basename(filename));
+}
+
+static void
+statusbar_cf_file_export_specified_packets_finished_cb(gpointer data _U_)
+{
+ /* Pop the "Exporting to:" message off the status bar. */
+ statusbar_pop_file_msg();
+}
+
+static void
+statusbar_cf_file_export_specified_packets_failed_cb(gpointer data _U_)
+{
+ /* Pop the "Exporting to:" message off the status bar. */
+ statusbar_pop_file_msg();
+}
+
+static void
+statusbar_cf_file_export_specified_packets_stopped_cb(gpointer data _U_)
+{
+ /* Pop the "Saving:" message off the status bar. */
+ statusbar_pop_file_msg();
+}
+
void
@@ -983,6 +1018,21 @@ statusbar_cf_callback(gint event, gpointer data, gpointer user_data _U_)
case(cf_cb_file_save_failed):
statusbar_cf_file_save_failed_cb(data);
break;
+ case(cf_cb_file_save_stopped):
+ statusbar_cf_file_save_stopped_cb(data);
+ break;
+ case(cf_cb_file_export_specified_packets_started):
+ statusbar_cf_file_export_specified_packets_started_cb(data);
+ break;
+ case(cf_cb_file_export_specified_packets_finished):
+ statusbar_cf_file_export_specified_packets_finished_cb(data);
+ break;
+ case(cf_cb_file_export_specified_packets_failed):
+ statusbar_cf_file_export_specified_packets_failed_cb(data);
+ break;
+ case(cf_cb_file_export_specified_packets_stopped):
+ statusbar_cf_file_export_specified_packets_stopped_cb(data);
+ break;
default:
g_warning("statusbar_cf_callback: event %u unknown", event);
g_assert_not_reached();