#include <wsutil/tempfile.h>
#include <wsutil/file_util.h>
#include <wsutil/filesystem.h>
+#include <wsutil/json_dumper.h>
#include <version_info.h>
#include <wiretap/merge.h>
#include <epan/strutil.h>
#include <epan/addr_resolv.h>
#include <epan/color_filters.h>
+#include <epan/secrets.h>
#include "cfile.h"
#include "file.h"
the packets, so we know how much we'll ultimately need. */
ws_buffer_init(&cf->buf, 1500);
- /* Create new epan session for dissection.
- * (The old one was freed in cf_close().)
- */
- cf->epan = ws_epan_new(cf);
-
/* We're about to start reading the file. */
cf->state = FILE_READ_IN_PROGRESS;
cf->provider.prev_cap = NULL;
cf->cum_bytes = 0;
+ /* Create new epan session for dissection.
+ * (The old one was freed in cf_close().)
+ */
+ cf->epan = ws_epan_new(cf);
+
packet_list_queue_draw();
cf_callback_invoke(cf_cb_file_opened, cf);
- if ((cf->cd_t == WTAP_FILE_TYPE_SUBTYPE_BER)
- || (cf->cd_t == WTAP_FILE_TYPE_SUBTYPE_PEM)) {
+ if (cf->cd_t == WTAP_FILE_TYPE_SUBTYPE_BER) {
/* tell the BER dissector the file name */
ber_set_filename(cf->filename);
}
wtap_set_cb_new_ipv4(cf->provider.wth, add_ipv4_name);
wtap_set_cb_new_ipv6(cf->provider.wth, (wtap_new_ipv6_callback_t) add_ipv6_name);
+ wtap_set_cb_new_secrets(cf->provider.wth, secrets_wtap_callback);
return CF_OK;
/* Die if we're in the middle of reading a file. */
g_assert(cf->state != FILE_READ_IN_PROGRESS);
+ g_assert(!cf->read_lock);
cf_callback_invoke(cf_cb_file_closing, cf);
gboolean compiled;
volatile gboolean is_read_aborted = FALSE;
+ /* The update_progress_dlg call below might end up accepting a user request to
+ * trigger redissection/rescans which can modify/destroy the dissection
+ * context ("cf->epan"). That condition should be prevented by callers, but in
+ * case it occurs let's fail gracefully.
+ */
+ if (cf->read_lock) {
+ g_warning("Failing due to recursive cf_read(\"%s\", %d) call!",
+ cf->filename, reloading);
+ return CF_READ_ERROR;
+ }
+ cf->read_lock = TRUE;
+
/* Compile the current display filter.
* We assume this will not fail since cf->dfilter is only set in
* cf_filter IFF the filter was valid.
else
cf_callback_invoke(cf_cb_file_read_started, cf);
- /* Record whether the file is compressed.
+ /* Record the file's compression type.
XXX - do we know this at open time? */
- cf->iscompressed = wtap_iscompressed(cf->provider.wth);
+ cf->compression_type = wtap_get_compression_type(cf->provider.wth);
/* The packet list window will be empty until the file is completly loaded */
packet_list_freeze();
packets_bar_update();
g_timer_start(prog_timer);
}
+ /*
+ * The previous GUI triggers should not have destroyed the running
+ * session. If that did happen, it could blow up when read_record tries
+ * to use the destroyed edt.session, so detect it right here.
+ */
+ g_assert(edt.session == cf->epan);
}
if (cf->state == FILE_READ_ABORTED) {
packet_list_select_first_row();
}
+ /* It is safe again to execute redissections. */
+ g_assert(cf->read_lock);
+ cf->read_lock = FALSE;
+
if (is_read_aborted) {
/*
* Well, the user decided to exit Wireshark while reading this *offline*
* cf_continue_tail). Clean up accordingly.
*/
cf_close(cf);
+ cf->redissection_queued = RESCAN_NONE;
return CF_READ_ABORTED;
}
+ if (cf->redissection_queued != RESCAN_NONE) {
+ /* Redissection was queued up. Clear the request and perform it now. */
+ gboolean redissect = cf->redissection_queued == RESCAN_REDISSECT;
+ rescan_packets(cf, "Reprocessing", "all packets", redissect);
+ }
+
if (cf->stop_flag) {
simple_message_box(ESD_TYPE_WARN, NULL,
"The remaining packets in the file were discarded.\n"
aren't any packets left to read) exit. */
break;
}
- if (read_record(cf, dfcode, &edt, (column_info *) cinfo, data_offset)) {
+ if (read_record(cf, dfcode, &edt, cinfo, data_offset)) {
newly_displayed_packets++;
}
to_read--;
return displayname;
}
+gchar *
+cf_get_basename(capture_file *cf)
+{
+ gchar *displayname;
+
+ /* Return a name to use in the GUI for the basename for files to
+ which we save statistics */
+ if (!cf->is_tempfile) {
+ /* Get the last component of the file name, and use that. */
+ if (cf->filename) {
+ displayname = g_filename_display_basename(cf->filename);
+
+ /* If the file name ends with any extension that corresponds
+ to a file type we support - including compressed versions
+ of those files - strip it off. */
+ size_t displayname_len = strlen(displayname);
+ GSList *extensions = wtap_get_all_file_extensions_list();
+ GSList *suffix;
+ for (suffix = extensions; suffix != NULL; suffix = g_slist_next(suffix)) {
+ /* Does the file name end with that extension? */
+ const char *extension = (char *)suffix->data;
+ size_t extension_len = strlen(extension);
+ if (displayname_len > extension_len &&
+ displayname[displayname_len - extension_len - 1] == '.' &&
+ strcmp(&displayname[displayname_len - extension_len], extension) == 0) {
+ /* Yes. Strip the extension off, and return the result. */
+ displayname[displayname_len - extension_len - 1] = '\0';
+ break;
+ }
+ }
+ wtap_free_extensions_list(extensions);
+ } else {
+ displayname=g_strdup("");
+ }
+ } else {
+ /* The file we read is a temporary file from a live capture or
+ a merge operation; we don't mention its name, but, if it's
+ from a capture, give the source of the capture. */
+ if (cf->source) {
+ displayname = g_strdup(cf->source);
+ } else {
+ displayname = g_strdup("");
+ }
+ }
+ return displayname;
+}
+
void cf_set_tempfile_source(capture_file *cf, gchar *source) {
if (cf->source) {
g_free(cf->source);
* TODO: actually detect that situation or maybe apply other optimizations? */
if (edt->tree && color_filters_used()) {
color_filters_prime_edt(edt);
- fdata->flags.need_colorize = 1;
+ fdata->need_colorize = 1;
}
#endif
- if (!fdata->flags.visited) {
+ if (!fdata->visited) {
/* This is the first pass, so prime the epan_dissect_t with the
hfids postdissectors want on the first pass. */
prime_epan_dissect_with_postdissector_wanted_hfids(edt);
/* If we don't have a display filter, set "passed_dfilter" to 1. */
if (dfcode != NULL) {
- fdata->flags.passed_dfilter = dfilter_apply_edt(dfcode, edt) ? 1 : 0;
+ fdata->passed_dfilter = dfilter_apply_edt(dfcode, edt) ? 1 : 0;
- if (fdata->flags.passed_dfilter) {
+ if (fdata->passed_dfilter) {
/* This frame passed the display filter but it may depend on other
* (potentially not displayed) frames. Find those frames and mark them
* as depended upon.
g_slist_foreach(edt->pi.dependent_frames, find_and_mark_frame_depended_upon, cf->provider.frames);
}
} else
- fdata->flags.passed_dfilter = 1;
+ fdata->passed_dfilter = 1;
- if (fdata->flags.passed_dfilter || fdata->flags.ref_time)
+ if (fdata->passed_dfilter || fdata->ref_time)
cf->displayed_count++;
if (add_to_packet_list) {
packet_list_append(cinfo, fdata);
}
- if (fdata->flags.passed_dfilter || fdata->flags.ref_time)
+ if (fdata->passed_dfilter || fdata->ref_time)
{
frame_data_set_after_dissect(fdata, &cf->cum_bytes);
cf->provider.prev_dis = fdata;
cf->packet_comment_count++;
cf->f_datalen = offset + fdlocal.cap_len;
- if (!cf->redissecting) {
+ /* When a redissection is in progress (or queued), do not process packets.
+ * This will be done once all (new) packets have been scanned. */
+ if (!cf->redissecting && cf->redissection_queued == RESCAN_NONE) {
add_packet_to_packet_list(fdata, cf, edt, dfcode,
cinfo, rec, buf, TRUE);
}
/* Now rescan the packet list, applying the new filter, but not
- throwing away information constructed on a previous pass. */
- if (cf->state != FILE_CLOSED) {
- if (dftext == NULL) {
- rescan_packets(cf, "Resetting", "Filter", FALSE);
- } else {
- rescan_packets(cf, "Filtering", dftext, FALSE);
+ * throwing away information constructed on a previous pass.
+ * If a dissection is already in progress, queue it.
+ */
+ if (cf->redissection_queued == RESCAN_NONE) {
+ if (cf->read_lock) {
+ cf->redissection_queued = RESCAN_SCAN;
+ } else if (cf->state != FILE_CLOSED) {
+ if (dftext == NULL) {
+ rescan_packets(cf, "Resetting", "Filter", FALSE);
+ } else {
+ rescan_packets(cf, "Filtering", dftext, FALSE);
+ }
}
}
void
cf_redissect_packets(capture_file *cf)
{
+ if (cf->read_lock || cf->redissection_queued == RESCAN_SCAN) {
+ /* Dissection in progress, signal redissection rather than rescanning. That
+ * would destroy the current (in-progress) dissection in "cf_read" which
+ * will cause issues when "cf_read" tries to add packets to the list.
+ * If a previous rescan was requested, "upgrade" it to a full redissection.
+ */
+ cf->redissection_queued = RESCAN_REDISSECT;
+ }
+ if (cf->redissection_queued != RESCAN_NONE) {
+ /* Redissection is (already) queued, wait for "cf_read" to finish. */
+ return;
+ }
+
if (cf->state != FILE_CLOSED) {
+ /* Restart dissection in case no cf_read is pending. */
rescan_packets(cf, "Reprocessing", "all packets", TRUE);
}
}
gboolean add_to_packet_list = FALSE;
gboolean compiled;
guint32 frames_count;
+ gboolean queued_rescan_type = RESCAN_NONE;
+
+ /* Rescan in progress, clear pending actions. */
+ cf->redissection_queued = RESCAN_NONE;
+ g_assert(!cf->read_lock);
+ cf->read_lock = TRUE;
/* Compile the current display filter.
* We assume this will not fail since cf->dfilter is only set in
epan_dissect_init(&edt, cf->epan, create_proto_tree, FALSE);
+ if (redissect) {
+ /*
+ * Decryption secrets are read while sequentially processing records and
+ * then passed to the dissector. During redissection, the previous secrets
+ * are lost (see epan_free above), but they are not read again from the
+ * file as only packet records are re-read. Therefore reset the wtap secrets
+ * callback such that wtap resupplies the secrets callback with previously
+ * read secrets.
+ */
+ wtap_set_cb_new_secrets(cf->provider.wth, secrets_wtap_callback);
+ }
+
for (framenum = 1; framenum <= frames_count; framenum++) {
fdata = frame_data_sequence_find(cf->provider.frames, framenum);
g_timer_start(prog_timer);
}
+ queued_rescan_type = cf->redissection_queued;
+ if (queued_rescan_type != RESCAN_NONE) {
+ /* A redissection was requested while an existing redissection was
+ * pending. */
+ break;
+ }
+
if (cf->stop_flag) {
/* Well, the user decided to abort the filtering. Just stop.
}
/* Frame dependencies from the previous dissection/filtering are no longer valid. */
- fdata->flags.dependent_of_displayed = 0;
+ fdata->dependent_of_displayed = 0;
if (!cf_read_record(cf, fdata))
break; /* error reading the frame */
/* If the previous frame is displayed, and we haven't yet seen the
selected frame, remember that frame - it's the closest one we've
yet seen before the selected frame. */
- if (prev_frame_num != -1 && !selected_frame_seen && prev_frame->flags.passed_dfilter) {
+ if (prev_frame_num != -1 && !selected_frame_seen && prev_frame->passed_dfilter) {
preceding_frame_num = prev_frame_num;
preceding_frame = prev_frame;
}
seen displayed after the selected frame, remember this frame -
it's the closest one we've yet seen at or after the selected
frame. */
- if (fdata->flags.passed_dfilter && selected_frame_seen && following_frame_num == -1) {
+ if (fdata->passed_dfilter && selected_frame_seen && following_frame_num == -1) {
following_frame_num = fdata->num;
following_frame = fdata;
}
if (fdata == selected_frame) {
selected_frame_seen = TRUE;
- if (fdata->flags.passed_dfilter)
+ if (fdata->passed_dfilter)
selected_frame_num = fdata->num;
}
/* Cleanup and release all dfilter resources */
dfilter_free(dfcode);
+
+ /* It is safe again to execute redissections. */
+ g_assert(cf->read_lock);
+ cf->read_lock = FALSE;
+
+ /* If another rescan (due to dfilter change) or redissection (due to profile
+ * change) was requested, the rescan above is aborted and restarted here. */
+ if (queued_rescan_type != RESCAN_NONE) {
+ redissect = redissect || queued_rescan_type == RESCAN_REDISSECT;
+ rescan_packets(cf, "Reprocessing", "all packets", redissect);
+ }
}
cf->provider.ref = fdata;
/* if this frames is marked as a reference time frame, reset
firstsec and firstusec to this frame */
- if (fdata->flags.ref_time)
+ if (fdata->ref_time)
cf->provider.ref = fdata;
/* If we don't have the time stamp of the previous displayed packet,
/* If this frame is displayed, get the time elapsed between the
previous displayed packet and this packet. */
- if ( fdata->flags.passed_dfilter ) {
+ if ( fdata->passed_dfilter ) {
fdata->prev_dis_num = cf->provider.prev_dis->num;
cf->provider.prev_dis = fdata;
}
/*
* Byte counts
*/
- if ( (fdata->flags.passed_dfilter) || (fdata->flags.ref_time) ) {
+ if ( (fdata->passed_dfilter) || (fdata->ref_time) ) {
/* This frame either passed the display filter list or is marked as
a time reference frame. All time reference frames are displayed
even if they don't pass the display filter */
- if (fdata->flags.ref_time) {
+ if (fdata->ref_time) {
/* if this was a TIME REF frame we should reset the cum_bytes field */
cf->cum_bytes = fdata->pkt_len;
fdata->cum_bytes = cf->cum_bytes;
{
guint32 framenum;
frame_data *fdata;
+ wtap_rec rec;
Buffer buf;
psp_return_t ret = PSP_FINISHED;
GTimeVal progbar_start_time;
gchar progbar_status_str[100];
range_process_e process_this;
- wtap_rec rec;
wtap_rec_init(&rec);
ws_buffer_init(&buf, 1500);
/* Progress so far. */
progbar_val = 0.0f;
+ if (cf->read_lock) {
+ g_warning("Failing due to nested process_specified_records(\"%s\") call!", cf->filename);
+ return PSP_FAILED;
+ }
+ cf->read_lock = TRUE;
+
cf->stop_flag = FALSE;
g_get_current_time(&progbar_start_time);
destroy_progress_dlg(progbar);
g_timer_destroy(prog_timer);
+ g_assert(cf->read_lock);
+ cf->read_lock = FALSE;
+
wtap_rec_cleanup(&rec);
ws_buffer_free(&buf);
"all packets", TRUE, retap_packet,
&callback_args, TRUE);
+ packet_range_cleanup(&range);
epan_dissect_cleanup(&callback_args.edt);
cf_callback_invoke(cf_cb_file_retap_finished, cf);
if (args->print_formfeed) {
if (!new_page(args->print_args->stream))
goto fail;
+
+ /*
+ * Print another header line if we print a packet summary on the
+ * new page.
+ */
+ if (args->print_args->print_col_headings)
+ args->print_header_line = TRUE;
} else {
if (args->print_separator) {
if (!print_line(args->print_args->stream, 0, ""))
FILE *fh;
epan_dissect_t edt;
print_args_t *print_args;
+ json_dumper jdumper;
} write_packet_callback_args_t;
static gboolean
/* Write out the information in that tree. */
write_json_proto_tree(NULL, args->print_args->print_dissections,
args->print_args->print_hex, NULL, PF_NONE,
- &args->edt, &cf->cinfo, proto_node_group_children_by_unique, args->fh);
+ &args->edt, &cf->cinfo, proto_node_group_children_by_unique,
+ &args->jdumper);
epan_dissect_reset(&args->edt);
if (fh == NULL)
return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
- write_json_preamble(fh);
+ callback_args.jdumper = write_json_preamble(fh);
if (ferror(fh)) {
fclose(fh);
return CF_PRINT_WRITE_ERROR;
return CF_PRINT_WRITE_ERROR;
}
- write_json_finale(fh);
+ write_json_finale(&callback_args.jdumper);
if (ferror(fh)) {
fclose(fh);
return CF_PRINT_WRITE_ERROR;
static match_result
match_marked(capture_file *cf _U_, frame_data *fdata, void *criterion _U_)
{
- return fdata->flags.marked ? MR_MATCHED : MR_NOTMATCHED;
+ return fdata->marked ? MR_MATCHED : MR_NOTMATCHED;
}
gboolean
static match_result
match_time_reference(capture_file *cf _U_, frame_data *fdata, void *criterion _U_)
{
- return fdata->flags.ref_time ? MR_MATCHED : MR_NOTMATCHED;
+ return fdata->ref_time ? MR_MATCHED : MR_NOTMATCHED;
}
static gboolean
{
frame_data *start_fd;
guint32 framenum;
+ guint32 prev_framenum;
frame_data *fdata;
frame_data *new_fd = NULL;
progdlg_t *progbar = NULL;
start_fd = cf->current_frame;
if (start_fd != NULL) {
- /* 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;
- framenum = start_fd->num;
+ prev_framenum = start_fd->num;
+ } else {
+ prev_framenum = 0; /* No start packet selected. */
+ }
- g_timer_start(prog_timer);
- /* Progress so far. */
- progbar_val = 0.0f;
+ /* 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;
+ framenum = prev_framenum;
+
+ g_timer_start(prog_timer);
+ /* Progress so far. */
+ progbar_val = 0.0f;
- cf->stop_flag = FALSE;
- g_get_current_time(&start_time);
+ cf->stop_flag = FALSE;
+ g_get_current_time(&start_time);
- title = cf->sfilter?cf->sfilter:"";
- for (;;) {
- /* Create the progress bar if necessary.
- We check on every iteration of the loop, so that it takes no
- longer than the standard time to create it (otherwise, for a
+ title = cf->sfilter?cf->sfilter:"";
+ for (;;) {
+ /* Create the progress bar if necessary.
+ We check on every iteration of the loop, so that it takes no
+ longer than the standard time to create it (otherwise, for a
large file, we might take considerably longer than that standard
- time in order to get to the next progress bar step). */
- if (progbar == NULL)
- progbar = delayed_create_progress_dlg(cf->window, "Searching", title,
- FALSE, &cf->stop_flag, &start_time, progbar_val);
+ time in order to get to the next progress bar step). */
+ if (progbar == NULL)
+ progbar = delayed_create_progress_dlg(cf->window, "Searching", title,
+ FALSE, &cf->stop_flag, &start_time, progbar_val);
- /*
- * Update the progress bar, but do it only after PROGBAR_UPDATE_INTERVAL
- * has elapsed. Calling update_progress_dlg and packets_bar_update will
- * likely trigger UI paint events, which might take a while depending on
- * the platform and display. Reset our timer *after* painting.
+ /*
+ * Update the progress bar, but do it only after PROGBAR_UPDATE_INTERVAL
+ * has elapsed. Calling update_progress_dlg and packets_bar_update will
+ * likely trigger UI paint events, which might take a while depending on
+ * the platform and display. Reset our timer *after* painting.
+ */
+ if (g_timer_elapsed(prog_timer, NULL) > PROGBAR_UPDATE_INTERVAL) {
+ /* let's not divide by zero. I should never be started
+ * with count == 0, so let's assert that
*/
- if (g_timer_elapsed(prog_timer, NULL) > PROGBAR_UPDATE_INTERVAL) {
- /* let's not divide by zero. I should never be started
- * with count == 0, so let's assert that
- */
- g_assert(cf->count > 0);
-
- progbar_val = (gfloat) count / cf->count;
+ g_assert(cf->count > 0);
- g_snprintf(status_str, sizeof(status_str),
- "%4u of %u packets", count, cf->count);
- update_progress_dlg(progbar, progbar_val, status_str);
+ progbar_val = (gfloat) count / cf->count;
- g_timer_start(prog_timer);
- }
+ g_snprintf(status_str, sizeof(status_str),
+ "%4u of %u packets", count, cf->count);
+ update_progress_dlg(progbar, progbar_val, status_str);
- if (cf->stop_flag) {
- /* Well, the user decided to abort the search. Go back to the
- frame where we started. */
- new_fd = start_fd;
- break;
- }
+ g_timer_start(prog_timer);
+ }
- /* Go past the current frame. */
- if (dir == SD_BACKWARD) {
- /* Go on to the previous frame. */
- if (framenum == 1) {
- /*
- * XXX - other apps have a bit more of a detailed message
- * for this, and instead of offering "OK" and "Cancel",
- * they offer things such as "Continue" and "Cancel";
- * we need an API for popping up alert boxes with
- * {Verb} and "Cancel".
- */
-
- if (prefs.gui_find_wrap)
- {
- statusbar_push_temporary_msg("Search reached the beginning. Continuing at end.");
- framenum = cf->count; /* wrap around */
- }
- else
- {
- statusbar_push_temporary_msg("Search reached the beginning.");
- framenum = start_fd->num; /* stay on previous packet */
- }
- } else
- framenum--;
- } else {
- /* Go on to the next frame. */
- if (framenum == cf->count) {
- if (prefs.gui_find_wrap)
- {
- statusbar_push_temporary_msg("Search reached the end. Continuing at beginning.");
- framenum = 1; /* wrap around */
- }
- else
- {
- statusbar_push_temporary_msg("Search reached the end.");
- framenum = start_fd->num; /* stay on previous packet */
- }
- } else
- framenum++;
- }
- fdata = frame_data_sequence_find(cf->provider.frames, framenum);
+ if (cf->stop_flag) {
+ /* Well, the user decided to abort the search. Go back to the
+ frame where we started. */
+ new_fd = start_fd;
+ break;
+ }
- count++;
+ /* Go past the current frame. */
+ if (dir == SD_BACKWARD) {
+ /* Go on to the previous frame. */
+ if (framenum <= 1) {
+ /*
+ * XXX - other apps have a bit more of a detailed message
+ * for this, and instead of offering "OK" and "Cancel",
+ * they offer things such as "Continue" and "Cancel";
+ * we need an API for popping up alert boxes with
+ * {Verb} and "Cancel".
+ */
- /* Is this packet in the display? */
- if (fdata->flags.passed_dfilter) {
- /* Yes. Does it match the search criterion? */
- result = (*match_function)(cf, fdata, criterion);
- if (result == MR_ERROR) {
- /* Error; our caller has reported the error. Go back to the frame
- where we started. */
- new_fd = start_fd;
- break;
- } else if (result == MR_MATCHED) {
- /* Yes. Go to the new frame. */
- new_fd = fdata;
- break;
+ if (prefs.gui_find_wrap) {
+ statusbar_push_temporary_msg("Search reached the beginning. Continuing at end.");
+ framenum = cf->count; /* wrap around */
+ } else {
+ statusbar_push_temporary_msg("Search reached the beginning.");
+ framenum = prev_framenum; /* stay on previous packet */
}
- }
+ } else
+ framenum--;
+ } else {
+ /* Go on to the next frame. */
+ if (framenum == cf->count) {
+ if (prefs.gui_find_wrap) {
+ statusbar_push_temporary_msg("Search reached the end. Continuing at beginning.");
+ framenum = 1; /* wrap around */
+ } else {
+ statusbar_push_temporary_msg("Search reached the end.");
+ framenum = prev_framenum; /* stay on previous packet */
+ }
+ } else
+ framenum++;
+ }
- if (fdata == start_fd) {
- /* We're back to the frame we were on originally, and that frame
- doesn't match the search filter. The search failed. */
+ fdata = frame_data_sequence_find(cf->provider.frames, framenum);
+ count++;
+
+ /* Is this packet in the display? */
+ if (fdata && fdata->passed_dfilter) {
+ /* Yes. Does it match the search criterion? */
+ result = (*match_function)(cf, fdata, criterion);
+ if (result == MR_ERROR) {
+ /* Error; our caller has reported the error. Go back to the frame
+ where we started. */
+ new_fd = start_fd;
+ break;
+ } else if (result == MR_MATCHED) {
+ /* Yes. Go to the new frame. */
+ new_fd = fdata;
break;
}
}
- /* We're done scanning the packets; destroy the progress bar if it
- was created. */
- if (progbar != NULL)
- destroy_progress_dlg(progbar);
- g_timer_destroy(prog_timer);
+ if (fdata == start_fd) {
+ /* We're back to the frame we were on originally, and that frame
+ doesn't match the search filter. The search failed. */
+ break;
+ }
}
+ /* We're done scanning the packets; destroy the progress bar if it
+ was created. */
+ if (progbar != NULL)
+ destroy_progress_dlg(progbar);
+ g_timer_destroy(prog_timer);
+
if (new_fd != NULL) {
/* Find and select */
cf->search_in_progress = TRUE;
statusbar_push_temporary_msg("There is no packet number %u.", fnumber);
return FALSE; /* we failed to go to that packet */
}
- if (!fdata->flags.passed_dfilter) {
+ if (!fdata->passed_dfilter) {
/* that packet currently isn't displayed */
/* XXX - add it to the set of displayed packets? */
statusbar_push_temporary_msg("Packet number %u isn't displayed.", fnumber);
void
cf_mark_frame(capture_file *cf, frame_data *frame)
{
- if (! frame->flags.marked) {
- frame->flags.marked = TRUE;
+ if (! frame->marked) {
+ frame->marked = TRUE;
if (cf->count > cf->marked_count)
cf->marked_count++;
}
void
cf_unmark_frame(capture_file *cf, frame_data *frame)
{
- if (frame->flags.marked) {
- frame->flags.marked = FALSE;
+ if (frame->marked) {
+ frame->marked = FALSE;
if (cf->marked_count > 0)
cf->marked_count--;
}
void
cf_ignore_frame(capture_file *cf, frame_data *frame)
{
- if (! frame->flags.ignored) {
- frame->flags.ignored = TRUE;
+ if (! frame->ignored) {
+ frame->ignored = TRUE;
if (cf->count > cf->ignored_count)
cf->ignored_count++;
}
void
cf_unignore_frame(capture_file *cf, frame_data *frame)
{
- if (frame->flags.ignored) {
- frame->flags.ignored = FALSE;
+ if (frame->ignored) {
+ frame->ignored = FALSE;
if (cf->ignored_count > 0)
cf->ignored_count--;
}
char *comment;
/* fetch user comment */
- if (fd->flags.has_user_comment)
+ if (fd->has_user_comment)
return g_strdup(cap_file_provider_get_user_comment(&cf->provider, fd));
/* fetch phdr comment */
- if (fd->flags.has_phdr_comment) {
+ if (fd->has_phdr_comment) {
wtap_rec rec; /* Record metadata */
Buffer buf; /* Record data */
/* Make changes based on anything that the user has done but that
hasn't been saved yet. */
- if (fdata->flags.has_user_comment)
+ if (fdata->has_user_comment)
pkt_comment = cap_file_provider_get_user_comment(&cf->provider, fdata);
else
pkt_comment = rec->opt_comment;
new_rec.opt_comment = g_strdup(pkt_comment);
- new_rec.has_comment_changed = fdata->flags.has_user_comment ? TRUE : FALSE;
+ new_rec.has_comment_changed = fdata->has_user_comment ? TRUE : FALSE;
/* XXX - what if times have been shifted? */
/* and save the packet */
cf_callback_invoke(cf_cb_file_rescan_started, cf);
- /* Record whether the file is compressed.
+ /* Record the file's compression type.
XXX - do we know this at open time? */
- cf->iscompressed = wtap_iscompressed(cf->provider.wth);
+ cf->compression_type = wtap_get_compression_type(cf->provider.wth);
/* Find the size of the file. */
size = wtap_file_size(cf->provider.wth, NULL);
cf_write_status_t
cf_save_records(capture_file *cf, const char *fname, guint save_format,
- gboolean compressed, gboolean discard_comments,
- gboolean dont_reopen)
+ wtap_compression_type compression_type,
+ gboolean discard_comments, gboolean dont_reopen)
{
gchar *err_info;
gchar *fname_new = NULL;
save_callback_args_t callback_args;
gboolean needs_reload = FALSE;
+ /* XXX caller should avoid saving the file while a read is pending
+ * (e.g. by delaying the save action) */
+ if (cf->read_lock) {
+ g_warning("cf_save_records(\"%s\") while the file is being read, potential crash ahead", fname);
+ }
+
cf_callback_invoke(cf_cb_file_save_started, (gpointer)fname);
addr_lists = get_addrinfo_list();
- if (save_format == cf->cd_t && compressed == cf->iscompressed
+ if (save_format == cf->cd_t && compression_type == cf->compression_type
&& !discard_comments && !cf->unsaved_changes
&& (wtap_addrinfo_list_empty(addr_lists) || !wtap_dump_has_name_resolution(save_format))) {
/* We're saving in the format it's already in, and we're not discarding
or moving the capture file, we have to do it by writing the packets
out in Wiretap. */
- GArray *shb_hdrs = NULL;
- wtapng_iface_descriptions_t *idb_inf = NULL;
- GArray *nrb_hdrs = NULL;
+ wtap_dump_params params;
int encap;
- /* XXX: what free's this shb_hdr? */
- shb_hdrs = wtap_file_get_shb_for_new_file(cf->provider.wth);
- idb_inf = wtap_file_get_idb_info(cf->provider.wth);
- nrb_hdrs = wtap_file_get_nrb_for_new_file(cf->provider.wth);
+ /* XXX: what free's params.shb_hdr? */
+ wtap_dump_params_init(¶ms, cf->provider.wth);
/* Determine what file encapsulation type we should use. */
encap = wtap_dump_file_encap_type(cf->linktypes);
+ params.encap = encap;
+
+ /* Use the snaplen from cf (XXX - does wtap_dump_params_init handle that?) */
+ params.snaplen = cf->snap;
if (file_exists(fname)) {
/* We're overwriting an existing file; write out to a new file,
we *HAVE* to do that, otherwise we're overwriting the file
from which we're reading the packets that we're writing!) */
fname_new = g_strdup_printf("%s~", fname);
- pdh = wtap_dump_open_ng(fname_new, save_format, encap, cf->snap,
- compressed, shb_hdrs, idb_inf, nrb_hdrs, &err);
+ pdh = wtap_dump_open(fname_new, save_format, compression_type, ¶ms,
+ &err);
} else {
- pdh = wtap_dump_open_ng(fname, save_format, encap, cf->snap,
- compressed, shb_hdrs, idb_inf, nrb_hdrs, &err);
+ pdh = wtap_dump_open(fname, save_format, compression_type, ¶ms, &err);
}
- g_free(idb_inf);
- idb_inf = NULL;
+ /* XXX idb_inf is documented to be used until wtap_dump_close. */
+ g_free(params.idb_inf);
+ params.idb_inf = NULL;
if (pdh == NULL) {
cfile_dump_open_failure_alert_box(fname, err, save_format);
for (framenum = 1; framenum <= cf->count; framenum++) {
fdata = frame_data_sequence_find(cf->provider.frames, framenum);
- fdata->flags.has_phdr_comment = FALSE;
- fdata->flags.has_user_comment = FALSE;
+ fdata->has_phdr_comment = FALSE;
+ fdata->has_user_comment = FALSE;
}
if (cf->provider.frames_user_comments) {
cf_write_status_t
cf_export_specified_packets(capture_file *cf, const char *fname,
packet_range_t *range, guint save_format,
- gboolean compressed)
+ wtap_compression_type compression_type)
{
gchar *fname_new = NULL;
int err;
wtap_dumper *pdh;
save_callback_args_t callback_args;
- GArray *shb_hdrs = NULL;
- wtapng_iface_descriptions_t *idb_inf = NULL;
- GArray *nrb_hdrs = NULL;
+ wtap_dump_params params;
int encap;
packet_range_process_init(range);
written, don't special-case the operation - read each packet
and then write it out if it's one of the specified ones. */
- /* XXX: what free's this shb_hdr? */
- shb_hdrs = wtap_file_get_shb_for_new_file(cf->provider.wth);
- idb_inf = wtap_file_get_idb_info(cf->provider.wth);
- nrb_hdrs = wtap_file_get_nrb_for_new_file(cf->provider.wth);
+ /* XXX: what free's params.shb_hdr? */
+ wtap_dump_params_init(¶ms, cf->provider.wth);
/* Determine what file encapsulation type we should use. */
encap = wtap_dump_file_encap_type(cf->linktypes);
+ params.encap = encap;
+
+ /* Use the snaplen from cf (XXX - does wtap_dump_params_init handle that?) */
+ params.snaplen = cf->snap;
if (file_exists(fname)) {
/* We're overwriting an existing file; write out to a new file,
we *HAVE* to do that, otherwise we're overwriting the file
from which we're reading the packets that we're writing!) */
fname_new = g_strdup_printf("%s~", fname);
- pdh = wtap_dump_open_ng(fname_new, save_format, encap, cf->snap,
- compressed, shb_hdrs, idb_inf, nrb_hdrs, &err);
+ pdh = wtap_dump_open(fname_new, save_format, compression_type, ¶ms,
+ &err);
} else {
- pdh = wtap_dump_open_ng(fname, save_format, encap, cf->snap,
- compressed, shb_hdrs, idb_inf, nrb_hdrs, &err);
+ pdh = wtap_dump_open(fname, save_format, compression_type, ¶ms, &err);
}
- g_free(idb_inf);
- idb_inf = NULL;
+ /* XXX idb_inf is documented to be used until wtap_dump_close. */
+ g_free(params.idb_inf);
+ params.idb_inf = NULL;
if (pdh == NULL) {
cfile_dump_open_failure_alert_box(fname, err, save_format);
gboolean is_tempfile;
int err;
+ if (cf->read_lock) {
+ g_warning("Failing cf_reload(\"%s\") since a read is in progress", cf->filename);
+ return;
+ }
+
/* If the file could be opened, "cf_open()" calls "cf_close()"
to get rid of state for the old capture file before filling in state
for the new capture file. "cf_close()" will remove the file if