Revert "TODO: smb2: simplify preauth_hash calculation..."
[wireshark-sm.git] / file.c
blob263d342fc34ed8c2957e7485fd4dd35b0cc756c3
1 /* file.c
2 * File I/O routines
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
11 #include <config.h>
12 #define WS_LOG_DOMAIN LOG_DOMAIN_CAPTURE
14 #include <time.h>
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <ctype.h>
20 #include <errno.h>
22 #include <wsutil/file_util.h>
23 #include <wsutil/filesystem.h>
24 #include <wsutil/json_dumper.h>
25 #include <wsutil/wslog.h>
26 #include <wsutil/ws_assert.h>
27 #include <wsutil/version_info.h>
29 #include <wiretap/merge.h>
31 #include <epan/exceptions.h>
32 #include <epan/epan.h>
33 #include <epan/column.h>
34 #include <epan/packet.h>
35 #include <epan/column-utils.h>
36 #include <epan/expert.h>
37 #include <epan/prefs.h>
38 #include <epan/dfilter/dfilter.h>
39 #include <epan/epan_dissect.h>
40 #include <epan/tap.h>
41 #include <epan/timestamp.h>
42 #include <epan/strutil.h>
43 #include <epan/addr_resolv.h>
44 #include <epan/color_filters.h>
45 #include <epan/secrets.h>
47 #include "cfile.h"
48 #include "file.h"
49 #include "fileset.h"
50 #include "frame_tvbuff.h"
52 #include "ui/alert_box.h"
53 #include "ui/simple_dialog.h"
54 #include "ui/main_statusbar.h"
55 #include "ui/progress_dlg.h"
56 #include "ui/urls.h"
57 #include "ui/ws_ui_util.h"
58 #include "ui/packet_list_utils.h"
60 /* Needed for addrinfo */
61 #include <sys/types.h>
63 #ifdef HAVE_SYS_SOCKET_H
64 #include <sys/socket.h>
65 #endif
67 #ifdef HAVE_NETINET_IN_H
68 # include <netinet/in.h>
69 #endif
71 #ifdef _WIN32
72 # include <winsock2.h>
73 # include <ws2tcpip.h>
74 #endif
76 static gboolean read_record(capture_file *cf, wtap_rec *rec, Buffer *buf,
77 dfilter_t *dfcode, epan_dissect_t *edt, column_info *cinfo, gint64 offset,
78 fifo_string_cache_t *frame_dup_cache, GChecksum *frame_cksum);
80 static void rescan_packets(capture_file *cf, const char *action, const char *action_item, gboolean redissect);
82 typedef enum {
83 MR_NOTMATCHED,
84 MR_MATCHED,
85 MR_ERROR
86 } match_result;
87 typedef match_result (*ws_match_function)(capture_file *, frame_data *,
88 wtap_rec *, Buffer *, void *);
89 static match_result match_protocol_tree(capture_file *cf, frame_data *fdata,
90 wtap_rec *, Buffer *, void *criterion);
91 static void match_subtree_text(proto_node *node, gpointer data);
92 static void match_subtree_text_reverse(proto_node *node, gpointer data);
93 static match_result match_summary_line(capture_file *cf, frame_data *fdata,
94 wtap_rec *, Buffer *, void *criterion);
95 static match_result match_narrow_and_wide(capture_file *cf, frame_data *fdata,
96 wtap_rec *, Buffer *, void *criterion);
97 static match_result match_narrow_and_wide_reverse(capture_file *cf, frame_data *fdata,
98 wtap_rec *, Buffer *, void *criterion);
99 static match_result match_narrow_and_wide_case(capture_file *cf, frame_data *fdata,
100 wtap_rec *, Buffer *, void *criterion);
101 static match_result match_narrow_and_wide_case_reverse(capture_file *cf, frame_data *fdata,
102 wtap_rec *, Buffer *, void *criterion);
103 static match_result match_narrow_case(capture_file *cf, frame_data *fdata,
104 wtap_rec *, Buffer *, void *criterion);
105 static match_result match_narrow_case_reverse(capture_file *cf, frame_data *fdata,
106 wtap_rec *, Buffer *, void *criterion);
107 static match_result match_wide(capture_file *cf, frame_data *fdata,
108 wtap_rec *, Buffer *, void *criterion);
109 static match_result match_wide_reverse(capture_file *cf, frame_data *fdata,
110 wtap_rec *, Buffer *, void *criterion);
111 static match_result match_wide_case(capture_file *cf, frame_data *fdata,
112 wtap_rec *, Buffer *, void *criterion);
113 static match_result match_wide_case_reverse(capture_file *cf, frame_data *fdata,
114 wtap_rec *, Buffer *, void *criterion);
115 static match_result match_binary(capture_file *cf, frame_data *fdata,
116 wtap_rec *, Buffer *, void *criterion);
117 static match_result match_binary_reverse(capture_file *cf, frame_data *fdata,
118 wtap_rec *, Buffer *, void *criterion);
119 static match_result match_regex(capture_file *cf, frame_data *fdata,
120 wtap_rec *, Buffer *, void *criterion);
121 static match_result match_regex_reverse(capture_file *cf, frame_data *fdata,
122 wtap_rec *, Buffer *, void *criterion);
123 static match_result match_dfilter(capture_file *cf, frame_data *fdata,
124 wtap_rec *, Buffer *, void *criterion);
125 static match_result match_marked(capture_file *cf, frame_data *fdata,
126 wtap_rec *, Buffer *, void *criterion);
127 static match_result match_time_reference(capture_file *cf, frame_data *fdata,
128 wtap_rec *, Buffer *, void *criterion);
129 static gboolean find_packet(capture_file *cf, ws_match_function match_function,
130 void *criterion, search_direction dir);
132 static void cf_rename_failure_alert_box(const char *filename, int err);
134 /* Seconds spent processing packets between pushing UI updates. */
135 #define PROGBAR_UPDATE_INTERVAL 0.150
137 /* Show the progress bar after this many seconds. */
138 #define PROGBAR_SHOW_DELAY 0.5
141 * Maximum number of records we support in a file.
143 * It is, at most, the maximum value of a guint32, as we use a guint32
144 * for the frame number.
146 * We allow it to be set to a lower value; see issue #16908 for why
147 * we're doing this. Thanks, Qt!
149 static guint32 max_records = G_MAXUINT32;
151 void
152 cf_set_max_records(guint max_records_arg)
154 max_records = max_records_arg;
158 * We could probably use g_signal_...() instead of the callbacks below but that
159 * would require linking our CLI programs to libgobject and creating an object
160 * instance for the signals.
162 typedef struct {
163 cf_callback_t cb_fct;
164 gpointer user_data;
165 } cf_callback_data_t;
167 static GList *cf_callbacks;
169 static void
170 cf_callback_invoke(int event, gpointer data)
172 cf_callback_data_t *cb;
173 GList *cb_item = cf_callbacks;
175 /* there should be at least one interested */
176 ws_assert(cb_item != NULL);
178 while (cb_item != NULL) {
179 cb = (cf_callback_data_t *)cb_item->data;
180 cb->cb_fct(event, data, cb->user_data);
181 cb_item = g_list_next(cb_item);
185 void
186 cf_callback_add(cf_callback_t func, gpointer user_data)
188 cf_callback_data_t *cb;
190 cb = g_new(cf_callback_data_t,1);
191 cb->cb_fct = func;
192 cb->user_data = user_data;
194 cf_callbacks = g_list_prepend(cf_callbacks, cb);
197 void
198 cf_callback_remove(cf_callback_t func, gpointer user_data)
200 cf_callback_data_t *cb;
201 GList *cb_item = cf_callbacks;
203 while (cb_item != NULL) {
204 cb = (cf_callback_data_t *)cb_item->data;
205 if (cb->cb_fct == func && cb->user_data == user_data) {
206 cf_callbacks = g_list_remove(cf_callbacks, cb);
207 g_free(cb);
208 return;
210 cb_item = g_list_next(cb_item);
213 ws_assert_not_reached();
216 gulong
217 cf_get_computed_elapsed(capture_file *cf)
219 return cf->computed_elapsed;
222 static void
223 compute_elapsed(capture_file *cf, gint64 start_time)
225 gint64 delta_time = g_get_monotonic_time() - start_time;
227 cf->computed_elapsed = (gulong) (delta_time / 1000); /* ms */
230 static epan_t *
231 ws_epan_new(capture_file *cf)
233 static const struct packet_provider_funcs funcs = {
234 cap_file_provider_get_frame_ts,
235 cap_file_provider_get_interface_name,
236 cap_file_provider_get_interface_description,
237 cap_file_provider_get_modified_block
240 return epan_new(&cf->provider, &funcs);
243 cf_status_t
244 cf_open(capture_file *cf, const char *fname, unsigned int type, gboolean is_tempfile, int *err)
246 wtap *wth;
247 gchar *err_info;
249 wth = wtap_open_offline(fname, type, err, &err_info, TRUE);
250 if (wth == NULL)
251 goto fail;
253 /* The open succeeded. Close whatever capture file we had open,
254 and fill in the information for this file. */
255 cf_close(cf);
257 /* Initialize the record metadata. */
258 wtap_rec_init(&cf->rec);
260 /* XXX - we really want to initialize this after we've read all
261 the packets, so we know how much we'll ultimately need. */
262 ws_buffer_init(&cf->buf, 1514);
264 /* We're about to start reading the file. */
265 cf->state = FILE_READ_IN_PROGRESS;
267 /* If there was a pending redissection for the old file (there
268 * shouldn't be), clear it. cf_close() should have failed if the
269 * old file's read lock was held, but it doesn't hurt to clear it. */
270 cf->read_lock = FALSE;
271 cf->redissection_queued = RESCAN_NONE;
273 cf->provider.wth = wth;
274 cf->f_datalen = 0;
276 /* Set the file name because we need it to set the follow stream filter.
277 XXX - is that still true? We need it for other reasons, though,
278 in any case. */
279 cf->filename = g_strdup(fname);
281 /* Indicate whether it's a permanent or temporary file. */
282 cf->is_tempfile = is_tempfile;
284 /* No user changes yet. */
285 cf->unsaved_changes = FALSE;
287 cf->computed_elapsed = 0;
289 cf->cd_t = wtap_file_type_subtype(cf->provider.wth);
290 cf->open_type = type;
291 cf->linktypes = g_array_sized_new(FALSE, FALSE, (guint) sizeof(int), 1);
292 cf->count = 0;
293 cf->packet_comment_count = 0;
294 cf->displayed_count = 0;
295 cf->marked_count = 0;
296 cf->ignored_count = 0;
297 cf->ref_time_count = 0;
298 cf->drops_known = FALSE;
299 cf->drops = 0;
300 cf->snap = wtap_snapshot_length(cf->provider.wth);
302 /* Allocate a frame_data_sequence for the frames in this file */
303 cf->provider.frames = new_frame_data_sequence();
305 nstime_set_zero(&cf->elapsed_time);
306 cf->provider.ref = NULL;
307 cf->provider.prev_dis = NULL;
308 cf->provider.prev_cap = NULL;
309 cf->cum_bytes = 0;
311 /* Create new epan session for dissection.
312 * (The old one was freed in cf_close().)
314 cf->epan = ws_epan_new(cf);
316 packet_list_queue_draw();
317 cf_callback_invoke(cf_cb_file_opened, cf);
319 wtap_set_cb_new_ipv4(cf->provider.wth, add_ipv4_name);
320 wtap_set_cb_new_ipv6(cf->provider.wth, (wtap_new_ipv6_callback_t) add_ipv6_name);
321 wtap_set_cb_new_secrets(cf->provider.wth, secrets_wtap_callback);
323 return CF_OK;
325 fail:
326 cfile_open_failure_alert_box(fname, *err, err_info);
327 return CF_ERROR;
331 * Add an encapsulation type to cf->linktypes.
333 static void
334 cf_add_encapsulation_type(capture_file *cf, int encap)
336 guint i;
338 for (i = 0; i < cf->linktypes->len; i++) {
339 if (g_array_index(cf->linktypes, gint, i) == encap)
340 return; /* it's already there */
342 /* It's not already there - add it. */
343 g_array_append_val(cf->linktypes, encap);
346 /* Reset everything to a pristine state */
347 void
348 cf_close(capture_file *cf)
350 cf->stop_flag = FALSE;
351 if (cf->state == FILE_CLOSED || cf->state == FILE_READ_PENDING)
352 return; /* Nothing to do */
354 /* Die if we're in the middle of reading a file. */
355 ws_assert(cf->state != FILE_READ_IN_PROGRESS);
356 ws_assert(!cf->read_lock);
358 cf_callback_invoke(cf_cb_file_closing, cf);
360 /* close things, if not already closed before */
361 color_filters_cleanup();
363 if (cf->provider.wth) {
364 wtap_close(cf->provider.wth);
365 cf->provider.wth = NULL;
367 /* We have no file open... */
368 if (cf->filename != NULL) {
369 /* If it's a temporary file, remove it. */
370 if (cf->is_tempfile)
371 ws_unlink(cf->filename);
372 g_free(cf->filename);
373 cf->filename = NULL;
375 /* ...which means we have no changes to that file to save. */
376 cf->unsaved_changes = FALSE;
378 /* no open_routine type */
379 cf->open_type = WTAP_TYPE_AUTO;
381 /* Clean up the record metadata. */
382 wtap_rec_cleanup(&cf->rec);
384 /* Clear the packet list. */
385 packet_list_freeze();
386 packet_list_clear();
387 packet_list_thaw();
389 /* Free up the packet buffer. */
390 ws_buffer_free(&cf->buf);
392 dfilter_free(cf->rfcode);
393 cf->rfcode = NULL;
394 if (cf->provider.frames != NULL) {
395 free_frame_data_sequence(cf->provider.frames);
396 cf->provider.frames = NULL;
398 if (cf->provider.frames_modified_blocks) {
399 g_tree_destroy(cf->provider.frames_modified_blocks);
400 cf->provider.frames_modified_blocks = NULL;
402 cf_unselect_packet(cf); /* nothing to select */
403 cf->first_displayed = 0;
404 cf->last_displayed = 0;
406 /* No frames, no frame selected, no field in that frame selected. */
407 cf->count = 0;
408 cf->current_frame = NULL;
409 cf->finfo_selected = NULL;
411 /* No frame link-layer types, either. */
412 if (cf->linktypes != NULL) {
413 g_array_free(cf->linktypes, TRUE);
414 cf->linktypes = NULL;
417 cf->f_datalen = 0;
418 nstime_set_zero(&cf->elapsed_time);
420 reset_tap_listeners();
422 epan_free(cf->epan);
423 cf->epan = NULL;
425 /* We have no file open. */
426 cf->state = FILE_CLOSED;
428 cf_callback_invoke(cf_cb_file_closed, cf);
432 * TRUE if the progress dialog doesn't exist and it looks like we'll
433 * take > PROGBAR_SHOW_DELAY (500ms) to load, FALSE otherwise.
435 static inline gboolean
436 progress_is_slow(progdlg_t *progdlg, GTimer *prog_timer, gint64 size, gint64 pos)
438 double elapsed;
440 if (progdlg) return FALSE;
441 elapsed = g_timer_elapsed(prog_timer, NULL);
442 /* This only gets checked between reading records, which doesn't help if
443 * a single record takes a very long time, e.g., the first TLS packet if
444 * the SSLKEYLOGFILE is very large. (#17051) */
445 if ((elapsed * 2 > PROGBAR_SHOW_DELAY && (size / pos) >= 2) /* It looks like we're going to be slow. */
446 || elapsed > PROGBAR_SHOW_DELAY) { /* We are indeed slow. */
447 return TRUE;
449 return FALSE;
452 static float
453 calc_progbar_val(capture_file *cf, gint64 size, gint64 file_pos, gchar *status_str, gulong status_size)
455 float progbar_val;
457 progbar_val = (gfloat) file_pos / (gfloat) size;
458 if (progbar_val > 1.0) {
460 /* The file probably grew while we were reading it.
461 * Update file size, and try again.
463 size = wtap_file_size(cf->provider.wth, NULL);
465 if (size >= 0)
466 progbar_val = (gfloat) file_pos / (gfloat) size;
468 /* If it's still > 1, either "wtap_file_size()" failed (in which
469 * case there's not much we can do about it), or the file
470 * *shrank* (in which case there's not much we can do about
471 * it); just clip the progress value at 1.0.
473 if (progbar_val > 1.0f)
474 progbar_val = 1.0f;
477 snprintf(status_str, status_size,
478 "%" PRId64 "KB of %" PRId64 "KB",
479 file_pos / 1024, size / 1024);
481 return progbar_val;
484 cf_read_status_t
485 cf_read(capture_file *cf, gboolean reloading)
487 int err = 0;
488 gchar *err_info = NULL;
489 volatile gboolean too_many_records = FALSE;
490 gchar *name_ptr;
491 progdlg_t *volatile progbar = NULL;
492 GTimer *prog_timer = g_timer_new();
493 gint64 size;
494 gint64 start_time;
495 epan_dissect_t edt;
496 wtap_rec rec;
497 Buffer buf;
498 dfilter_t *dfcode = NULL;
499 column_info *cinfo;
500 volatile gboolean create_proto_tree;
501 guint tap_flags;
502 gboolean compiled _U_;
503 volatile gboolean is_read_aborted = FALSE;
505 /* The update_progress_dlg call below might end up accepting a user request to
506 * trigger redissection/rescans which can modify/destroy the dissection
507 * context ("cf->epan"). That condition should be prevented by callers, but in
508 * case it occurs let's fail gracefully.
510 if (cf->read_lock) {
511 ws_warning("Failing due to recursive cf_read(\"%s\", %d) call!",
512 cf->filename, reloading);
513 return CF_READ_ERROR;
515 /* This is a full dissection, so clear any pending request for one. */
516 cf->redissection_queued = RESCAN_NONE;
517 cf->read_lock = TRUE;
519 /* Compile the current display filter.
520 * The code it compiles to might have changed, e.g. if a display
521 * filter macro used has changed.
523 * We assume this will not fail since cf->dfilter is only set in
524 * cf_filter IFF the filter was valid.
525 * XXX - This is not necessarily true, if the filter has a FT_IPv4
526 * or FT_IPv6 field compared to a resolved hostname in it, because
527 * we do a new host lookup, and that *could* timeout this time
528 * (though with the read lock above we shouldn't have many lookups at
529 * once, reducing the chances of that)... (#19612)
531 if (cf->dfilter) {
532 compiled = dfilter_compile(cf->dfilter, &dfcode, NULL);
533 ws_assert(compiled && dfcode);
536 dfilter_free(cf->dfcode);
537 cf->dfcode = dfcode;
539 /* The compiled dfilter might have a field reference; recompiling it
540 * means that the field references won't match anything. That's what
541 * we want since this is a new sequential read and we don't have
542 * a selected frame with a tree. (Will taps with filters with display
543 * references also have cleared display references?)
546 /* Get the union of the flags for all tap listeners. */
547 tap_flags = union_of_tap_listener_flags();
550 * Determine whether we need to create a protocol tree.
551 * We do if:
553 * we're going to apply a display filter;
555 * one of the tap listeners is going to apply a filter;
557 * one of the tap listeners requires a protocol tree;
559 * a postdissector wants field values or protocols on
560 * the first pass.
562 create_proto_tree =
563 (cf->dfcode != NULL || have_filtering_tap_listeners() ||
564 (tap_flags & TL_REQUIRES_PROTO_TREE) || postdissectors_want_hfids());
566 reset_tap_listeners();
568 name_ptr = g_filename_display_basename(cf->filename);
570 if (reloading)
571 cf_callback_invoke(cf_cb_file_reload_started, cf);
572 else
573 cf_callback_invoke(cf_cb_file_read_started, cf);
575 /* Record the file's compression type.
576 XXX - do we know this at open time? */
577 cf->compression_type = wtap_get_compression_type(cf->provider.wth);
579 /* The packet list window will be empty until the file is completely loaded */
580 packet_list_freeze();
582 cf->stop_flag = FALSE;
583 start_time = g_get_monotonic_time();
585 epan_dissect_init(&edt, cf->epan, create_proto_tree, FALSE);
587 /* If the display filter or any tap listeners require the columns,
588 * construct them. */
589 cinfo = (tap_listeners_require_columns() ||
590 dfilter_requires_columns(cf->dfcode)) ? &cf->cinfo : NULL;
592 /* Find the size of the file. */
593 size = wtap_file_size(cf->provider.wth, NULL);
595 /* If we are to ignore duplicate frames, we need a container to store
596 * hashes frame contents */
597 fifo_string_cache_t frame_dup_cache;
598 GChecksum *volatile cksum = NULL;
600 if (prefs.ignore_dup_frames) {
601 fifo_string_cache_init(&frame_dup_cache, prefs.ignore_dup_frames_cache_entries, g_free);
602 cksum = g_checksum_new(G_CHECKSUM_SHA256);
605 g_timer_start(prog_timer);
607 wtap_rec_init(&rec);
608 ws_buffer_init(&buf, 1514);
610 TRY {
611 gint64 file_pos;
612 gint64 data_offset;
614 float progbar_val;
615 gchar status_str[100];
617 while ((wtap_read(cf->provider.wth, &rec, &buf, &err, &err_info,
618 &data_offset))) {
619 if (size >= 0) {
620 if (cf->count == max_records) {
622 * Quit if we've already read the maximum number of
623 * records allowed.
625 too_many_records = TRUE;
626 break;
628 file_pos = wtap_read_so_far(cf->provider.wth);
630 /* Create the progress bar if necessary. */
631 if (progress_is_slow(progbar, prog_timer, size, file_pos)) {
632 progbar_val = calc_progbar_val(cf, size, file_pos, status_str, sizeof(status_str));
633 progbar = delayed_create_progress_dlg(cf->window, NULL, NULL, TRUE,
634 &cf->stop_flag, progbar_val);
638 * Update the progress bar, but do it only after
639 * PROGBAR_UPDATE_INTERVAL has elapsed. Calling update_progress_dlg
640 * and packets_bar_update will likely trigger UI paint events, which
641 * might take a while depending on the platform and display. Reset
642 * our timer *after* painting.
644 if (progbar && g_timer_elapsed(prog_timer, NULL) > PROGBAR_UPDATE_INTERVAL) {
645 progbar_val = calc_progbar_val(cf, size, file_pos, status_str, sizeof(status_str));
646 /* update the packet bar content on the first run or frequently on very large files */
647 update_progress_dlg(progbar, progbar_val, status_str);
648 compute_elapsed(cf, start_time);
649 packets_bar_update();
650 g_timer_start(prog_timer);
653 * The previous GUI triggers should not have destroyed the running
654 * session. If that did happen, it could blow up when read_record tries
655 * to use the destroyed edt.session, so detect it right here.
657 ws_assert(edt.session == cf->epan);
660 if (cf->state == FILE_READ_ABORTED) {
661 /* Well, the user decided to exit Wireshark. Break out of the
662 loop, and let the code below (which is called even if there
663 aren't any packets left to read) exit. */
664 is_read_aborted = TRUE;
665 break;
667 if (cf->stop_flag) {
668 /* Well, the user decided to abort the read. He/She will be warned and
669 it might be enough for him/her to work with the already loaded
670 packets.
671 This is especially true for very large capture files, where you don't
672 want to wait loading the whole file (which may last minutes or even
673 hours even on fast machines) just to see that it was the wrong file. */
674 break;
676 read_record(cf, &rec, &buf, cf->dfcode, &edt, cinfo, data_offset, &frame_dup_cache, cksum);
677 wtap_rec_reset(&rec);
680 CATCH(OutOfMemoryError) {
681 simple_message_box(ESD_TYPE_ERROR, NULL,
682 "More information and workarounds can be found at\n"
683 WS_WIKI_URL("KnownBugs/OutOfMemory"),
684 "Sorry, but Wireshark has run out of memory and has to terminate now.");
685 #if 0
686 /* Could we close the current capture and free up memory from that? */
687 #else
688 /* we have to terminate, as we cannot recover from the memory error */
689 exit(1);
690 #endif
692 ENDTRY;
694 // If we're ignoring duplicate frames, clear the data structures.
695 // We really could look at prefs.ignore_dup_frames here, but it's even
696 // safer to check if we had allocated 'cksum'.
697 if (cksum != NULL) {
698 fifo_string_cache_free(&frame_dup_cache);
699 g_checksum_free(cksum);
702 /* We're done reading sequentially through the file. */
703 cf->state = FILE_READ_DONE;
705 /* Destroy the progress bar if it was created. */
706 if (progbar != NULL)
707 destroy_progress_dlg(progbar);
708 g_timer_destroy(prog_timer);
710 /* Free the display name */
711 g_free(name_ptr);
713 epan_dissect_cleanup(&edt);
714 wtap_rec_cleanup(&rec);
715 ws_buffer_free(&buf);
717 /* Close the sequential I/O side, to free up memory it requires. */
718 wtap_sequential_close(cf->provider.wth);
720 /* Allow the protocol dissectors to free up memory that they
721 * don't need after the sequential run-through of the packets. */
722 postseq_cleanup_all_protocols();
724 /* compute the time it took to load the file */
725 compute_elapsed(cf, start_time);
727 /* Set the file encapsulation type now; we don't know what it is until
728 we've looked at all the packets, as we don't know until then whether
729 there's more than one type (and thus whether it's
730 WTAP_ENCAP_PER_PACKET). */
731 cf->lnk_t = wtap_file_encap(cf->provider.wth);
733 cf->current_frame = frame_data_sequence_find(cf->provider.frames, cf->first_displayed);
735 packet_list_thaw();
737 /* It is safe again to execute redissections or sort. */
738 ws_assert(cf->read_lock);
739 cf->read_lock = FALSE;
741 if (reloading)
742 cf_callback_invoke(cf_cb_file_reload_finished, cf);
743 else
744 cf_callback_invoke(cf_cb_file_read_finished, cf);
746 /* If we have any displayed packets to select, select the first of those
747 packets by making the first row the selected row. */
748 if (cf->first_displayed != 0) {
749 packet_list_select_row_from_data(NULL);
752 if (is_read_aborted) {
754 * Well, the user decided to exit Wireshark while reading this *offline*
755 * capture file (Live captures are handled by something like
756 * cf_continue_tail). Clean up accordingly.
758 cf_close(cf);
759 cf->redissection_queued = RESCAN_NONE;
760 return CF_READ_ABORTED;
763 if (cf->redissection_queued != RESCAN_NONE) {
764 /* Redissection was queued up. Clear the request and perform it now. */
765 gboolean redissect = cf->redissection_queued == RESCAN_REDISSECT;
766 rescan_packets(cf, NULL, NULL, redissect);
769 if (cf->stop_flag) {
770 simple_message_box(ESD_TYPE_WARN, NULL,
771 "The remaining packets in the file were discarded.\n"
772 "\n"
773 "As a lot of packets from the original file will be missing,\n"
774 "remember to be careful when saving the current content to a file.\n",
775 "File loading was cancelled.");
776 return CF_READ_ERROR;
779 if (err != 0) {
780 /* Put up a message box noting that the read failed somewhere along
781 the line. Don't throw out the stuff we managed to read, though,
782 if any. */
783 cfile_read_failure_alert_box(NULL, err, err_info);
784 return CF_READ_ERROR;
785 } else if (too_many_records) {
786 simple_message_box(ESD_TYPE_WARN, NULL,
787 "The remaining packets in the file were discarded.\n"
788 "\n"
789 "As a lot of packets from the original file will be missing,\n"
790 "remember to be careful when saving the current content to a file.\n"
791 "\n"
792 "The command-line utility editcap can be used to split "
793 "the file into multiple smaller files",
794 "The file contains more records than the maximum "
795 "supported number of records, %u.", max_records);
796 return CF_READ_ERROR;
797 } else
798 return CF_READ_OK;
801 #ifdef HAVE_LIBPCAP
802 cf_read_status_t
803 cf_continue_tail(capture_file *cf, volatile int to_read, wtap_rec *rec,
804 Buffer *buf, int *err, fifo_string_cache_t *frame_dup_cache, GChecksum *frame_cksum)
806 gchar *err_info;
807 volatile int newly_displayed_packets = 0;
808 epan_dissect_t edt;
809 gboolean create_proto_tree;
810 guint tap_flags;
812 /* Don't compile the current display filter. The current display filter
813 * text might compile to different code than when the capture started:
815 * If it has a IP address resolved name, calling get_host_ipaddr every
816 * time new packets arrive can mean a *lot* of gethostbyname calls
817 * in flight at once, eventually leading to a timeout (#19612).
818 * addr_resolv.c says that ares_gethostbyname is "usually interactive",
819 * unlike ares_gethostbyaddr (used in dissection), and violating that
820 * expectation is bad.
822 * If it has a display filter macro, the definition might have changed.
824 * If it has a field reference, the selected frame / current proto tree
825 * might have changed, and we don't have the old one. If we recompile,
826 * we can't set the field references to the old values.
828 * For a rescan, redissection, reload, retap, or opening a new file, we
829 * want to compile. What about here, when new frames have arrived in a live
830 * capture? We might be able to cache the host lookup, and a user might want
831 * the new display filter macro definition, but the user almost surely wants
832 * the field references to refer to values from the proto tree when the
833 * filter was applied, not whatever it happens to be now if the user has
834 * clicked on a different packet.
836 * To get the new compiled filter, the user should refilter.
839 /* Get the union of the flags for all tap listeners. */
840 tap_flags = union_of_tap_listener_flags();
843 * Determine whether we need to create a protocol tree.
844 * We do if:
846 * we're going to apply a display filter;
848 * one of the tap listeners is going to apply a filter;
850 * one of the tap listeners requires a protocol tree;
852 * a postdissector wants field values or protocols on
853 * the first pass.
855 create_proto_tree =
856 (cf->dfcode != NULL || have_filtering_tap_listeners() ||
857 (tap_flags & TL_REQUIRES_PROTO_TREE) || postdissectors_want_hfids());
859 *err = 0;
861 /* Don't freeze/thaw the list when doing live capture */
862 /*packet_list_freeze();*/
864 epan_dissect_init(&edt, cf->epan, create_proto_tree, FALSE);
866 TRY {
867 gint64 data_offset = 0;
868 column_info *cinfo;
870 /* If the display filter or any tap listeners require the columns,
871 * construct them. */
872 cinfo = (tap_listeners_require_columns() ||
873 dfilter_requires_columns(cf->dfcode)) ? &cf->cinfo : NULL;
875 while (to_read != 0) {
876 wtap_cleareof(cf->provider.wth);
877 if (!wtap_read(cf->provider.wth, rec, buf, err, &err_info,
878 &data_offset)) {
879 break;
881 if (cf->state == FILE_READ_ABORTED) {
882 /* Well, the user decided to exit Wireshark. Break out of the
883 loop, and let the code below (which is called even if there
884 aren't any packets left to read) exit. */
885 break;
887 if (read_record(cf, rec, buf, cf->dfcode, &edt, cinfo, data_offset, frame_dup_cache, frame_cksum)) {
888 newly_displayed_packets++;
890 to_read--;
892 wtap_rec_reset(rec);
894 CATCH(OutOfMemoryError) {
895 simple_message_box(ESD_TYPE_ERROR, NULL,
896 "More information and workarounds can be found at\n"
897 WS_WIKI_URL("KnownBugs/OutOfMemory"),
898 "Sorry, but Wireshark has run out of memory and has to terminate now.");
899 #if 0
900 /* Could we close the current capture and free up memory from that? */
901 return CF_READ_ABORTED;
902 #else
903 /* we have to terminate, as we cannot recover from the memory error */
904 exit(1);
905 #endif
907 ENDTRY;
909 /* Update the file encapsulation; it might have changed based on the
910 packets we've read. */
911 cf->lnk_t = wtap_file_encap(cf->provider.wth);
913 epan_dissect_cleanup(&edt);
915 /* Don't freeze/thaw the list when doing live capture */
916 /*packet_list_thaw();*/
917 /* With the new packet list the first packet
918 * isn't automatically selected.
920 if (!cf->current_frame && !packet_list_multi_select_active())
921 packet_list_select_row_from_data(NULL);
923 if (cf->state == FILE_READ_ABORTED) {
924 /* Well, the user decided to exit Wireshark. Return CF_READ_ABORTED
925 so that our caller can kill off the capture child process;
926 this will cause an EOF on the pipe from the child, so
927 "cf_finish_tail()" will be called, and it will clean up
928 and exit. */
929 return CF_READ_ABORTED;
930 } else if (*err != 0) {
931 /* We got an error reading the capture file.
932 XXX - pop up a dialog box instead? */
933 if (err_info != NULL) {
934 ws_warning("Error \"%s\" while reading \"%s\" (\"%s\")",
935 wtap_strerror(*err), cf->filename, err_info);
936 g_free(err_info);
937 } else {
938 ws_warning("Error \"%s\" while reading \"%s\"",
939 wtap_strerror(*err), cf->filename);
941 return CF_READ_ERROR;
942 } else
943 return CF_READ_OK;
946 void
947 cf_fake_continue_tail(capture_file *cf)
949 if (cf->state == FILE_CLOSED) {
950 cf->state = FILE_READ_PENDING;
954 cf_read_status_t
955 cf_finish_tail(capture_file *cf, wtap_rec *rec, Buffer *buf, int *err,
956 fifo_string_cache_t *frame_dup_cache, GChecksum *frame_cksum)
958 gchar *err_info;
959 gint64 data_offset;
960 column_info *cinfo;
961 epan_dissect_t edt;
962 gboolean create_proto_tree;
963 guint tap_flags;
965 /* All the comments above in cf_continue_tail apply regarding the
966 * current display filter.
969 /* Get the union of the flags for all tap listeners. */
970 tap_flags = union_of_tap_listener_flags();
972 /* If the display filter or any tap listeners require the columns,
973 * construct them. */
974 cinfo = (tap_listeners_require_columns() ||
975 dfilter_requires_columns(cf->dfcode)) ? &cf->cinfo : NULL;
978 * Determine whether we need to create a protocol tree.
979 * We do if:
981 * we're going to apply a display filter;
983 * one of the tap listeners is going to apply a filter;
985 * one of the tap listeners requires a protocol tree;
987 * a postdissector wants field values or protocols on
988 * the first pass.
990 create_proto_tree =
991 (cf->dfcode != NULL || have_filtering_tap_listeners() ||
992 (tap_flags & TL_REQUIRES_PROTO_TREE) || postdissectors_want_hfids());
994 if (cf->provider.wth == NULL) {
995 cf_close(cf);
996 return CF_READ_ERROR;
999 /* Don't freeze/thaw the list when doing live capture */
1000 /*packet_list_freeze();*/
1002 epan_dissect_init(&edt, cf->epan, create_proto_tree, FALSE);
1004 while ((wtap_read(cf->provider.wth, rec, buf, err, &err_info, &data_offset))) {
1005 if (cf->state == FILE_READ_ABORTED) {
1006 /* Well, the user decided to abort the read. Break out of the
1007 loop, and let the code below (which is called even if there
1008 aren't any packets left to read) exit. */
1009 break;
1011 read_record(cf, rec, buf, cf->dfcode, &edt, cinfo, data_offset, frame_dup_cache, frame_cksum);
1012 wtap_rec_reset(rec);
1015 epan_dissect_cleanup(&edt);
1017 /* Don't freeze/thaw the list when doing live capture */
1018 /*packet_list_thaw();*/
1020 if (cf->state == FILE_READ_ABORTED) {
1021 /* Well, the user decided to abort the read. We're only called
1022 when the child capture process closes the pipe to us (meaning
1023 it's probably exited), so we can just close the capture
1024 file; we return CF_READ_ABORTED so our caller can do whatever
1025 is appropriate when that happens. */
1026 cf_close(cf);
1027 return CF_READ_ABORTED;
1030 /* We're done reading sequentially through the file. */
1031 cf->state = FILE_READ_DONE;
1033 /* We're done reading sequentially through the file; close the
1034 sequential I/O side, to free up memory it requires. */
1035 wtap_sequential_close(cf->provider.wth);
1037 /* Allow the protocol dissectors to free up memory that they
1038 * don't need after the sequential run-through of the packets. */
1039 postseq_cleanup_all_protocols();
1041 /* Update the file encapsulation; it might have changed based on the
1042 packets we've read. */
1043 cf->lnk_t = wtap_file_encap(cf->provider.wth);
1045 /* Update the details in the file-set dialog, as the capture file
1046 * has likely grown since we first stat-ed it */
1047 fileset_update_file(cf->filename);
1049 if (*err != 0) {
1050 /* We got an error reading the capture file.
1051 XXX - pop up a dialog box? */
1052 if (err_info != NULL) {
1053 ws_warning("Error \"%s\" while reading \"%s\" (\"%s\")",
1054 wtap_strerror(*err), cf->filename, err_info);
1055 g_free(err_info);
1056 } else {
1057 ws_warning("Error \"%s\" while reading \"%s\"",
1058 wtap_strerror(*err), cf->filename);
1060 return CF_READ_ERROR;
1061 } else {
1062 return CF_READ_OK;
1065 #endif /* HAVE_LIBPCAP */
1067 gchar *
1068 cf_get_display_name(capture_file *cf)
1070 gchar *displayname;
1072 /* Return a name to use in displays */
1073 if (!cf->is_tempfile) {
1074 /* Get the last component of the file name, and use that. */
1075 if (cf->filename) {
1076 displayname = g_filename_display_basename(cf->filename);
1077 } else {
1078 displayname=g_strdup("(No file)");
1080 } else {
1081 /* The file we read is a temporary file from a live capture or
1082 a merge operation; we don't mention its name, but, if it's
1083 from a capture, give the source of the capture. */
1084 if (cf->source) {
1085 displayname = g_strdup(cf->source);
1086 } else {
1087 displayname = g_strdup("(Untitled)");
1090 return displayname;
1093 gchar *
1094 cf_get_basename(capture_file *cf)
1096 gchar *displayname;
1098 /* Return a name to use in the GUI for the basename for files to
1099 which we save statistics */
1100 if (!cf->is_tempfile) {
1101 /* Get the last component of the file name, and use that. */
1102 if (cf->filename) {
1103 displayname = g_filename_display_basename(cf->filename);
1105 /* If the file name ends with any extension that corresponds
1106 to a file type we support - including compressed versions
1107 of those files - strip it off. */
1108 size_t displayname_len = strlen(displayname);
1109 GSList *extensions = wtap_get_all_file_extensions_list();
1110 GSList *suffix;
1111 for (suffix = extensions; suffix != NULL; suffix = g_slist_next(suffix)) {
1112 /* Does the file name end with that extension? */
1113 const char *extension = (char *)suffix->data;
1114 size_t extension_len = strlen(extension);
1115 if (displayname_len > extension_len &&
1116 displayname[displayname_len - extension_len - 1] == '.' &&
1117 strcmp(&displayname[displayname_len - extension_len], extension) == 0) {
1118 /* Yes. Strip the extension off, and return the result. */
1119 displayname[displayname_len - extension_len - 1] = '\0';
1120 break;
1123 wtap_free_extensions_list(extensions);
1124 } else {
1125 displayname=g_strdup("");
1127 } else {
1128 /* The file we read is a temporary file from a live capture or
1129 a merge operation; we don't mention its name, but, if it's
1130 from a capture, give the source of the capture. */
1131 if (cf->source) {
1132 displayname = g_strdup(cf->source);
1133 } else {
1134 displayname = g_strdup("");
1137 return displayname;
1140 void
1141 cf_set_tempfile_source(capture_file *cf, gchar *source)
1143 if (cf->source) {
1144 g_free(cf->source);
1147 if (source) {
1148 cf->source = g_strdup(source);
1149 } else {
1150 cf->source = g_strdup("");
1154 const gchar *
1155 cf_get_tempfile_source(capture_file *cf)
1157 if (!cf->source) {
1158 return "";
1161 return cf->source;
1164 /* XXX - use a macro instead? */
1166 cf_get_packet_count(capture_file *cf)
1168 return cf->count;
1171 /* XXX - use a macro instead? */
1172 gboolean
1173 cf_is_tempfile(capture_file *cf)
1175 return cf->is_tempfile;
1178 void
1179 cf_set_tempfile(capture_file *cf, gboolean is_tempfile)
1181 cf->is_tempfile = is_tempfile;
1185 /* XXX - use a macro instead? */
1186 void
1187 cf_set_drops_known(capture_file *cf, gboolean drops_known)
1189 cf->drops_known = drops_known;
1192 /* XXX - use a macro instead? */
1193 void
1194 cf_set_drops(capture_file *cf, guint32 drops)
1196 cf->drops = drops;
1199 /* XXX - use a macro instead? */
1200 gboolean
1201 cf_get_drops_known(capture_file *cf)
1203 return cf->drops_known;
1206 /* XXX - use a macro instead? */
1207 guint32
1208 cf_get_drops(capture_file *cf)
1210 return cf->drops;
1213 void
1214 cf_set_rfcode(capture_file *cf, dfilter_t *rfcode)
1216 cf->rfcode = rfcode;
1219 static void
1220 add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
1221 epan_dissect_t *edt, dfilter_t *dfcode, column_info *cinfo,
1222 wtap_rec *rec, Buffer *buf, gboolean add_to_packet_list)
1224 frame_data_set_before_dissect(fdata, &cf->elapsed_time,
1225 &cf->provider.ref, cf->provider.prev_dis);
1226 cf->provider.prev_cap = fdata;
1228 if (dfcode != NULL) {
1229 epan_dissect_prime_with_dfilter(edt, dfcode);
1231 #if 0
1232 /* Prepare coloring rules, this ensures that display filter rules containing
1233 * frame.color_rule references are still processed.
1234 * TODO: actually detect that situation or maybe apply other optimizations? */
1235 if (edt->tree && color_filters_used()) {
1236 color_filters_prime_edt(edt);
1237 fdata->need_colorize = 1;
1239 #endif
1241 if (!fdata->visited) {
1242 /* This is the first pass, so prime the epan_dissect_t with the
1243 hfids postdissectors want on the first pass. */
1244 prime_epan_dissect_with_postdissector_wanted_hfids(edt);
1247 /* Initialize passed_dfilter here so that dissectors can hide packets. */
1248 /* XXX We might want to add a separate "visible" bit to frame_data instead. */
1249 fdata->passed_dfilter = 1;
1251 /* Dissect the frame. */
1252 epan_dissect_run_with_taps(edt, cf->cd_t, rec,
1253 frame_tvbuff_new_buffer(&cf->provider, fdata, buf),
1254 fdata, cinfo);
1256 if (fdata->passed_dfilter && dfcode != NULL) {
1257 fdata->passed_dfilter = dfilter_apply_edt(dfcode, edt) ? 1 : 0;
1259 if (fdata->passed_dfilter && edt->pi.fd->dependent_frames) {
1260 /* This frame passed the display filter but it may depend on other
1261 * (potentially not displayed) frames. Find those frames and mark them
1262 * as depended upon.
1264 g_hash_table_foreach(edt->pi.fd->dependent_frames, find_and_mark_frame_depended_upon, cf->provider.frames);
1268 if (fdata->passed_dfilter || fdata->ref_time)
1269 cf->displayed_count++;
1271 if (add_to_packet_list) {
1272 /* We fill the needed columns from new_packet_list */
1273 packet_list_append(cinfo, fdata);
1276 if (fdata->passed_dfilter || fdata->ref_time)
1278 frame_data_set_after_dissect(fdata, &cf->cum_bytes);
1279 /* The only way we use prev_dis is to get the time stamp of
1280 * the previous displayed frame, so ignore it if it doesn't
1281 * have a time stamp, because we're presumably interested in
1282 * the timestamp of the previously displayed frame with a
1283 * time. XXX: What if in the future we want to use the previously
1284 * displayed frame for something else, too?
1286 if (fdata->has_ts) {
1287 cf->provider.prev_dis = fdata;
1290 /* If we haven't yet seen the first frame, this is it. */
1291 if (cf->first_displayed == 0)
1292 cf->first_displayed = fdata->num;
1294 /* This is the last frame we've seen so far. */
1295 cf->last_displayed = fdata->num;
1298 epan_dissect_reset(edt);
1302 * Read in a new record.
1303 * Returns TRUE if the packet was added to the packet (record) list,
1304 * FALSE otherwise.
1306 static gboolean
1307 read_record(capture_file *cf, wtap_rec *rec, Buffer *buf, dfilter_t *dfcode,
1308 epan_dissect_t *edt, column_info *cinfo, gint64 offset,
1309 fifo_string_cache_t *frame_dup_cache, GChecksum *frame_cksum)
1311 frame_data fdlocal;
1312 frame_data *fdata;
1313 gboolean passed = TRUE;
1314 gboolean added = FALSE;
1315 const gchar *cksum_string;
1316 gboolean was_in_cache;
1318 /* Add this packet's link-layer encapsulation type to cf->linktypes, if
1319 it's not already there.
1320 XXX - yes, this is O(N), so if every packet had a different
1321 link-layer encapsulation type, it'd be O(N^2) to read the file, but
1322 there are probably going to be a small number of encapsulation types
1323 in a file. */
1324 if (rec->rec_type == REC_TYPE_PACKET) {
1325 cf_add_encapsulation_type(cf, rec->rec_header.packet_header.pkt_encap);
1328 /* The frame number of this packet, if we add it to the set of frames,
1329 would be one more than the count of frames in the file so far. */
1330 frame_data_init(&fdlocal, cf->count + 1, rec, offset, cf->cum_bytes);
1332 if (cf->rfcode) {
1333 epan_dissect_t rf_edt;
1334 column_info *rf_cinfo = NULL;
1336 epan_dissect_init(&rf_edt, cf->epan, TRUE, FALSE);
1337 epan_dissect_prime_with_dfilter(&rf_edt, cf->rfcode);
1338 if (dfilter_requires_columns(cf->rfcode)) {
1339 rf_cinfo = &cf->cinfo;
1341 epan_dissect_run(&rf_edt, cf->cd_t, rec,
1342 frame_tvbuff_new_buffer(&cf->provider, &fdlocal, buf),
1343 &fdlocal, rf_cinfo);
1344 passed = dfilter_apply_edt(cf->rfcode, &rf_edt);
1345 epan_dissect_cleanup(&rf_edt);
1348 if (passed) {
1349 added = TRUE;
1351 /* This does a shallow copy of fdlocal, which is good enough. */
1352 fdata = frame_data_sequence_add(cf->provider.frames, &fdlocal);
1354 cf->count++;
1355 if (rec->block != NULL)
1356 cf->packet_comment_count += wtap_block_count_option(rec->block, OPT_COMMENT);
1357 cf->f_datalen = offset + fdlocal.cap_len;
1359 // Should we check if the frame data is a duplicate, and thus, ignore
1360 // this frame?
1361 if (frame_cksum != NULL && rec->rec_type == REC_TYPE_PACKET) {
1362 g_checksum_reset(frame_cksum);
1363 g_checksum_update(frame_cksum, ws_buffer_start_ptr(buf), ws_buffer_length(buf));
1364 cksum_string = g_strdup(g_checksum_get_string(frame_cksum));
1365 was_in_cache = fifo_string_cache_insert(frame_dup_cache, cksum_string);
1366 if (was_in_cache) {
1367 g_free((gpointer)cksum_string);
1368 fdata->ignored = TRUE;
1369 cf->ignored_count++;
1373 /* When a redissection is in progress (or queued), do not process packets.
1374 * This will be done once all (new) packets have been scanned. */
1375 if (!cf->redissecting && cf->redissection_queued == RESCAN_NONE) {
1376 add_packet_to_packet_list(fdata, cf, edt, dfcode, cinfo, rec, buf, TRUE);
1380 return added;
1384 typedef struct _callback_data_t {
1385 gpointer pd_window;
1386 gint64 f_len;
1387 progdlg_t *progbar;
1388 GTimer *prog_timer;
1389 bool stop_flag;
1390 } callback_data_t;
1393 static bool
1394 merge_callback(merge_event event, int num _U_,
1395 const merge_in_file_t in_files[], const guint in_file_count,
1396 void *data)
1398 guint i;
1399 callback_data_t *cb_data = (callback_data_t*) data;
1401 ws_assert(cb_data != NULL);
1403 switch (event) {
1405 case MERGE_EVENT_INPUT_FILES_OPENED:
1406 /* do nothing */
1407 break;
1409 case MERGE_EVENT_FRAME_TYPE_SELECTED:
1410 /* do nothing */
1411 break;
1413 case MERGE_EVENT_READY_TO_MERGE:
1414 /* Get the sum of the sizes of all the files. */
1415 for (i = 0; i < in_file_count; i++)
1416 cb_data->f_len += in_files[i].size;
1418 cb_data->prog_timer = g_timer_new();
1419 g_timer_start(cb_data->prog_timer);
1420 break;
1422 case MERGE_EVENT_RECORD_WAS_READ:
1424 /* Create the progress bar if necessary.
1425 We check on every iteration of the loop, so that it takes no
1426 longer than the standard time to create it (otherwise, for a
1427 large file, we might take considerably longer than that standard
1428 time in order to get to the next progress bar step). */
1429 if (cb_data->progbar == NULL) {
1430 cb_data->progbar = delayed_create_progress_dlg(cb_data->pd_window, NULL, NULL,
1431 FALSE, &cb_data->stop_flag, 0.0f);
1435 * Update the progress bar, but do it only after
1436 * PROGBAR_UPDATE_INTERVAL has elapsed. Calling update_progress_dlg
1437 * and packets_bar_update will likely trigger UI paint events, which
1438 * might take a while depending on the platform and display. Reset
1439 * our timer *after* painting.
1441 if (g_timer_elapsed(cb_data->prog_timer, NULL) > PROGBAR_UPDATE_INTERVAL) {
1442 float progbar_val;
1443 gint64 file_pos = 0;
1444 /* Get the sum of the seek positions in all of the files. */
1445 for (i = 0; i < in_file_count; i++)
1446 file_pos += wtap_read_so_far(in_files[i].wth);
1448 progbar_val = (gfloat) file_pos / (gfloat) cb_data->f_len;
1449 if (progbar_val > 1.0f) {
1450 /* Some file probably grew while we were reading it.
1451 That "shouldn't happen", so we'll just clip the progress
1452 value at 1.0. */
1453 progbar_val = 1.0f;
1456 if (cb_data->progbar != NULL) {
1457 gchar status_str[100];
1458 snprintf(status_str, sizeof(status_str),
1459 "%" PRId64 "KB of %" PRId64 "KB",
1460 file_pos / 1024, cb_data->f_len / 1024);
1461 update_progress_dlg(cb_data->progbar, progbar_val, status_str);
1463 g_timer_start(cb_data->prog_timer);
1466 break;
1468 case MERGE_EVENT_DONE:
1469 /* We're done merging the files; destroy the progress bar if it was created. */
1470 if (cb_data->progbar != NULL)
1471 destroy_progress_dlg(cb_data->progbar);
1472 g_timer_destroy(cb_data->prog_timer);
1473 break;
1476 return cb_data->stop_flag;
1481 cf_status_t
1482 cf_merge_files_to_tempfile(gpointer pd_window, const char *temp_dir, char **out_filenamep,
1483 int in_file_count, const char *const *in_filenames,
1484 int file_type, gboolean do_append)
1486 int err = 0;
1487 gchar *err_info = NULL;
1488 guint err_fileno;
1489 guint32 err_framenum;
1490 merge_result status;
1491 merge_progress_callback_t cb;
1492 callback_data_t *cb_data = g_new0(callback_data_t, 1);
1494 /* prepare our callback routine */
1495 cb_data->pd_window = pd_window;
1496 cb.callback_func = merge_callback;
1497 cb.data = cb_data;
1499 cf_callback_invoke(cf_cb_file_merge_started, NULL);
1501 /* merge the files */
1502 status = merge_files_to_tempfile(temp_dir, out_filenamep, "wireshark", file_type,
1503 in_filenames,
1504 in_file_count, do_append,
1505 IDB_MERGE_MODE_ALL_SAME, 0 /* snaplen */,
1506 "Wireshark", &cb, &err, &err_info,
1507 &err_fileno, &err_framenum);
1509 g_free(cb.data);
1511 switch (status) {
1512 case MERGE_OK:
1513 break;
1515 case MERGE_USER_ABORTED:
1516 /* this isn't really an error, though we will return CF_ERROR later */
1517 break;
1519 case MERGE_ERR_CANT_OPEN_INFILE:
1520 cfile_open_failure_alert_box(in_filenames[err_fileno], err, err_info);
1521 break;
1523 case MERGE_ERR_CANT_OPEN_OUTFILE:
1524 cfile_dump_open_failure_alert_box(*out_filenamep, err, err_info,
1525 file_type);
1526 break;
1528 case MERGE_ERR_CANT_READ_INFILE:
1529 cfile_read_failure_alert_box(in_filenames[err_fileno], err, err_info);
1530 break;
1532 case MERGE_ERR_BAD_PHDR_INTERFACE_ID:
1533 simple_error_message_box("Record %u of \"%s\" has an interface ID that does not match any IDB in its file.",
1534 err_framenum, in_filenames[err_fileno]);
1535 break;
1537 case MERGE_ERR_CANT_WRITE_OUTFILE:
1538 cfile_write_failure_alert_box(in_filenames[err_fileno],
1539 *out_filenamep, err, err_info,
1540 err_framenum, file_type);
1541 break;
1543 case MERGE_ERR_CANT_CLOSE_OUTFILE:
1544 cfile_close_failure_alert_box(*out_filenamep, err, err_info);
1545 break;
1547 default:
1548 simple_error_message_box("Unknown merge_files error %d", status);
1549 break;
1552 cf_callback_invoke(cf_cb_file_merge_finished, NULL);
1554 if (status != MERGE_OK) {
1555 /* Callers aren't expected to treat an error or an explicit abort
1556 differently - we put up error dialogs ourselves, so they don't
1557 have to. */
1558 return CF_ERROR;
1559 } else
1560 return CF_OK;
1563 cf_status_t
1564 cf_filter_packets(capture_file *cf, gchar *dftext, gboolean force)
1566 const char *filter_new = dftext ? dftext : "";
1567 const char *filter_old = cf->dfilter ? cf->dfilter : "";
1568 dfilter_t *dfcode;
1569 df_error_t *df_err;
1571 /* if new filter equals old one, do nothing unless told to do so */
1572 /* XXX - The text can be the same without compiling to the same code.
1573 * (Macros, field references, etc.)
1575 if (!force && strcmp(filter_new, filter_old) == 0) {
1576 return CF_OK;
1579 dfcode=NULL;
1581 if (dftext == NULL) {
1582 /* The new filter is an empty filter (i.e., display all packets).
1583 * so leave dfcode==NULL
1585 } else {
1587 * We have a filter; make a copy of it (as we'll be saving it),
1588 * and try to compile it.
1590 dftext = g_strdup(dftext);
1591 if (!dfilter_compile(dftext, &dfcode, &df_err)) {
1592 /* The attempt failed; report an error. */
1593 simple_message_box(ESD_TYPE_ERROR, NULL,
1594 "See the help for a description of the display filter syntax.",
1595 "\"%s\" isn't a valid display filter: %s",
1596 dftext, df_err->msg);
1597 df_error_free(&df_err);
1598 g_free(dftext);
1599 return CF_ERROR;
1602 /* Was it empty? */
1603 if (dfcode == NULL) {
1604 /* Yes - free the filter text, and set it to null. */
1605 g_free(dftext);
1606 dftext = NULL;
1610 /* We have a valid filter. Replace the current filter. */
1611 g_free(cf->dfilter);
1612 cf->dfilter = dftext;
1614 /* We'll recompile this when the rescan starts, or in cf_read()
1615 * if no file is open currently. However, if no file is open and
1616 * we start a new capture, we want to use this rather than
1617 * recompiling in cf_continue_tail() */
1618 dfilter_free(cf->dfcode);
1619 cf->dfcode = dfcode;
1621 /* Now rescan the packet list, applying the new filter, but not
1622 * throwing away information constructed on a previous pass.
1623 * If a dissection is already in progress, queue it.
1625 if (cf->redissection_queued == RESCAN_NONE) {
1626 if (cf->read_lock) {
1627 cf->redissection_queued = RESCAN_SCAN;
1628 } else if (cf->state != FILE_CLOSED) {
1629 if (dftext == NULL) {
1630 rescan_packets(cf, "Resetting", "filter", FALSE);
1631 } else {
1632 rescan_packets(cf, "Filtering", dftext, FALSE);
1637 return CF_OK;
1640 void
1641 cf_redissect_packets(capture_file *cf)
1643 if (cf->read_lock || cf->redissection_queued == RESCAN_SCAN) {
1644 /* Dissection in progress, signal redissection rather than rescanning. That
1645 * would destroy the current (in-progress) dissection in "cf_read" which
1646 * will cause issues when "cf_read" tries to add packets to the list.
1647 * If a previous rescan was requested, "upgrade" it to a full redissection.
1649 cf->redissection_queued = RESCAN_REDISSECT;
1651 if (cf->redissection_queued != RESCAN_NONE) {
1652 /* Redissection is (already) queued, wait for "cf_read" to finish. */
1653 /* XXX - what if whatever set and later clears read_lock is *not*
1654 * cf_read, e.g. process_specified_records ? We need to handle a
1655 * queued redissection there too like we do in cf_read.
1657 return;
1660 if (cf->state != FILE_CLOSED) {
1661 /* Restart dissection in case no cf_read is pending. */
1662 rescan_packets(cf, "Reprocessing", "all packets", TRUE);
1666 gboolean
1667 cf_read_record(capture_file *cf, const frame_data *fdata,
1668 wtap_rec *rec, Buffer *buf)
1670 int err;
1671 gchar *err_info;
1673 if (!wtap_seek_read(cf->provider.wth, fdata->file_off, rec, buf, &err, &err_info)) {
1674 cfile_read_failure_alert_box(cf->filename, err, err_info);
1675 return FALSE;
1677 return TRUE;
1680 gboolean
1681 cf_read_record_no_alert(capture_file *cf, const frame_data *fdata,
1682 wtap_rec *rec, Buffer *buf)
1684 int err;
1685 gchar *err_info;
1687 if (!wtap_seek_read(cf->provider.wth, fdata->file_off, rec, buf, &err, &err_info)) {
1688 g_free(err_info);
1689 return FALSE;
1691 return TRUE;
1694 gboolean
1695 cf_read_current_record(capture_file *cf)
1697 return cf_read_record(cf, cf->current_frame, &cf->rec, &cf->buf);
1700 /* Rescan the list of packets, reconstructing the CList.
1702 "action" describes why we're doing this; it's used in the progress
1703 dialog box.
1705 "action_item" describes what we're doing; it's used in the progress
1706 dialog box.
1708 "redissect" is TRUE if we need to make the dissectors reconstruct
1709 any state information they have (because a preference that affects
1710 some dissector has changed, meaning some dissector might construct
1711 its state differently from the way it was constructed the last time). */
1712 static void
1713 rescan_packets(capture_file *cf, const char *action, const char *action_item, gboolean redissect)
1715 /* Rescan packets new packet list */
1716 guint32 framenum;
1717 frame_data *fdata;
1718 wtap_rec rec;
1719 Buffer buf;
1720 progdlg_t *progbar = NULL;
1721 GTimer *prog_timer = g_timer_new();
1722 int count;
1723 frame_data *selected_frame, *preceding_frame, *following_frame, *prev_frame;
1724 int selected_frame_num, preceding_frame_num, following_frame_num, prev_frame_num;
1725 gboolean selected_frame_seen;
1726 float progbar_val;
1727 gint64 start_time;
1728 gchar status_str[100];
1729 epan_dissect_t edt;
1730 dfilter_t *dfcode = NULL;
1731 column_info *cinfo;
1732 gboolean create_proto_tree;
1733 gboolean filtering_tap_listeners = FALSE;
1734 guint tap_flags;
1735 gboolean add_to_packet_list = FALSE;
1736 gboolean compiled _U_;
1737 guint32 frames_count;
1738 rescan_type queued_rescan_type = RESCAN_NONE;
1740 if (cf->state == FILE_CLOSED || cf->state == FILE_READ_PENDING) {
1741 return;
1744 /* Rescan in progress, clear pending actions. */
1745 cf->redissection_queued = RESCAN_NONE;
1746 ws_assert(!cf->read_lock);
1747 cf->read_lock = TRUE;
1749 wtap_rec_init(&rec);
1750 ws_buffer_init(&buf, 1514);
1752 /* Compile the current display filter.
1753 * The code it compiles to might have changed, e.g. if a display
1754 * filter macro used has changed.
1756 * We assume this will not fail since cf->dfilter is only set in
1757 * cf_filter IFF the filter was valid.
1758 * XXX - This is not necessarily true, if the filter has a FT_IPv4
1759 * or FT_IPv6 field compared to a resolved hostname in it, because
1760 * we do a new host lookup, and that *could* timeout this time
1761 * (though with the read lock above we shouldn't have many lookups at
1762 * once, reducing the chances of that)... (#19612)
1764 if (cf->dfilter) {
1765 compiled = dfilter_compile(cf->dfilter, &dfcode, NULL);
1766 ws_assert(compiled && dfcode);
1769 dfilter_free(cf->dfcode);
1770 cf->dfcode = dfcode;
1772 /* Do we have any tap listeners with filters? */
1773 filtering_tap_listeners = have_filtering_tap_listeners();
1775 /* Update references in filters (if any) for the protocol
1776 * tree corresponding to the currently selected frame in the GUI. */
1777 if (cf->edt != NULL && cf->edt->tree != NULL) {
1778 if (cf->dfcode)
1779 dfilter_load_field_references(cf->dfcode, cf->edt->tree);
1780 if (filtering_tap_listeners)
1781 tap_listeners_load_field_references(cf->edt);
1784 if (cf->dfcode != NULL) {
1785 dfilter_log_full(LOG_DOMAIN_DFILTER, LOG_LEVEL_NOISY, NULL, -1, NULL,
1786 cf->dfcode, "Rescanning packets with display filter");
1789 /* Get the union of the flags for all tap listeners. */
1790 tap_flags = union_of_tap_listener_flags();
1792 /* If the display filter or any tap listeners require the columns,
1793 * construct them. */
1794 cinfo = (tap_listeners_require_columns() ||
1795 dfilter_requires_columns(cf->dfcode)) ? &cf->cinfo : NULL;
1798 * Determine whether we need to create a protocol tree.
1799 * We do if:
1801 * we're going to apply a display filter;
1803 * one of the tap listeners is going to apply a filter;
1805 * one of the tap listeners requires a protocol tree;
1807 * we're redissecting and a postdissector wants field
1808 * values or protocols on the first pass.
1810 create_proto_tree =
1811 (cf->dfcode != NULL || filtering_tap_listeners ||
1812 (tap_flags & TL_REQUIRES_PROTO_TREE) ||
1813 (redissect && postdissectors_want_hfids()));
1815 reset_tap_listeners();
1816 /* Which frame, if any, is the currently selected frame?
1817 XXX - should the selected frame or the focus frame be the "current"
1818 frame, that frame being the one from which "Find Frame" searches
1819 start? */
1820 selected_frame = cf->current_frame;
1822 /* Mark frame num as not found */
1823 selected_frame_num = -1;
1825 /* Freeze the packet list while we redo it, so we don't get any
1826 screen updates while it happens. */
1827 packet_list_freeze();
1829 if (redissect) {
1830 /* We need to re-initialize all the state information that protocols
1831 keep, because some preference that controls a dissector has changed,
1832 which might cause the state information to be constructed differently
1833 by that dissector. */
1835 /* We might receive new packets while redissecting, and we don't
1836 want to dissect those before their time. */
1837 cf->redissecting = TRUE;
1839 /* 'reset' dissection session */
1840 epan_free(cf->epan);
1841 if (cf->edt && cf->edt->pi.fd) {
1842 /* All pointers in "per frame proto data" for the currently selected
1843 packet are allocated in wmem_file_scope() and deallocated in epan_free().
1844 Free them here to avoid unintended usage in packet_list_clear(). */
1845 frame_data_destroy(cf->edt->pi.fd);
1847 cf->epan = ws_epan_new(cf);
1848 cf->cinfo.epan = cf->epan;
1850 /* A new Lua tap listener may be registered in lua_prime_all_fields()
1851 called via epan_new() / init_dissection() when reloading Lua plugins. */
1852 if (!create_proto_tree && have_filtering_tap_listeners()) {
1853 create_proto_tree = TRUE;
1855 if (!cinfo && tap_listeners_require_columns()) {
1856 cinfo = &cf->cinfo;
1859 /* We need to redissect the packets so we have to discard our old
1860 * packet list store. */
1861 packet_list_clear();
1862 add_to_packet_list = TRUE;
1865 /* We don't yet know which will be the first and last frames displayed. */
1866 cf->first_displayed = 0;
1867 cf->last_displayed = 0;
1869 /* We currently don't display any packets */
1870 cf->displayed_count = 0;
1872 /* Iterate through the list of frames. Call a routine for each frame
1873 to check whether it should be displayed and, if so, add it to
1874 the display list. */
1875 cf->provider.ref = NULL;
1876 cf->provider.prev_dis = NULL;
1877 cf->provider.prev_cap = NULL;
1878 cf->cum_bytes = 0;
1880 cf_callback_invoke(cf_cb_file_rescan_started, cf);
1882 g_timer_start(prog_timer);
1883 /* Count of packets at which we've looked. */
1884 count = 0;
1885 /* Progress so far. */
1886 progbar_val = 0.0f;
1888 cf->stop_flag = FALSE;
1889 start_time = g_get_monotonic_time();
1891 /* no previous row yet */
1892 prev_frame_num = -1;
1893 prev_frame = NULL;
1895 preceding_frame_num = -1;
1896 preceding_frame = NULL;
1897 following_frame_num = -1;
1898 following_frame = NULL;
1900 selected_frame_seen = FALSE;
1902 frames_count = cf->count;
1904 epan_dissect_init(&edt, cf->epan, create_proto_tree, FALSE);
1906 if (redissect) {
1908 * Decryption secrets and name resolution blocks are read while
1909 * sequentially processing records and then passed to the dissector.
1910 * During redissection, the previous information is lost (see epan_free
1911 * above), but they are not read again from the file as only packet
1912 * records are re-read. Therefore reset the wtap secrets and name
1913 * resolution callbacks such that wtap resupplies the callbacks with
1914 * previously read information.
1916 wtap_set_cb_new_ipv4(cf->provider.wth, add_ipv4_name);
1917 wtap_set_cb_new_ipv6(cf->provider.wth, (wtap_new_ipv6_callback_t) add_ipv6_name);
1918 wtap_set_cb_new_secrets(cf->provider.wth, secrets_wtap_callback);
1921 for (framenum = 1; framenum <= frames_count; framenum++) {
1922 fdata = frame_data_sequence_find(cf->provider.frames, framenum);
1924 /* Create the progress bar if necessary.
1925 We check on every iteration of the loop, so that it takes no
1926 longer than the standard time to create it (otherwise, for a
1927 large file, we might take considerably longer than that standard
1928 time in order to get to the next progress bar step). */
1929 if (progbar == NULL)
1930 progbar = delayed_create_progress_dlg(cf->window, action, action_item, TRUE,
1931 &cf->stop_flag,
1932 progbar_val);
1935 * Update the progress bar, but do it only after PROGBAR_UPDATE_INTERVAL
1936 * has elapsed. Calling update_progress_dlg and packets_bar_update will
1937 * likely trigger UI paint events, which might take a while depending on
1938 * the platform and display. Reset our timer *after* painting.
1940 if (g_timer_elapsed(prog_timer, NULL) > PROGBAR_UPDATE_INTERVAL) {
1941 /* let's not divide by zero. I should never be started
1942 * with count == 0, so let's assert that
1944 ws_assert(cf->count > 0);
1945 progbar_val = (gfloat) count / frames_count;
1947 if (progbar != NULL) {
1948 snprintf(status_str, sizeof(status_str),
1949 "%4u of %u frames", count, frames_count);
1950 update_progress_dlg(progbar, progbar_val, status_str);
1953 g_timer_start(prog_timer);
1956 queued_rescan_type = cf->redissection_queued;
1957 if (queued_rescan_type != RESCAN_NONE) {
1958 /* A redissection was requested while an existing redissection was
1959 * pending. */
1960 break;
1963 if (cf->stop_flag) {
1964 /* Well, the user decided to abort the filtering. Just stop.
1966 XXX - go back to the previous filter? Users probably just
1967 want not to wait for a filtering operation to finish;
1968 unless we cancel by having no filter, reverting to the
1969 previous filter will probably be even more expensive than
1970 continuing the filtering, as it involves going back to the
1971 beginning and filtering, and even with no filter we currently
1972 have to re-generate the entire clist, which is also expensive.
1974 I'm not sure what Network Monitor does, but it doesn't appear
1975 to give you an unfiltered display if you cancel. */
1976 break;
1979 count++;
1981 if (redissect) {
1982 /* Since all state for the frame was destroyed, mark the frame
1983 * as not visited, free the GSList referring to the state
1984 * data (the per-frame data itself was freed by
1985 * "init_dissection()"), and null out the GSList pointer. */
1986 frame_data_reset(fdata);
1987 frames_count = cf->count;
1990 /* Frame dependencies from the previous dissection/filtering are no longer valid. */
1991 fdata->dependent_of_displayed = 0;
1993 if (!cf_read_record(cf, fdata, &rec, &buf))
1994 break; /* error reading the frame */
1996 /* If the previous frame is displayed, and we haven't yet seen the
1997 selected frame, remember that frame - it's the closest one we've
1998 yet seen before the selected frame. */
1999 if (prev_frame_num != -1 && !selected_frame_seen && prev_frame->passed_dfilter) {
2000 preceding_frame_num = prev_frame_num;
2001 preceding_frame = prev_frame;
2004 add_packet_to_packet_list(fdata, cf, &edt, cf->dfcode,
2005 cinfo, &rec, &buf,
2006 add_to_packet_list);
2008 /* If this frame is displayed, and this is the first frame we've
2009 seen displayed after the selected frame, remember this frame -
2010 it's the closest one we've yet seen at or after the selected
2011 frame. */
2012 if (fdata->passed_dfilter && selected_frame_seen && following_frame_num == -1) {
2013 following_frame_num = fdata->num;
2014 following_frame = fdata;
2016 if (fdata == selected_frame) {
2017 selected_frame_seen = TRUE;
2018 if (fdata->passed_dfilter)
2019 selected_frame_num = fdata->num;
2022 /* Remember this frame - it'll be the previous frame
2023 on the next pass through the loop. */
2024 prev_frame_num = fdata->num;
2025 prev_frame = fdata;
2026 wtap_rec_reset(&rec);
2029 epan_dissect_cleanup(&edt);
2030 wtap_rec_cleanup(&rec);
2031 ws_buffer_free(&buf);
2033 /* We are done redissecting the packet list. */
2034 cf->redissecting = FALSE;
2036 if (redissect) {
2037 frames_count = cf->count;
2038 /* Clear out what remains of the visited flags and per-frame data
2039 pointers.
2041 XXX - that may cause various forms of bogosity when dissecting
2042 these frames, as they won't have been seen by this sequential
2043 pass, but the only alternative I see is to keep scanning them
2044 even though the user requested that the scan stop, and that
2045 would leave the user stuck with an Wireshark grinding on
2046 until it finishes. Should we just stick them with that? */
2047 for (; framenum <= frames_count; framenum++) {
2048 fdata = frame_data_sequence_find(cf->provider.frames, framenum);
2049 frame_data_reset(fdata);
2053 /* We're done filtering the packets; destroy the progress bar if it
2054 was created. */
2055 if (progbar != NULL)
2056 destroy_progress_dlg(progbar);
2057 g_timer_destroy(prog_timer);
2059 /* Unfreeze the packet list. */
2060 if (!add_to_packet_list)
2061 packet_list_recreate_visible_rows();
2063 /* Compute the time it took to filter the file */
2064 compute_elapsed(cf, start_time);
2066 packet_list_thaw();
2068 /* It is safe again to execute redissections or sort. */
2069 ws_assert(cf->read_lock);
2070 cf->read_lock = FALSE;
2072 cf_callback_invoke(cf_cb_file_rescan_finished, cf);
2074 if (selected_frame_num == -1) {
2075 /* The selected frame didn't pass the filter. */
2076 if (selected_frame == NULL) {
2077 /* That's because there *was* no selected frame. Make the first
2078 displayed frame the current frame. */
2079 selected_frame_num = 0;
2080 } else {
2081 /* Find the nearest displayed frame to the selected frame (whether
2082 it's before or after that frame) and make that the current frame.
2083 If the next and previous displayed frames are equidistant from the
2084 selected frame, choose the next one. */
2085 ws_assert(following_frame == NULL ||
2086 following_frame->num >= selected_frame->num);
2087 ws_assert(preceding_frame == NULL ||
2088 preceding_frame->num <= selected_frame->num);
2089 if (following_frame == NULL) {
2090 /* No frame after the selected frame passed the filter, so we
2091 have to select the last displayed frame before the selected
2092 frame. */
2093 selected_frame_num = preceding_frame_num;
2094 selected_frame = preceding_frame;
2095 } else if (preceding_frame == NULL) {
2096 /* No frame before the selected frame passed the filter, so we
2097 have to select the first displayed frame after the selected
2098 frame. */
2099 selected_frame_num = following_frame_num;
2100 selected_frame = following_frame;
2101 } else {
2102 /* Frames before and after the selected frame passed the filter, so
2103 we'll select the previous frame */
2104 selected_frame_num = preceding_frame_num;
2105 selected_frame = preceding_frame;
2110 if (selected_frame_num == -1) {
2111 /* There are no frames displayed at all. */
2112 cf_unselect_packet(cf);
2113 } else {
2114 /* Either the frame that was selected passed the filter, or we've
2115 found the nearest displayed frame to that frame. Select it, make
2116 it the focus row, and make it visible. */
2117 /* Set to invalid to force update of packet list and packet details */
2118 if (selected_frame_num == 0) {
2119 packet_list_select_row_from_data(NULL);
2120 }else{
2121 if (!packet_list_select_row_from_data(selected_frame)) {
2122 /* We didn't find a row corresponding to this frame.
2123 This means that the frame isn't being displayed currently,
2124 so we can't select it. */
2125 simple_message_box(ESD_TYPE_INFO, NULL,
2126 "The capture file is probably not fully dissected.",
2127 "End of capture exceeded.");
2132 /* If another rescan (due to dfilter change) or redissection (due to profile
2133 * change) was requested, the rescan above is aborted and restarted here. */
2134 if (queued_rescan_type != RESCAN_NONE) {
2135 redissect = redissect || queued_rescan_type == RESCAN_REDISSECT;
2136 rescan_packets(cf, "Reprocessing", "all packets", redissect);
2142 * Scan through all frame data and recalculate the ref time
2143 * without rereading the file.
2144 * XXX - do we need a progress bar or is this fast enough?
2146 void
2147 cf_reftime_packets(capture_file* cf)
2149 guint32 framenum;
2150 frame_data *fdata;
2151 nstime_t rel_ts;
2153 cf->provider.ref = NULL;
2154 cf->provider.prev_dis = NULL;
2155 cf->cum_bytes = 0;
2157 for (framenum = 1; framenum <= cf->count; framenum++) {
2158 fdata = frame_data_sequence_find(cf->provider.frames, framenum);
2160 /* just add some value here until we know if it is being displayed or not */
2161 fdata->cum_bytes = cf->cum_bytes + fdata->pkt_len;
2164 * Timestamps
2167 if (fdata->has_ts) {
2168 /* If we don't have the time stamp of the first packet in the
2169 capture, it's because this is the first packet. Save the time
2170 stamp of this packet as the time stamp of the first packet. */
2171 if (cf->provider.ref == NULL)
2172 cf->provider.ref = fdata;
2173 /* if this frames is marked as a reference time frame, reset
2174 firstsec and firstusec to this frame */
2175 if (fdata->ref_time)
2176 cf->provider.ref = fdata;
2178 /* Get the time elapsed between the first packet and this one. */
2179 fdata->frame_ref_num = (fdata != cf->provider.ref) ? cf->provider.ref->num : 0;
2180 nstime_delta(&rel_ts, &fdata->abs_ts, &cf->provider.ref->abs_ts);
2182 /* If it's greater than the current elapsed time, set the elapsed
2183 time to it (we check for "greater than" so as not to be
2184 confused by time moving backwards). */
2185 if ((gint32)cf->elapsed_time.secs < rel_ts.secs
2186 || ((gint32)cf->elapsed_time.secs == rel_ts.secs && (gint32)cf->elapsed_time.nsecs < rel_ts.nsecs)) {
2187 cf->elapsed_time = rel_ts;
2190 /* If this frame is displayed, get the time elapsed between the
2191 previous displayed packet and this packet. */
2192 /* XXX: What if in the future we want to use the previously
2193 * displayed frame for something else, too? Then we'd want
2194 * to store this frame as prev_dis even if it doesn't have a
2195 * timestamp. */
2196 if ( fdata->passed_dfilter ) {
2197 /* If we don't have the time stamp of the previous displayed
2198 packet, it's because this is the first displayed packet.
2199 Save the time stamp of this packet as the time stamp of
2200 the previous displayed packet. */
2201 if (cf->provider.prev_dis == NULL) {
2202 cf->provider.prev_dis = fdata;
2205 fdata->prev_dis_num = cf->provider.prev_dis->num;
2206 cf->provider.prev_dis = fdata;
2208 } else {
2209 /* If this frame doesn't have a timestamp, don't calculate
2210 anything with relative times. */
2211 /* However, if this frame is marked as a reference time frame,
2212 clear the reference frame so that the next frame with a
2213 timestamp becomes the reference frame. */
2214 if (fdata->ref_time) {
2215 cf->provider.ref = NULL;
2220 * Byte counts
2222 if ( (fdata->passed_dfilter) || (fdata->ref_time) ) {
2223 /* This frame either passed the display filter list or is marked as
2224 a time reference frame. All time reference frames are displayed
2225 even if they don't pass the display filter */
2226 if (fdata->ref_time) {
2227 /* if this was a TIME REF frame we should reset the cum_bytes field */
2228 cf->cum_bytes = fdata->pkt_len;
2229 fdata->cum_bytes = cf->cum_bytes;
2230 } else {
2231 /* increase cum_bytes with this packets length */
2232 cf->cum_bytes += fdata->pkt_len;
2238 typedef enum {
2239 PSP_FINISHED,
2240 PSP_STOPPED,
2241 PSP_FAILED
2242 } psp_return_t;
2244 static psp_return_t
2245 process_specified_records(capture_file *cf, packet_range_t *range,
2246 const char *string1, const char *string2, gboolean terminate_is_stop,
2247 bool (*callback)(capture_file *, frame_data *,
2248 wtap_rec *, Buffer *, void *),
2249 void *callback_args,
2250 gboolean show_progress_bar)
2252 guint32 framenum;
2253 frame_data *fdata;
2254 wtap_rec rec;
2255 Buffer buf;
2256 psp_return_t ret = PSP_FINISHED;
2258 progdlg_t *progbar = NULL;
2259 GTimer *prog_timer = g_timer_new();
2260 int progbar_count;
2261 float progbar_val;
2262 gchar progbar_status_str[100];
2263 range_process_e process_this;
2265 wtap_rec_init(&rec);
2266 ws_buffer_init(&buf, 1514);
2268 g_timer_start(prog_timer);
2269 /* Count of packets at which we've looked. */
2270 progbar_count = 0;
2271 /* Progress so far. */
2272 progbar_val = 0.0f;
2274 /* XXX - It should be ok to have multiple readers, so long as nothing
2275 * frees the epan context, e.g. rescan_packets with redissect true,
2276 * or anything that closes the file (including reload and certain forms
2277 * of saving.) This is mostly to stop cf_save_records but should probably
2278 * be handled by callers in order to allow multiple readers (e.g.,
2279 * restarting taps after adding or changing one.) We should probably
2280 * make this a real reader-writer lock.
2282 if (cf->read_lock) {
2283 ws_warning("Failing due to nested process_specified_records(\"%s\") call!", cf->filename);
2284 return PSP_FAILED;
2286 cf->read_lock = TRUE;
2288 cf->stop_flag = FALSE;
2290 if (range != NULL)
2291 packet_range_process_init(range);
2293 /* Iterate through all the packets, printing the packets that
2294 were selected by the current display filter. */
2295 for (framenum = 1; framenum <= cf->count; framenum++) {
2296 fdata = frame_data_sequence_find(cf->provider.frames, framenum);
2298 /* Create the progress bar if necessary.
2299 We check on every iteration of the loop, so that it takes no
2300 longer than the standard time to create it (otherwise, for a
2301 large file, we might take considerably longer than that standard
2302 time in order to get to the next progress bar step). */
2303 if (show_progress_bar && progbar == NULL)
2304 progbar = delayed_create_progress_dlg(cf->window, string1, string2,
2305 terminate_is_stop,
2306 &cf->stop_flag,
2307 progbar_val);
2310 * Update the progress bar, but do it only after PROGBAR_UPDATE_INTERVAL
2311 * has elapsed. Calling update_progress_dlg and packets_bar_update will
2312 * likely trigger UI paint events, which might take a while depending on
2313 * the platform and display. Reset our timer *after* painting.
2315 if (progbar && g_timer_elapsed(prog_timer, NULL) > PROGBAR_UPDATE_INTERVAL) {
2316 /* let's not divide by zero. I should never be started
2317 * with count == 0, so let's assert that
2319 ws_assert(cf->count > 0);
2320 progbar_val = (gfloat) progbar_count / cf->count;
2322 snprintf(progbar_status_str, sizeof(progbar_status_str),
2323 "%4u of %u packets", progbar_count, cf->count);
2324 update_progress_dlg(progbar, progbar_val, progbar_status_str);
2326 g_timer_start(prog_timer);
2329 if (cf->stop_flag) {
2330 /* Well, the user decided to abort the operation. Just stop,
2331 and arrange to return PSP_STOPPED to our caller, so they know
2332 it was stopped explicitly. */
2333 ret = PSP_STOPPED;
2334 break;
2337 progbar_count++;
2339 if (range != NULL) {
2340 /* do we have to process this packet? */
2341 process_this = packet_range_process_packet(range, fdata);
2342 if (process_this == range_process_next) {
2343 /* this packet uninteresting, continue with next one */
2344 continue;
2345 } else if (process_this == range_processing_finished) {
2346 /* all interesting packets processed, stop the loop */
2347 break;
2351 /* Get the packet */
2352 if (!cf_read_record(cf, fdata, &rec, &buf)) {
2353 /* Attempt to get the packet failed. */
2354 ret = PSP_FAILED;
2355 break;
2357 /* Process the packet */
2358 if (!callback(cf, fdata, &rec, &buf, callback_args)) {
2359 /* Callback failed. We assume it reported the error appropriately. */
2360 ret = PSP_FAILED;
2361 break;
2363 wtap_rec_reset(&rec);
2366 /* We're done printing the packets; destroy the progress bar if
2367 it was created. */
2368 if (progbar != NULL)
2369 destroy_progress_dlg(progbar);
2370 g_timer_destroy(prog_timer);
2372 ws_assert(cf->read_lock);
2373 cf->read_lock = FALSE;
2375 wtap_rec_cleanup(&rec);
2376 ws_buffer_free(&buf);
2378 return ret;
2381 typedef struct {
2382 epan_dissect_t edt;
2383 column_info *cinfo;
2384 } retap_callback_args_t;
2386 static bool
2387 retap_packet(capture_file *cf, frame_data *fdata, wtap_rec *rec, Buffer *buf,
2388 void *argsp)
2390 retap_callback_args_t *args = (retap_callback_args_t *)argsp;
2392 epan_dissect_run_with_taps(&args->edt, cf->cd_t, rec,
2393 frame_tvbuff_new_buffer(&cf->provider, fdata, buf),
2394 fdata, args->cinfo);
2395 epan_dissect_reset(&args->edt);
2397 return true;
2400 cf_read_status_t
2401 cf_retap_packets(capture_file *cf)
2403 packet_range_t range;
2404 retap_callback_args_t callback_args;
2405 gboolean create_proto_tree;
2406 gboolean filtering_tap_listeners;
2407 guint tap_flags;
2408 psp_return_t ret;
2410 /* Presumably the user closed the capture file. */
2411 if (cf == NULL) {
2412 return CF_READ_ABORTED;
2415 /* XXX - If cf->read_lock is true, process_specified_records will fail
2416 * due to a nested call. We fail here so that we don't reset the tap
2417 * listeners if this tap isn't going to succeed.
2419 if (cf->read_lock) {
2420 ws_warning("Failing due to nested process_specified_records(\"%s\") call!", cf->filename);
2421 return CF_READ_ERROR;
2424 cf_callback_invoke(cf_cb_file_retap_started, cf);
2426 /* Do we have any tap listeners with filters? */
2427 filtering_tap_listeners = have_filtering_tap_listeners();
2429 /* Update references in filters (if any) for the protocol
2430 * tree corresponding to the currently selected frame in the GUI. */
2431 /* XXX - What if we *don't* have a currently selected frame in the GUI,
2432 * but we did the last time we loaded field references? Then they'll
2433 * match something instead of nothing (unless they've been recompiled).
2434 * Should we have a way to clear the field references even with a NULL tree?
2436 if (cf->edt != NULL && cf->edt->tree != NULL) {
2437 if (filtering_tap_listeners)
2438 tap_listeners_load_field_references(cf->edt);
2441 /* Get the union of the flags for all tap listeners. */
2442 tap_flags = union_of_tap_listener_flags();
2444 /* If any tap listeners require the columns, construct them. */
2445 callback_args.cinfo = (tap_listeners_require_columns()) ? &cf->cinfo : NULL;
2448 * Determine whether we need to create a protocol tree.
2449 * We do if:
2451 * one of the tap listeners is going to apply a filter;
2453 * one of the tap listeners requires a protocol tree.
2455 create_proto_tree =
2456 (filtering_tap_listeners || (tap_flags & TL_REQUIRES_PROTO_TREE));
2458 /* Reset the tap listeners. */
2459 reset_tap_listeners();
2460 uint32_t count = cf->count;
2462 epan_dissect_init(&callback_args.edt, cf->epan, create_proto_tree, FALSE);
2464 /* Iterate through the list of packets, dissecting all packets and
2465 re-running the taps. */
2466 packet_range_init(&range, cf);
2467 packet_range_process_init(&range);
2469 if (cf->state == FILE_READ_IN_PROGRESS) {
2470 /* We're not done with the sequential read of the file and might
2471 * add more frames while process_specified_records is going. We
2472 * don't want to tap new frames twice, so limit the range to the
2473 * frames already here.
2475 * cf_read sets read_lock so we don't tap in case of an offline
2476 * file, but cf_continue_tail and cf_finish_tail don't, and we
2477 * don't want them to, because tapping new packets in a live
2478 * capture is a common use case.
2480 * Note that most other users of process_specified_records (saving,
2481 * printing) do want to process new packets, unlike taps.
2483 if (count) {
2484 char* range_str = g_strdup_printf("-%u", count);
2485 packet_range_convert_str(&range, range_str);
2486 g_free(range_str);
2487 } else {
2488 /* range_t treats a missing number as meaning 1, not 0, and
2489 * reverses the order if backwards; thus the syntax -0 means
2490 * 0-1, so to only take zero packets we do this.
2492 packet_range_convert_str(&range, "0");
2494 range.process = range_process_user_range;
2497 ret = process_specified_records(cf, &range, "Recalculating statistics on",
2498 "all packets", TRUE, retap_packet,
2499 &callback_args, TRUE);
2501 packet_range_cleanup(&range);
2502 epan_dissect_cleanup(&callback_args.edt);
2504 cf_callback_invoke(cf_cb_file_retap_finished, cf);
2506 switch (ret) {
2507 case PSP_FINISHED:
2508 /* Completed successfully. */
2509 return CF_READ_OK;
2511 case PSP_STOPPED:
2512 /* Well, the user decided to abort the refiltering.
2513 Return CF_READ_ABORTED so our caller knows they did that. */
2514 return CF_READ_ABORTED;
2516 case PSP_FAILED:
2517 /* Error while retapping. */
2518 return CF_READ_ERROR;
2521 ws_assert_not_reached();
2522 return CF_READ_OK;
2525 typedef struct {
2526 print_args_t *print_args;
2527 gboolean print_header_line;
2528 char *header_line_buf;
2529 int header_line_buf_len;
2530 gboolean print_formfeed;
2531 gboolean print_separator;
2532 char *line_buf;
2533 int line_buf_len;
2534 gint *col_widths;
2535 int num_visible_cols;
2536 gint *visible_cols;
2537 epan_dissect_t edt;
2538 } print_callback_args_t;
2540 static bool
2541 print_packet(capture_file *cf, frame_data *fdata, wtap_rec *rec, Buffer *buf,
2542 void *argsp)
2544 print_callback_args_t *args = (print_callback_args_t *)argsp;
2545 int i;
2546 char *cp;
2547 int line_len;
2548 int column_len;
2549 int cp_off;
2550 char bookmark_name[9+10+1]; /* "__frameNNNNNNNNNN__\0" */
2551 char bookmark_title[6+10+1]; /* "Frame NNNNNNNNNN__\0" */
2552 col_item_t* col_item;
2553 const gchar* col_text;
2555 /* Fill in the column information if we're printing the summary
2556 information. */
2557 if (args->print_args->print_summary) {
2558 col_custom_prime_edt(&args->edt, &cf->cinfo);
2559 epan_dissect_run(&args->edt, cf->cd_t, rec,
2560 frame_tvbuff_new_buffer(&cf->provider, fdata, buf),
2561 fdata, &cf->cinfo);
2562 epan_dissect_fill_in_columns(&args->edt, FALSE, TRUE);
2563 } else
2564 epan_dissect_run(&args->edt, cf->cd_t, rec,
2565 frame_tvbuff_new_buffer(&cf->provider, fdata, buf),
2566 fdata, NULL);
2568 if (args->print_formfeed) {
2569 if (!new_page(args->print_args->stream))
2570 goto fail;
2573 * Print another header line if we print a packet summary on the
2574 * new page.
2576 if (args->print_args->print_col_headings)
2577 args->print_header_line = TRUE;
2578 } else {
2579 if (args->print_separator) {
2580 if (!print_line(args->print_args->stream, 0, ""))
2581 goto fail;
2586 * We generate bookmarks, if the output format supports them.
2587 * The name is "__frameN__".
2589 snprintf(bookmark_name, sizeof bookmark_name, "__frame%u__", fdata->num);
2591 if (args->print_args->print_summary) {
2592 if (!args->print_args->print_col_headings)
2593 args->print_header_line = FALSE;
2594 if (args->print_header_line) {
2595 if (!print_line(args->print_args->stream, 0, args->header_line_buf))
2596 goto fail;
2597 args->print_header_line = FALSE; /* we might not need to print any more */
2599 cp = &args->line_buf[0];
2600 line_len = 0;
2601 for (i = 0; i < args->num_visible_cols; i++) {
2602 col_item = &cf->cinfo.columns[args->visible_cols[i]];
2603 col_text = get_column_text(&cf->cinfo, args->visible_cols[i]);
2604 /* Find the length of the string for this column. */
2605 column_len = (int) strlen(col_text);
2606 if (args->col_widths[i] > column_len)
2607 column_len = args->col_widths[i];
2609 /* Make sure there's room in the line buffer for the column; if not,
2610 double its length. */
2611 line_len += column_len + 1; /* "+1" for space */
2612 if (line_len > args->line_buf_len) {
2613 cp_off = (int) (cp - args->line_buf);
2614 args->line_buf_len = 2 * line_len;
2615 args->line_buf = (char *)g_realloc(args->line_buf, args->line_buf_len + 1);
2616 cp = args->line_buf + cp_off;
2619 /* Right-justify the packet number column. */
2620 if (col_item->col_fmt == COL_NUMBER)
2621 snprintf(cp, column_len+1, "%*s", args->col_widths[i], col_text);
2622 else
2623 snprintf(cp, column_len+1, "%-*s", args->col_widths[i], col_text);
2624 cp += column_len;
2625 if (i != args->num_visible_cols - 1)
2626 *cp++ = ' ';
2628 *cp = '\0';
2631 * Generate a bookmark, using the summary line as the title.
2633 if (!print_bookmark(args->print_args->stream, bookmark_name,
2634 args->line_buf))
2635 goto fail;
2637 if (!print_line(args->print_args->stream, 0, args->line_buf))
2638 goto fail;
2639 } else {
2641 * Generate a bookmark, using "Frame N" as the title, as we're not
2642 * printing the summary line.
2644 snprintf(bookmark_title, sizeof bookmark_title, "Frame %u", fdata->num);
2645 if (!print_bookmark(args->print_args->stream, bookmark_name,
2646 bookmark_title))
2647 goto fail;
2648 } /* if (print_summary) */
2650 if (args->print_args->print_dissections != print_dissections_none) {
2651 if (args->print_args->print_summary) {
2652 /* Separate the summary line from the tree with a blank line. */
2653 if (!print_line(args->print_args->stream, 0, ""))
2654 goto fail;
2657 /* Print the information in that tree. */
2658 if (!proto_tree_print(args->print_args->print_dissections,
2659 args->print_args->print_hex, &args->edt, NULL,
2660 args->print_args->stream))
2661 goto fail;
2663 /* Print a blank line if we print anything after this (aka more than one packet). */
2664 args->print_separator = TRUE;
2666 /* Print a header line if we print any more packet summaries */
2667 if (args->print_args->print_col_headings)
2668 args->print_header_line = TRUE;
2671 if (args->print_args->print_hex) {
2672 if (args->print_args->print_summary || (args->print_args->print_dissections != print_dissections_none)) {
2673 if (!print_line(args->print_args->stream, 0, ""))
2674 goto fail;
2676 /* Print the full packet data as hex. */
2677 if (!print_hex_data(args->print_args->stream, &args->edt, args->print_args->hexdump_options))
2678 goto fail;
2680 /* Print a blank line if we print anything after this (aka more than one packet). */
2681 args->print_separator = TRUE;
2683 /* Print a header line if we print any more packet summaries */
2684 if (args->print_args->print_col_headings)
2685 args->print_header_line = TRUE;
2686 } /* if (args->print_args->print_dissections != print_dissections_none) */
2688 epan_dissect_reset(&args->edt);
2690 /* do we want to have a formfeed between each packet from now on? */
2691 if (args->print_args->print_formfeed) {
2692 args->print_formfeed = TRUE;
2695 return true;
2697 fail:
2698 epan_dissect_reset(&args->edt);
2699 return false;
2702 cf_print_status_t
2703 cf_print_packets(capture_file *cf, print_args_t *print_args,
2704 gboolean show_progress_bar)
2706 print_callback_args_t callback_args;
2707 gint data_width;
2708 char *cp;
2709 int i, cp_off, column_len, line_len;
2710 int num_visible_col = 0, last_visible_col = 0, visible_col_count;
2711 psp_return_t ret;
2712 GList *clp;
2713 fmt_data *cfmt;
2714 gboolean proto_tree_needed;
2716 callback_args.print_args = print_args;
2717 callback_args.print_header_line = print_args->print_col_headings;
2718 callback_args.header_line_buf = NULL;
2719 callback_args.header_line_buf_len = 256;
2720 callback_args.print_formfeed = FALSE;
2721 callback_args.print_separator = FALSE;
2722 callback_args.line_buf = NULL;
2723 callback_args.line_buf_len = 256;
2724 callback_args.col_widths = NULL;
2725 callback_args.num_visible_cols = 0;
2726 callback_args.visible_cols = NULL;
2728 if (!print_preamble(print_args->stream, cf->filename, get_ws_vcs_version_info())) {
2729 destroy_print_stream(print_args->stream);
2730 return CF_PRINT_WRITE_ERROR;
2733 if (print_args->print_summary) {
2734 /* We're printing packet summaries. Allocate the header line buffer
2735 and get the column widths. */
2736 callback_args.header_line_buf = (char *)g_malloc(callback_args.header_line_buf_len + 1);
2738 /* Find the number of visible columns and the last visible column */
2739 for (i = 0; i < prefs.num_cols; i++) {
2741 clp = g_list_nth(prefs.col_list, i);
2742 if (clp == NULL) /* Sanity check, Invalid column requested */
2743 continue;
2745 cfmt = (fmt_data *) clp->data;
2746 if (cfmt->visible) {
2747 num_visible_col++;
2748 last_visible_col = i;
2752 /* if num_visible_col is 0, we are done */
2753 if (num_visible_col == 0) {
2754 g_free(callback_args.header_line_buf);
2755 return CF_PRINT_OK;
2758 /* Find the widths for each of the columns - maximum of the
2759 width of the title and the width of the data - and construct
2760 a buffer with a line containing the column titles. */
2761 callback_args.num_visible_cols = num_visible_col;
2762 callback_args.col_widths = g_new(gint, num_visible_col);
2763 callback_args.visible_cols = g_new(gint, num_visible_col);
2764 cp = &callback_args.header_line_buf[0];
2765 line_len = 0;
2766 visible_col_count = 0;
2767 for (i = 0; i < cf->cinfo.num_cols; i++) {
2769 clp = g_list_nth(prefs.col_list, i);
2770 if (clp == NULL) /* Sanity check, Invalid column requested */
2771 continue;
2773 cfmt = (fmt_data *) clp->data;
2774 if (cfmt->visible == FALSE)
2775 continue;
2777 /* Save the order of visible columns */
2778 callback_args.visible_cols[visible_col_count] = i;
2780 /* Don't pad the last column. */
2781 if (i == last_visible_col)
2782 callback_args.col_widths[visible_col_count] = 0;
2783 else {
2784 callback_args.col_widths[visible_col_count] = (gint) strlen(cf->cinfo.columns[i].col_title);
2785 data_width = get_column_char_width(get_column_format(i));
2786 if (data_width > callback_args.col_widths[visible_col_count])
2787 callback_args.col_widths[visible_col_count] = data_width;
2790 /* Find the length of the string for this column. */
2791 column_len = (int) strlen(cf->cinfo.columns[i].col_title);
2792 if (callback_args.col_widths[visible_col_count] > column_len)
2793 column_len = callback_args.col_widths[visible_col_count];
2795 /* Make sure there's room in the line buffer for the column; if not,
2796 double its length. */
2797 line_len += column_len + 1; /* "+1" for space */
2798 if (line_len > callback_args.header_line_buf_len) {
2799 cp_off = (int) (cp - callback_args.header_line_buf);
2800 callback_args.header_line_buf_len = 2 * line_len;
2801 callback_args.header_line_buf = (char *)g_realloc(callback_args.header_line_buf,
2802 callback_args.header_line_buf_len + 1);
2803 cp = callback_args.header_line_buf + cp_off;
2806 /* Right-justify the packet number column. */
2807 /* if (cf->cinfo.col_fmt[i] == COL_NUMBER)
2808 snprintf(cp, column_len+1, "%*s", callback_args.col_widths[visible_col_count], cf->cinfo.columns[i].col_title);
2809 else*/
2810 snprintf(cp, column_len+1, "%-*s", callback_args.col_widths[visible_col_count], cf->cinfo.columns[i].col_title);
2811 cp += column_len;
2812 if (i != cf->cinfo.num_cols - 1)
2813 *cp++ = ' ';
2815 visible_col_count++;
2817 *cp = '\0';
2819 /* Now start out the main line buffer with the same length as the
2820 header line buffer. */
2821 callback_args.line_buf_len = callback_args.header_line_buf_len;
2822 callback_args.line_buf = (char *)g_malloc(callback_args.line_buf_len + 1);
2823 } /* if (print_summary) */
2825 /* Create the protocol tree, and make it visible, if we're printing
2826 the dissection or the hex data.
2827 XXX - do we need it if we're just printing the hex data? */
2828 proto_tree_needed =
2829 callback_args.print_args->print_dissections != print_dissections_none ||
2830 callback_args.print_args->print_hex ||
2831 have_custom_cols(&cf->cinfo) || have_field_extractors();
2832 epan_dissect_init(&callback_args.edt, cf->epan, proto_tree_needed, proto_tree_needed);
2834 /* Iterate through the list of packets, printing the packets we were
2835 told to print. */
2836 ret = process_specified_records(cf, &print_args->range, "Printing",
2837 "selected packets", TRUE, print_packet,
2838 &callback_args, show_progress_bar);
2839 epan_dissect_cleanup(&callback_args.edt);
2840 g_free(callback_args.header_line_buf);
2841 g_free(callback_args.line_buf);
2842 g_free(callback_args.col_widths);
2843 g_free(callback_args.visible_cols);
2845 switch (ret) {
2847 case PSP_FINISHED:
2848 /* Completed successfully. */
2849 break;
2851 case PSP_STOPPED:
2852 /* Well, the user decided to abort the printing.
2854 XXX - note that what got generated before they did that
2855 will get printed if we're piping to a print program; we'd
2856 have to write to a file and then hand that to the print
2857 program to make it actually not print anything. */
2858 break;
2860 case PSP_FAILED:
2861 /* Error while printing.
2863 XXX - note that what got generated before they did that
2864 will get printed if we're piping to a print program; we'd
2865 have to write to a file and then hand that to the print
2866 program to make it actually not print anything. */
2867 destroy_print_stream(print_args->stream);
2868 return CF_PRINT_WRITE_ERROR;
2871 if (!print_finale(print_args->stream)) {
2872 destroy_print_stream(print_args->stream);
2873 return CF_PRINT_WRITE_ERROR;
2876 if (!destroy_print_stream(print_args->stream))
2877 return CF_PRINT_WRITE_ERROR;
2879 return CF_PRINT_OK;
2882 typedef struct {
2883 FILE *fh;
2884 epan_dissect_t edt;
2885 print_args_t *print_args;
2886 json_dumper jdumper;
2887 } write_packet_callback_args_t;
2889 static bool
2890 write_pdml_packet(capture_file *cf, frame_data *fdata, wtap_rec *rec,
2891 Buffer *buf, void *argsp)
2893 write_packet_callback_args_t *args = (write_packet_callback_args_t *)argsp;
2895 /* Create the protocol tree, but don't fill in the column information. */
2896 epan_dissect_run(&args->edt, cf->cd_t, rec,
2897 frame_tvbuff_new_buffer(&cf->provider, fdata, buf),
2898 fdata, NULL);
2900 /* Write out the information in that tree. */
2901 write_pdml_proto_tree(NULL, &args->edt, &cf->cinfo, args->fh, FALSE);
2903 epan_dissect_reset(&args->edt);
2905 return !ferror(args->fh);
2908 cf_print_status_t
2909 cf_write_pdml_packets(capture_file *cf, print_args_t *print_args)
2911 write_packet_callback_args_t callback_args;
2912 FILE *fh;
2913 psp_return_t ret;
2915 fh = ws_fopen(print_args->file, "w");
2916 if (fh == NULL)
2917 return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
2919 write_pdml_preamble(fh, cf->filename);
2920 if (ferror(fh)) {
2921 fclose(fh);
2922 return CF_PRINT_WRITE_ERROR;
2925 callback_args.fh = fh;
2926 callback_args.print_args = print_args;
2927 epan_dissect_init(&callback_args.edt, cf->epan, TRUE, TRUE);
2929 /* Iterate through the list of packets, printing the packets we were
2930 told to print. */
2931 ret = process_specified_records(cf, &print_args->range, "Writing PDML",
2932 "selected packets", TRUE,
2933 write_pdml_packet, &callback_args, TRUE);
2935 epan_dissect_cleanup(&callback_args.edt);
2937 switch (ret) {
2939 case PSP_FINISHED:
2940 /* Completed successfully. */
2941 break;
2943 case PSP_STOPPED:
2944 /* Well, the user decided to abort the printing. */
2945 break;
2947 case PSP_FAILED:
2948 /* Error while printing. */
2949 fclose(fh);
2950 return CF_PRINT_WRITE_ERROR;
2953 write_pdml_finale(fh);
2954 if (ferror(fh)) {
2955 fclose(fh);
2956 return CF_PRINT_WRITE_ERROR;
2959 /* XXX - check for an error */
2960 fclose(fh);
2962 return CF_PRINT_OK;
2965 static bool
2966 write_psml_packet(capture_file *cf, frame_data *fdata, wtap_rec *rec,
2967 Buffer *buf, void *argsp)
2969 write_packet_callback_args_t *args = (write_packet_callback_args_t *)argsp;
2971 /* Fill in the column information */
2972 col_custom_prime_edt(&args->edt, &cf->cinfo);
2973 epan_dissect_run(&args->edt, cf->cd_t, rec,
2974 frame_tvbuff_new_buffer(&cf->provider, fdata, buf),
2975 fdata, &cf->cinfo);
2976 epan_dissect_fill_in_columns(&args->edt, FALSE, TRUE);
2978 /* Write out the column information. */
2979 write_psml_columns(&args->edt, args->fh, FALSE);
2981 epan_dissect_reset(&args->edt);
2983 return !ferror(args->fh);
2986 cf_print_status_t
2987 cf_write_psml_packets(capture_file *cf, print_args_t *print_args)
2989 write_packet_callback_args_t callback_args;
2990 FILE *fh;
2991 psp_return_t ret;
2993 gboolean proto_tree_needed;
2995 fh = ws_fopen(print_args->file, "w");
2996 if (fh == NULL)
2997 return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
2999 write_psml_preamble(&cf->cinfo, fh);
3000 if (ferror(fh)) {
3001 fclose(fh);
3002 return CF_PRINT_WRITE_ERROR;
3005 callback_args.fh = fh;
3006 callback_args.print_args = print_args;
3008 /* Fill in the column information, only create the protocol tree
3009 if having custom columns or field extractors. */
3010 proto_tree_needed = have_custom_cols(&cf->cinfo) || have_field_extractors();
3011 epan_dissect_init(&callback_args.edt, cf->epan, proto_tree_needed, proto_tree_needed);
3013 /* Iterate through the list of packets, printing the packets we were
3014 told to print. */
3015 ret = process_specified_records(cf, &print_args->range, "Writing PSML",
3016 "selected packets", TRUE,
3017 write_psml_packet, &callback_args, TRUE);
3019 epan_dissect_cleanup(&callback_args.edt);
3021 switch (ret) {
3023 case PSP_FINISHED:
3024 /* Completed successfully. */
3025 break;
3027 case PSP_STOPPED:
3028 /* Well, the user decided to abort the printing. */
3029 break;
3031 case PSP_FAILED:
3032 /* Error while printing. */
3033 fclose(fh);
3034 return CF_PRINT_WRITE_ERROR;
3037 write_psml_finale(fh);
3038 if (ferror(fh)) {
3039 fclose(fh);
3040 return CF_PRINT_WRITE_ERROR;
3043 /* XXX - check for an error */
3044 fclose(fh);
3046 return CF_PRINT_OK;
3049 static bool
3050 write_csv_packet(capture_file *cf, frame_data *fdata, wtap_rec *rec,
3051 Buffer *buf, void *argsp)
3053 write_packet_callback_args_t *args = (write_packet_callback_args_t *)argsp;
3055 /* Fill in the column information */
3056 col_custom_prime_edt(&args->edt, &cf->cinfo);
3057 epan_dissect_run(&args->edt, cf->cd_t, rec,
3058 frame_tvbuff_new_buffer(&cf->provider, fdata, buf),
3059 fdata, &cf->cinfo);
3060 epan_dissect_fill_in_columns(&args->edt, FALSE, TRUE);
3062 /* Write out the column information. */
3063 write_csv_columns(&args->edt, args->fh);
3065 epan_dissect_reset(&args->edt);
3067 return !ferror(args->fh);
3070 cf_print_status_t
3071 cf_write_csv_packets(capture_file *cf, print_args_t *print_args)
3073 write_packet_callback_args_t callback_args;
3074 gboolean proto_tree_needed;
3075 FILE *fh;
3076 psp_return_t ret;
3078 fh = ws_fopen(print_args->file, "w");
3079 if (fh == NULL)
3080 return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
3082 write_csv_column_titles(&cf->cinfo, fh);
3083 if (ferror(fh)) {
3084 fclose(fh);
3085 return CF_PRINT_WRITE_ERROR;
3088 callback_args.fh = fh;
3089 callback_args.print_args = print_args;
3091 /* only create the protocol tree if having custom columns or field extractors. */
3092 proto_tree_needed = have_custom_cols(&cf->cinfo) || have_field_extractors();
3093 epan_dissect_init(&callback_args.edt, cf->epan, proto_tree_needed, proto_tree_needed);
3095 /* Iterate through the list of packets, printing the packets we were
3096 told to print. */
3097 ret = process_specified_records(cf, &print_args->range, "Writing CSV",
3098 "selected packets", TRUE,
3099 write_csv_packet, &callback_args, TRUE);
3101 epan_dissect_cleanup(&callback_args.edt);
3103 switch (ret) {
3105 case PSP_FINISHED:
3106 /* Completed successfully. */
3107 break;
3109 case PSP_STOPPED:
3110 /* Well, the user decided to abort the printing. */
3111 break;
3113 case PSP_FAILED:
3114 /* Error while printing. */
3115 fclose(fh);
3116 return CF_PRINT_WRITE_ERROR;
3119 /* XXX - check for an error */
3120 fclose(fh);
3122 return CF_PRINT_OK;
3125 static bool
3126 carrays_write_packet(capture_file *cf, frame_data *fdata, wtap_rec *rec,
3127 Buffer *buf, void *argsp)
3129 write_packet_callback_args_t *args = (write_packet_callback_args_t *)argsp;
3131 epan_dissect_run(&args->edt, cf->cd_t, rec,
3132 frame_tvbuff_new_buffer(&cf->provider, fdata, buf),
3133 fdata, NULL);
3134 write_carrays_hex_data(fdata->num, args->fh, &args->edt);
3135 epan_dissect_reset(&args->edt);
3137 return !ferror(args->fh);
3140 cf_print_status_t
3141 cf_write_carrays_packets(capture_file *cf, print_args_t *print_args)
3143 write_packet_callback_args_t callback_args;
3144 FILE *fh;
3145 psp_return_t ret;
3147 fh = ws_fopen(print_args->file, "w");
3149 if (fh == NULL)
3150 return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
3152 if (ferror(fh)) {
3153 fclose(fh);
3154 return CF_PRINT_WRITE_ERROR;
3157 callback_args.fh = fh;
3158 callback_args.print_args = print_args;
3159 epan_dissect_init(&callback_args.edt, cf->epan, TRUE, TRUE);
3161 /* Iterate through the list of packets, printing the packets we were
3162 told to print. */
3163 ret = process_specified_records(cf, &print_args->range,
3164 "Writing C Arrays",
3165 "selected packets", TRUE,
3166 carrays_write_packet, &callback_args, TRUE);
3168 epan_dissect_cleanup(&callback_args.edt);
3170 switch (ret) {
3171 case PSP_FINISHED:
3172 /* Completed successfully. */
3173 break;
3174 case PSP_STOPPED:
3175 /* Well, the user decided to abort the printing. */
3176 break;
3177 case PSP_FAILED:
3178 /* Error while printing. */
3179 fclose(fh);
3180 return CF_PRINT_WRITE_ERROR;
3183 fclose(fh);
3184 return CF_PRINT_OK;
3187 static bool
3188 write_json_packet(capture_file *cf, frame_data *fdata, wtap_rec *rec,
3189 Buffer *buf, void *argsp)
3191 write_packet_callback_args_t *args = (write_packet_callback_args_t *)argsp;
3193 /* Create the protocol tree, but don't fill in the column information. */
3194 epan_dissect_run(&args->edt, cf->cd_t, rec,
3195 frame_tvbuff_new_buffer(&cf->provider, fdata, buf),
3196 fdata, NULL);
3198 /* Write out the information in that tree. */
3199 write_json_proto_tree(NULL, args->print_args->print_dissections,
3200 args->print_args->print_hex,
3201 &args->edt, &cf->cinfo, proto_node_group_children_by_unique,
3202 &args->jdumper);
3204 epan_dissect_reset(&args->edt);
3206 return !ferror(args->fh);
3209 cf_print_status_t
3210 cf_write_json_packets(capture_file *cf, print_args_t *print_args)
3212 write_packet_callback_args_t callback_args;
3213 FILE *fh;
3214 psp_return_t ret;
3216 fh = ws_fopen(print_args->file, "w");
3217 if (fh == NULL)
3218 return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
3220 callback_args.jdumper = write_json_preamble(fh);
3221 if (ferror(fh)) {
3222 fclose(fh);
3223 return CF_PRINT_WRITE_ERROR;
3226 callback_args.fh = fh;
3227 callback_args.print_args = print_args;
3228 epan_dissect_init(&callback_args.edt, cf->epan, TRUE, TRUE);
3230 /* Iterate through the list of packets, printing the packets we were
3231 told to print. */
3232 ret = process_specified_records(cf, &print_args->range, "Writing JSON",
3233 "selected packets", TRUE,
3234 write_json_packet, &callback_args, TRUE);
3236 epan_dissect_cleanup(&callback_args.edt);
3238 switch (ret) {
3240 case PSP_FINISHED:
3241 /* Completed successfully. */
3242 break;
3244 case PSP_STOPPED:
3245 /* Well, the user decided to abort the printing. */
3246 break;
3248 case PSP_FAILED:
3249 /* Error while printing. */
3250 fclose(fh);
3251 return CF_PRINT_WRITE_ERROR;
3254 write_json_finale(&callback_args.jdumper);
3255 if (ferror(fh)) {
3256 fclose(fh);
3257 return CF_PRINT_WRITE_ERROR;
3260 /* XXX - check for an error */
3261 fclose(fh);
3263 return CF_PRINT_OK;
3266 gboolean
3267 cf_find_packet_protocol_tree(capture_file *cf, const char *string,
3268 search_direction dir, bool multiple)
3270 match_data mdata;
3272 mdata.frame_matched = FALSE;
3273 mdata.halt = FALSE;
3274 mdata.string = string;
3275 mdata.string_len = strlen(string);
3276 mdata.cf = cf;
3277 mdata.prev_finfo = cf->finfo_selected;
3278 if (multiple && cf->finfo_selected && cf->edt) {
3279 if (dir == SD_FORWARD) {
3280 proto_tree_children_foreach(cf->edt->tree, match_subtree_text, &mdata);
3281 } else {
3282 proto_tree_children_foreach(cf->edt->tree, match_subtree_text_reverse, &mdata);
3284 if (mdata.frame_matched) {
3285 packet_list_select_finfo(mdata.finfo);
3286 return TRUE;
3289 return find_packet(cf, match_protocol_tree, &mdata, dir);
3292 field_info*
3293 cf_find_string_protocol_tree(capture_file *cf, proto_tree *tree)
3295 match_data mdata;
3296 mdata.frame_matched = FALSE;
3297 mdata.halt = FALSE;
3298 mdata.string = convert_string_case(cf->sfilter, cf->case_type);
3299 mdata.string_len = strlen(mdata.string);
3300 mdata.cf = cf;
3301 mdata.prev_finfo = NULL;
3302 /* Iterate through all the nodes looking for matching text */
3303 if (cf->dir == SD_FORWARD) {
3304 proto_tree_children_foreach(tree, match_subtree_text, &mdata);
3305 } else {
3306 proto_tree_children_foreach(tree, match_subtree_text_reverse, &mdata);
3308 g_free((char *)mdata.string);
3309 return mdata.frame_matched ? mdata.finfo : NULL;
3312 static match_result
3313 match_protocol_tree(capture_file *cf, frame_data *fdata,
3314 wtap_rec *rec, Buffer *buf, void *criterion)
3316 match_data *mdata = (match_data *)criterion;
3317 epan_dissect_t edt;
3319 /* Load the frame's data. */
3320 if (!cf_read_record(cf, fdata, rec, buf)) {
3321 /* Attempt to get the packet failed. */
3322 return MR_ERROR;
3325 /* Construct the protocol tree, including the displayed text */
3326 epan_dissect_init(&edt, cf->epan, TRUE, TRUE);
3327 /* We don't need the column information */
3328 epan_dissect_run(&edt, cf->cd_t, rec,
3329 frame_tvbuff_new_buffer(&cf->provider, fdata, buf),
3330 fdata, NULL);
3332 /* Iterate through all the nodes, seeing if they have text that matches. */
3333 mdata->cf = cf;
3334 mdata->frame_matched = FALSE;
3335 mdata->halt = FALSE;
3336 mdata->prev_finfo = NULL;
3337 /* We don't care about the direction here, because we're just looking
3338 * for one match and we'll destroy this tree anyway. (We find the actual
3339 * field later in PacketList::selectionChanged().) Forwards is faster.
3341 proto_tree_children_foreach(edt.tree, match_subtree_text, mdata);
3342 epan_dissect_cleanup(&edt);
3343 return mdata->frame_matched ? MR_MATCHED : MR_NOTMATCHED;
3346 static void
3347 match_subtree_text(proto_node *node, gpointer data)
3349 match_data *mdata = (match_data *) data;
3350 const gchar *string = mdata->string;
3351 size_t string_len = mdata->string_len;
3352 capture_file *cf = mdata->cf;
3353 field_info *fi = PNODE_FINFO(node);
3354 gchar label_str[ITEM_LABEL_LENGTH];
3355 gchar *label_ptr;
3356 size_t label_len;
3357 guint32 i, i_restart;
3358 guint8 c_char;
3359 size_t c_match = 0;
3361 /* dissection with an invisible proto tree? */
3362 ws_assert(fi);
3364 if (mdata->frame_matched) {
3365 /* We already had a match; don't bother doing any more work. */
3366 return;
3369 /* Don't match invisible entries. */
3370 if (proto_item_is_hidden(node))
3371 return;
3373 if (mdata->prev_finfo) {
3374 /* Haven't found the old match, so don't match this node. */
3375 if (fi == mdata->prev_finfo) {
3376 /* Found the old match, look for the next one after this. */
3377 mdata->prev_finfo = NULL;
3379 } else {
3380 /* was a free format label produced? */
3381 if (fi->rep) {
3382 label_ptr = fi->rep->representation;
3383 } else {
3384 /* no, make a generic label */
3385 label_ptr = label_str;
3386 proto_item_fill_label(fi, label_str);
3389 if (cf->regex) {
3390 if (ws_regex_matches(cf->regex, label_ptr)) {
3391 mdata->frame_matched = TRUE;
3392 mdata->finfo = fi;
3393 return;
3395 } else if (cf->case_type) {
3396 /* Case insensitive match */
3397 label_len = strlen(label_ptr);
3398 i_restart = 0;
3399 for (i = 0; i < label_len; i++) {
3400 if (i_restart == 0 && c_match == 0 && (label_len - i < string_len))
3401 break;
3402 c_char = label_ptr[i];
3403 c_char = g_ascii_toupper(c_char);
3404 /* If c_match is non-zero, save candidate for retrying full match. */
3405 if (c_match > 0 && i_restart == 0 && c_char == string[0])
3406 i_restart = i;
3407 if (c_char == string[c_match]) {
3408 c_match++;
3409 if (c_match == string_len) {
3410 mdata->frame_matched = TRUE;
3411 mdata->finfo = fi;
3412 /* No need to look further; we have a match */
3413 return;
3415 } else if (i_restart) {
3416 i = i_restart;
3417 c_match = 1;
3418 i_restart = 0;
3419 } else
3420 c_match = 0;
3422 } else if (strstr(label_ptr, string) != NULL) {
3423 /* Case sensitive match */
3424 mdata->frame_matched = TRUE;
3425 mdata->finfo = fi;
3426 return;
3430 /* Recurse into the subtree, if it exists */
3431 if (node->first_child != NULL)
3432 proto_tree_children_foreach(node, match_subtree_text, mdata);
3435 static void
3436 match_subtree_text_reverse(proto_node *node, gpointer data)
3438 match_data *mdata = (match_data *) data;
3439 const gchar *string = mdata->string;
3440 size_t string_len = mdata->string_len;
3441 capture_file *cf = mdata->cf;
3442 field_info *fi = PNODE_FINFO(node);
3443 gchar label_str[ITEM_LABEL_LENGTH];
3444 gchar *label_ptr;
3445 size_t label_len;
3446 guint32 i, i_restart;
3447 guint8 c_char;
3448 size_t c_match = 0;
3450 /* dissection with an invisible proto tree? */
3451 ws_assert(fi);
3453 /* We don't have an easy way to search backwards in the tree
3454 * (see also, proto_find_field_from_offset()) because we don't
3455 * have a previous node pointer, so we search backwards by
3456 * searching forwards, only stopping if we see the old match
3457 * (if we have one).
3460 if (mdata->halt) {
3461 return;
3464 /* Don't match invisible entries. */
3465 if (proto_item_is_hidden(node))
3466 return;
3468 if (mdata->prev_finfo && fi == mdata->prev_finfo) {
3469 /* Found the old match, use the previous match. */
3470 mdata->halt = TRUE;
3471 return;
3474 /* was a free format label produced? */
3475 if (fi->rep) {
3476 label_ptr = fi->rep->representation;
3477 } else {
3478 /* no, make a generic label */
3479 label_ptr = label_str;
3480 proto_item_fill_label(fi, label_str);
3483 if (cf->regex) {
3484 if (ws_regex_matches(cf->regex, label_ptr)) {
3485 mdata->frame_matched = TRUE;
3486 mdata->finfo = fi;
3488 } else if (cf->case_type) {
3489 /* Case insensitive match */
3490 label_len = strlen(label_ptr);
3491 i_restart = 0;
3492 for (i = 0; i < label_len; i++) {
3493 if (i_restart == 0 && c_match == 0 && (label_len - i < string_len))
3494 break;
3495 c_char = label_ptr[i];
3496 c_char = g_ascii_toupper(c_char);
3497 /* If c_match is non-zero, save candidate for retrying full match. */
3498 if (c_match > 0 && i_restart == 0 && c_char == string[0])
3499 i_restart = i;
3500 if (c_char == string[c_match]) {
3501 c_match++;
3502 if (c_match == string_len) {
3503 mdata->frame_matched = TRUE;
3504 mdata->finfo = fi;
3505 break;
3507 } else if (i_restart) {
3508 i = i_restart;
3509 c_match = 1;
3510 i_restart = 0;
3511 } else
3512 c_match = 0;
3514 } else if (strstr(label_ptr, string) != NULL) {
3515 /* Case sensitive match */
3516 mdata->frame_matched = TRUE;
3517 mdata->finfo = fi;
3520 /* Recurse into the subtree, if it exists */
3521 if (node->first_child != NULL)
3522 proto_tree_children_foreach(node, match_subtree_text_reverse, mdata);
3525 gboolean
3526 cf_find_packet_summary_line(capture_file *cf, const char *string,
3527 search_direction dir)
3529 match_data mdata;
3531 mdata.string = string;
3532 mdata.string_len = strlen(string);
3533 return find_packet(cf, match_summary_line, &mdata, dir);
3536 static match_result
3537 match_summary_line(capture_file *cf, frame_data *fdata,
3538 wtap_rec *rec, Buffer *buf, void *criterion)
3540 match_data *mdata = (match_data *)criterion;
3541 const gchar *string = mdata->string;
3542 size_t string_len = mdata->string_len;
3543 epan_dissect_t edt;
3544 const char *info_column;
3545 size_t info_column_len;
3546 match_result result = MR_NOTMATCHED;
3547 gint colx;
3548 guint32 i, i_restart;
3549 guint8 c_char;
3550 size_t c_match = 0;
3552 /* Load the frame's data. */
3553 if (!cf_read_record(cf, fdata, rec, buf)) {
3554 /* Attempt to get the packet failed. */
3555 return MR_ERROR;
3558 /* Don't bother constructing the protocol tree */
3559 epan_dissect_init(&edt, cf->epan, FALSE, FALSE);
3560 /* Get the column information */
3561 epan_dissect_run(&edt, cf->cd_t, rec,
3562 frame_tvbuff_new_buffer(&cf->provider, fdata, buf),
3563 fdata, &cf->cinfo);
3565 /* Find the Info column */
3566 for (colx = 0; colx < cf->cinfo.num_cols; colx++) {
3567 if (cf->cinfo.columns[colx].fmt_matx[COL_INFO]) {
3568 /* Found it. See if we match. */
3569 info_column = get_column_text(edt.pi.cinfo, colx);
3570 info_column_len = strlen(info_column);
3571 if (cf->regex) {
3572 if (ws_regex_matches(cf->regex, info_column)) {
3573 result = MR_MATCHED;
3574 break;
3576 } else if (cf->case_type) {
3577 /* Case insensitive match */
3578 i_restart = 0;
3579 for (i = 0; i < info_column_len; i++) {
3580 if (i_restart == 0 && c_match == 0 && (info_column_len - i < string_len))
3581 break;
3582 c_char = info_column[i];
3583 c_char = g_ascii_toupper(c_char);
3584 /* If c_match is non-zero, save candidate for retrying full match. */
3585 if (c_match > 0 && i_restart == 0 && c_char == string[0])
3586 i_restart = i;
3587 if (c_char == string[c_match]) {
3588 c_match++;
3589 if (c_match == string_len) {
3590 result = MR_MATCHED;
3591 break;
3593 } else if (i_restart) {
3594 i = i_restart;
3595 c_match = 1;
3596 i_restart = 0;
3597 } else
3598 c_match = 0;
3600 } else if (strstr(info_column, string) != NULL) {
3601 /* Case sensitive match */
3602 result = MR_MATCHED;
3604 break;
3607 epan_dissect_cleanup(&edt);
3608 return result;
3611 typedef struct {
3612 const guint8 *data;
3613 size_t data_len;
3614 ws_mempbrk_pattern *pattern;
3615 } cbs_t; /* "Counted byte string" */
3619 * The current match_* routines only support ASCII case insensitivity and don't
3620 * convert UTF-8 inputs to UTF-16 for matching. The UTF-16 support just
3621 * interleaves with \0 bytes, which works for 7 bit ASCII.
3623 * We could modify them to use the GLib Unicode routines or the International
3624 * Components for Unicode library but it's not apparent that we could do so
3625 * without consuming a lot more CPU and memory or that searching would be
3626 * significantly better.
3628 * XXX: We could test the search string to see if it's all ASCII, and if not
3629 * use Unicode aware routines for case insensitive searches or any UTF-16
3630 * search.
3633 gboolean
3634 cf_find_packet_data(capture_file *cf, const guint8 *string, size_t string_size,
3635 search_direction dir, bool multiple)
3637 cbs_t info;
3638 guint8 needles[3];
3639 ws_mempbrk_pattern pattern = {0};
3640 ws_match_function match_function;
3642 info.data = string;
3643 info.data_len = string_size;
3645 /* Regex, String or hex search? */
3646 if (cf->regex) {
3647 /* Regular Expression search */
3648 match_function = (cf->dir == SD_FORWARD) ? match_regex : match_regex_reverse;
3649 } else if (cf->string) {
3650 /* String search - what type of string? */
3651 if (cf->case_type) {
3652 needles[0] = string[0];
3653 needles[1] = g_ascii_tolower(needles[0]);
3654 needles[2] = '\0';
3655 ws_mempbrk_compile(&pattern, needles);
3656 info.pattern = &pattern;
3657 switch (cf->scs_type) {
3659 case SCS_NARROW_AND_WIDE:
3660 match_function = (cf->dir == SD_FORWARD) ? match_narrow_and_wide_case : match_narrow_and_wide_case_reverse;
3661 break;
3663 case SCS_NARROW:
3664 match_function = (cf->dir == SD_FORWARD) ? match_narrow_case : match_narrow_case_reverse;
3665 break;
3667 case SCS_WIDE:
3668 match_function = (cf->dir == SD_FORWARD) ? match_wide_case : match_wide_case_reverse;
3669 break;
3671 default:
3672 ws_assert_not_reached();
3673 return FALSE;
3676 } else {
3677 switch (cf->scs_type) {
3679 case SCS_NARROW_AND_WIDE:
3680 match_function = (cf->dir == SD_FORWARD) ? match_narrow_and_wide : match_narrow_and_wide_reverse;
3681 break;
3683 case SCS_NARROW:
3684 /* Narrow, case-sensitive match is the same as looking
3685 * for a converted hexstring. */
3686 match_function = (cf->dir == SD_FORWARD) ? match_binary : match_binary_reverse;
3687 break;
3689 case SCS_WIDE:
3690 match_function = (cf->dir == SD_FORWARD) ? match_wide : match_wide_reverse;
3691 break;
3693 default:
3694 ws_assert_not_reached();
3695 return FALSE;
3698 } else {
3699 match_function = (cf->dir == SD_FORWARD) ? match_binary : match_binary_reverse;
3702 if (multiple && cf->current_frame && (cf->search_pos || cf->search_len)) {
3703 /* Use the current frame (this will perform the equivalent of
3704 * cf_read_current_record() in match_function).
3706 if (match_function(cf, cf->current_frame, &cf->rec, &cf->buf, &info)) {
3707 cf->search_in_progress = TRUE;
3708 if (cf->edt) {
3709 field_info *fi = NULL;
3710 /* The regex match can match an empty string. */
3711 if (cf->search_len) {
3712 fi = proto_find_field_from_offset(cf->edt->tree, cf->search_pos + cf->search_len - 1, cf->edt->tvb);
3714 packet_list_select_finfo(fi);
3715 } else {
3716 packet_list_select_row_from_data(cf->current_frame);
3718 cf->search_in_progress = FALSE;
3719 return TRUE;
3722 cf->search_pos = 0; /* Reset the position */
3723 cf->search_len = 0; /* Reset length */
3724 return find_packet(cf, match_function, &info, dir);
3727 static match_result
3728 match_narrow_and_wide(capture_file *cf, frame_data *fdata,
3729 wtap_rec *rec, Buffer *buf, void *criterion)
3731 cbs_t *info = (cbs_t *)criterion;
3732 const guint8 *ascii_text = info->data;
3733 size_t textlen = info->data_len;
3734 match_result result;
3735 guint32 buf_len;
3736 guint8 *pd, *buf_start, *buf_end;
3737 guint32 i;
3738 guint8 c_char;
3739 size_t c_match = 0;
3741 /* Load the frame's data. */
3742 if (!cf_read_record(cf, fdata, rec, buf)) {
3743 /* Attempt to get the packet failed. */
3744 return MR_ERROR;
3747 result = MR_NOTMATCHED;
3748 buf_len = fdata->cap_len;
3749 buf_start = ws_buffer_start_ptr(buf);
3750 buf_end = buf_start + buf_len;
3751 pd = buf_start;
3752 if (cf->search_len || cf->search_pos) {
3753 /* we want to start searching one byte past the previous match start */
3754 pd += cf->search_pos + 1;
3756 for (; pd < buf_end; pd++) {
3757 pd = (guint8 *)memchr(pd, ascii_text[0], buf_end - pd);
3758 if (pd == NULL) break;
3759 /* Try narrow match at this start location */
3760 c_match = 0;
3761 for (i = 0; pd + i < buf_end; i++) {
3762 c_char = pd[i];
3763 if (c_char == ascii_text[c_match]) {
3764 c_match++;
3765 if (c_match == textlen) {
3766 result = MR_MATCHED;
3767 /* Save position and length for highlighting the field. */
3768 cf->search_pos = (uint32_t)(pd - buf_start);
3769 cf->search_len = (uint32_t)(i + 1);
3770 goto done;
3772 } else {
3773 break;
3777 /* Now try wide match at the same start location. */
3778 c_match = 0;
3779 for (i = 0; pd + i < buf_end; i++) {
3780 c_char = pd[i];
3781 if (c_char == ascii_text[c_match]) {
3782 c_match++;
3783 if (c_match == textlen) {
3784 result = MR_MATCHED;
3785 /* Save position and length for highlighting the field. */
3786 cf->search_pos = (uint32_t)(pd - buf_start);
3787 cf->search_len = (uint32_t)(i + 1);
3788 goto done;
3790 i++;
3791 if (pd + i >= buf_end || pd[i] != '\0') break;
3792 } else {
3793 break;
3798 done:
3799 return result;
3802 static match_result
3803 match_narrow_and_wide_reverse(capture_file *cf, frame_data *fdata,
3804 wtap_rec *rec, Buffer *buf, void *criterion)
3806 cbs_t *info = (cbs_t *)criterion;
3807 const guint8 *ascii_text = info->data;
3808 size_t textlen = info->data_len;
3809 match_result result;
3810 guint32 buf_len;
3811 guint8 *pd, *buf_start, *buf_end;
3812 guint32 i;
3813 guint8 c_char;
3814 size_t c_match = 0;
3816 /* Load the frame's data. */
3817 if (!cf_read_record(cf, fdata, rec, buf)) {
3818 /* Attempt to get the packet failed. */
3819 return MR_ERROR;
3822 result = MR_NOTMATCHED;
3823 /* Has to be room to hold the sought data. */
3824 if (textlen > fdata->cap_len) {
3825 return result;
3827 buf_len = fdata->cap_len;
3828 buf_start = ws_buffer_start_ptr(buf);
3829 buf_end = buf_start + buf_len;
3830 pd = buf_end - textlen;
3831 if (cf->search_len || cf->search_pos) {
3832 /* we want to start searching one byte before the previous match start */
3833 pd = buf_start + cf->search_pos - 1;
3835 for (; pd < buf_end; pd++) {
3836 pd = (uint8_t *)ws_memrchr(buf_start, ascii_text[0], pd - buf_start + 1);
3837 if (pd == NULL) break;
3838 /* Try narrow match at this start location */
3839 c_match = 0;
3840 for (i = 0; pd + i < buf_end; i++) {
3841 c_char = pd[i];
3842 if (c_char == ascii_text[c_match]) {
3843 c_match++;
3844 if (c_match == textlen) {
3845 result = MR_MATCHED;
3846 /* Save position and length for highlighting the field. */
3847 cf->search_pos = (uint32_t)(pd - buf_start);
3848 cf->search_len = (uint32_t)(i + 1);
3849 goto done;
3851 } else {
3852 break;
3856 /* Now try wide match at the same start location. */
3857 c_match = 0;
3858 for (i = 0; pd + i < buf_end; i++) {
3859 c_char = pd[i];
3860 if (c_char == ascii_text[c_match]) {
3861 c_match++;
3862 if (c_match == textlen) {
3863 result = MR_MATCHED;
3864 /* Save position and length for highlighting the field. */
3865 cf->search_pos = (uint32_t)(pd - buf_start);
3866 cf->search_len = (uint32_t)(i + 1);
3867 goto done;
3869 i++;
3870 if (pd + i >= buf_end || pd[i] != '\0') break;
3871 } else {
3872 break;
3877 done:
3878 return result;
3881 /* Case insensitive match */
3882 static match_result
3883 match_narrow_and_wide_case(capture_file *cf, frame_data *fdata,
3884 wtap_rec *rec, Buffer *buf, void *criterion)
3886 cbs_t *info = (cbs_t *)criterion;
3887 const guint8 *ascii_text = info->data;
3888 size_t textlen = info->data_len;
3889 ws_mempbrk_pattern *pattern = info->pattern;
3890 match_result result;
3891 guint32 buf_len;
3892 guint8 *pd, *buf_start, *buf_end;
3893 guint32 i;
3894 guint8 c_char;
3895 size_t c_match = 0;
3897 /* Load the frame's data. */
3898 if (!cf_read_record(cf, fdata, rec, buf)) {
3899 /* Attempt to get the packet failed. */
3900 return MR_ERROR;
3903 ws_assert(pattern != NULL);
3905 result = MR_NOTMATCHED;
3906 buf_len = fdata->cap_len;
3907 buf_start = ws_buffer_start_ptr(buf);
3908 buf_end = buf_start + buf_len;
3909 pd = buf_start;
3910 if (cf->search_len || cf->search_pos) {
3911 /* we want to start searching one byte past the previous match start */
3912 pd += cf->search_pos + 1;
3914 for (; pd < buf_end; pd++) {
3915 pd = (guint8 *)ws_mempbrk_exec(pd, buf_end - pd, pattern, &c_char);
3916 if (pd == NULL) break;
3917 /* Try narrow match at this start location */
3918 c_match = 0;
3919 for (i = 0; pd + i < buf_end; i++) {
3920 c_char = g_ascii_toupper(pd[i]);
3921 if (c_char == ascii_text[c_match]) {
3922 c_match++;
3923 if (c_match == textlen) {
3924 result = MR_MATCHED;
3925 /* Save position and length for highlighting the field. */
3926 cf->search_pos = (uint32_t)(pd - buf_start);
3927 cf->search_len = (uint32_t)(i + 1);
3928 goto done;
3930 } else {
3931 break;
3935 /* Now try wide match at the same start location. */
3936 c_match = 0;
3937 for (i = 0; pd + i < buf_end; i++) {
3938 c_char = g_ascii_toupper(pd[i]);
3939 if (c_char == ascii_text[c_match]) {
3940 c_match++;
3941 if (c_match == textlen) {
3942 result = MR_MATCHED;
3943 /* Save position and length for highlighting the field. */
3944 cf->search_pos = (uint32_t)(pd - buf_start);
3945 cf->search_len = (uint32_t)(i + 1);
3946 goto done;
3948 i++;
3949 if (pd + i >= buf_end || pd[i] != '\0') break;
3950 } else {
3951 break;
3956 done:
3957 return result;
3960 static match_result
3961 match_narrow_and_wide_case_reverse(capture_file *cf, frame_data *fdata,
3962 wtap_rec *rec, Buffer *buf, void *criterion)
3964 cbs_t *info = (cbs_t *)criterion;
3965 const guint8 *ascii_text = info->data;
3966 size_t textlen = info->data_len;
3967 ws_mempbrk_pattern *pattern = info->pattern;
3968 match_result result;
3969 guint32 buf_len;
3970 guint8 *pd, *buf_start, *buf_end;
3971 guint32 i;
3972 guint8 c_char;
3973 size_t c_match = 0;
3975 /* Load the frame's data. */
3976 if (!cf_read_record(cf, fdata, rec, buf)) {
3977 /* Attempt to get the packet failed. */
3978 return MR_ERROR;
3981 ws_assert(pattern != NULL);
3983 result = MR_NOTMATCHED;
3984 /* Has to be room to hold the sought data. */
3985 if (textlen > fdata->cap_len) {
3986 return result;
3988 buf_len = fdata->cap_len;
3989 buf_start = ws_buffer_start_ptr(buf);
3990 buf_end = buf_start + buf_len;
3991 pd = buf_end - textlen;
3992 if (cf->search_len || cf->search_pos) {
3993 /* we want to start searching one byte before the previous match start */
3994 pd = buf_start + cf->search_pos - 1;
3996 for (; pd >= buf_start; pd--) {
3997 pd = (guint8 *)ws_memrpbrk_exec(buf_start, pd - buf_start + 1, pattern, &c_char);
3998 if (pd == NULL) break;
3999 /* Try narrow match at this start location */
4000 c_match = 0;
4001 for (i = 0; pd + i < buf_end; i++) {
4002 c_char = g_ascii_toupper(pd[i]);
4003 if (c_char == ascii_text[c_match]) {
4004 c_match++;
4005 if (c_match == textlen) {
4006 result = MR_MATCHED;
4007 /* Save position and length for highlighting the field. */
4008 cf->search_pos = (uint32_t)(pd - buf_start);
4009 cf->search_len = (uint32_t)(i + 1);
4010 goto done;
4012 } else {
4013 break;
4017 /* Now try wide match at the same start location. */
4018 c_match = 0;
4019 for (i = 0; pd + i < buf_end; i++) {
4020 c_char = g_ascii_toupper(pd[i]);
4021 if (c_char == ascii_text[c_match]) {
4022 c_match++;
4023 if (c_match == textlen) {
4024 result = MR_MATCHED;
4025 /* Save position and length for highlighting the field. */
4026 cf->search_pos = (uint32_t)(pd - buf_start);
4027 cf->search_len = (uint32_t)(i + 1);
4028 goto done;
4030 i++;
4031 if (pd + i >= buf_end || pd[i] != '\0') break;
4032 } else {
4033 break;
4038 done:
4039 return result;
4042 /* Case insensitive match */
4043 static match_result
4044 match_narrow_case(capture_file *cf, frame_data *fdata,
4045 wtap_rec *rec, Buffer *buf, void *criterion)
4047 cbs_t *info = (cbs_t *)criterion;
4048 const guint8 *ascii_text = info->data;
4049 size_t textlen = info->data_len;
4050 ws_mempbrk_pattern *pattern = info->pattern;
4051 match_result result;
4052 guint32 buf_len;
4053 guint8 *pd, *buf_start, *buf_end;
4054 guint32 i;
4055 guint8 c_char;
4056 size_t c_match = 0;
4058 /* Load the frame's data. */
4059 if (!cf_read_record(cf, fdata, rec, buf)) {
4060 /* Attempt to get the packet failed. */
4061 return MR_ERROR;
4064 ws_assert(pattern != NULL);
4066 result = MR_NOTMATCHED;
4067 buf_len = fdata->cap_len;
4068 buf_start = ws_buffer_start_ptr(buf);
4069 buf_end = buf_start + buf_len;
4070 pd = buf_start;
4071 if (cf->search_len || cf->search_pos) {
4072 /* we want to start searching one byte past the previous match start */
4073 pd += cf->search_pos + 1;
4075 for (; pd < buf_end; pd++) {
4076 pd = (guint8 *)ws_mempbrk_exec(pd, buf_end - pd, pattern, &c_char);
4077 if (pd == NULL) break;
4078 c_match = 0;
4079 for (i = 0; pd + i < buf_end; i++) {
4080 c_char = g_ascii_toupper(pd[i]);
4081 if (c_char == ascii_text[c_match]) {
4082 c_match++;
4083 if (c_match == textlen) {
4084 /* Save position and length for highlighting the field. */
4085 result = MR_MATCHED;
4086 cf->search_pos = (uint32_t)(pd - buf_start);
4087 cf->search_len = (uint32_t)(i + 1);
4088 goto done;
4090 } else {
4091 break;
4096 done:
4097 return result;
4100 static match_result
4101 match_narrow_case_reverse(capture_file *cf, frame_data *fdata,
4102 wtap_rec *rec, Buffer *buf, void *criterion)
4104 cbs_t *info = (cbs_t *)criterion;
4105 const guint8 *ascii_text = info->data;
4106 size_t textlen = info->data_len;
4107 ws_mempbrk_pattern *pattern = info->pattern;
4108 match_result result;
4109 guint32 buf_len;
4110 guint8 *pd, *buf_start, *buf_end;
4111 guint32 i;
4112 guint8 c_char;
4113 size_t c_match = 0;
4115 /* Load the frame's data. */
4116 if (!cf_read_record(cf, fdata, rec, buf)) {
4117 /* Attempt to get the packet failed. */
4118 return MR_ERROR;
4121 ws_assert(pattern != NULL);
4123 result = MR_NOTMATCHED;
4124 /* Has to be room to hold the sought data. */
4125 if (textlen > fdata->cap_len) {
4126 return result;
4128 buf_len = fdata->cap_len;
4129 buf_start = ws_buffer_start_ptr(buf);
4130 buf_end = buf_start + buf_len;
4131 pd = buf_end - textlen;
4132 if (cf->search_len || cf->search_pos) {
4133 /* we want to start searching one byte before the previous match start */
4134 pd = buf_start + cf->search_pos - 1;
4136 for (; pd >= buf_start; pd--) {
4137 pd = (guint8 *)ws_memrpbrk_exec(buf_start, pd - buf_start + 1, pattern, &c_char);
4138 if (pd == NULL) break;
4139 c_match = 0;
4140 for (i = 0; pd + i < buf_end; i++) {
4141 c_char = g_ascii_toupper(pd[i]);
4142 if (c_char == ascii_text[c_match]) {
4143 c_match++;
4144 if (c_match == textlen) {
4145 /* Save position and length for highlighting the field. */
4146 result = MR_MATCHED;
4147 cf->search_pos = (uint32_t)(pd - buf_start);
4148 cf->search_len = (uint32_t)(i + 1);
4149 goto done;
4151 } else {
4152 break;
4157 done:
4158 return result;
4161 static match_result
4162 match_wide(capture_file *cf, frame_data *fdata,
4163 wtap_rec *rec, Buffer *buf, void *criterion)
4165 cbs_t *info = (cbs_t *)criterion;
4166 const guint8 *ascii_text = info->data;
4167 size_t textlen = info->data_len;
4168 match_result result;
4169 guint32 buf_len;
4170 guint8 *pd, *buf_start, *buf_end;
4171 guint32 i;
4172 guint8 c_char;
4173 size_t c_match = 0;
4175 /* Load the frame's data. */
4176 if (!cf_read_record(cf, fdata, rec, buf)) {
4177 /* Attempt to get the packet failed. */
4178 return MR_ERROR;
4181 result = MR_NOTMATCHED;
4182 buf_len = fdata->cap_len;
4183 buf_start = ws_buffer_start_ptr(buf);
4184 buf_end = buf_start + buf_len;
4185 pd = buf_start;
4186 if (cf->search_len || cf->search_pos) {
4187 /* we want to start searching one byte past the previous match start */
4188 pd += cf->search_pos + 1;
4190 for (; pd < buf_end; pd++) {
4191 pd = (guint8 *)memchr(pd, ascii_text[0], buf_end - pd);
4192 if (pd == NULL) break;
4193 c_match = 0;
4194 for (i = 0; pd + i < buf_end; i++) {
4195 c_char = pd[i];
4196 if (c_char == ascii_text[c_match]) {
4197 c_match++;
4198 if (c_match == textlen) {
4199 result = MR_MATCHED;
4200 /* Save position and length for highlighting the field. */
4201 cf->search_pos = (uint32_t)(pd - buf_start);
4202 cf->search_len = (uint32_t)(i + 1);
4203 goto done;
4205 i++;
4206 if (pd + i >= buf_end || pd[i] != '\0') break;
4207 } else {
4208 break;
4213 done:
4214 return result;
4217 static match_result
4218 match_wide_reverse(capture_file *cf, frame_data *fdata,
4219 wtap_rec *rec, Buffer *buf, void *criterion)
4221 cbs_t *info = (cbs_t *)criterion;
4222 const guint8 *ascii_text = info->data;
4223 size_t textlen = info->data_len;
4224 match_result result;
4225 guint32 buf_len;
4226 guint8 *pd, *buf_start, *buf_end;
4227 guint32 i;
4228 guint8 c_char;
4229 size_t c_match = 0;
4231 /* Load the frame's data. */
4232 if (!cf_read_record(cf, fdata, rec, buf)) {
4233 /* Attempt to get the packet failed. */
4234 return MR_ERROR;
4237 result = MR_NOTMATCHED;
4238 /* Has to be room to hold the sought data. */
4239 if (textlen > fdata->cap_len) {
4240 return result;
4242 buf_len = fdata->cap_len;
4243 buf_start = ws_buffer_start_ptr(buf);
4244 buf_end = buf_start + buf_len;
4245 pd = buf_end - textlen;
4246 if (cf->search_len || cf->search_pos) {
4247 /* we want to start searching one byte before the previous match start */
4248 pd = buf_start + cf->search_pos - 1;
4250 for (; pd < buf_end; pd++) {
4251 pd = (uint8_t *)ws_memrchr(buf_start, ascii_text[0], pd - buf_start + 1);
4252 if (pd == NULL) break;
4253 c_match = 0;
4254 for (i = 0; pd + i < buf_end; i++) {
4255 c_char = pd[i];
4256 if (c_char == ascii_text[c_match]) {
4257 c_match++;
4258 if (c_match == textlen) {
4259 result = MR_MATCHED;
4260 /* Save position and length for highlighting the field. */
4261 cf->search_pos = (uint32_t)(pd - buf_start);
4262 cf->search_len = (uint32_t)(i + 1);
4263 goto done;
4265 i++;
4266 if (pd + i >= buf_end || pd[i] != '\0') break;
4267 } else {
4268 break;
4273 done:
4274 return result;
4277 /* Case insensitive match */
4278 static match_result
4279 match_wide_case(capture_file *cf, frame_data *fdata,
4280 wtap_rec *rec, Buffer *buf, void *criterion)
4282 cbs_t *info = (cbs_t *)criterion;
4283 const guint8 *ascii_text = info->data;
4284 size_t textlen = info->data_len;
4285 ws_mempbrk_pattern *pattern = info->pattern;
4286 match_result result;
4287 guint32 buf_len;
4288 guint8 *pd, *buf_start, *buf_end;
4289 guint32 i;
4290 guint8 c_char;
4291 size_t c_match = 0;
4293 /* Load the frame's data. */
4294 if (!cf_read_record(cf, fdata, rec, buf)) {
4295 /* Attempt to get the packet failed. */
4296 return MR_ERROR;
4299 ws_assert(pattern != NULL);
4301 result = MR_NOTMATCHED;
4302 buf_len = fdata->cap_len;
4303 buf_start = ws_buffer_start_ptr(buf);
4304 buf_end = buf_start + buf_len;
4305 pd = buf_start;
4306 if (cf->search_len || cf->search_pos) {
4307 /* we want to start searching one byte past the previous match start */
4308 pd += cf->search_pos + 1;
4310 for (; pd < buf_end; pd++) {
4311 pd = (guint8 *)ws_mempbrk_exec(pd, buf_end - pd, pattern, &c_char);
4312 if (pd == NULL) break;
4313 c_match = 0;
4314 for (i = 0; pd + i < buf_end; i++) {
4315 c_char = g_ascii_toupper(pd[i]);
4316 if (c_char == ascii_text[c_match]) {
4317 c_match++;
4318 if (c_match == textlen) {
4319 result = MR_MATCHED;
4320 /* Save position and length for highlighting the field. */
4321 cf->search_pos = (uint32_t)(pd - buf_start);
4322 cf->search_len = (uint32_t)(i + 1);
4323 goto done;
4325 i++;
4326 if (pd + i >= buf_end || pd[i] != '\0') break;
4327 } else {
4328 break;
4333 done:
4334 return result;
4337 /* Case insensitive match */
4338 static match_result
4339 match_wide_case_reverse(capture_file *cf, frame_data *fdata,
4340 wtap_rec *rec, Buffer *buf, void *criterion)
4342 cbs_t *info = (cbs_t *)criterion;
4343 const guint8 *ascii_text = info->data;
4344 size_t textlen = info->data_len;
4345 ws_mempbrk_pattern *pattern = info->pattern;
4346 match_result result;
4347 guint32 buf_len;
4348 guint8 *pd, *buf_start, *buf_end;
4349 guint32 i;
4350 guint8 c_char;
4351 size_t c_match = 0;
4353 /* Load the frame's data. */
4354 if (!cf_read_record(cf, fdata, rec, buf)) {
4355 /* Attempt to get the packet failed. */
4356 return MR_ERROR;
4359 ws_assert(pattern != NULL);
4361 result = MR_NOTMATCHED;
4362 /* Has to be room to hold the sought data. */
4363 if (textlen > fdata->cap_len) {
4364 return result;
4366 buf_len = fdata->cap_len;
4367 buf_start = ws_buffer_start_ptr(buf);
4368 buf_end = buf_start + buf_len;
4369 pd = buf_end - textlen;
4370 if (cf->search_len || cf->search_pos) {
4371 /* we want to start searching one byte before the previous match start */
4372 pd = buf_start + cf->search_pos - 1;
4374 for (; pd >= buf_start; pd--) {
4375 pd = (guint8 *)ws_memrpbrk_exec(buf_start, pd - buf_start + 1, pattern, &c_char);
4376 if (pd == NULL) break;
4377 c_match = 0;
4378 for (i = 0; pd + i < buf_end; i++) {
4379 c_char = g_ascii_toupper(pd[i]);
4380 if (c_char == ascii_text[c_match]) {
4381 c_match++;
4382 if (c_match == textlen) {
4383 result = MR_MATCHED;
4384 /* Save position and length for highlighting the field. */
4385 cf->search_pos = (uint32_t)(pd - buf_start);
4386 cf->search_len = (uint32_t)(i + 1);
4387 goto done;
4389 i++;
4390 if (pd + i >= buf_end || pd[i] != '\0') break;
4391 } else {
4392 break;
4397 done:
4398 return result;
4401 static match_result
4402 match_binary(capture_file *cf, frame_data *fdata,
4403 wtap_rec *rec, Buffer *buf, void *criterion)
4405 cbs_t *info = (cbs_t *)criterion;
4406 size_t datalen = info->data_len;
4407 match_result result;
4408 const uint8_t *pd = NULL, *buf_start;
4410 /* Load the frame's data. */
4411 if (!cf_read_record(cf, fdata, rec, buf)) {
4412 /* Attempt to get the packet failed. */
4413 return MR_ERROR;
4416 result = MR_NOTMATCHED;
4417 buf_start = ws_buffer_start_ptr(buf);
4418 size_t offset = 0;
4419 if (cf->search_len || cf->search_pos) {
4420 /* we want to start searching one byte past the previous match start */
4421 offset = cf->search_pos + 1;
4423 if (offset < fdata->cap_len) {
4424 pd = ws_memmem(buf_start + offset, fdata->cap_len - offset, info->data, datalen);
4426 if (pd != NULL) {
4427 result = MR_MATCHED;
4428 /* Save position and length for highlighting the field. */
4429 cf->search_pos = (uint32_t)(pd - buf_start);
4430 cf->search_len = (uint32_t)datalen;
4433 return result;
4436 static match_result
4437 match_binary_reverse(capture_file *cf, frame_data *fdata,
4438 wtap_rec *rec, Buffer *buf, void *criterion)
4440 cbs_t *info = (cbs_t *)criterion;
4441 size_t datalen = info->data_len;
4442 match_result result;
4443 const uint8_t *pd = NULL, *buf_start;
4445 /* Load the frame's data. */
4446 if (!cf_read_record(cf, fdata, rec, buf)) {
4447 /* Attempt to get the packet failed. */
4448 return MR_ERROR;
4451 result = MR_NOTMATCHED;
4452 buf_start = ws_buffer_start_ptr(buf);
4453 /* Has to be room to hold the sought data. */
4454 if (datalen > fdata->cap_len) {
4455 return result;
4457 pd = buf_start + fdata->cap_len - datalen;
4458 if (cf->search_len || cf->search_pos) {
4459 /* we want to start searching one byte before the previous match start */
4460 pd = buf_start + cf->search_pos - 1;
4462 for (; pd >= buf_start; pd--) {
4463 pd = (uint8_t *)ws_memrchr(buf_start, info->data[0], pd - buf_start + 1);
4464 if (pd == NULL) break;
4465 if (memcmp(pd, info->data, datalen) == 0) {
4466 result = MR_MATCHED;
4467 /* Save position and length for highlighting the field. */
4468 cf->search_pos = (uint32_t)(pd - buf_start);
4469 cf->search_len = (uint32_t)datalen;
4470 break;
4474 return result;
4477 static match_result
4478 match_regex(capture_file *cf, frame_data *fdata,
4479 wtap_rec *rec, Buffer *buf, void *criterion _U_)
4481 match_result result = MR_NOTMATCHED;
4482 size_t result_pos[2] = {0, 0};
4484 /* Load the frame's data. */
4485 if (!cf_read_record(cf, fdata, rec, buf)) {
4486 /* Attempt to get the packet failed. */
4487 return MR_ERROR;
4490 size_t offset = 0;
4491 if (cf->search_len || cf->search_pos) {
4492 /* we want to start searching one byte past the previous match start */
4493 offset = cf->search_pos + 1;
4495 if (offset < fdata->cap_len) {
4496 if (ws_regex_matches_pos(cf->regex,
4497 (const gchar *)ws_buffer_start_ptr(buf),
4498 fdata->cap_len, offset,
4499 result_pos)) {
4500 //TODO: A chosen regex can match the empty string (zero length)
4501 // which doesn't make a lot of sense for searching the packet bytes.
4502 // Should we search with the PCRE2_NOTEMPTY option?
4503 //TODO: Fix cast.
4504 /* Save position and length for highlighting the field. */
4505 cf->search_pos = (guint32)(result_pos[0]);
4506 cf->search_len = (guint32)(result_pos[1] - result_pos[0]);
4507 result = MR_MATCHED;
4510 return result;
4513 static match_result
4514 match_regex_reverse(capture_file *cf, frame_data *fdata,
4515 wtap_rec *rec, Buffer *buf, void *criterion _U_)
4517 match_result result = MR_NOTMATCHED;
4518 size_t result_pos[2] = {0, 0};
4520 /* Load the frame's data. */
4521 if (!cf_read_record(cf, fdata, rec, buf)) {
4522 /* Attempt to get the packet failed. */
4523 return MR_ERROR;
4526 size_t offset = fdata->cap_len - 1;
4527 if (cf->search_pos) {
4528 /* we want to start searching one byte before the previous match */
4529 offset = cf->search_pos - 1;
4531 for (; offset > 0; offset--) {
4532 if (ws_regex_matches_pos(cf->regex,
4533 (const gchar *)ws_buffer_start_ptr(buf),
4534 fdata->cap_len, offset,
4535 result_pos)) {
4536 //TODO: A chosen regex can match the empty string (zero length)
4537 // which doesn't make a lot of sense for searching the packet bytes.
4538 // Should we search with the PCRE2_NOTEMPTY option?
4539 //TODO: Fix cast.
4540 /* Save position and length for highlighting the field. */
4541 cf->search_pos = (guint32)(result_pos[0]);
4542 cf->search_len = (guint32)(result_pos[1] - result_pos[0]);
4543 result = MR_MATCHED;
4544 break;
4547 return result;
4550 gboolean
4551 cf_find_packet_dfilter(capture_file *cf, dfilter_t *sfcode,
4552 search_direction dir)
4554 return find_packet(cf, match_dfilter, sfcode, dir);
4557 gboolean
4558 cf_find_packet_dfilter_string(capture_file *cf, const char *filter,
4559 search_direction dir)
4561 dfilter_t *sfcode;
4562 gboolean result;
4564 if (!dfilter_compile(filter, &sfcode, NULL)) {
4566 * XXX - this shouldn't happen, as the filter string is machine
4567 * generated
4569 return FALSE;
4571 if (sfcode == NULL) {
4573 * XXX - this shouldn't happen, as the filter string is machine
4574 * generated.
4576 return FALSE;
4578 result = find_packet(cf, match_dfilter, sfcode, dir);
4579 dfilter_free(sfcode);
4580 return result;
4583 static match_result
4584 match_dfilter(capture_file *cf, frame_data *fdata,
4585 wtap_rec *rec, Buffer *buf, void *criterion)
4587 dfilter_t *sfcode = (dfilter_t *)criterion;
4588 epan_dissect_t edt;
4589 match_result result;
4591 /* Load the frame's data. */
4592 if (!cf_read_record(cf, fdata, rec, buf)) {
4593 /* Attempt to get the packet failed. */
4594 return MR_ERROR;
4597 epan_dissect_init(&edt, cf->epan, TRUE, FALSE);
4598 epan_dissect_prime_with_dfilter(&edt, sfcode);
4599 epan_dissect_run(&edt, cf->cd_t, rec,
4600 frame_tvbuff_new_buffer(&cf->provider, fdata, buf),
4601 fdata, NULL);
4602 result = dfilter_apply_edt(sfcode, &edt) ? MR_MATCHED : MR_NOTMATCHED;
4603 epan_dissect_cleanup(&edt);
4604 return result;
4607 gboolean
4608 cf_find_packet_marked(capture_file *cf, search_direction dir)
4610 return find_packet(cf, match_marked, NULL, dir);
4613 static match_result
4614 match_marked(capture_file *cf _U_, frame_data *fdata, wtap_rec *rec _U_,
4615 Buffer *buf _U_, void *criterion _U_)
4617 return fdata->marked ? MR_MATCHED : MR_NOTMATCHED;
4620 gboolean
4621 cf_find_packet_time_reference(capture_file *cf, search_direction dir)
4623 return find_packet(cf, match_time_reference, NULL, dir);
4626 static match_result
4627 match_time_reference(capture_file *cf _U_, frame_data *fdata, wtap_rec *rec _U_,
4628 Buffer *buf _U_, void *criterion _U_)
4630 return fdata->ref_time ? MR_MATCHED : MR_NOTMATCHED;
4633 static gboolean
4634 find_packet(capture_file *cf, ws_match_function match_function,
4635 void *criterion, search_direction dir)
4637 frame_data *start_fd;
4638 guint32 framenum;
4639 guint32 prev_framenum;
4640 frame_data *fdata;
4641 wtap_rec rec;
4642 Buffer buf;
4643 frame_data *new_fd = NULL;
4644 progdlg_t *progbar = NULL;
4645 GTimer *prog_timer = g_timer_new();
4646 int count;
4647 gboolean succeeded;
4648 float progbar_val;
4649 gchar status_str[100];
4650 match_result result;
4652 wtap_rec_init(&rec);
4653 ws_buffer_init(&buf, 1514);
4655 start_fd = cf->current_frame;
4656 if (start_fd != NULL) {
4657 prev_framenum = start_fd->num;
4658 } else {
4659 prev_framenum = 0; /* No start packet selected. */
4662 /* Iterate through the list of packets, starting at the packet we've
4663 picked, calling a routine to run the filter on the packet, see if
4664 it matches, and stop if so. */
4665 count = 0;
4666 framenum = prev_framenum;
4668 g_timer_start(prog_timer);
4669 /* Progress so far. */
4670 progbar_val = 0.0f;
4672 cf->stop_flag = FALSE;
4674 for (;;) {
4675 /* Create the progress bar if necessary.
4676 We check on every iteration of the loop, so that it takes no
4677 longer than the standard time to create it (otherwise, for a
4678 large file, we might take considerably longer than that standard
4679 time in order to get to the next progress bar step). */
4680 if (progbar == NULL)
4681 progbar = delayed_create_progress_dlg(cf->window, NULL, NULL,
4682 FALSE, &cf->stop_flag, progbar_val);
4685 * Update the progress bar, but do it only after PROGBAR_UPDATE_INTERVAL
4686 * has elapsed. Calling update_progress_dlg and packets_bar_update will
4687 * likely trigger UI paint events, which might take a while depending on
4688 * the platform and display. Reset our timer *after* painting.
4690 if (g_timer_elapsed(prog_timer, NULL) > PROGBAR_UPDATE_INTERVAL) {
4691 /* let's not divide by zero. I should never be started
4692 * with count == 0, so let's assert that
4694 ws_assert(cf->count > 0);
4696 progbar_val = (gfloat) count / cf->count;
4698 snprintf(status_str, sizeof(status_str),
4699 "%4u of %u packets", count, cf->count);
4700 update_progress_dlg(progbar, progbar_val, status_str);
4702 g_timer_start(prog_timer);
4705 if (cf->stop_flag) {
4706 /* Well, the user decided to abort the search. Go back to the
4707 frame where we started. */
4708 new_fd = start_fd;
4709 break;
4712 /* Go past the current frame. */
4713 if (dir == SD_BACKWARD) {
4714 /* Go on to the previous frame. */
4715 if (framenum <= 1) {
4717 * XXX - other apps have a bit more of a detailed message
4718 * for this, and instead of offering "OK" and "Cancel",
4719 * they offer things such as "Continue" and "Cancel";
4720 * we need an API for popping up alert boxes with
4721 * {Verb} and "Cancel".
4724 if (prefs.gui_find_wrap) {
4725 statusbar_push_temporary_msg("Search reached the beginning. Continuing at end.");
4726 framenum = cf->count; /* wrap around */
4727 } else {
4728 statusbar_push_temporary_msg("Search reached the beginning.");
4729 framenum = prev_framenum; /* stay on previous packet */
4731 } else
4732 framenum--;
4733 } else {
4734 /* Go on to the next frame. */
4735 if (framenum == cf->count) {
4736 if (prefs.gui_find_wrap) {
4737 statusbar_push_temporary_msg("Search reached the end. Continuing at beginning.");
4738 framenum = 1; /* wrap around */
4739 } else {
4740 statusbar_push_temporary_msg("Search reached the end.");
4741 framenum = prev_framenum; /* stay on previous packet */
4743 } else
4744 framenum++;
4747 fdata = frame_data_sequence_find(cf->provider.frames, framenum);
4748 count++;
4750 /* Is this packet in the display? */
4751 if (fdata && fdata->passed_dfilter) {
4752 /* Yes. Does it match the search criterion? */
4753 result = (*match_function)(cf, fdata, &rec, &buf, criterion);
4754 if (result == MR_ERROR) {
4755 /* Error; our caller has reported the error. Go back to the frame
4756 where we started. */
4757 new_fd = start_fd;
4758 break;
4759 } else if (result == MR_MATCHED) {
4760 /* Yes. Go to the new frame. */
4761 new_fd = fdata;
4762 break;
4764 wtap_rec_reset(&rec);
4767 if (fdata == start_fd) {
4768 /* We're back to the frame we were on originally, and that frame
4769 doesn't match the search filter. The search failed. */
4770 break;
4774 /* We're done scanning the packets; destroy the progress bar if it
4775 was created. */
4776 if (progbar != NULL)
4777 destroy_progress_dlg(progbar);
4778 g_timer_destroy(prog_timer);
4780 if (new_fd != NULL) {
4781 /* We found a frame that's displayed and that matches.
4782 Try to find and select the packet summary list row for that frame. */
4783 gboolean found_row;
4785 cf->search_in_progress = TRUE;
4786 found_row = packet_list_select_row_from_data(new_fd);
4787 cf->search_in_progress = FALSE;
4788 if (!found_row) {
4789 /* We didn't find a row corresponding to this frame.
4790 This means that the frame isn't being displayed currently,
4791 so we can't select it. */
4792 cf->search_pos = 0; /* Reset the position */
4793 cf->search_len = 0; /* Reset length */
4794 simple_message_box(ESD_TYPE_INFO, NULL,
4795 "The capture file is probably not fully dissected.",
4796 "End of capture exceeded.");
4797 succeeded = FALSE; /* The search succeeded but we didn't find the row */
4798 } else
4799 succeeded = TRUE; /* The search succeeded and we found the row */
4800 } else
4801 succeeded = FALSE; /* The search failed */
4802 wtap_rec_cleanup(&rec);
4803 ws_buffer_free(&buf);
4804 return succeeded;
4807 gboolean
4808 cf_goto_frame(capture_file *cf, guint fnumber, gboolean exact)
4810 frame_data *fdata;
4812 if (cf == NULL || cf->provider.frames == NULL) {
4813 /* we don't have a loaded capture file - fix for bugs 11810 & 11989 */
4814 statusbar_push_temporary_msg("There is no file loaded");
4815 return FALSE; /* we failed to go to that packet */
4818 fdata = frame_data_sequence_find(cf->provider.frames, fnumber);
4820 if (fdata == NULL) {
4821 /* we didn't find a packet with that packet number */
4822 statusbar_push_temporary_msg("There is no packet number %u.", fnumber);
4823 return FALSE; /* we failed to go to that packet */
4825 if (!fdata->passed_dfilter) {
4826 /* that packet currently isn't displayed */
4827 /* XXX - add it to the set of displayed packets? */
4828 if (cf->first_displayed == 0 || exact) {
4829 /* We only want that exact frame, or no frames are displayed. */
4830 statusbar_push_temporary_msg("Packet number %u isn't displayed.", fnumber);
4831 return FALSE; /* we failed to go to that packet */
4833 if (fdata->prev_dis_num == 0) {
4834 /* There is no previous displayed frame, so this frame is
4835 * before the first displayed frame. Go to the first line,
4836 * which is the closest frame.
4838 fdata = NULL; /* This will select the first row. */
4839 statusbar_push_temporary_msg("Packet number %u isn't displayed, going to the first displayed packet, %u.", fnumber, cf->first_displayed);
4840 } else {
4841 uint32_t delta = fnumber - fdata->prev_dis_num;
4842 /* The next displayed frame might be closer, we can do an
4843 * O(log n) binary search for the earliest displayed frame
4844 * in the open interval (fnumber, fnumber + delta).
4846 * This is possibly overkill, we could just go to the previous
4847 * displayed frame.
4849 frame_data *fdata2;
4850 uint32_t lower_bound = fnumber + 1;
4851 uint32_t upper_bound = fnumber + delta - 1;
4852 bool found = false;
4853 while (lower_bound <= upper_bound) {
4854 uint32_t middle = (lower_bound + upper_bound) / 2;
4855 fdata2 = frame_data_sequence_find(cf->provider.frames, middle);
4856 if (fdata2 == NULL) {
4857 /* We don't have a frame of that number, so search before it. */
4858 upper_bound = middle - 1;
4859 continue;
4861 /* We have a frame of that number. What's the displayed
4862 * frame before it? */
4863 if (fdata2->prev_dis_num > fnumber) {
4864 /* The previous frame that passed the filter is also after
4865 * our target, so our answer is no later than that.
4867 upper_bound = fdata2->prev_dis_num;
4868 } else {
4869 /* The previous displayed frame is before fnumber.
4870 * (We already know fnumber itself is not displayed.)
4871 * Is this frame itself displayed?
4873 if (fdata2->passed_dfilter) {
4874 /* Yes. So this is our answer. */
4875 found = true;
4876 break;
4878 /* No. So our answer, if any, is after this frame. */
4879 lower_bound = middle + 1;
4882 if (found) {
4883 fdata = fdata2;
4884 statusbar_push_temporary_msg("Packet number %u isn't displayed, going to the next displayed packet, %u.", fnumber, fdata->num);
4885 } else {
4886 statusbar_push_temporary_msg("Packet number %u isn't displayed, going to the previous displayed packet, %u.", fnumber, fdata->prev_dis_num);
4887 fdata = frame_data_sequence_find(cf->provider.frames, fdata->prev_dis_num);
4892 if (!packet_list_select_row_from_data(fdata)) {
4893 /* We didn't find a row corresponding to this frame.
4894 This means that the frame isn't being displayed currently,
4895 so we can't select it. */
4896 simple_message_box(ESD_TYPE_INFO, NULL,
4897 "The capture file is probably not fully dissected.",
4898 "End of capture exceeded.");
4899 return FALSE;
4901 return TRUE; /* we got to that packet */
4905 * Go to frame specified by currently selected protocol tree item.
4907 gboolean
4908 cf_goto_framenum(capture_file *cf)
4910 const header_field_info *hfinfo;
4911 guint32 framenum;
4913 if (cf->finfo_selected) {
4914 hfinfo = cf->finfo_selected->hfinfo;
4915 ws_assert(hfinfo);
4916 if (hfinfo->type == FT_FRAMENUM) {
4917 framenum = fvalue_get_uinteger(cf->finfo_selected->value);
4918 if (framenum != 0) {
4919 /* We probably only want to go to the exact match,
4920 * even though "Go to Previous Packet in History" exists.
4922 return cf_goto_frame(cf, framenum, TRUE);
4927 return FALSE;
4930 /* Select the packet on a given row. */
4931 void
4932 cf_select_packet(capture_file *cf, frame_data *fdata)
4934 epan_dissect_t *old_edt;
4936 /* check the frame data struct pointer for this frame */
4937 if (fdata == NULL) {
4938 return;
4941 /* Get the data in that frame. */
4942 if (!cf_read_record(cf, fdata, &cf->rec, &cf->buf)) {
4943 return;
4946 /* Record that this frame is the current frame. */
4947 cf->current_frame = fdata;
4950 * The change to defer freeing the current epan_dissect_t was in
4951 * commit a2bb94c3b33d53f42534aceb7cc67aab1d1fb1f9; to quote
4952 * that commit's comment:
4954 * Clear GtkTreeStore before freeing edt
4956 * When building current data for packet details treeview we store two
4957 * things.
4958 * - Generated string with item label
4959 * - Pointer to node field_info structure
4961 * After epan_dissect_{free, cleanup} pointer to field_info node is no
4962 * longer valid so we should clear GtkTreeStore before freeing.
4964 * XXX - we're no longer using GTK+; is there a way to ensure that
4965 * *nothing* refers to any of the current frame information before
4966 * we replace it?
4968 old_edt = cf->edt;
4969 /* Create the logical protocol tree. */
4970 /* We don't need the columns here. */
4971 cf->edt = epan_dissect_new(cf->epan, TRUE, TRUE);
4973 tap_build_interesting(cf->edt);
4974 epan_dissect_run(cf->edt, cf->cd_t, &cf->rec,
4975 frame_tvbuff_new_buffer(&cf->provider, cf->current_frame, &cf->buf),
4976 cf->current_frame, NULL);
4978 if (old_edt != NULL)
4979 epan_dissect_free(old_edt);
4982 /* Unselect the selected packet, if any. */
4983 void
4984 cf_unselect_packet(capture_file *cf)
4986 epan_dissect_t *old_edt = cf->edt;
4989 * See the comment in cf_select_packet() about deferring the freeing
4990 * of the old cf->edt.
4992 cf->edt = NULL;
4994 /* No packet is selected. */
4995 cf->current_frame = NULL;
4997 /* Destroy the epan_dissect_t for the unselected packet. */
4998 if (old_edt != NULL)
4999 epan_dissect_free(old_edt);
5003 * Mark a particular frame.
5005 void
5006 cf_mark_frame(capture_file *cf, frame_data *frame)
5008 if (! frame->marked) {
5009 frame->marked = TRUE;
5010 if (cf->count > cf->marked_count)
5011 cf->marked_count++;
5016 * Unmark a particular frame.
5018 void
5019 cf_unmark_frame(capture_file *cf, frame_data *frame)
5021 if (frame->marked) {
5022 frame->marked = FALSE;
5023 if (cf->marked_count > 0)
5024 cf->marked_count--;
5029 * Ignore a particular frame.
5031 void
5032 cf_ignore_frame(capture_file *cf, frame_data *frame)
5034 if (! frame->ignored) {
5035 frame->ignored = TRUE;
5036 if (cf->count > cf->ignored_count)
5037 cf->ignored_count++;
5042 * Un-ignore a particular frame.
5044 void
5045 cf_unignore_frame(capture_file *cf, frame_data *frame)
5047 if (frame->ignored) {
5048 frame->ignored = FALSE;
5049 if (cf->ignored_count > 0)
5050 cf->ignored_count--;
5055 * Modify the section comment.
5057 void
5058 cf_update_section_comment(capture_file *cf, gchar *comment)
5060 wtap_block_t shb_inf;
5061 gchar *shb_comment;
5063 /* Get the first SHB. */
5064 /* XXX - support multiple SHBs */
5065 shb_inf = wtap_file_get_shb(cf->provider.wth, 0);
5067 /* Get the first comment from the SHB. */
5068 /* XXX - support multiple comments */
5069 if (wtap_block_get_nth_string_option_value(shb_inf, OPT_COMMENT, 0, &shb_comment) != WTAP_OPTTYPE_SUCCESS) {
5070 /* There's no comment - add one. */
5071 wtap_block_add_string_option(shb_inf, OPT_COMMENT, comment, strlen(comment));
5072 } else {
5073 /* See if the comment has changed or not */
5074 if (strcmp(shb_comment, comment) == 0) {
5075 g_free(comment);
5076 return;
5079 /* The comment has changed, let's update it */
5080 wtap_block_set_nth_string_option_value(shb_inf, OPT_COMMENT, 0, comment, strlen(comment));
5082 /* Mark the file as having unsaved changes */
5083 cf->unsaved_changes = TRUE;
5087 * Modify the section comments for a given section.
5089 void
5090 cf_update_section_comments(capture_file *cf, unsigned shb_idx, char **comments)
5092 wtap_block_t shb_inf;
5093 gchar *shb_comment;
5095 shb_inf = wtap_file_get_shb(cf->provider.wth, shb_idx);
5096 if (shb_inf == NULL) {
5097 /* Shouldn't happen. XXX: Report it if it does? */
5098 return;
5101 unsigned n_comments = g_strv_length(comments);
5102 unsigned i;
5103 char* comment;
5105 for (i = 0; i < n_comments; i++) {
5106 comment = comments[i];
5107 if (wtap_block_get_nth_string_option_value(shb_inf, OPT_COMMENT, i, &shb_comment) != WTAP_OPTTYPE_SUCCESS) {
5108 /* There's no comment - add one. */
5109 wtap_block_add_string_option_owned(shb_inf, OPT_COMMENT, comment);
5110 cf->unsaved_changes = TRUE;
5111 } else {
5112 /* See if the comment has changed or not */
5113 if (strcmp(shb_comment, comment) != 0) {
5114 /* The comment has changed, let's update it */
5115 wtap_block_set_nth_string_option_value(shb_inf, OPT_COMMENT, 0, comment, strlen(comment));
5116 cf->unsaved_changes = TRUE;
5118 g_free(comment);
5121 /* We either transferred ownership of the comments or freed them
5122 * above, so free the array of strings but not the strings themselves. */
5123 g_free(comments);
5125 /* If there are extra old comments, remove them. Start at the end. */
5126 for (i = wtap_block_count_option(shb_inf, OPT_COMMENT); i > n_comments; i--) {
5127 wtap_block_remove_nth_option_instance(shb_inf, OPT_COMMENT, i - 1);
5128 cf->unsaved_changes = TRUE;
5133 * Get the packet block for a packet (record).
5134 * If the block has been edited, it returns the result of the edit,
5135 * otherwise it returns the block from the file.
5136 * NB. Caller must wtap_block_unref() the result when done.
5138 wtap_block_t
5139 cf_get_packet_block(capture_file *cf, const frame_data *fd)
5141 /* If this block has been modified, fetch the modified version */
5142 if (fd->has_modified_block)
5143 return wtap_block_ref(cap_file_provider_get_modified_block(&cf->provider, fd));
5144 else {
5145 wtap_rec rec; /* Record metadata */
5146 Buffer buf; /* Record data */
5147 wtap_block_t block;
5149 /* fetch record block */
5150 wtap_rec_init(&rec);
5151 ws_buffer_init(&buf, 1514);
5153 if (!cf_read_record(cf, fd, &rec, &buf))
5154 { /* XXX, what we can do here? */ }
5156 /* rec.block is owned by the record, steal it before it is gone. */
5157 block = wtap_block_ref(rec.block);
5159 wtap_rec_cleanup(&rec);
5160 ws_buffer_free(&buf);
5161 return block;
5166 * Update(replace) the block on a capture from a frame
5168 gboolean
5169 cf_set_modified_block(capture_file *cf, frame_data *fd, const wtap_block_t new_block)
5171 wtap_block_t pkt_block = cf_get_packet_block(cf, fd);
5173 /* It's possible to further modify the modified block "in place" by doing
5174 * a call to cf_get_packet_block() that returns an already created modified
5175 * block, modifying that, and calling this function.
5176 * If the caller did that, then the block pointers will be equal.
5178 if (pkt_block == new_block) {
5179 /* No need to save anything here, the caller changes went right
5180 * onto the block.
5181 * Unfortunately we don't have a way to know how many comments were
5182 * in the block before the caller modified it, so tell the caller
5183 * it is its responsibility to update the comment count.
5185 return FALSE;
5187 else {
5188 if (pkt_block)
5189 cf->packet_comment_count -= wtap_block_count_option(pkt_block, OPT_COMMENT);
5191 if (new_block)
5192 cf->packet_comment_count += wtap_block_count_option(new_block, OPT_COMMENT);
5194 cap_file_provider_set_modified_block(&cf->provider, fd, new_block);
5196 expert_update_comment_count(cf->packet_comment_count);
5199 /* Either way, we have unsaved changes. */
5200 wtap_block_unref(pkt_block);
5201 cf->unsaved_changes = TRUE;
5202 return TRUE;
5206 * What types of comments does this capture file have?
5208 guint32
5209 cf_comment_types(capture_file *cf)
5211 guint32 comment_types = 0;
5214 * Does this file have any sections with at least one comment?
5216 for (guint section_number = 0;
5217 section_number < wtap_file_get_num_shbs(cf->provider.wth);
5218 section_number++) {
5219 wtap_block_t shb_inf;
5220 char *shb_comment;
5222 shb_inf = wtap_file_get_shb(cf->provider.wth, section_number);
5224 /* Try to get the first comment from that SHB. */
5225 if (wtap_block_get_nth_string_option_value(shb_inf, OPT_COMMENT, 0,
5226 &shb_comment) == WTAP_OPTTYPE_SUCCESS) {
5227 /* We succeeded, so this file has at least one section comment. */
5228 comment_types |= WTAP_COMMENT_PER_SECTION;
5230 /* We don't need to search any more. */
5231 break;
5234 if (cf->packet_comment_count != 0)
5235 comment_types |= WTAP_COMMENT_PER_PACKET;
5236 return comment_types;
5240 * Add a resolved address to this file's list of resolved addresses.
5242 gboolean
5243 cf_add_ip_name_from_string(capture_file *cf, const char *addr, const char *name)
5246 * XXX - support multiple resolved address lists, and add to the one
5247 * attached to this file?
5249 if (!add_ip_name_from_string(addr, name))
5250 return FALSE;
5252 /* OK, we have unsaved changes. */
5253 cf->unsaved_changes = TRUE;
5254 return TRUE;
5257 typedef struct {
5258 wtap_dumper *pdh;
5259 const char *fname;
5260 int file_type;
5261 gboolean export;
5262 } save_callback_args_t;
5265 * Save a capture to a file, in a particular format, saving either
5266 * all packets, all currently-displayed packets, or all marked packets.
5268 * Returns TRUE if it succeeds, FALSE otherwise; if it fails, it pops
5269 * up a message box for the failure.
5271 static bool
5272 save_record(capture_file *cf, frame_data *fdata, wtap_rec *rec,
5273 Buffer *buf, void *argsp)
5275 save_callback_args_t *args = (save_callback_args_t *)argsp;
5276 wtap_rec new_rec;
5277 int err;
5278 gchar *err_info;
5279 wtap_block_t pkt_block;
5281 /* Copy the record information from what was read in from the file. */
5282 new_rec = *rec;
5284 /* Make changes based on anything that the user has done but that
5285 hasn't been saved yet. */
5286 if (fdata->has_modified_block)
5287 pkt_block = cap_file_provider_get_modified_block(&cf->provider, fdata);
5288 else
5289 pkt_block = rec->block;
5290 new_rec.block = pkt_block;
5291 new_rec.block_was_modified = fdata->has_modified_block ? TRUE : FALSE;
5293 if (!nstime_is_zero(&fdata->shift_offset)) {
5294 if (new_rec.presence_flags & WTAP_HAS_TS) {
5295 nstime_add(&new_rec.ts, &fdata->shift_offset);
5299 /* and save the packet */
5300 if (!wtap_dump(args->pdh, &new_rec, ws_buffer_start_ptr(buf), &err, &err_info)) {
5301 cfile_write_failure_alert_box(NULL, args->fname, err, err_info, fdata->num,
5302 args->file_type);
5303 return FALSE;
5306 /* If we are saving (i.e., replacing the current file with the one we're
5307 * writing), then update the frame data to clear the shift offset.
5308 * This keeps us from having to re-read the entire file.
5309 * We could do this in rescan_file(), but
5310 * 1) Ideally we shouldn't have to call rescan_file if all we're doing
5311 * is changing the timestamps, since that shouldn't change the offsets.
5312 * 2) The long term goal is to try to do the offset adjustment here
5313 * instead of using rescan_file, which should be faster (#1257).
5315 * If we're exporting to a different file, then don't do that.
5317 if (!args->export && new_rec.presence_flags & WTAP_HAS_TS) {
5318 nstime_set_zero(&fdata->shift_offset);
5321 return TRUE;
5325 * Can this capture file be written out in any format using Wiretap
5326 * rather than by copying the raw data?
5328 gboolean
5329 cf_can_write_with_wiretap(capture_file *cf)
5331 /* We don't care whether we support the comments in this file or not;
5332 if we can't, we'll offer the user the option of discarding the
5333 comments. */
5334 return wtap_dump_can_write(cf->linktypes, 0);
5338 * Should we let the user do a save?
5340 * We should if:
5342 * the file has unsaved changes, and we can save it in some
5343 * format through Wiretap
5345 * or
5347 * the file is a temporary file and has no unsaved changes (so
5348 * that "saving" it just means copying it).
5350 * XXX - we shouldn't allow files to be edited if they can't be saved,
5351 * so cf->unsaved_changes should be true only if the file can be saved.
5353 * We don't care whether we support the comments in this file or not;
5354 * if we can't, we'll offer the user the option of discarding the
5355 * comments.
5357 gboolean
5358 cf_can_save(capture_file *cf)
5360 if (cf->unsaved_changes && wtap_dump_can_write(cf->linktypes, 0)) {
5361 /* Saved changes, and we can write it out with Wiretap. */
5362 return TRUE;
5365 if (cf->is_tempfile && !cf->unsaved_changes) {
5367 * Temporary file with no unsaved changes, so we can just do a
5368 * raw binary copy.
5370 return TRUE;
5373 /* Nothing to save. */
5374 return FALSE;
5378 * Should we let the user do a "save as"?
5380 * That's true if:
5382 * we can save it in some format through Wiretap
5384 * or
5386 * the file is a temporary file and has no unsaved changes (so
5387 * that "saving" it just means copying it).
5389 * XXX - we shouldn't allow files to be edited if they can't be saved,
5390 * so cf->unsaved_changes should be true only if the file can be saved.
5392 * We don't care whether we support the comments in this file or not;
5393 * if we can't, we'll offer the user the option of discarding the
5394 * comments.
5396 gboolean
5397 cf_can_save_as(capture_file *cf)
5399 if (wtap_dump_can_write(cf->linktypes, 0)) {
5400 /* We can write it out with Wiretap. */
5401 return TRUE;
5404 if (cf->is_tempfile && !cf->unsaved_changes) {
5406 * Temporary file with no unsaved changes, so we can just do a
5407 * raw binary copy.
5409 return TRUE;
5412 /* Nothing to save. */
5413 return FALSE;
5417 * Does this file have unsaved data?
5419 gboolean
5420 cf_has_unsaved_data(capture_file *cf)
5423 * If this is a temporary file, or a file with unsaved changes, it
5424 * has unsaved data.
5426 return (cf->is_tempfile && cf->count>0) || cf->unsaved_changes;
5430 * Quick scan to find packet offsets.
5432 static cf_read_status_t
5433 rescan_file(capture_file *cf, const char *fname, gboolean is_tempfile)
5435 wtap_rec rec;
5436 Buffer buf;
5437 int err;
5438 gchar *err_info;
5439 gchar *name_ptr;
5440 gint64 data_offset;
5441 progdlg_t *progbar = NULL;
5442 GTimer *prog_timer = g_timer_new();
5443 gint64 size;
5444 float progbar_val;
5445 gint64 start_time;
5446 gchar status_str[100];
5447 guint32 framenum;
5448 frame_data *fdata;
5450 /* Close the old handle. */
5451 wtap_close(cf->provider.wth);
5453 /* Open the new file. */
5454 /* XXX: this will go through all open_routines for a matching one. But right
5455 now rescan_file() is only used when a file is being saved to a different
5456 format than the original, and the user is not given a choice of which
5457 reader to use (only which format to save it in), so doing this makes
5458 sense for now. (XXX: Now it is also used when saving a changed file,
5459 e.g. comments or time-shifted frames.) */
5460 cf->provider.wth = wtap_open_offline(fname, WTAP_TYPE_AUTO, &err, &err_info, TRUE);
5461 if (cf->provider.wth == NULL) {
5462 cfile_open_failure_alert_box(fname, err, err_info);
5463 return CF_READ_ERROR;
5466 /* We're scanning a file whose contents should be the same as what
5467 we had before, so we don't discard dissection state etc.. */
5468 cf->f_datalen = 0;
5470 /* Set the file name because we need it to set the follow stream filter.
5471 XXX - is that still true? We need it for other reasons, though,
5472 in any case. */
5473 if (cf->filename != NULL) {
5474 g_free(cf->filename);
5476 cf->filename = g_strdup(fname);
5478 /* Indicate whether it's a permanent or temporary file. */
5479 cf->is_tempfile = is_tempfile;
5481 /* No user changes yet. */
5482 cf->unsaved_changes = FALSE;
5484 cf->cd_t = wtap_file_type_subtype(cf->provider.wth);
5485 if (cf->linktypes != NULL) {
5486 g_array_free(cf->linktypes, TRUE);
5488 cf->linktypes = g_array_sized_new(FALSE, FALSE, (guint) sizeof(int), 1);
5490 cf->snap = wtap_snapshot_length(cf->provider.wth);
5492 name_ptr = g_filename_display_basename(cf->filename);
5494 cf_callback_invoke(cf_cb_file_rescan_started, cf);
5496 /* Record the file's compression type.
5497 XXX - do we know this at open time? */
5498 cf->compression_type = wtap_get_compression_type(cf->provider.wth);
5500 /* Find the size of the file. */
5501 size = wtap_file_size(cf->provider.wth, NULL);
5503 g_timer_start(prog_timer);
5505 cf->stop_flag = FALSE;
5506 start_time = g_get_monotonic_time();
5508 framenum = 0;
5509 wtap_rec_init(&rec);
5510 ws_buffer_init(&buf, 1514);
5511 while ((wtap_read(cf->provider.wth, &rec, &buf, &err, &err_info,
5512 &data_offset))) {
5513 framenum++;
5514 fdata = frame_data_sequence_find(cf->provider.frames, framenum);
5515 if (G_LIKELY(fdata != NULL)) {
5516 fdata->file_off = data_offset;
5518 if (size >= 0) {
5519 cf->f_datalen = wtap_read_so_far(cf->provider.wth);
5521 /* Create the progress bar if necessary. */
5522 if (progress_is_slow(progbar, prog_timer, size, cf->f_datalen)) {
5523 progbar_val = calc_progbar_val(cf, size, cf->f_datalen, status_str, sizeof(status_str));
5524 progbar = delayed_create_progress_dlg(cf->window, NULL, NULL,
5525 TRUE, &cf->stop_flag, progbar_val);
5529 * Update the progress bar, but do it only after PROGBAR_UPDATE_INTERVAL
5530 * has elapsed. Calling update_progress_dlg and packets_bar_update will
5531 * likely trigger UI paint events, which might take a while depending on
5532 * the platform and display. Reset our timer *after* painting.
5534 if (progbar && g_timer_elapsed(prog_timer, NULL) > PROGBAR_UPDATE_INTERVAL) {
5535 progbar_val = calc_progbar_val(cf, size, cf->f_datalen, status_str, sizeof(status_str));
5536 /* update the packet bar content on the first run or frequently on very large files */
5537 update_progress_dlg(progbar, progbar_val, status_str);
5538 compute_elapsed(cf, start_time);
5539 packets_bar_update();
5540 g_timer_start(prog_timer);
5544 if (cf->stop_flag) {
5545 /* Well, the user decided to abort the rescan. Sadly, as this
5546 isn't a reread, recovering is difficult, so we'll just
5547 close the current capture. */
5548 break;
5551 /* Add this packet's link-layer encapsulation type to cf->linktypes, if
5552 it's not already there.
5553 XXX - yes, this is O(N), so if every packet had a different
5554 link-layer encapsulation type, it'd be O(N^2) to read the file, but
5555 there are probably going to be a small number of encapsulation types
5556 in a file. */
5557 if (rec.rec_type == REC_TYPE_PACKET) {
5558 cf_add_encapsulation_type(cf, rec.rec_header.packet_header.pkt_encap);
5560 wtap_rec_reset(&rec);
5562 wtap_rec_cleanup(&rec);
5563 ws_buffer_free(&buf);
5565 /* Free the display name */
5566 g_free(name_ptr);
5568 /* We're done reading the file; destroy the progress bar if it was created. */
5569 if (progbar != NULL)
5570 destroy_progress_dlg(progbar);
5571 g_timer_destroy(prog_timer);
5573 /* We're done reading sequentially through the file. */
5574 cf->state = FILE_READ_DONE;
5576 /* Close the sequential I/O side, to free up memory it requires. */
5577 wtap_sequential_close(cf->provider.wth);
5579 /* compute the time it took to load the file */
5580 compute_elapsed(cf, start_time);
5582 /* Set the file encapsulation type now; we don't know what it is until
5583 we've looked at all the packets, as we don't know until then whether
5584 there's more than one type (and thus whether it's
5585 WTAP_ENCAP_PER_PACKET). */
5586 cf->lnk_t = wtap_file_encap(cf->provider.wth);
5588 cf_callback_invoke(cf_cb_file_rescan_finished, cf);
5590 if (cf->stop_flag) {
5591 /* Our caller will give up at this point. */
5592 return CF_READ_ABORTED;
5595 if (err != 0) {
5596 /* Put up a message box noting that the read failed somewhere along
5597 the line. Don't throw out the stuff we managed to read, though,
5598 if any. */
5599 cfile_read_failure_alert_box(NULL, err, err_info);
5600 return CF_READ_ERROR;
5601 } else
5602 return CF_READ_OK;
5605 cf_write_status_t
5606 cf_save_records(capture_file *cf, const char *fname, guint save_format,
5607 wtap_compression_type compression_type,
5608 gboolean discard_comments, gboolean dont_reopen)
5610 gchar *err_info;
5611 gchar *fname_new = NULL;
5612 wtap_dumper *pdh;
5613 frame_data *fdata;
5614 addrinfo_lists_t *addr_lists;
5615 guint framenum;
5616 int err;
5617 #ifdef _WIN32
5618 gchar *display_basename;
5619 #endif
5620 enum {
5621 SAVE_WITH_MOVE,
5622 SAVE_WITH_COPY,
5623 SAVE_WITH_WTAP
5624 } how_to_save;
5625 save_callback_args_t callback_args;
5626 callback_args.export = FALSE;
5627 bool needs_reload = false;
5629 /* XXX caller should avoid saving the file while a read is pending
5630 * (e.g. by delaying the save action) */
5631 if (cf->read_lock) {
5632 ws_warning("cf_save_records(\"%s\") while the file is being read, potential crash ahead", fname);
5635 cf_callback_invoke(cf_cb_file_save_started, (gpointer)fname);
5637 addr_lists = get_addrinfo_list();
5639 if (save_format == cf->cd_t && compression_type == cf->compression_type
5640 && !discard_comments && !cf->unsaved_changes
5641 && (wtap_addrinfo_list_empty(addr_lists) || wtap_file_type_subtype_supports_block(save_format, WTAP_BLOCK_NAME_RESOLUTION) == BLOCK_NOT_SUPPORTED)) {
5642 /* We're saving in the format it's already in, and we're not discarding
5643 comments, and there are no changes we have in memory that aren't saved
5644 to the file, and we have no name resolution information to write or
5645 the file format we're saving in doesn't support writing name
5646 resolution information, so we can just move or copy the raw data. */
5648 if (cf->is_tempfile) {
5649 /* The file being saved is a temporary file from a live
5650 capture, so it doesn't need to stay around under that name;
5651 first, try renaming the capture buffer file to the new name.
5652 This acts as a "safe save", in that, if the file already
5653 exists, the existing file will be removed only if the rename
5654 succeeds.
5656 Sadly, on Windows, as we have the current capture file
5657 open, even MoveFileEx() with MOVEFILE_REPLACE_EXISTING
5658 (to cause the rename to remove an existing target), as
5659 done by ws_stdio_rename() (ws_rename() is #defined to
5660 be ws_stdio_rename() on Windows) will fail.
5662 According to the MSDN documentation for CreateFile(), if,
5663 when we open a capture file, we were to directly do a CreateFile(),
5664 opening with FILE_SHARE_DELETE|FILE_SHARE_READ, and then
5665 convert it to a file descriptor with _open_osfhandle(),
5666 that would allow the file to be renamed out from under us.
5668 However, that doesn't work in practice. Perhaps the problem
5669 is that the process doing the rename is the process that
5670 has the file open. */
5671 #ifndef _WIN32
5672 if (ws_rename(cf->filename, fname) == 0) {
5673 /* That succeeded - there's no need to copy the source file. */
5674 how_to_save = SAVE_WITH_MOVE;
5675 } else {
5676 if (errno == EXDEV) {
5677 /* They're on different file systems, so we have to copy the
5678 file. */
5679 how_to_save = SAVE_WITH_COPY;
5680 } else {
5681 /* The rename failed, but not because they're on different
5682 file systems - put up an error message. (Or should we
5683 just punt and try to copy? The only reason why I'd
5684 expect the rename to fail and the copy to succeed would
5685 be if we didn't have permission to remove the file from
5686 the temporary directory, and that might be fixable - but
5687 is it worth requiring the user to go off and fix it?) */
5688 cf_rename_failure_alert_box(fname, errno);
5689 goto fail;
5692 #else
5693 /* Windows - copy the file to its new location. */
5694 how_to_save = SAVE_WITH_COPY;
5695 #endif
5696 } else {
5697 /* It's a permanent file, so we should copy it, and not remove the
5698 original. */
5699 how_to_save = SAVE_WITH_COPY;
5702 if (how_to_save == SAVE_WITH_COPY) {
5703 /* Copy the file, if we haven't moved it. If we're overwriting
5704 an existing file, we do it with a "safe save", by writing
5705 to a new file and, if the write succeeds, renaming the
5706 new file on top of the old file. */
5707 if (file_exists(fname)) {
5708 fname_new = ws_strdup_printf("%s~", fname);
5709 if (!copy_file_binary_mode(cf->filename, fname_new))
5710 goto fail;
5711 } else {
5712 if (!copy_file_binary_mode(cf->filename, fname))
5713 goto fail;
5716 } else {
5717 /* Either we're saving in a different format or we're saving changes,
5718 such as added, modified, or removed comments, that haven't yet
5719 been written to the underlying file; we can't do that by copying
5720 or moving the capture file, we have to do it by writing the packets
5721 out in Wiretap. */
5723 wtap_dump_params params;
5724 int encap;
5726 how_to_save = SAVE_WITH_WTAP;
5727 wtap_dump_params_init(&params, cf->provider.wth);
5729 /* Determine what file encapsulation type we should use. */
5730 encap = wtap_dump_required_file_encap_type(cf->linktypes);
5731 params.encap = encap;
5733 /* Use the snaplen from cf (XXX - does wtap_dump_params_init handle that?) */
5734 params.snaplen = cf->snap;
5736 if (file_exists(fname)) {
5737 /* We're overwriting an existing file; write out to a new file,
5738 and, if that succeeds, rename the new file on top of the
5739 old file. That makes this a "safe save", so that we don't
5740 lose the old file if we have a problem writing out the new
5741 file. (If the existing file is the current capture file,
5742 we *HAVE* to do that, otherwise we're overwriting the file
5743 from which we're reading the packets that we're writing!) */
5744 fname_new = ws_strdup_printf("%s~", fname);
5745 pdh = wtap_dump_open(fname_new, save_format, compression_type, &params,
5746 &err, &err_info);
5747 } else {
5748 pdh = wtap_dump_open(fname, save_format, compression_type, &params,
5749 &err, &err_info);
5751 /* XXX idb_inf is documented to be used until wtap_dump_close. */
5752 g_free(params.idb_inf);
5753 params.idb_inf = NULL;
5755 if (pdh == NULL) {
5756 cfile_dump_open_failure_alert_box(fname, err, err_info, save_format);
5757 goto fail;
5760 /* Add address resolution */
5761 wtap_dump_set_addrinfo_list(pdh, addr_lists);
5763 /* Iterate through the list of packets, processing all the packets. */
5764 callback_args.pdh = pdh;
5765 callback_args.fname = fname;
5766 callback_args.file_type = save_format;
5767 switch (process_specified_records(cf, NULL, "Saving", "packets",
5768 TRUE, save_record, &callback_args, TRUE)) {
5770 case PSP_FINISHED:
5771 /* Completed successfully. */
5772 break;
5774 case PSP_STOPPED:
5775 /* The user decided to abort the saving.
5776 If we're writing to a temporary file, remove it.
5777 XXX - should we do so even if we're not writing to a
5778 temporary file? */
5779 wtap_dump_close(pdh, NULL, &err, &err_info);
5780 if (fname_new != NULL)
5781 ws_unlink(fname_new);
5782 cf_callback_invoke(cf_cb_file_save_stopped, NULL);
5783 wtap_dump_params_cleanup(&params);
5784 return CF_WRITE_ABORTED;
5786 case PSP_FAILED:
5787 /* Error while saving.
5788 If we're writing to a temporary file, remove it. */
5789 if (fname_new != NULL)
5790 ws_unlink(fname_new);
5791 wtap_dump_close(pdh, NULL, &err, &err_info);
5792 wtap_dump_params_cleanup(&params);
5793 goto fail;
5796 if (!wtap_dump_close(pdh, &needs_reload, &err, &err_info)) {
5797 cfile_close_failure_alert_box(fname, err, err_info);
5798 wtap_dump_params_cleanup(&params);
5799 goto fail;
5802 wtap_dump_params_cleanup(&params);
5805 if (fname_new != NULL) {
5806 /* We wrote out to fname_new, and should rename it on top of
5807 fname. fname_new is now closed, so that should be possible even
5808 on Windows. However, on Windows, we first need to close whatever
5809 file descriptors we have open for fname. */
5810 #ifdef _WIN32
5811 wtap_fdclose(cf->provider.wth);
5812 #endif
5813 /* Now do the rename. */
5814 if (ws_rename(fname_new, fname) == -1) {
5815 /* Well, the rename failed. */
5816 cf_rename_failure_alert_box(fname, errno);
5817 #ifdef _WIN32
5818 /* Attempt to reopen the random file descriptor using the
5819 current file's filename. (At this point, the sequential
5820 file descriptor is closed.) */
5821 if (!wtap_fdreopen(cf->provider.wth, cf->filename, &err)) {
5822 /* Oh, well, we're screwed. */
5823 display_basename = g_filename_display_basename(cf->filename);
5824 simple_error_message_box(
5825 file_open_error_message(err, FALSE), display_basename);
5826 g_free(display_basename);
5828 #endif
5829 goto fail;
5831 g_free(fname_new);
5834 /* If this was a temporary file, and we didn't do the save by doing
5835 a move, so the tempoary file is still around under its old name,
5836 remove it. */
5837 if (cf->is_tempfile && how_to_save != SAVE_WITH_MOVE) {
5838 /* If this fails, there's not much we can do, so just ignore errors. */
5839 ws_unlink(cf->filename);
5842 cf_callback_invoke(cf_cb_file_save_finished, NULL);
5843 cf->unsaved_changes = FALSE;
5845 if (!dont_reopen) {
5846 switch (how_to_save) {
5848 case SAVE_WITH_MOVE:
5849 /* We just moved the file, so the wtap structure refers to the
5850 new file, and all the information other than the filename
5851 and the "is temporary" status applies to the new file; just
5852 update that. */
5853 g_free(cf->filename);
5854 cf->filename = g_strdup(fname);
5855 cf->is_tempfile = FALSE;
5856 cf_callback_invoke(cf_cb_file_fast_save_finished, cf);
5857 break;
5859 case SAVE_WITH_COPY:
5860 /* We just copied the file, so all the information other than
5861 the file descriptors, the filename, and the "is temporary"
5862 status applies to the new file; just update that. */
5863 wtap_fdclose(cf->provider.wth);
5864 /* Attempt to reopen the random file descriptor using the
5865 new file's filename. (At this point, the sequential
5866 file descriptor is closed.) */
5867 if (!wtap_fdreopen(cf->provider.wth, fname, &err)) {
5868 cfile_open_failure_alert_box(fname, err, err_info);
5869 cf_close(cf);
5870 } else {
5871 g_free(cf->filename);
5872 cf->filename = g_strdup(fname);
5873 cf->is_tempfile = FALSE;
5875 cf_callback_invoke(cf_cb_file_fast_save_finished, cf);
5876 break;
5878 case SAVE_WITH_WTAP:
5879 /* Open and read the file we saved to.
5881 XXX - this is somewhat of a waste; we already have the
5882 packets, all this gets us is updated file type information
5883 (which we could just stuff into "cf"), and having the new
5884 file be the one we have opened and from which we're reading
5885 the data, and it means we have to spend time opening and
5886 reading the file, which could be a significant amount of
5887 time if the file is large.
5889 If the capture-file-writing code were to return the
5890 seek offset of each packet it writes, we could save that
5891 in the frame_data structure for the frame, and just open
5892 the file without reading it again...
5894 ...as long as, for gzipped files, the process of writing
5895 out the file *also* generates the information needed to
5896 support fast random access to the compressed file. */
5897 /* rescan_file will cause us to try all open_routines, so
5898 reset cfile's open_type */
5899 cf->open_type = WTAP_TYPE_AUTO;
5900 /* There are cases when SAVE_WITH_WTAP can result in new packets
5901 being written to the file, e.g ERF records
5902 In that case, we need to reload the whole file */
5903 if(needs_reload) {
5904 if (cf_open(cf, fname, WTAP_TYPE_AUTO, FALSE, &err) == CF_OK) {
5905 if (cf_read(cf, /*reloading=*/TRUE) != CF_READ_OK) {
5906 /* The rescan failed; just close the file. Either
5907 a dialog was popped up for the failure, so the
5908 user knows what happened, or they stopped the
5909 rescan, in which case they know what happened. */
5910 /* XXX: This is inconsistent with normal open/reload behaviour. */
5911 cf_close(cf);
5915 else {
5916 if (rescan_file(cf, fname, FALSE) != CF_READ_OK) {
5917 /* The rescan failed; just close the file. Either
5918 a dialog was popped up for the failure, so the
5919 user knows what happened, or they stopped the
5920 rescan, in which case they know what happened. */
5921 cf_close(cf);
5924 break;
5927 /* If we were told to discard the comments, do so. */
5928 if (discard_comments) {
5929 /* Remove SHB comment, if any. */
5930 wtap_write_shb_comment(cf->provider.wth, NULL);
5932 /* remove all user comments */
5933 for (framenum = 1; framenum <= cf->count; framenum++) {
5934 fdata = frame_data_sequence_find(cf->provider.frames, framenum);
5936 // XXX: This also ignores non-comment options like verdict
5937 fdata->has_modified_block = FALSE;
5940 if (cf->provider.frames_modified_blocks) {
5941 g_tree_destroy(cf->provider.frames_modified_blocks);
5942 cf->provider.frames_modified_blocks = NULL;
5945 cf->packet_comment_count = 0;
5948 return CF_WRITE_OK;
5950 fail:
5951 if (fname_new != NULL) {
5952 /* We were trying to write to a temporary file; get rid of it if it
5953 exists. (We don't care whether this fails, as, if it fails,
5954 there's not much we can do about it. I guess if it failed for
5955 a reason other than "it doesn't exist", we could report an
5956 error, so the user knows there's a junk file that they might
5957 want to clean up.) */
5958 ws_unlink(fname_new);
5959 g_free(fname_new);
5961 cf_callback_invoke(cf_cb_file_save_failed, NULL);
5962 return CF_WRITE_ERROR;
5965 cf_write_status_t
5966 cf_export_specified_packets(capture_file *cf, const char *fname,
5967 packet_range_t *range, guint save_format,
5968 wtap_compression_type compression_type)
5970 gchar *fname_new = NULL;
5971 int err;
5972 gchar *err_info;
5973 wtap_dumper *pdh;
5974 save_callback_args_t callback_args;
5975 wtap_dump_params params;
5976 int encap;
5978 callback_args.export = TRUE;
5979 packet_range_process_init(range);
5981 /* We're writing out specified packets from the specified capture
5982 file to another file. Even if all captured packets are to be
5983 written, don't special-case the operation - read each packet
5984 and then write it out if it's one of the specified ones. */
5986 wtap_dump_params_init(&params, cf->provider.wth);
5988 /* Determine what file encapsulation type we should use. */
5989 encap = wtap_dump_required_file_encap_type(cf->linktypes);
5990 params.encap = encap;
5992 /* Use the snaplen from cf (XXX - does wtap_dump_params_init handle that?) */
5993 params.snaplen = cf->snap;
5995 if (file_exists(fname)) {
5996 /* We're overwriting an existing file; write out to a new file,
5997 and, if that succeeds, rename the new file on top of the
5998 old file. That makes this a "safe save", so that we don't
5999 lose the old file if we have a problem writing out the new
6000 file. (If the existing file is the current capture file,
6001 we *HAVE* to do that, otherwise we're overwriting the file
6002 from which we're reading the packets that we're writing!) */
6003 fname_new = ws_strdup_printf("%s~", fname);
6004 pdh = wtap_dump_open(fname_new, save_format, compression_type, &params,
6005 &err, &err_info);
6006 } else {
6007 pdh = wtap_dump_open(fname, save_format, compression_type, &params,
6008 &err, &err_info);
6010 /* XXX idb_inf is documented to be used until wtap_dump_close. */
6011 g_free(params.idb_inf);
6012 params.idb_inf = NULL;
6014 if (pdh == NULL) {
6015 cfile_dump_open_failure_alert_box(fname, err, err_info, save_format);
6016 goto fail;
6019 /* Add address resolution */
6020 wtap_dump_set_addrinfo_list(pdh, get_addrinfo_list());
6022 /* Iterate through the list of packets, processing the packets we were
6023 told to process.
6025 XXX - we've already called "packet_range_process_init(range)", but
6026 "process_specified_records()" will do it again. Fortunately,
6027 that's harmless in this case, as we haven't done anything to
6028 "range" since we initialized it. */
6029 callback_args.pdh = pdh;
6030 callback_args.fname = fname;
6031 callback_args.file_type = save_format;
6032 switch (process_specified_records(cf, range, "Writing", "specified records",
6033 TRUE, save_record, &callback_args, TRUE)) {
6035 case PSP_FINISHED:
6036 /* Completed successfully. */
6037 break;
6039 case PSP_STOPPED:
6040 /* The user decided to abort the saving.
6041 If we're writing to a temporary file, remove it.
6042 XXX - should we do so even if we're not writing to a
6043 temporary file? */
6044 wtap_dump_close(pdh, NULL, &err, &err_info);
6045 if (fname_new != NULL) {
6046 ws_unlink(fname_new);
6047 g_free(fname_new);
6049 wtap_dump_params_cleanup(&params);
6051 return CF_WRITE_ABORTED;
6052 break;
6054 case PSP_FAILED:
6055 /* Error while saving. */
6056 wtap_dump_close(pdh, NULL, &err, &err_info);
6058 * We don't report any error from closing; the error that caused
6059 * process_specified_records() to fail has already been reported.
6061 goto fail;
6064 if (!wtap_dump_close(pdh, NULL, &err, &err_info)) {
6065 cfile_close_failure_alert_box(fname, err, err_info);
6066 goto fail;
6069 if (fname_new != NULL) {
6070 /* We wrote out to fname_new, and should rename it on top of
6071 fname; fname is now closed, so that should be possible even
6072 on Windows. Do the rename. */
6073 if (ws_rename(fname_new, fname) == -1) {
6074 /* Well, the rename failed. */
6075 cf_rename_failure_alert_box(fname, errno);
6076 goto fail;
6078 g_free(fname_new);
6080 wtap_dump_params_cleanup(&params);
6082 return CF_WRITE_OK;
6084 fail:
6085 if (fname_new != NULL) {
6086 /* We were trying to write to a temporary file; get rid of it if it
6087 exists. (We don't care whether this fails, as, if it fails,
6088 there's not much we can do about it. I guess if it failed for
6089 a reason other than "it doesn't exist", we could report an
6090 error, so the user knows there's a junk file that they might
6091 want to clean up.) */
6092 ws_unlink(fname_new);
6093 g_free(fname_new);
6095 wtap_dump_params_cleanup(&params);
6097 return CF_WRITE_ERROR;
6101 * XXX - whether we mention the source pathname, the target pathname,
6102 * or both depends on the error and on what we find if we look for
6103 * one or both of them.
6105 static void
6106 cf_rename_failure_alert_box(const char *filename, int err)
6108 gchar *display_basename;
6110 display_basename = g_filename_display_basename(filename);
6111 switch (err) {
6113 case ENOENT:
6114 /* XXX - should check whether the source exists and, if not,
6115 report it as the problem and, if so, report the destination
6116 as the problem. */
6117 simple_error_message_box("The path to the file \"%s\" doesn't exist.",
6118 display_basename);
6119 break;
6121 case EACCES:
6122 /* XXX - if we're doing a rename after a safe save, we should
6123 probably say something else. */
6124 simple_error_message_box("You don't have permission to move the capture file to \"%s\".",
6125 display_basename);
6126 break;
6128 default:
6129 /* XXX - this should probably mention both the source and destination
6130 pathnames. */
6131 simple_error_message_box("The file \"%s\" could not be moved: %s.",
6132 display_basename, wtap_strerror(err));
6133 break;
6135 g_free(display_basename);
6138 /* Reload the current capture file. */
6139 cf_status_t
6140 cf_reload(capture_file *cf)
6142 gchar *filename;
6143 gboolean is_tempfile;
6144 cf_status_t cf_status = CF_OK;
6145 int err;
6147 if (cf->read_lock) {
6148 ws_warning("Failing cf_reload(\"%s\") since a read is in progress", cf->filename);
6149 return CF_ERROR;
6152 /* If the file could be opened, "cf_open()" calls "cf_close()"
6153 to get rid of state for the old capture file before filling in state
6154 for the new capture file. "cf_close()" will remove the file if
6155 it's a temporary file; we don't want that to happen (for one thing,
6156 it'd prevent subsequent reopens from working). Remember whether it's
6157 a temporary file, mark it as not being a temporary file, and then
6158 reopen it as the type of file it was.
6160 Also, "cf_close()" will free "cf->filename", so we must make
6161 a copy of it first. */
6162 filename = g_strdup(cf->filename);
6163 is_tempfile = cf->is_tempfile;
6164 cf->is_tempfile = FALSE;
6165 if (cf_open(cf, filename, cf->open_type, is_tempfile, &err) == CF_OK) {
6166 switch (cf_read(cf, /*reloading=*/TRUE)) {
6168 case CF_READ_OK:
6169 case CF_READ_ERROR:
6170 /* Just because we got an error, that doesn't mean we were unable
6171 to read any of the file; we handle what we could get from the
6172 file. */
6173 break;
6175 case CF_READ_ABORTED:
6176 /* The user bailed out of re-reading the capture file; the
6177 capture file has been closed. */
6178 break;
6180 } else {
6181 /* The open failed, so "cf->is_tempfile" wasn't set to "is_tempfile".
6182 Instead, the file was left open, so we should restore "cf->is_tempfile"
6183 ourselves.
6185 XXX - change the menu? Presumably "cf_open()" will do that;
6186 make sure it does! */
6187 cf->is_tempfile = is_tempfile;
6188 cf_status = CF_ERROR;
6190 /* "cf_open()" made a copy of the file name we handed it, so
6191 we should free up our copy. */
6192 g_free(filename);
6193 return cf_status;