#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);
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) {
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;
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);
}
/* 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;
}
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);
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
count++;
/* Is this packet in the display? */
- if (fdata && fdata->flags.passed_dfilter) {
+ if (fdata && fdata->passed_dfilter) {
/* Yes. Does it match the search criterion? */
result = (*match_function)(cf, fdata, criterion);
if (result == MR_ERROR) {
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