Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / file.c
blob7a43db503ac247c6ebe74329a5703b55b1b302f4
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>
28 #include <wsutil/report_message.h>
30 #include <wiretap/merge.h>
32 #include <epan/exceptions.h>
33 #include <epan/epan.h>
34 #include <epan/column.h>
35 #include <epan/packet.h>
36 #include <epan/column-utils.h>
37 #include <epan/expert.h>
38 #include <epan/prefs.h>
39 #include <epan/dfilter/dfilter.h>
40 #include <epan/epan_dissect.h>
41 #include <epan/tap.h>
42 #include <epan/timestamp.h>
43 #include <epan/strutil.h>
44 #include <epan/addr_resolv.h>
45 #include <epan/color_filters.h>
46 #include <epan/secrets.h>
48 #include "cfile.h"
49 #include "file.h"
50 #include "fileset.h"
52 #include "ui/simple_dialog.h"
53 #include "ui/main_statusbar.h"
54 #include "ui/progress_dlg.h"
55 #include "ui/urls.h"
56 #include "ui/ws_ui_util.h"
57 #include "ui/packet_list_utils.h"
59 /* Needed for addrinfo */
60 #include <sys/types.h>
62 #ifdef HAVE_SYS_SOCKET_H
63 #include <sys/socket.h>
64 #endif
66 #ifdef HAVE_NETINET_IN_H
67 # include <netinet/in.h>
68 #endif
70 #ifdef _WIN32
71 # include <winsock2.h>
72 # include <ws2tcpip.h>
73 #endif
75 static bool read_record(capture_file *cf, wtap_rec *rec, dfilter_t *dfcode,
76 epan_dissect_t *edt, column_info *cinfo, int64_t offset,
77 fifo_string_cache_t *frame_dup_cache, GChecksum *frame_cksum);
79 static void rescan_packets(capture_file *cf, const char *action, const char *action_item, bool redissect);
81 typedef enum {
82 MR_NOTMATCHED,
83 MR_MATCHED,
84 MR_ERROR
85 } match_result;
86 typedef match_result (*ws_match_function)(capture_file *, frame_data *,
87 wtap_rec *, void *);
88 static match_result match_protocol_tree(capture_file *cf, frame_data *fdata,
89 wtap_rec *, void *criterion);
90 static void match_subtree_text(proto_node *node, void *data);
91 static void match_subtree_text_reverse(proto_node *node, void *data);
92 static match_result match_summary_line(capture_file *cf, frame_data *fdata,
93 wtap_rec *, void *criterion);
94 static match_result match_narrow_and_wide(capture_file *cf, frame_data *fdata,
95 wtap_rec *, void *criterion);
96 static match_result match_narrow_and_wide_reverse(capture_file *cf, frame_data *fdata,
97 wtap_rec *, void *criterion);
98 static match_result match_narrow_and_wide_case(capture_file *cf, frame_data *fdata,
99 wtap_rec *, void *criterion);
100 static match_result match_narrow_and_wide_case_reverse(capture_file *cf, frame_data *fdata,
101 wtap_rec *, void *criterion);
102 static match_result match_narrow_case(capture_file *cf, frame_data *fdata,
103 wtap_rec *, void *criterion);
104 static match_result match_narrow_case_reverse(capture_file *cf, frame_data *fdata,
105 wtap_rec *, void *criterion);
106 static match_result match_wide(capture_file *cf, frame_data *fdata,
107 wtap_rec *, void *criterion);
108 static match_result match_wide_reverse(capture_file *cf, frame_data *fdata,
109 wtap_rec *, void *criterion);
110 static match_result match_wide_case(capture_file *cf, frame_data *fdata,
111 wtap_rec *, void *criterion);
112 static match_result match_wide_case_reverse(capture_file *cf, frame_data *fdata,
113 wtap_rec *, void *criterion);
114 static match_result match_binary(capture_file *cf, frame_data *fdata,
115 wtap_rec *, void *criterion);
116 static match_result match_binary_reverse(capture_file *cf, frame_data *fdata,
117 wtap_rec *, void *criterion);
118 static match_result match_regex(capture_file *cf, frame_data *fdata,
119 wtap_rec *, void *criterion);
120 static match_result match_regex_reverse(capture_file *cf, frame_data *fdata,
121 wtap_rec *, void *criterion);
122 static match_result match_dfilter(capture_file *cf, frame_data *fdata,
123 wtap_rec *, void *criterion);
124 static match_result match_marked(capture_file *cf, frame_data *fdata,
125 wtap_rec *, void *criterion);
126 static match_result match_time_reference(capture_file *cf, frame_data *fdata,
127 wtap_rec *, void *criterion);
128 static bool find_packet(capture_file *cf, ws_match_function match_function,
129 void *criterion, search_direction dir, bool start_current);
131 /* Seconds spent processing packets between pushing UI updates. */
132 #define PROGBAR_UPDATE_INTERVAL 0.150
134 /* Show the progress bar after this many seconds. */
135 #define PROGBAR_SHOW_DELAY 0.5
138 * Maximum number of records we support in a file.
140 * It is, at most, the maximum value of a uint32_t, as we use a uint32_t
141 * for the frame number.
143 * We allow it to be set to a lower value; see issue #16908 for why
144 * we're doing this. Thanks, Qt!
146 static uint32_t max_records = UINT32_MAX;
148 void
149 cf_set_max_records(unsigned max_records_arg)
151 max_records = max_records_arg;
155 * We could probably use g_signal_...() instead of the callbacks below but that
156 * would require linking our CLI programs to libgobject and creating an object
157 * instance for the signals.
159 typedef struct {
160 cf_callback_t cb_fct;
161 void * user_data;
162 } cf_callback_data_t;
164 static GList *cf_callbacks;
166 static void
167 cf_callback_invoke(int event, void *data)
169 cf_callback_data_t *cb;
170 GList *cb_item = cf_callbacks;
172 /* there should be at least one interested */
173 ws_assert(cb_item != NULL);
175 while (cb_item != NULL) {
176 cb = (cf_callback_data_t *)cb_item->data;
177 cb->cb_fct(event, data, cb->user_data);
178 cb_item = g_list_next(cb_item);
182 void
183 cf_callback_add(cf_callback_t func, void *user_data)
185 cf_callback_data_t *cb;
187 cb = g_new(cf_callback_data_t,1);
188 cb->cb_fct = func;
189 cb->user_data = user_data;
191 cf_callbacks = g_list_prepend(cf_callbacks, cb);
194 void
195 cf_callback_remove(cf_callback_t func, void *user_data)
197 cf_callback_data_t *cb;
198 GList *cb_item = cf_callbacks;
200 while (cb_item != NULL) {
201 cb = (cf_callback_data_t *)cb_item->data;
202 if (cb->cb_fct == func && cb->user_data == user_data) {
203 cf_callbacks = g_list_remove(cf_callbacks, cb);
204 g_free(cb);
205 return;
207 cb_item = g_list_next(cb_item);
210 ws_assert_not_reached();
213 unsigned long
214 cf_get_computed_elapsed(capture_file *cf)
216 return cf->computed_elapsed;
219 static void
220 compute_elapsed(capture_file *cf, int64_t start_time)
222 int64_t delta_time = g_get_monotonic_time() - start_time;
224 cf->computed_elapsed = (unsigned long) (delta_time / 1000); /* ms */
227 static epan_t *
228 ws_epan_new(capture_file *cf)
230 static const struct packet_provider_funcs funcs = {
231 cap_file_provider_get_frame_ts,
232 cap_file_provider_get_interface_name,
233 cap_file_provider_get_interface_description,
234 cap_file_provider_get_modified_block
237 return epan_new(&cf->provider, &funcs);
240 cf_status_t
241 cf_open(capture_file *cf, const char *fname, unsigned int type, bool is_tempfile, int *err)
243 wtap *wth;
244 char *err_info;
246 wth = wtap_open_offline(fname, type, err, &err_info, true);
247 if (wth == NULL)
248 goto fail;
250 /* The open succeeded. Close whatever capture file we had open,
251 and fill in the information for this file. */
252 cf_close(cf);
254 /* Initialize the record information.
255 XXX - we really want to initialize this after we've read all
256 the packets, so we know how much we'll ultimately need. */
257 wtap_rec_init(&cf->rec, 1514);
259 /* We're about to start reading the file. */
260 cf->state = FILE_READ_IN_PROGRESS;
262 /* If there was a pending redissection for the old file (there
263 * shouldn't be), clear it. cf_close() should have failed if the
264 * old file's read lock was held, but it doesn't hurt to clear it. */
265 cf->read_lock = false;
266 cf->redissection_queued = RESCAN_NONE;
268 cf->provider.wth = wth;
269 cf->f_datalen = 0;
271 /* Set the file name because we need it to set the follow stream filter.
272 XXX - is that still true? We need it for other reasons, though,
273 in any case. */
274 cf->filename = g_strdup(fname);
276 /* Indicate whether it's a permanent or temporary file. */
277 cf->is_tempfile = is_tempfile;
279 /* No user changes yet. */
280 cf->unsaved_changes = false;
282 cf->computed_elapsed = 0;
284 /* Record the file's type and compression type. */
285 cf->cd_t = wtap_file_type_subtype(cf->provider.wth);
286 cf->compression_type = wtap_get_compression_type(cf->provider.wth);
288 cf->open_type = type;
289 cf->linktypes = g_array_sized_new(FALSE, FALSE, (unsigned) sizeof(int), 1);
290 cf->count = 0;
291 cf->packet_comment_count = 0;
292 cf->displayed_count = 0;
293 cf->marked_count = 0;
294 cf->ignored_count = 0;
295 cf->ref_time_count = 0;
296 cf->drops_known = false;
297 cf->drops = 0;
298 cf->snap = wtap_snapshot_length(cf->provider.wth);
300 /* Allocate a frame_data_sequence for the frames in this file */
301 cf->provider.frames = new_frame_data_sequence();
303 nstime_set_zero(&cf->elapsed_time);
304 cf->provider.ref = NULL;
305 cf->provider.prev_dis = NULL;
306 cf->provider.prev_cap = NULL;
307 cf->cum_bytes = 0;
309 /* Create new epan session for dissection.
310 * (The old one was freed in cf_close().)
312 cf->epan = ws_epan_new(cf);
314 packet_list_queue_draw();
315 cf_callback_invoke(cf_cb_file_opened, cf);
317 wtap_set_cb_new_ipv4(cf->provider.wth, add_ipv4_name);
318 wtap_set_cb_new_ipv6(cf->provider.wth, (wtap_new_ipv6_callback_t) add_ipv6_name);
319 wtap_set_cb_new_secrets(cf->provider.wth, secrets_wtap_callback);
321 return CF_OK;
323 fail:
324 report_cfile_open_failure(fname, *err, err_info);
325 return CF_ERROR;
329 * Add an encapsulation type to cf->linktypes.
331 static void
332 cf_add_encapsulation_type(capture_file *cf, int encap)
334 unsigned i;
336 for (i = 0; i < cf->linktypes->len; i++) {
337 if (g_array_index(cf->linktypes, int, i) == encap)
338 return; /* it's already there */
340 /* It's not already there - add it. */
341 g_array_append_val(cf->linktypes, encap);
344 /* Reset everything to a pristine state */
345 void
346 cf_close(capture_file *cf)
348 cf->stop_flag = false;
349 if (cf->state == FILE_CLOSED || cf->state == FILE_READ_PENDING)
350 return; /* Nothing to do */
352 /* Die if we're in the middle of reading a file. */
353 ws_assert(cf->state != FILE_READ_IN_PROGRESS);
354 ws_assert(!cf->read_lock);
356 cf_callback_invoke(cf_cb_file_closing, cf);
358 /* close things, if not already closed before */
359 color_filters_cleanup();
361 if (cf->provider.wth) {
362 wtap_close(cf->provider.wth);
363 cf->provider.wth = NULL;
365 /* We have no file open... */
366 if (cf->filename != NULL) {
367 /* If it's a temporary file, remove it. */
368 if (cf->is_tempfile)
369 ws_unlink(cf->filename);
370 g_free(cf->filename);
371 cf->filename = NULL;
373 /* ...which means we have no changes to that file to save. */
374 cf->unsaved_changes = false;
376 /* no open_routine type */
377 cf->open_type = WTAP_TYPE_AUTO;
379 /* Clean up the record information. */
380 wtap_rec_cleanup(&cf->rec);
382 /* Clear the packet list. */
383 packet_list_freeze();
384 packet_list_clear();
385 packet_list_thaw();
387 dfilter_free(cf->rfcode);
388 cf->rfcode = NULL;
389 if (cf->provider.frames != NULL) {
390 free_frame_data_sequence(cf->provider.frames);
391 cf->provider.frames = NULL;
393 if (cf->provider.frames_modified_blocks) {
394 g_tree_destroy(cf->provider.frames_modified_blocks);
395 cf->provider.frames_modified_blocks = NULL;
397 cf_unselect_packet(cf); /* nothing to select */
398 cf->first_displayed = 0;
399 cf->last_displayed = 0;
401 /* No frames, no frame selected, no field in that frame selected. */
402 cf->count = 0;
403 cf->current_frame = NULL;
404 cf->finfo_selected = NULL;
406 /* No frame link-layer types, either. */
407 if (cf->linktypes != NULL) {
408 g_array_free(cf->linktypes, TRUE);
409 cf->linktypes = NULL;
412 cf->f_datalen = 0;
413 nstime_set_zero(&cf->elapsed_time);
415 reset_tap_listeners();
417 epan_free(cf->epan);
418 cf->epan = NULL;
420 /* We have no file open. */
421 cf->state = FILE_CLOSED;
423 cf_callback_invoke(cf_cb_file_closed, cf);
427 * true if the progress dialog doesn't exist and it looks like we'll
428 * take > PROGBAR_SHOW_DELAY (500ms) to load, false otherwise.
430 static inline bool
431 progress_is_slow(progdlg_t *progdlg, GTimer *prog_timer, int64_t size, int64_t pos)
433 double elapsed;
435 if (progdlg) return false;
436 elapsed = g_timer_elapsed(prog_timer, NULL);
437 /* This only gets checked between reading records, which doesn't help if
438 * a single record takes a very long time, e.g., the first TLS packet if
439 * the SSLKEYLOGFILE is very large. (#17051) */
440 if ((elapsed * 2 > PROGBAR_SHOW_DELAY && (size / pos) >= 2) /* It looks like we're going to be slow. */
441 || elapsed > PROGBAR_SHOW_DELAY) { /* We are indeed slow. */
442 return true;
444 return false;
447 static float
448 calc_progbar_val(capture_file *cf, int64_t size, int64_t file_pos, char *status_str, unsigned long status_size)
450 float progbar_val;
452 progbar_val = (float) file_pos / (float) size;
453 if (progbar_val > 1.0) {
455 /* The file probably grew while we were reading it.
456 * Update file size, and try again.
458 size = wtap_file_size(cf->provider.wth, NULL);
460 if (size >= 0)
461 progbar_val = (float) file_pos / (float) size;
463 /* If it's still > 1, either "wtap_file_size()" failed (in which
464 * case there's not much we can do about it), or the file
465 * *shrank* (in which case there's not much we can do about
466 * it); just clip the progress value at 1.0.
468 if (progbar_val > 1.0f)
469 progbar_val = 1.0f;
472 snprintf(status_str, status_size,
473 "%" PRId64 "KB of %" PRId64 "KB",
474 file_pos / 1024, size / 1024);
476 return progbar_val;
479 cf_read_status_t
480 cf_read(capture_file *cf, bool reloading)
482 int err = 0;
483 char *err_info = NULL;
484 volatile bool too_many_records = false;
485 char *name_ptr;
486 progdlg_t *volatile progbar = NULL;
487 GTimer *prog_timer = g_timer_new();
488 int64_t size;
489 int64_t start_time;
490 epan_dissect_t edt;
491 wtap_rec rec;
492 dfilter_t *dfcode = NULL;
493 column_info *cinfo;
494 volatile bool create_proto_tree;
495 unsigned tap_flags;
496 bool compiled _U_;
497 volatile bool is_read_aborted = false;
499 /* The update_progress_dlg call below might end up accepting a user request to
500 * trigger redissection/rescans which can modify/destroy the dissection
501 * context ("cf->epan"). That condition should be prevented by callers, but in
502 * case it occurs let's fail gracefully.
504 if (cf->read_lock) {
505 ws_warning("Failing due to recursive cf_read(\"%s\", %d) call!",
506 cf->filename, reloading);
507 return CF_READ_ERROR;
509 /* This is a full dissection, so clear any pending request for one. */
510 cf->redissection_queued = RESCAN_NONE;
511 cf->read_lock = true;
513 /* Compile the current display filter.
514 * The code it compiles to might have changed, e.g. if a display
515 * filter macro used has changed.
517 * We assume this will not fail since cf->dfilter is only set in
518 * cf_filter IFF the filter was valid.
519 * XXX - This is not necessarily true, if the filter has a FT_IPv4
520 * or FT_IPv6 field compared to a resolved hostname in it, because
521 * we do a new host lookup, and that *could* timeout this time
522 * (though with the read lock above we shouldn't have many lookups at
523 * once, reducing the chances of that)... (#19612)
525 if (cf->dfilter) {
526 compiled = dfilter_compile(cf->dfilter, &dfcode, NULL);
527 ws_assert(compiled && dfcode);
530 dfilter_free(cf->dfcode);
531 cf->dfcode = dfcode;
533 /* The compiled dfilter might have a field reference; recompiling it
534 * means that the field references won't match anything. That's what
535 * we want since this is a new sequential read and we don't have
536 * a selected frame with a tree. (Will taps with filters with display
537 * references also have cleared display references?)
540 /* Get the union of the flags for all tap listeners. */
541 tap_flags = union_of_tap_listener_flags();
544 * Determine whether we need to create a protocol tree.
545 * We do if:
547 * we're going to apply a display filter;
549 * one of the tap listeners is going to apply a filter;
551 * one of the tap listeners requires a protocol tree;
553 * a postdissector wants field values or protocols on
554 * the first pass.
556 create_proto_tree =
557 (cf->dfcode != NULL || have_filtering_tap_listeners() ||
558 (tap_flags & TL_REQUIRES_PROTO_TREE) || postdissectors_want_hfids());
560 reset_tap_listeners();
562 name_ptr = g_filename_display_basename(cf->filename);
564 if (reloading)
565 cf_callback_invoke(cf_cb_file_reload_started, cf);
566 else
567 cf_callback_invoke(cf_cb_file_read_started, cf);
569 /* The packet list window will be empty until the file is completely loaded */
570 packet_list_freeze();
572 cf->stop_flag = false;
573 start_time = g_get_monotonic_time();
575 epan_dissect_init(&edt, cf->epan, create_proto_tree, false);
577 /* If the display filter or any tap listeners require the columns,
578 * construct them. */
579 cinfo = (tap_listeners_require_columns() ||
580 dfilter_requires_columns(cf->dfcode)) ? &cf->cinfo : NULL;
582 /* Find the size of the file. */
583 size = wtap_file_size(cf->provider.wth, NULL);
585 /* If we are to ignore duplicate frames, we need a container to store
586 * hashes frame contents */
587 fifo_string_cache_t frame_dup_cache;
588 GChecksum *volatile cksum = NULL;
590 if (prefs.ignore_dup_frames) {
591 fifo_string_cache_init(&frame_dup_cache, prefs.ignore_dup_frames_cache_entries, g_free);
592 cksum = g_checksum_new(G_CHECKSUM_SHA256);
595 g_timer_start(prog_timer);
597 wtap_rec_init(&rec, 1514);
599 TRY {
600 int64_t file_pos;
601 int64_t data_offset;
603 float progbar_val;
604 char status_str[100];
606 while ((wtap_read(cf->provider.wth, &rec, &err, &err_info,
607 &data_offset))) {
608 if (size >= 0) {
609 if (cf->count == max_records) {
611 * Quit if we've already read the maximum number of
612 * records allowed.
614 too_many_records = true;
615 break;
617 file_pos = wtap_read_so_far(cf->provider.wth);
619 /* Create the progress bar if necessary. */
620 if (progress_is_slow(progbar, prog_timer, size, file_pos)) {
621 progbar_val = calc_progbar_val(cf, size, file_pos, status_str, sizeof(status_str));
622 progbar = delayed_create_progress_dlg(cf->window, NULL, NULL, true,
623 &cf->stop_flag, progbar_val);
627 * Update the progress bar, but do it only after
628 * PROGBAR_UPDATE_INTERVAL has elapsed. Calling update_progress_dlg
629 * and packets_bar_update will likely trigger UI paint events, which
630 * might take a while depending on the platform and display. Reset
631 * our timer *after* painting.
633 if (progbar && g_timer_elapsed(prog_timer, NULL) > PROGBAR_UPDATE_INTERVAL) {
634 progbar_val = calc_progbar_val(cf, size, file_pos, status_str, sizeof(status_str));
635 /* update the packet bar content on the first run or frequently on very large files */
636 update_progress_dlg(progbar, progbar_val, status_str);
637 compute_elapsed(cf, start_time);
638 packets_bar_update();
639 g_timer_start(prog_timer);
642 * The previous GUI triggers should not have destroyed the running
643 * session. If that did happen, it could blow up when read_record tries
644 * to use the destroyed edt.session, so detect it right here.
646 ws_assert(edt.session == cf->epan);
649 if (cf->state == FILE_READ_ABORTED) {
650 /* Well, the user decided to exit Wireshark. Break out of the
651 loop, and let the code below (which is called even if there
652 aren't any packets left to read) exit. */
653 is_read_aborted = true;
654 break;
656 if (cf->stop_flag) {
657 /* Well, the user decided to abort the read. He/She will be warned and
658 it might be enough for him/her to work with the already loaded
659 packets.
660 This is especially true for very large capture files, where you don't
661 want to wait loading the whole file (which may last minutes or even
662 hours even on fast machines) just to see that it was the wrong file. */
663 break;
665 read_record(cf, &rec, cf->dfcode, &edt, cinfo, data_offset, &frame_dup_cache, cksum);
666 wtap_rec_reset(&rec);
669 CATCH(OutOfMemoryError) {
670 simple_message_box(ESD_TYPE_ERROR, NULL,
671 "More information and workarounds can be found at\n"
672 WS_WIKI_URL("KnownBugs/OutOfMemory"),
673 "Sorry, but Wireshark has run out of memory and has to terminate now.");
674 #if 0
675 /* Could we close the current capture and free up memory from that? */
676 #else
677 /* we have to terminate, as we cannot recover from the memory error */
678 exit(1);
679 #endif
681 ENDTRY;
683 // If we're ignoring duplicate frames, clear the data structures.
684 // We really could look at prefs.ignore_dup_frames here, but it's even
685 // safer to check if we had allocated 'cksum'.
686 if (cksum != NULL) {
687 fifo_string_cache_free(&frame_dup_cache);
688 g_checksum_free(cksum);
691 /* We're done reading sequentially through the file. */
692 cf->state = FILE_READ_DONE;
694 /* Destroy the progress bar if it was created. */
695 if (progbar != NULL)
696 destroy_progress_dlg(progbar);
697 g_timer_destroy(prog_timer);
699 /* Free the display name */
700 g_free(name_ptr);
702 epan_dissect_cleanup(&edt);
703 wtap_rec_cleanup(&rec);
705 /* Close the sequential I/O side, to free up memory it requires. */
706 wtap_sequential_close(cf->provider.wth);
708 /* Allow the protocol dissectors to free up memory that they
709 * don't need after the sequential run-through of the packets. */
710 postseq_cleanup_all_protocols();
712 /* compute the time it took to load the file */
713 compute_elapsed(cf, start_time);
715 /* Set the file encapsulation type now; we don't know what it is until
716 we've looked at all the packets, as we don't know until then whether
717 there's more than one type (and thus whether it's
718 WTAP_ENCAP_PER_PACKET). */
719 cf->lnk_t = wtap_file_encap(cf->provider.wth);
721 cf->current_frame = frame_data_sequence_find(cf->provider.frames, cf->first_displayed);
723 packet_list_thaw();
725 /* It is safe again to execute redissections or sort. */
726 ws_assert(cf->read_lock);
727 cf->read_lock = false;
729 if (reloading)
730 cf_callback_invoke(cf_cb_file_reload_finished, cf);
731 else
732 cf_callback_invoke(cf_cb_file_read_finished, cf);
734 /* If we have any displayed packets to select, select the first of those
735 packets by making the first row the selected row. */
736 if (cf->first_displayed != 0) {
737 packet_list_select_row_from_data(NULL);
740 if (is_read_aborted) {
742 * Well, the user decided to exit Wireshark while reading this *offline*
743 * capture file (Live captures are handled by something like
744 * cf_continue_tail). Clean up accordingly.
746 cf_close(cf);
747 cf->redissection_queued = RESCAN_NONE;
748 return CF_READ_ABORTED;
751 if (cf->redissection_queued != RESCAN_NONE) {
752 /* Redissection was queued up. Clear the request and perform it now. */
753 bool redissect = cf->redissection_queued == RESCAN_REDISSECT;
754 rescan_packets(cf, NULL, NULL, redissect);
757 if (cf->stop_flag) {
758 simple_message_box(ESD_TYPE_WARN, NULL,
759 "The remaining packets in the file were discarded.\n"
760 "\n"
761 "As a lot of packets from the original file will be missing,\n"
762 "remember to be careful when saving the current content to a file.\n",
763 "File loading was cancelled.");
764 return CF_READ_ERROR;
767 if (err != 0) {
768 /* Put up a message box noting that the read failed somewhere along
769 the line. Don't throw out the stuff we managed to read, though,
770 if any. */
771 report_cfile_read_failure(NULL, err, err_info);
772 return CF_READ_ERROR;
773 } else if (too_many_records) {
774 simple_message_box(ESD_TYPE_WARN, NULL,
775 "The remaining packets in the file were discarded.\n"
776 "\n"
777 "As a lot of packets from the original file will be missing,\n"
778 "remember to be careful when saving the current content to a file.\n"
779 "\n"
780 "The command-line utility editcap can be used to split "
781 "the file into multiple smaller files",
782 "The file contains more records than the maximum "
783 "supported number of records, %u.", max_records);
784 return CF_READ_ERROR;
785 } else
786 return CF_READ_OK;
789 #ifdef HAVE_LIBPCAP
790 cf_read_status_t
791 cf_continue_tail(capture_file *cf, volatile int to_read, wtap_rec *rec,
792 int *err, fifo_string_cache_t *frame_dup_cache, GChecksum *frame_cksum)
794 char *err_info;
795 volatile int newly_displayed_packets = 0;
796 epan_dissect_t edt;
797 bool create_proto_tree;
798 unsigned tap_flags;
800 /* Don't compile the current display filter. The current display filter
801 * text might compile to different code than when the capture started:
803 * If it has a IP address resolved name, calling get_host_ipaddr every
804 * time new packets arrive can mean a *lot* of gethostbyname calls
805 * in flight at once, eventually leading to a timeout (#19612).
806 * addr_resolv.c says that ares_gethostbyname is "usually interactive",
807 * unlike ares_gethostbyaddr (used in dissection), and violating that
808 * expectation is bad.
810 * If it has a display filter macro, the definition might have changed.
812 * If it has a field reference, the selected frame / current proto tree
813 * might have changed, and we don't have the old one. If we recompile,
814 * we can't set the field references to the old values.
816 * For a rescan, redissection, reload, retap, or opening a new file, we
817 * want to compile. What about here, when new frames have arrived in a live
818 * capture? We might be able to cache the host lookup, and a user might want
819 * the new display filter macro definition, but the user almost surely wants
820 * the field references to refer to values from the proto tree when the
821 * filter was applied, not whatever it happens to be now if the user has
822 * clicked on a different packet.
824 * To get the new compiled filter, the user should refilter.
827 /* Get the union of the flags for all tap listeners. */
828 tap_flags = union_of_tap_listener_flags();
831 * Determine whether we need to create a protocol tree.
832 * We do if:
834 * we're going to apply a display filter;
836 * one of the tap listeners is going to apply a filter;
838 * one of the tap listeners requires a protocol tree;
840 * a postdissector wants field values or protocols on
841 * the first pass.
843 create_proto_tree =
844 (cf->dfcode != NULL || have_filtering_tap_listeners() ||
845 (tap_flags & TL_REQUIRES_PROTO_TREE) || postdissectors_want_hfids());
847 *err = 0;
849 /* Don't freeze/thaw the list when doing live capture */
850 /*packet_list_freeze();*/
852 epan_dissect_init(&edt, cf->epan, create_proto_tree, false);
854 TRY {
855 int64_t data_offset = 0;
856 column_info *cinfo;
858 /* If the display filter or any tap listeners require the columns,
859 * construct them. */
860 cinfo = (tap_listeners_require_columns() ||
861 dfilter_requires_columns(cf->dfcode)) ? &cf->cinfo : NULL;
863 while (to_read != 0) {
864 wtap_cleareof(cf->provider.wth);
865 if (!wtap_read(cf->provider.wth, rec, err, &err_info,
866 &data_offset)) {
867 break;
869 if (cf->state == FILE_READ_ABORTED) {
870 /* Well, the user decided to exit Wireshark. Break out of the
871 loop, and let the code below (which is called even if there
872 aren't any packets left to read) exit. */
873 break;
875 if (read_record(cf, rec, cf->dfcode, &edt, cinfo, data_offset, frame_dup_cache, frame_cksum)) {
876 newly_displayed_packets++;
878 to_read--;
880 wtap_rec_reset(rec);
882 CATCH(OutOfMemoryError) {
883 simple_message_box(ESD_TYPE_ERROR, NULL,
884 "More information and workarounds can be found at\n"
885 WS_WIKI_URL("KnownBugs/OutOfMemory"),
886 "Sorry, but Wireshark has run out of memory and has to terminate now.");
887 #if 0
888 /* Could we close the current capture and free up memory from that? */
889 return CF_READ_ABORTED;
890 #else
891 /* we have to terminate, as we cannot recover from the memory error */
892 exit(1);
893 #endif
895 ENDTRY;
897 /* Update the file encapsulation; it might have changed based on the
898 packets we've read. */
899 cf->lnk_t = wtap_file_encap(cf->provider.wth);
901 epan_dissect_cleanup(&edt);
903 /* Don't freeze/thaw the list when doing live capture */
904 /*packet_list_thaw();*/
905 /* With the new packet list the first packet
906 * isn't automatically selected.
908 if (!cf->current_frame && !packet_list_multi_select_active())
909 packet_list_select_row_from_data(NULL);
911 if (cf->state == FILE_READ_ABORTED) {
912 /* Well, the user decided to exit Wireshark. Return CF_READ_ABORTED
913 so that our caller can kill off the capture child process;
914 this will cause an EOF on the pipe from the child, so
915 "cf_finish_tail()" will be called, and it will clean up
916 and exit. */
917 return CF_READ_ABORTED;
918 } else if (*err != 0) {
919 /* We got an error reading the capture file.
920 XXX - pop up a dialog box instead? */
921 if (err_info != NULL) {
922 ws_warning("Error \"%s\" while reading \"%s\" (\"%s\")",
923 wtap_strerror(*err), cf->filename, err_info);
924 g_free(err_info);
925 } else {
926 ws_warning("Error \"%s\" while reading \"%s\"",
927 wtap_strerror(*err), cf->filename);
929 return CF_READ_ERROR;
930 } else
931 return CF_READ_OK;
934 void
935 cf_fake_continue_tail(capture_file *cf)
937 if (cf->state == FILE_CLOSED) {
938 cf->state = FILE_READ_PENDING;
942 cf_read_status_t
943 cf_finish_tail(capture_file *cf, wtap_rec *rec, int *err,
944 fifo_string_cache_t *frame_dup_cache, GChecksum *frame_cksum)
946 char *err_info;
947 int64_t data_offset;
948 column_info *cinfo;
949 epan_dissect_t edt;
950 bool create_proto_tree;
951 unsigned tap_flags;
953 /* All the comments above in cf_continue_tail apply regarding the
954 * current display filter.
957 /* Get the union of the flags for all tap listeners. */
958 tap_flags = union_of_tap_listener_flags();
960 /* If the display filter or any tap listeners require the columns,
961 * construct them. */
962 cinfo = (tap_listeners_require_columns() ||
963 dfilter_requires_columns(cf->dfcode)) ? &cf->cinfo : NULL;
966 * Determine whether we need to create a protocol tree.
967 * We do if:
969 * we're going to apply a display filter;
971 * one of the tap listeners is going to apply a filter;
973 * one of the tap listeners requires a protocol tree;
975 * a postdissector wants field values or protocols on
976 * the first pass.
978 create_proto_tree =
979 (cf->dfcode != NULL || have_filtering_tap_listeners() ||
980 (tap_flags & TL_REQUIRES_PROTO_TREE) || postdissectors_want_hfids());
982 if (cf->provider.wth == NULL) {
983 cf_close(cf);
984 return CF_READ_ERROR;
987 /* Don't freeze/thaw the list when doing live capture */
988 /*packet_list_freeze();*/
990 epan_dissect_init(&edt, cf->epan, create_proto_tree, false);
992 while ((wtap_read(cf->provider.wth, rec, err, &err_info, &data_offset))) {
993 if (cf->state == FILE_READ_ABORTED) {
994 /* Well, the user decided to abort the read. Break out of the
995 loop, and let the code below (which is called even if there
996 aren't any packets left to read) exit. */
997 break;
999 read_record(cf, rec, cf->dfcode, &edt, cinfo, data_offset, frame_dup_cache, frame_cksum);
1000 wtap_rec_reset(rec);
1003 epan_dissect_cleanup(&edt);
1005 /* Don't freeze/thaw the list when doing live capture */
1006 /*packet_list_thaw();*/
1008 if (cf->state == FILE_READ_ABORTED) {
1009 /* Well, the user decided to abort the read. We're only called
1010 when the child capture process closes the pipe to us (meaning
1011 it's probably exited), so we can just close the capture
1012 file; we return CF_READ_ABORTED so our caller can do whatever
1013 is appropriate when that happens. */
1014 cf_close(cf);
1015 return CF_READ_ABORTED;
1018 /* We're done reading sequentially through the file. */
1019 cf->state = FILE_READ_DONE;
1021 /* We're done reading sequentially through the file; close the
1022 sequential I/O side, to free up memory it requires. */
1023 wtap_sequential_close(cf->provider.wth);
1025 /* Allow the protocol dissectors to free up memory that they
1026 * don't need after the sequential run-through of the packets. */
1027 postseq_cleanup_all_protocols();
1029 /* Update the file encapsulation; it might have changed based on the
1030 packets we've read. */
1031 cf->lnk_t = wtap_file_encap(cf->provider.wth);
1033 /* Update the details in the file-set dialog, as the capture file
1034 * has likely grown since we first stat-ed it */
1035 fileset_update_file(cf->filename);
1037 if (*err != 0) {
1038 /* We got an error reading the capture file.
1039 XXX - pop up a dialog box? */
1040 if (err_info != NULL) {
1041 ws_warning("Error \"%s\" while reading \"%s\" (\"%s\")",
1042 wtap_strerror(*err), cf->filename, err_info);
1043 g_free(err_info);
1044 } else {
1045 ws_warning("Error \"%s\" while reading \"%s\"",
1046 wtap_strerror(*err), cf->filename);
1048 return CF_READ_ERROR;
1049 } else {
1050 return CF_READ_OK;
1053 #endif /* HAVE_LIBPCAP */
1055 char *
1056 cf_get_display_name(capture_file *cf)
1058 char *displayname;
1060 /* Return a name to use in displays */
1061 if (!cf->is_tempfile) {
1062 /* Get the last component of the file name, and use that. */
1063 if (cf->filename) {
1064 displayname = g_filename_display_basename(cf->filename);
1065 } else {
1066 displayname=g_strdup("(No file)");
1068 } else {
1069 /* The file we read is a temporary file from a live capture or
1070 a merge operation; we don't mention its name, but, if it's
1071 from a capture, give the source of the capture. */
1072 if (cf->source) {
1073 displayname = g_strdup(cf->source);
1074 } else {
1075 displayname = g_strdup("(Untitled)");
1078 return displayname;
1081 char *
1082 cf_get_basename(capture_file *cf)
1084 char *displayname;
1086 /* Return a name to use in the GUI for the basename for files to
1087 which we save statistics */
1088 if (!cf->is_tempfile) {
1089 /* Get the last component of the file name, and use that. */
1090 if (cf->filename) {
1091 displayname = g_filename_display_basename(cf->filename);
1093 /* If the file name ends with any extension that corresponds
1094 to a file type we support - including compressed versions
1095 of those files - strip it off. */
1096 size_t displayname_len = strlen(displayname);
1097 GSList *extensions = wtap_get_all_file_extensions_list();
1098 GSList *suffix;
1099 for (suffix = extensions; suffix != NULL; suffix = g_slist_next(suffix)) {
1100 /* Does the file name end with that extension? */
1101 const char *extension = (char *)suffix->data;
1102 size_t extension_len = strlen(extension);
1103 if (displayname_len > extension_len &&
1104 displayname[displayname_len - extension_len - 1] == '.' &&
1105 strcmp(&displayname[displayname_len - extension_len], extension) == 0) {
1106 /* Yes. Strip the extension off, and return the result. */
1107 displayname[displayname_len - extension_len - 1] = '\0';
1108 break;
1111 wtap_free_extensions_list(extensions);
1112 } else {
1113 displayname=g_strdup("");
1115 } else {
1116 /* The file we read is a temporary file from a live capture or
1117 a merge operation; we don't mention its name, but, if it's
1118 from a capture, give the source of the capture. */
1119 if (cf->source) {
1120 displayname = g_strdup(cf->source);
1121 } else {
1122 displayname = g_strdup("");
1125 return displayname;
1128 void
1129 cf_set_tempfile_source(capture_file *cf, char *source)
1131 if (cf->source) {
1132 g_free(cf->source);
1135 if (source) {
1136 cf->source = g_strdup(source);
1137 } else {
1138 cf->source = g_strdup("");
1142 const char *
1143 cf_get_tempfile_source(capture_file *cf)
1145 if (!cf->source) {
1146 return "";
1149 return cf->source;
1152 /* XXX - use a macro instead? */
1154 cf_get_packet_count(capture_file *cf)
1156 return cf->count;
1159 /* XXX - use a macro instead? */
1160 bool
1161 cf_is_tempfile(capture_file *cf)
1163 return cf->is_tempfile;
1166 void
1167 cf_set_tempfile(capture_file *cf, bool is_tempfile)
1169 cf->is_tempfile = is_tempfile;
1173 /* XXX - use a macro instead? */
1174 void
1175 cf_set_drops_known(capture_file *cf, bool drops_known)
1177 cf->drops_known = drops_known;
1180 /* XXX - use a macro instead? */
1181 void
1182 cf_set_drops(capture_file *cf, uint32_t drops)
1184 cf->drops = drops;
1187 /* XXX - use a macro instead? */
1188 bool
1189 cf_get_drops_known(capture_file *cf)
1191 return cf->drops_known;
1194 /* XXX - use a macro instead? */
1195 uint32_t
1196 cf_get_drops(capture_file *cf)
1198 return cf->drops;
1201 void
1202 cf_set_rfcode(capture_file *cf, dfilter_t *rfcode)
1204 cf->rfcode = rfcode;
1207 static void
1208 add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
1209 epan_dissect_t *edt, dfilter_t *dfcode, column_info *cinfo,
1210 wtap_rec *rec, bool add_to_packet_list)
1212 frame_data_set_before_dissect(fdata, &cf->elapsed_time,
1213 &cf->provider.ref, cf->provider.prev_dis);
1214 cf->provider.prev_cap = fdata;
1216 if (dfcode != NULL) {
1217 epan_dissect_prime_with_dfilter(edt, dfcode);
1219 #if 0
1220 /* Prepare coloring rules, this ensures that display filter rules containing
1221 * frame.color_rule references are still processed.
1222 * TODO: actually detect that situation or maybe apply other optimizations? */
1223 if (edt->tree && color_filters_used()) {
1224 color_filters_prime_edt(edt);
1225 fdata->need_colorize = 1;
1227 #endif
1229 if (!fdata->visited) {
1230 /* This is the first pass, so prime the epan_dissect_t with the
1231 hfids postdissectors want on the first pass. */
1232 prime_epan_dissect_with_postdissector_wanted_hfids(edt);
1235 /* Initialize passed_dfilter here so that dissectors can hide packets. */
1236 /* XXX We might want to add a separate "visible" bit to frame_data instead. */
1237 fdata->passed_dfilter = 1;
1239 /* Dissect the frame. */
1240 epan_dissect_run_with_taps(edt, cf->cd_t, rec, fdata, cinfo);
1242 if (fdata->passed_dfilter && dfcode != NULL) {
1243 fdata->passed_dfilter = dfilter_apply_edt(dfcode, edt) ? 1 : 0;
1245 if (fdata->passed_dfilter && edt->pi.fd->dependent_frames) {
1246 /* This frame passed the display filter but it may depend on other
1247 * (potentially not displayed) frames. Find those frames and mark them
1248 * as depended upon.
1250 g_hash_table_foreach(edt->pi.fd->dependent_frames, find_and_mark_frame_depended_upon, cf->provider.frames);
1254 if (fdata->passed_dfilter || fdata->ref_time) {
1255 cf->displayed_count++;
1256 fdata->dis_num = cf->displayed_count;
1259 if (add_to_packet_list) {
1260 /* We fill the needed columns from new_packet_list */
1261 packet_list_append(cinfo, fdata);
1264 if (fdata->passed_dfilter || fdata->ref_time)
1266 frame_data_set_after_dissect(fdata, &cf->cum_bytes);
1267 /* The only way we use prev_dis is to get the time stamp of
1268 * the previous displayed frame, so ignore it if it doesn't
1269 * have a time stamp, because we're presumably interested in
1270 * the timestamp of the previously displayed frame with a
1271 * time. XXX: What if in the future we want to use the previously
1272 * displayed frame for something else, too?
1274 if (fdata->has_ts) {
1275 cf->provider.prev_dis = fdata;
1278 /* If we haven't yet seen the first frame, this is it. */
1279 if (cf->first_displayed == 0)
1280 cf->first_displayed = fdata->num;
1282 /* This is the last frame we've seen so far. */
1283 cf->last_displayed = fdata->num;
1286 epan_dissect_reset(edt);
1290 * Read in a new record.
1291 * Returns true if the packet was added to the packet (record) list,
1292 * false otherwise.
1294 static bool
1295 read_record(capture_file *cf, wtap_rec *rec, dfilter_t *dfcode,
1296 epan_dissect_t *edt, column_info *cinfo, int64_t offset,
1297 fifo_string_cache_t *frame_dup_cache, GChecksum *frame_cksum)
1299 frame_data fdlocal;
1300 frame_data *fdata;
1301 bool passed = true;
1302 bool added = false;
1303 const char *cksum_string;
1304 bool was_in_cache;
1306 /* Add this packet's link-layer encapsulation type to cf->linktypes, if
1307 it's not already there.
1308 XXX - yes, this is O(N), so if every packet had a different
1309 link-layer encapsulation type, it'd be O(N^2) to read the file, but
1310 there are probably going to be a small number of encapsulation types
1311 in a file. */
1312 if (rec->rec_type == REC_TYPE_PACKET) {
1313 cf_add_encapsulation_type(cf, rec->rec_header.packet_header.pkt_encap);
1316 /* The frame number of this packet, if we add it to the set of frames,
1317 would be one more than the count of frames in the file so far. */
1318 frame_data_init(&fdlocal, cf->count + 1, rec, offset, cf->cum_bytes);
1320 if (cf->rfcode) {
1321 epan_dissect_t rf_edt;
1322 column_info *rf_cinfo = NULL;
1324 epan_dissect_init(&rf_edt, cf->epan, true, false);
1325 epan_dissect_prime_with_dfilter(&rf_edt, cf->rfcode);
1326 if (dfilter_requires_columns(cf->rfcode)) {
1327 rf_cinfo = &cf->cinfo;
1329 epan_dissect_run(&rf_edt, cf->cd_t, rec, &fdlocal, rf_cinfo);
1330 passed = dfilter_apply_edt(cf->rfcode, &rf_edt);
1331 epan_dissect_cleanup(&rf_edt);
1334 if (passed) {
1335 added = true;
1337 /* This does a shallow copy of fdlocal, which is good enough. */
1338 fdata = frame_data_sequence_add(cf->provider.frames, &fdlocal);
1340 cf->count++;
1341 if (rec->block != NULL)
1342 cf->packet_comment_count += wtap_block_count_option(rec->block, OPT_COMMENT);
1343 cf->f_datalen = offset + fdlocal.cap_len;
1345 // Should we check if the frame data is a duplicate, and thus, ignore
1346 // this frame?
1347 if (frame_cksum != NULL && rec->rec_type == REC_TYPE_PACKET) {
1348 g_checksum_reset(frame_cksum);
1349 g_checksum_update(frame_cksum, ws_buffer_start_ptr(&rec->data), ws_buffer_length(&rec->data));
1350 cksum_string = g_strdup(g_checksum_get_string(frame_cksum));
1351 was_in_cache = fifo_string_cache_insert(frame_dup_cache, cksum_string);
1352 if (was_in_cache) {
1353 g_free((void *)cksum_string);
1354 fdata->ignored = true;
1355 cf->ignored_count++;
1359 /* When a redissection is in progress (or queued), do not process packets.
1360 * This will be done once all (new) packets have been scanned. */
1361 if (!cf->redissecting && cf->redissection_queued == RESCAN_NONE) {
1362 add_packet_to_packet_list(fdata, cf, edt, dfcode, cinfo, rec, true);
1366 return added;
1370 typedef struct _callback_data_t {
1371 void * pd_window;
1372 int64_t f_len;
1373 progdlg_t *progbar;
1374 GTimer *prog_timer;
1375 bool stop_flag;
1376 } callback_data_t;
1379 static bool
1380 merge_callback(merge_event event, int num _U_,
1381 const merge_in_file_t in_files[], const unsigned in_file_count,
1382 void *data)
1384 unsigned i;
1385 callback_data_t *cb_data = (callback_data_t*) data;
1387 ws_assert(cb_data != NULL);
1389 switch (event) {
1391 case MERGE_EVENT_INPUT_FILES_OPENED:
1392 /* do nothing */
1393 break;
1395 case MERGE_EVENT_FRAME_TYPE_SELECTED:
1396 /* do nothing */
1397 break;
1399 case MERGE_EVENT_READY_TO_MERGE:
1400 /* Get the sum of the sizes of all the files. */
1401 for (i = 0; i < in_file_count; i++)
1402 cb_data->f_len += in_files[i].size;
1404 cb_data->prog_timer = g_timer_new();
1405 g_timer_start(cb_data->prog_timer);
1406 break;
1408 case MERGE_EVENT_RECORD_WAS_READ:
1410 /* Create the progress bar if necessary.
1411 We check on every iteration of the loop, so that it takes no
1412 longer than the standard time to create it (otherwise, for a
1413 large file, we might take considerably longer than that standard
1414 time in order to get to the next progress bar step). */
1415 if (cb_data->progbar == NULL) {
1416 cb_data->progbar = delayed_create_progress_dlg(cb_data->pd_window, NULL, NULL,
1417 false, &cb_data->stop_flag, 0.0f);
1421 * Update the progress bar, but do it only after
1422 * PROGBAR_UPDATE_INTERVAL has elapsed. Calling update_progress_dlg
1423 * and packets_bar_update will likely trigger UI paint events, which
1424 * might take a while depending on the platform and display. Reset
1425 * our timer *after* painting.
1427 if (g_timer_elapsed(cb_data->prog_timer, NULL) > PROGBAR_UPDATE_INTERVAL) {
1428 float progbar_val;
1429 int64_t file_pos = 0;
1430 /* Get the sum of the seek positions in all of the files. */
1431 for (i = 0; i < in_file_count; i++)
1432 file_pos += wtap_read_so_far(in_files[i].wth);
1434 progbar_val = (float) file_pos / (float) cb_data->f_len;
1435 if (progbar_val > 1.0f) {
1436 /* Some file probably grew while we were reading it.
1437 That "shouldn't happen", so we'll just clip the progress
1438 value at 1.0. */
1439 progbar_val = 1.0f;
1442 if (cb_data->progbar != NULL) {
1443 char status_str[100];
1444 snprintf(status_str, sizeof(status_str),
1445 "%" PRId64 "KB of %" PRId64 "KB",
1446 file_pos / 1024, cb_data->f_len / 1024);
1447 update_progress_dlg(cb_data->progbar, progbar_val, status_str);
1449 g_timer_start(cb_data->prog_timer);
1452 break;
1454 case MERGE_EVENT_DONE:
1455 /* We're done merging the files; destroy the progress bar if it was created. */
1456 if (cb_data->progbar != NULL)
1457 destroy_progress_dlg(cb_data->progbar);
1458 g_timer_destroy(cb_data->prog_timer);
1459 break;
1462 return cb_data->stop_flag;
1467 cf_status_t
1468 cf_merge_files_to_tempfile(void *pd_window, const char *temp_dir, char **out_filenamep,
1469 int in_file_count, const char *const *in_filenames,
1470 int file_type, bool do_append)
1472 bool status;
1473 merge_progress_callback_t cb;
1474 callback_data_t *cb_data = g_new0(callback_data_t, 1);
1476 /* prepare our callback routine */
1477 cb_data->pd_window = pd_window;
1478 cb.callback_func = merge_callback;
1479 cb.data = cb_data;
1481 cf_callback_invoke(cf_cb_file_merge_started, NULL);
1483 /* merge the files */
1484 status = merge_files_to_tempfile(temp_dir, out_filenamep, "wireshark", file_type,
1485 in_filenames,
1486 in_file_count, do_append,
1487 IDB_MERGE_MODE_ALL_SAME, 0 /* snaplen */,
1488 "Wireshark", &cb);
1490 g_free(cb.data);
1492 cf_callback_invoke(cf_cb_file_merge_finished, NULL);
1494 if (!status) {
1495 /* Callers aren't expected to treat an error or an explicit abort
1496 differently - the merge code puts up error dialogs itself, so
1497 they don't have to. */
1498 return CF_ERROR;
1499 } else
1500 return CF_OK;
1503 cf_status_t
1504 cf_filter_packets(capture_file *cf, char *dftext, bool force)
1506 const char *filter_new = dftext ? dftext : "";
1507 const char *filter_old = cf->dfilter ? cf->dfilter : "";
1508 dfilter_t *dfcode;
1509 df_error_t *df_err;
1511 /* if new filter equals old one, do nothing unless told to do so */
1512 /* XXX - The text can be the same without compiling to the same code.
1513 * (Macros, field references, etc.)
1515 if (!force && strcmp(filter_new, filter_old) == 0) {
1516 return CF_OK;
1519 dfcode=NULL;
1521 if (dftext == NULL) {
1522 /* The new filter is an empty filter (i.e., display all packets).
1523 * so leave dfcode==NULL
1525 } else {
1527 * We have a filter; make a copy of it (as we'll be saving it),
1528 * and try to compile it.
1530 dftext = g_strdup(dftext);
1531 if (!dfilter_compile(dftext, &dfcode, &df_err)) {
1532 /* The attempt failed; report an error. */
1533 simple_message_box(ESD_TYPE_ERROR, NULL,
1534 "See the help for a description of the display filter syntax.",
1535 "\"%s\" isn't a valid display filter: %s",
1536 dftext, df_err->msg);
1537 df_error_free(&df_err);
1538 g_free(dftext);
1539 return CF_ERROR;
1542 /* Was it empty? */
1543 if (dfcode == NULL) {
1544 /* Yes - free the filter text, and set it to null. */
1545 g_free(dftext);
1546 dftext = NULL;
1550 /* We have a valid filter. Replace the current filter. */
1551 g_free(cf->dfilter);
1552 cf->dfilter = dftext;
1554 /* We'll recompile this when the rescan starts, or in cf_read()
1555 * if no file is open currently. However, if no file is open and
1556 * we start a new capture, we want to use this rather than
1557 * recompiling in cf_continue_tail() */
1558 dfilter_free(cf->dfcode);
1559 cf->dfcode = dfcode;
1561 /* Now rescan the packet list, applying the new filter, but not
1562 * throwing away information constructed on a previous pass.
1563 * If a dissection is already in progress, queue it.
1565 if (cf->redissection_queued == RESCAN_NONE) {
1566 if (cf->read_lock) {
1567 cf->redissection_queued = RESCAN_SCAN;
1568 } else if (cf->state != FILE_CLOSED) {
1569 if (dftext == NULL) {
1570 rescan_packets(cf, "Resetting", "filter", false);
1571 } else {
1572 rescan_packets(cf, "Filtering", dftext, false);
1577 return CF_OK;
1580 void
1581 cf_redissect_packets(capture_file *cf)
1583 if (cf->read_lock || cf->redissection_queued == RESCAN_SCAN) {
1584 /* Dissection in progress, signal redissection rather than rescanning. That
1585 * would destroy the current (in-progress) dissection in "cf_read" which
1586 * will cause issues when "cf_read" tries to add packets to the list.
1587 * If a previous rescan was requested, "upgrade" it to a full redissection.
1589 cf->redissection_queued = RESCAN_REDISSECT;
1591 if (cf->redissection_queued != RESCAN_NONE) {
1592 /* Redissection is (already) queued, wait for "cf_read" to finish. */
1593 /* XXX - what if whatever set and later clears read_lock is *not*
1594 * cf_read, e.g. process_specified_records ? We need to handle a
1595 * queued redissection there too like we do in cf_read.
1597 return;
1600 if (cf->state != FILE_CLOSED) {
1601 /* Restart dissection in case no cf_read is pending. */
1602 rescan_packets(cf, "Reprocessing", "all packets", true);
1606 bool
1607 cf_read_record(capture_file *cf, const frame_data *fdata, wtap_rec *rec)
1609 int err;
1610 char *err_info;
1612 if (!wtap_seek_read(cf->provider.wth, fdata->file_off, rec, &err, &err_info)) {
1613 report_cfile_read_failure(cf->filename, err, err_info);
1614 return false;
1616 return true;
1619 bool
1620 cf_read_record_no_alert(capture_file *cf, const frame_data *fdata,
1621 wtap_rec *rec)
1623 int err;
1624 char *err_info;
1626 if (!wtap_seek_read(cf->provider.wth, fdata->file_off, rec, &err, &err_info)) {
1627 g_free(err_info);
1628 return false;
1630 return true;
1633 bool
1634 cf_read_current_record(capture_file *cf)
1636 return cf_read_record(cf, cf->current_frame, &cf->rec);
1639 /* Rescan the list of packets, reconstructing the CList.
1641 "action" describes why we're doing this; it's used in the progress
1642 dialog box.
1644 "action_item" describes what we're doing; it's used in the progress
1645 dialog box.
1647 "redissect" is true if we need to make the dissectors reconstruct
1648 any state information they have (because a preference that affects
1649 some dissector has changed, meaning some dissector might construct
1650 its state differently from the way it was constructed the last time). */
1651 static void
1652 rescan_packets(capture_file *cf, const char *action, const char *action_item, bool redissect)
1654 /* Rescan packets new packet list */
1655 uint32_t framenum;
1656 frame_data *fdata;
1657 wtap_rec rec;
1658 progdlg_t *progbar = NULL;
1659 GTimer *prog_timer = g_timer_new();
1660 int count;
1661 frame_data *selected_frame, *preceding_frame, *following_frame, *prev_frame;
1662 int selected_frame_num, preceding_frame_num, following_frame_num, prev_frame_num;
1663 bool selected_frame_seen;
1664 float progbar_val;
1665 int64_t start_time;
1666 char status_str[100];
1667 epan_dissect_t edt;
1668 dfilter_t *dfcode = NULL;
1669 column_info *cinfo;
1670 bool create_proto_tree;
1671 bool filtering_tap_listeners = false;
1672 unsigned tap_flags;
1673 bool add_to_packet_list = false;
1674 bool compiled _U_;
1675 uint32_t frames_count;
1676 rescan_type queued_rescan_type = RESCAN_NONE;
1678 if (cf->state == FILE_CLOSED || cf->state == FILE_READ_PENDING) {
1679 return;
1682 /* Rescan in progress, clear pending actions. */
1683 cf->redissection_queued = RESCAN_NONE;
1684 ws_assert(!cf->read_lock);
1685 cf->read_lock = true;
1687 wtap_rec_init(&rec, 1514);
1689 /* Compile the current display filter.
1690 * The code it compiles to might have changed, e.g. if a display
1691 * filter macro used has changed.
1693 * We assume this will not fail since cf->dfilter is only set in
1694 * cf_filter IFF the filter was valid.
1695 * XXX - This is not necessarily true, if the filter has a FT_IPv4
1696 * or FT_IPv6 field compared to a resolved hostname in it, because
1697 * we do a new host lookup, and that *could* timeout this time
1698 * (though with the read lock above we shouldn't have many lookups at
1699 * once, reducing the chances of that)... (#19612)
1701 if (cf->dfilter) {
1702 compiled = dfilter_compile(cf->dfilter, &dfcode, NULL);
1703 ws_assert(compiled && dfcode);
1706 dfilter_free(cf->dfcode);
1707 cf->dfcode = dfcode;
1709 /* Do we have any tap listeners with filters? */
1710 filtering_tap_listeners = have_filtering_tap_listeners();
1712 /* Update references in filters (if any) for the protocol
1713 * tree corresponding to the currently selected frame in the GUI. */
1714 if (cf->edt != NULL && cf->edt->tree != NULL) {
1715 if (cf->dfcode)
1716 dfilter_load_field_references(cf->dfcode, cf->edt->tree);
1717 if (filtering_tap_listeners)
1718 tap_listeners_load_field_references(cf->edt);
1721 if (cf->dfcode != NULL) {
1722 dfilter_log_full(LOG_DOMAIN_DFILTER, LOG_LEVEL_NOISY, NULL, -1, NULL,
1723 cf->dfcode, "Rescanning packets with display filter");
1726 /* Get the union of the flags for all tap listeners. */
1727 tap_flags = union_of_tap_listener_flags();
1729 /* If the display filter or any tap listeners require the columns,
1730 * construct them. */
1731 cinfo = (tap_listeners_require_columns() ||
1732 dfilter_requires_columns(cf->dfcode)) ? &cf->cinfo : NULL;
1735 * Determine whether we need to create a protocol tree.
1736 * We do if:
1738 * we're going to apply a display filter;
1740 * one of the tap listeners is going to apply a filter;
1742 * one of the tap listeners requires a protocol tree;
1744 * we're redissecting and a postdissector wants field
1745 * values or protocols on the first pass.
1747 create_proto_tree =
1748 (cf->dfcode != NULL || filtering_tap_listeners ||
1749 (tap_flags & TL_REQUIRES_PROTO_TREE) ||
1750 (redissect && postdissectors_want_hfids()));
1752 reset_tap_listeners();
1753 /* Which frame, if any, is the currently selected frame?
1754 XXX - should the selected frame or the focus frame be the "current"
1755 frame, that frame being the one from which "Find Frame" searches
1756 start? */
1757 selected_frame = cf->current_frame;
1759 /* Mark frame num as not found */
1760 selected_frame_num = -1;
1762 /* Freeze the packet list while we redo it, so we don't get any
1763 screen updates while it happens. */
1764 packet_list_freeze();
1766 if (redissect) {
1767 /* We need to re-initialize all the state information that protocols
1768 keep, because some preference that controls a dissector has changed,
1769 which might cause the state information to be constructed differently
1770 by that dissector. */
1772 /* We might receive new packets while redissecting, and we don't
1773 want to dissect those before their time. */
1774 cf->redissecting = true;
1776 /* 'reset' dissection session */
1777 epan_free(cf->epan);
1778 if (cf->edt && cf->edt->pi.fd) {
1779 /* All pointers in "per frame proto data" for the currently selected
1780 packet are allocated in wmem_file_scope() and deallocated in epan_free().
1781 Free them here to avoid unintended usage in packet_list_clear(). */
1782 frame_data_destroy(cf->edt->pi.fd);
1784 cf->epan = ws_epan_new(cf);
1785 cf->cinfo.epan = cf->epan;
1787 /* A new Lua tap listener may be registered in lua_prime_all_fields()
1788 called via epan_new() / init_dissection() when reloading Lua plugins. */
1789 if (!create_proto_tree && have_filtering_tap_listeners()) {
1790 create_proto_tree = true;
1792 if (!cinfo && tap_listeners_require_columns()) {
1793 cinfo = &cf->cinfo;
1796 /* We need to redissect the packets so we have to discard our old
1797 * packet list store. */
1798 packet_list_clear();
1799 add_to_packet_list = true;
1802 /* We don't yet know which will be the first and last frames displayed. */
1803 cf->first_displayed = 0;
1804 cf->last_displayed = 0;
1806 /* We currently don't display any packets */
1807 cf->displayed_count = 0;
1809 /* Iterate through the list of frames. Call a routine for each frame
1810 to check whether it should be displayed and, if so, add it to
1811 the display list. */
1812 cf->provider.ref = NULL;
1813 cf->provider.prev_dis = NULL;
1814 cf->provider.prev_cap = NULL;
1815 cf->cum_bytes = 0;
1817 cf_callback_invoke(cf_cb_file_rescan_started, cf);
1819 g_timer_start(prog_timer);
1820 /* Count of packets at which we've looked. */
1821 count = 0;
1822 /* Progress so far. */
1823 progbar_val = 0.0f;
1825 cf->stop_flag = false;
1826 start_time = g_get_monotonic_time();
1828 /* no previous row yet */
1829 prev_frame_num = -1;
1830 prev_frame = NULL;
1832 preceding_frame_num = -1;
1833 preceding_frame = NULL;
1834 following_frame_num = -1;
1835 following_frame = NULL;
1837 selected_frame_seen = false;
1839 frames_count = cf->count;
1841 epan_dissect_init(&edt, cf->epan, create_proto_tree, false);
1843 if (redissect) {
1845 * Decryption secrets and name resolution blocks are read while
1846 * sequentially processing records and then passed to the dissector.
1847 * During redissection, the previous information is lost (see epan_free
1848 * above), but they are not read again from the file as only packet
1849 * records are re-read. Therefore reset the wtap secrets and name
1850 * resolution callbacks such that wtap resupplies the callbacks with
1851 * previously read information.
1853 wtap_set_cb_new_ipv4(cf->provider.wth, add_ipv4_name);
1854 wtap_set_cb_new_ipv6(cf->provider.wth, (wtap_new_ipv6_callback_t) add_ipv6_name);
1855 wtap_set_cb_new_secrets(cf->provider.wth, secrets_wtap_callback);
1858 for (framenum = 1; framenum <= frames_count; framenum++) {
1859 fdata = frame_data_sequence_find(cf->provider.frames, framenum);
1861 /* Create the progress bar if necessary.
1862 We check on every iteration of the loop, so that it takes no
1863 longer than the standard time to create it (otherwise, for a
1864 large file, we might take considerably longer than that standard
1865 time in order to get to the next progress bar step). */
1866 if (progbar == NULL)
1867 progbar = delayed_create_progress_dlg(cf->window, action, action_item, true,
1868 &cf->stop_flag,
1869 progbar_val);
1872 * Update the progress bar, but do it only after PROGBAR_UPDATE_INTERVAL
1873 * has elapsed. Calling update_progress_dlg and packets_bar_update will
1874 * likely trigger UI paint events, which might take a while depending on
1875 * the platform and display. Reset our timer *after* painting.
1877 if (g_timer_elapsed(prog_timer, NULL) > PROGBAR_UPDATE_INTERVAL) {
1878 /* let's not divide by zero. I should never be started
1879 * with count == 0, so let's assert that
1881 ws_assert(cf->count > 0);
1882 progbar_val = (float) count / frames_count;
1884 if (progbar != NULL) {
1885 snprintf(status_str, sizeof(status_str),
1886 "%4u of %u frames", count, frames_count);
1887 update_progress_dlg(progbar, progbar_val, status_str);
1890 g_timer_start(prog_timer);
1893 queued_rescan_type = cf->redissection_queued;
1894 if (queued_rescan_type != RESCAN_NONE) {
1895 /* A redissection was requested while an existing redissection was
1896 * pending. */
1897 break;
1900 if (cf->stop_flag) {
1901 /* Well, the user decided to abort the filtering. Just stop.
1903 XXX - go back to the previous filter? Users probably just
1904 want not to wait for a filtering operation to finish;
1905 unless we cancel by having no filter, reverting to the
1906 previous filter will probably be even more expensive than
1907 continuing the filtering, as it involves going back to the
1908 beginning and filtering, and even with no filter we currently
1909 have to re-generate the entire clist, which is also expensive.
1911 I'm not sure what Network Monitor does, but it doesn't appear
1912 to give you an unfiltered display if you cancel. */
1913 break;
1916 count++;
1918 if (redissect) {
1919 /* Since all state for the frame was destroyed, mark the frame
1920 * as not visited, free the GSList referring to the state
1921 * data (the per-frame data itself was freed by
1922 * "init_dissection()"), and null out the GSList pointer. */
1923 frame_data_reset(fdata);
1924 frames_count = cf->count;
1927 /* Frame dependencies from the previous dissection/filtering are no longer valid. */
1928 fdata->dependent_of_displayed = 0;
1930 if (!cf_read_record(cf, fdata, &rec))
1931 break; /* error reading the frame */
1933 /* If the previous frame is displayed, and we haven't yet seen the
1934 selected frame, remember that frame - it's the closest one we've
1935 yet seen before the selected frame. */
1936 if (prev_frame_num != -1 && !selected_frame_seen && prev_frame->passed_dfilter) {
1937 preceding_frame_num = prev_frame_num;
1938 preceding_frame = prev_frame;
1941 add_packet_to_packet_list(fdata, cf, &edt, cf->dfcode, cinfo, &rec,
1942 add_to_packet_list);
1944 /* If this frame is displayed, and this is the first frame we've
1945 seen displayed after the selected frame, remember this frame -
1946 it's the closest one we've yet seen at or after the selected
1947 frame. */
1948 if (fdata->passed_dfilter && selected_frame_seen && following_frame_num == -1) {
1949 following_frame_num = fdata->num;
1950 following_frame = fdata;
1952 if (fdata == selected_frame) {
1953 selected_frame_seen = true;
1954 if (fdata->passed_dfilter)
1955 selected_frame_num = fdata->num;
1958 /* Remember this frame - it'll be the previous frame
1959 on the next pass through the loop. */
1960 prev_frame_num = fdata->num;
1961 prev_frame = fdata;
1962 wtap_rec_reset(&rec);
1965 epan_dissect_cleanup(&edt);
1966 wtap_rec_cleanup(&rec);
1968 /* We are done redissecting the packet list. */
1969 cf->redissecting = false;
1971 if (redissect) {
1972 frames_count = cf->count;
1973 /* Clear out what remains of the visited flags and per-frame data
1974 pointers.
1976 XXX - that may cause various forms of bogosity when dissecting
1977 these frames, as they won't have been seen by this sequential
1978 pass, but the only alternative I see is to keep scanning them
1979 even though the user requested that the scan stop, and that
1980 would leave the user stuck with an Wireshark grinding on
1981 until it finishes. Should we just stick them with that? */
1982 for (; framenum <= frames_count; framenum++) {
1983 fdata = frame_data_sequence_find(cf->provider.frames, framenum);
1984 frame_data_reset(fdata);
1988 /* We're done filtering the packets; destroy the progress bar if it
1989 was created. */
1990 if (progbar != NULL)
1991 destroy_progress_dlg(progbar);
1992 g_timer_destroy(prog_timer);
1994 /* Unfreeze the packet list. */
1995 if (!add_to_packet_list)
1996 packet_list_recreate_visible_rows();
1998 /* Compute the time it took to filter the file */
1999 compute_elapsed(cf, start_time);
2001 packet_list_thaw();
2003 /* It is safe again to execute redissections or sort. */
2004 ws_assert(cf->read_lock);
2005 cf->read_lock = false;
2007 cf_callback_invoke(cf_cb_file_rescan_finished, cf);
2009 if (selected_frame_num == -1) {
2010 /* The selected frame didn't pass the filter. */
2011 if (selected_frame == NULL) {
2012 /* That's because there *was* no selected frame. Make the first
2013 displayed frame the current frame. */
2014 selected_frame_num = 0;
2015 } else {
2016 /* Find the nearest displayed frame to the selected frame (whether
2017 it's before or after that frame) and make that the current frame.
2018 If the next and previous displayed frames are equidistant from the
2019 selected frame, choose the next one. */
2020 ws_assert(following_frame == NULL ||
2021 following_frame->num >= selected_frame->num);
2022 ws_assert(preceding_frame == NULL ||
2023 preceding_frame->num <= selected_frame->num);
2024 if (following_frame == NULL) {
2025 /* No frame after the selected frame passed the filter, so we
2026 have to select the last displayed frame before the selected
2027 frame. */
2028 selected_frame_num = preceding_frame_num;
2029 selected_frame = preceding_frame;
2030 } else if (preceding_frame == NULL) {
2031 /* No frame before the selected frame passed the filter, so we
2032 have to select the first displayed frame after the selected
2033 frame. */
2034 selected_frame_num = following_frame_num;
2035 selected_frame = following_frame;
2036 } else {
2037 /* Frames before and after the selected frame passed the filter, so
2038 we'll select the previous frame */
2039 selected_frame_num = preceding_frame_num;
2040 selected_frame = preceding_frame;
2045 if (selected_frame_num == -1) {
2046 /* There are no frames displayed at all. */
2047 cf_unselect_packet(cf);
2048 } else {
2049 /* Either the frame that was selected passed the filter, or we've
2050 found the nearest displayed frame to that frame. Select it, make
2051 it the focus row, and make it visible. */
2052 /* Set to invalid to force update of packet list and packet details */
2053 if (selected_frame_num == 0) {
2054 packet_list_select_row_from_data(NULL);
2055 }else{
2056 if (!packet_list_select_row_from_data(selected_frame)) {
2057 /* We didn't find a row corresponding to this frame.
2058 This means that the frame isn't being displayed currently,
2059 so we can't select it. */
2060 simple_message_box(ESD_TYPE_INFO, NULL,
2061 "The capture file is probably not fully dissected.",
2062 "End of capture exceeded.");
2067 /* If another rescan (due to dfilter change) or redissection (due to profile
2068 * change) was requested, the rescan above is aborted and restarted here. */
2069 if (queued_rescan_type != RESCAN_NONE) {
2070 redissect = redissect || queued_rescan_type == RESCAN_REDISSECT;
2071 rescan_packets(cf, "Reprocessing", "all packets", redissect);
2077 * Scan through all frame data and recalculate the ref time
2078 * without rereading the file.
2079 * XXX - do we need a progress bar or is this fast enough?
2081 void
2082 cf_reftime_packets(capture_file* cf)
2084 uint32_t framenum;
2085 frame_data *fdata;
2086 nstime_t rel_ts;
2088 cf->provider.ref = NULL;
2089 cf->provider.prev_dis = NULL;
2090 cf->cum_bytes = 0;
2092 for (framenum = 1; framenum <= cf->count; framenum++) {
2093 fdata = frame_data_sequence_find(cf->provider.frames, framenum);
2095 /* just add some value here until we know if it is being displayed or not */
2096 fdata->cum_bytes = cf->cum_bytes + fdata->pkt_len;
2099 * Timestamps
2102 if (fdata->has_ts) {
2103 /* If we don't have the time stamp of the first packet in the
2104 capture, it's because this is the first packet. Save the time
2105 stamp of this packet as the time stamp of the first packet. */
2106 if (cf->provider.ref == NULL)
2107 cf->provider.ref = fdata;
2108 /* if this frames is marked as a reference time frame, reset
2109 firstsec and firstusec to this frame */
2110 if (fdata->ref_time)
2111 cf->provider.ref = fdata;
2113 /* Get the time elapsed between the first packet and this one. */
2114 fdata->frame_ref_num = (fdata != cf->provider.ref) ? cf->provider.ref->num : 0;
2115 nstime_delta(&rel_ts, &fdata->abs_ts, &cf->provider.ref->abs_ts);
2117 /* If it's greater than the current elapsed time, set the elapsed
2118 time to it (we check for "greater than" so as not to be
2119 confused by time moving backwards). */
2120 if ((int32_t)cf->elapsed_time.secs < rel_ts.secs
2121 || ((int32_t)cf->elapsed_time.secs == rel_ts.secs && (int32_t)cf->elapsed_time.nsecs < rel_ts.nsecs)) {
2122 cf->elapsed_time = rel_ts;
2125 /* If this frame is displayed, get the time elapsed between the
2126 previous displayed packet and this packet. */
2127 /* XXX: What if in the future we want to use the previously
2128 * displayed frame for something else, too? Then we'd want
2129 * to store this frame as prev_dis even if it doesn't have a
2130 * timestamp. */
2131 if ( fdata->passed_dfilter ) {
2132 /* If we don't have the time stamp of the previous displayed
2133 packet, it's because this is the first displayed packet.
2134 Save the time stamp of this packet as the time stamp of
2135 the previous displayed packet. */
2136 if (cf->provider.prev_dis == NULL) {
2137 cf->provider.prev_dis = fdata;
2140 fdata->prev_dis_num = cf->provider.prev_dis->num;
2141 cf->provider.prev_dis = fdata;
2143 } else {
2144 /* If this frame doesn't have a timestamp, don't calculate
2145 anything with relative times. */
2146 /* However, if this frame is marked as a reference time frame,
2147 clear the reference frame so that the next frame with a
2148 timestamp becomes the reference frame. */
2149 if (fdata->ref_time) {
2150 cf->provider.ref = NULL;
2155 * Byte counts
2157 if ( (fdata->passed_dfilter) || (fdata->ref_time) ) {
2158 /* This frame either passed the display filter list or is marked as
2159 a time reference frame. All time reference frames are displayed
2160 even if they don't pass the display filter */
2161 if (fdata->ref_time) {
2162 /* if this was a TIME REF frame we should reset the cum_bytes field */
2163 cf->cum_bytes = fdata->pkt_len;
2164 fdata->cum_bytes = cf->cum_bytes;
2165 } else {
2166 /* increase cum_bytes with this packets length */
2167 cf->cum_bytes += fdata->pkt_len;
2173 typedef enum {
2174 PSP_FINISHED,
2175 PSP_STOPPED,
2176 PSP_FAILED
2177 } psp_return_t;
2179 static psp_return_t
2180 process_specified_records(capture_file *cf, packet_range_t *range,
2181 const char *string1, const char *string2, bool terminate_is_stop,
2182 bool (*callback)(capture_file *, frame_data *,
2183 wtap_rec *, void *),
2184 void *callback_args,
2185 bool show_progress_bar)
2187 uint32_t framenum;
2188 frame_data *fdata;
2189 wtap_rec rec;
2190 psp_return_t ret = PSP_FINISHED;
2192 progdlg_t *progbar = NULL;
2193 GTimer *prog_timer = g_timer_new();
2194 int progbar_count;
2195 float progbar_val;
2196 char progbar_status_str[100];
2197 range_process_e process_this;
2199 wtap_rec_init(&rec, 1514);
2201 g_timer_start(prog_timer);
2202 /* Count of packets at which we've looked. */
2203 progbar_count = 0;
2204 /* Progress so far. */
2205 progbar_val = 0.0f;
2207 /* XXX - It should be ok to have multiple readers, so long as nothing
2208 * frees the epan context, e.g. rescan_packets with redissect true,
2209 * or anything that closes the file (including reload and certain forms
2210 * of saving.) This is mostly to stop cf_save_records but should probably
2211 * be handled by callers in order to allow multiple readers (e.g.,
2212 * restarting taps after adding or changing one.) We should probably
2213 * make this a real reader-writer lock.
2215 if (cf->read_lock) {
2216 ws_warning("Failing due to nested process_specified_records(\"%s\") call!", cf->filename);
2217 return PSP_FAILED;
2219 cf->read_lock = true;
2221 cf->stop_flag = false;
2223 if (range != NULL)
2224 packet_range_process_init(range);
2226 /* Iterate through all the packets, printing the packets that
2227 were selected by the current display filter. */
2228 for (framenum = 1; framenum <= cf->count; framenum++) {
2229 fdata = frame_data_sequence_find(cf->provider.frames, framenum);
2231 /* Create the progress bar if necessary.
2232 We check on every iteration of the loop, so that it takes no
2233 longer than the standard time to create it (otherwise, for a
2234 large file, we might take considerably longer than that standard
2235 time in order to get to the next progress bar step). */
2236 if (show_progress_bar && progbar == NULL)
2237 progbar = delayed_create_progress_dlg(cf->window, string1, string2,
2238 terminate_is_stop,
2239 &cf->stop_flag,
2240 progbar_val);
2243 * Update the progress bar, but do it only after PROGBAR_UPDATE_INTERVAL
2244 * has elapsed. Calling update_progress_dlg and packets_bar_update will
2245 * likely trigger UI paint events, which might take a while depending on
2246 * the platform and display. Reset our timer *after* painting.
2248 if (progbar && g_timer_elapsed(prog_timer, NULL) > PROGBAR_UPDATE_INTERVAL) {
2249 /* let's not divide by zero. I should never be started
2250 * with count == 0, so let's assert that
2252 ws_assert(cf->count > 0);
2253 progbar_val = (float) progbar_count / cf->count;
2255 snprintf(progbar_status_str, sizeof(progbar_status_str),
2256 "%4u of %u packets", progbar_count, cf->count);
2257 update_progress_dlg(progbar, progbar_val, progbar_status_str);
2259 g_timer_start(prog_timer);
2262 if (cf->stop_flag) {
2263 /* Well, the user decided to abort the operation. Just stop,
2264 and arrange to return PSP_STOPPED to our caller, so they know
2265 it was stopped explicitly. */
2266 ret = PSP_STOPPED;
2267 break;
2270 progbar_count++;
2272 if (range != NULL) {
2273 /* do we have to process this packet? */
2274 process_this = packet_range_process_packet(range, fdata);
2275 if (process_this == range_process_next) {
2276 /* this packet uninteresting, continue with next one */
2277 continue;
2278 } else if (process_this == range_processing_finished) {
2279 /* all interesting packets processed, stop the loop */
2280 break;
2284 /* Get the packet */
2285 if (!cf_read_record(cf, fdata, &rec)) {
2286 /* Attempt to get the packet failed. */
2287 ret = PSP_FAILED;
2288 break;
2290 /* Process the packet */
2291 if (!callback(cf, fdata, &rec, callback_args)) {
2292 /* Callback failed. We assume it reported the error appropriately. */
2293 ret = PSP_FAILED;
2294 break;
2296 wtap_rec_reset(&rec);
2299 /* We're done printing the packets; destroy the progress bar if
2300 it was created. */
2301 if (progbar != NULL)
2302 destroy_progress_dlg(progbar);
2303 g_timer_destroy(prog_timer);
2305 ws_assert(cf->read_lock);
2306 cf->read_lock = false;
2308 wtap_rec_cleanup(&rec);
2310 return ret;
2313 typedef struct {
2314 epan_dissect_t edt;
2315 column_info *cinfo;
2316 } retap_callback_args_t;
2318 static bool
2319 retap_packet(capture_file *cf, frame_data *fdata, wtap_rec *rec, void *argsp)
2321 retap_callback_args_t *args = (retap_callback_args_t *)argsp;
2323 epan_dissect_run_with_taps(&args->edt, cf->cd_t, rec, fdata, args->cinfo);
2324 epan_dissect_reset(&args->edt);
2326 return true;
2329 cf_read_status_t
2330 cf_retap_packets(capture_file *cf)
2332 packet_range_t range;
2333 retap_callback_args_t callback_args;
2334 bool create_proto_tree;
2335 bool filtering_tap_listeners;
2336 unsigned tap_flags;
2337 psp_return_t ret;
2339 /* Presumably the user closed the capture file. */
2340 if (cf == NULL) {
2341 return CF_READ_ABORTED;
2344 /* XXX - If cf->read_lock is true, process_specified_records will fail
2345 * due to a nested call. We fail here so that we don't reset the tap
2346 * listeners if this tap isn't going to succeed.
2348 if (cf->read_lock) {
2349 ws_warning("Failing due to nested process_specified_records(\"%s\") call!", cf->filename);
2350 return CF_READ_ERROR;
2353 cf_callback_invoke(cf_cb_file_retap_started, cf);
2355 /* Do we have any tap listeners with filters? */
2356 filtering_tap_listeners = have_filtering_tap_listeners();
2358 /* Update references in filters (if any) for the protocol
2359 * tree corresponding to the currently selected frame in the GUI. */
2360 /* XXX - What if we *don't* have a currently selected frame in the GUI,
2361 * but we did the last time we loaded field references? Then they'll
2362 * match something instead of nothing (unless they've been recompiled).
2363 * Should we have a way to clear the field references even with a NULL tree?
2365 if (cf->edt != NULL && cf->edt->tree != NULL) {
2366 if (filtering_tap_listeners)
2367 tap_listeners_load_field_references(cf->edt);
2370 /* Get the union of the flags for all tap listeners. */
2371 tap_flags = union_of_tap_listener_flags();
2373 /* If any tap listeners require the columns, construct them. */
2374 callback_args.cinfo = (tap_listeners_require_columns()) ? &cf->cinfo : NULL;
2377 * Determine whether we need to create a protocol tree.
2378 * We do if:
2380 * one of the tap listeners is going to apply a filter;
2382 * one of the tap listeners requires a protocol tree.
2384 create_proto_tree =
2385 (filtering_tap_listeners || (tap_flags & TL_REQUIRES_PROTO_TREE));
2387 /* Reset the tap listeners. */
2388 reset_tap_listeners();
2389 uint32_t count = cf->count;
2391 epan_dissect_init(&callback_args.edt, cf->epan, create_proto_tree, false);
2393 /* Iterate through the list of packets, dissecting all packets and
2394 re-running the taps. */
2395 packet_range_init(&range, cf);
2396 packet_range_process_init(&range);
2398 if (cf->state == FILE_READ_IN_PROGRESS) {
2399 /* We're not done with the sequential read of the file and might
2400 * add more frames while process_specified_records is going. We
2401 * don't want to tap new frames twice, so limit the range to the
2402 * frames already here.
2404 * cf_read sets read_lock so we don't tap in case of an offline
2405 * file, but cf_continue_tail and cf_finish_tail don't, and we
2406 * don't want them to, because tapping new packets in a live
2407 * capture is a common use case.
2409 * Note that most other users of process_specified_records (saving,
2410 * printing) do want to process new packets, unlike taps.
2412 if (count) {
2413 char* range_str = g_strdup_printf("-%u", count);
2414 packet_range_convert_str(&range, range_str);
2415 g_free(range_str);
2416 } else {
2417 /* range_t treats a missing number as meaning 1, not 0, and
2418 * reverses the order if backwards; thus the syntax -0 means
2419 * 0-1, so to only take zero packets we do this.
2421 packet_range_convert_str(&range, "0");
2423 range.process = range_process_user_range;
2426 ret = process_specified_records(cf, &range, "Recalculating statistics on",
2427 "all packets", true, retap_packet,
2428 &callback_args, true);
2430 packet_range_cleanup(&range);
2431 epan_dissect_cleanup(&callback_args.edt);
2433 cf_callback_invoke(cf_cb_file_retap_finished, cf);
2435 switch (ret) {
2436 case PSP_FINISHED:
2437 /* Completed successfully. */
2438 return CF_READ_OK;
2440 case PSP_STOPPED:
2441 /* Well, the user decided to abort the refiltering.
2442 Return CF_READ_ABORTED so our caller knows they did that. */
2443 return CF_READ_ABORTED;
2445 case PSP_FAILED:
2446 /* Error while retapping. */
2447 return CF_READ_ERROR;
2450 ws_assert_not_reached();
2451 return CF_READ_OK;
2454 typedef struct {
2455 print_args_t *print_args;
2456 bool print_header_line;
2457 char *header_line_buf;
2458 int header_line_buf_len;
2459 bool print_formfeed;
2460 bool print_separator;
2461 char *line_buf;
2462 int line_buf_len;
2463 int *col_widths;
2464 int num_visible_cols;
2465 int *visible_cols;
2466 epan_dissect_t edt;
2467 } print_callback_args_t;
2469 static bool
2470 print_packet(capture_file *cf, frame_data *fdata, wtap_rec *rec, void *argsp)
2472 print_callback_args_t *args = (print_callback_args_t *)argsp;
2473 int i;
2474 char *cp;
2475 int line_len;
2476 int column_len;
2477 int cp_off;
2478 char bookmark_name[9+10+1]; /* "__frameNNNNNNNNNN__\0" */
2479 char bookmark_title[6+10+1]; /* "Frame NNNNNNNNNN__\0" */
2480 col_item_t* col_item;
2481 const char* col_text;
2483 /* Fill in the column information if we're printing the summary
2484 information. */
2485 if (args->print_args->print_summary) {
2486 col_custom_prime_edt(&args->edt, &cf->cinfo);
2487 epan_dissect_run(&args->edt, cf->cd_t, rec, fdata, &cf->cinfo);
2488 epan_dissect_fill_in_columns(&args->edt, false, true);
2489 } else
2490 epan_dissect_run(&args->edt, cf->cd_t, rec, fdata, NULL);
2492 if (args->print_formfeed) {
2493 if (!new_page(args->print_args->stream))
2494 goto fail;
2497 * Print another header line if we print a packet summary on the
2498 * new page.
2500 if (args->print_args->print_col_headings)
2501 args->print_header_line = true;
2502 } else {
2503 if (args->print_separator) {
2504 if (!print_line(args->print_args->stream, 0, ""))
2505 goto fail;
2510 * We generate bookmarks, if the output format supports them.
2511 * The name is "__frameN__".
2513 snprintf(bookmark_name, sizeof bookmark_name, "__frame%u__", fdata->num);
2515 if (args->print_args->print_summary) {
2516 if (!args->print_args->print_col_headings)
2517 args->print_header_line = false;
2518 if (args->print_header_line) {
2519 if (!print_line(args->print_args->stream, 0, args->header_line_buf))
2520 goto fail;
2521 args->print_header_line = false; /* we might not need to print any more */
2523 cp = &args->line_buf[0];
2524 line_len = 0;
2525 for (i = 0; i < args->num_visible_cols; i++) {
2526 col_item = &cf->cinfo.columns[args->visible_cols[i]];
2527 col_text = get_column_text(&cf->cinfo, args->visible_cols[i]);
2528 /* Find the length of the string for this column. */
2529 column_len = (int) strlen(col_text);
2530 if (args->col_widths[i] > column_len)
2531 column_len = args->col_widths[i];
2533 /* Make sure there's room in the line buffer for the column; if not,
2534 double its length. */
2535 line_len += column_len + 1; /* "+1" for space */
2536 if (line_len > args->line_buf_len) {
2537 cp_off = (int) (cp - args->line_buf);
2538 args->line_buf_len = 2 * line_len;
2539 args->line_buf = (char *)g_realloc(args->line_buf, args->line_buf_len + 1);
2540 cp = args->line_buf + cp_off;
2543 /* Right-justify the packet number column. */
2544 if (col_item->col_fmt == COL_NUMBER || col_item->col_fmt == COL_NUMBER_DIS)
2545 snprintf(cp, column_len+1, "%*s", args->col_widths[i], col_text);
2546 else
2547 snprintf(cp, column_len+1, "%-*s", args->col_widths[i], col_text);
2548 cp += column_len;
2549 if (i != args->num_visible_cols - 1)
2550 *cp++ = ' ';
2552 *cp = '\0';
2555 * Generate a bookmark, using the summary line as the title.
2557 if (!print_bookmark(args->print_args->stream, bookmark_name,
2558 args->line_buf))
2559 goto fail;
2561 if (!print_line(args->print_args->stream, 0, args->line_buf))
2562 goto fail;
2563 } else {
2565 * Generate a bookmark, using "Frame N" as the title, as we're not
2566 * printing the summary line.
2568 snprintf(bookmark_title, sizeof bookmark_title, "Frame %u", fdata->num);
2569 if (!print_bookmark(args->print_args->stream, bookmark_name,
2570 bookmark_title))
2571 goto fail;
2572 } /* if (print_summary) */
2574 if (args->print_args->print_dissections != print_dissections_none) {
2575 if (args->print_args->print_summary) {
2576 /* Separate the summary line from the tree with a blank line. */
2577 if (!print_line(args->print_args->stream, 0, ""))
2578 goto fail;
2581 /* Print the information in that tree. */
2582 if (!proto_tree_print(args->print_args->print_dissections,
2583 args->print_args->print_hex, &args->edt, NULL,
2584 args->print_args->stream))
2585 goto fail;
2587 /* Print a blank line if we print anything after this (aka more than one packet). */
2588 args->print_separator = true;
2590 /* Print a header line if we print any more packet summaries */
2591 if (args->print_args->print_col_headings)
2592 args->print_header_line = true;
2595 if (args->print_args->print_hex) {
2596 if (args->print_args->print_summary || (args->print_args->print_dissections != print_dissections_none)) {
2597 if (!print_line(args->print_args->stream, 0, ""))
2598 goto fail;
2600 /* Print the full packet data as hex. */
2601 if (!print_hex_data(args->print_args->stream, &args->edt, args->print_args->hexdump_options))
2602 goto fail;
2604 /* Print a blank line if we print anything after this (aka more than one packet). */
2605 args->print_separator = true;
2607 /* Print a header line if we print any more packet summaries */
2608 if (args->print_args->print_col_headings)
2609 args->print_header_line = true;
2610 } /* if (args->print_args->print_dissections != print_dissections_none) */
2612 epan_dissect_reset(&args->edt);
2614 /* do we want to have a formfeed between each packet from now on? */
2615 if (args->print_args->print_formfeed) {
2616 args->print_formfeed = true;
2619 return true;
2621 fail:
2622 epan_dissect_reset(&args->edt);
2623 return false;
2626 cf_print_status_t
2627 cf_print_packets(capture_file *cf, print_args_t *print_args,
2628 bool show_progress_bar)
2630 print_callback_args_t callback_args;
2631 int data_width;
2632 char *cp;
2633 int i, cp_off, column_len, line_len;
2634 int num_visible_col = 0, last_visible_col = 0, visible_col_count;
2635 psp_return_t ret;
2636 GList *clp;
2637 fmt_data *cfmt;
2638 bool proto_tree_needed;
2640 callback_args.print_args = print_args;
2641 callback_args.print_header_line = print_args->print_col_headings;
2642 callback_args.header_line_buf = NULL;
2643 callback_args.header_line_buf_len = 256;
2644 callback_args.print_formfeed = false;
2645 callback_args.print_separator = false;
2646 callback_args.line_buf = NULL;
2647 callback_args.line_buf_len = 256;
2648 callback_args.col_widths = NULL;
2649 callback_args.num_visible_cols = 0;
2650 callback_args.visible_cols = NULL;
2652 if (!print_preamble(print_args->stream, cf->filename, get_ws_vcs_version_info())) {
2653 destroy_print_stream(print_args->stream);
2654 return CF_PRINT_WRITE_ERROR;
2657 if (print_args->print_summary) {
2658 /* We're printing packet summaries. Allocate the header line buffer
2659 and get the column widths. */
2660 callback_args.header_line_buf = (char *)g_malloc(callback_args.header_line_buf_len + 1);
2662 /* Find the number of visible columns and the last visible column */
2663 for (i = 0; i < prefs.num_cols; i++) {
2665 clp = g_list_nth(prefs.col_list, i);
2666 if (clp == NULL) /* Sanity check, Invalid column requested */
2667 continue;
2669 cfmt = (fmt_data *) clp->data;
2670 if (cfmt->visible) {
2671 num_visible_col++;
2672 last_visible_col = i;
2676 /* if num_visible_col is 0, we are done */
2677 if (num_visible_col == 0) {
2678 g_free(callback_args.header_line_buf);
2679 return CF_PRINT_OK;
2682 /* Find the widths for each of the columns - maximum of the
2683 width of the title and the width of the data - and construct
2684 a buffer with a line containing the column titles. */
2685 callback_args.num_visible_cols = num_visible_col;
2686 callback_args.col_widths = g_new(int, num_visible_col);
2687 callback_args.visible_cols = g_new(int, num_visible_col);
2688 cp = &callback_args.header_line_buf[0];
2689 line_len = 0;
2690 visible_col_count = 0;
2691 for (i = 0; i < cf->cinfo.num_cols; i++) {
2693 clp = g_list_nth(prefs.col_list, i);
2694 if (clp == NULL) /* Sanity check, Invalid column requested */
2695 continue;
2697 cfmt = (fmt_data *) clp->data;
2698 if (cfmt->visible == false)
2699 continue;
2701 /* Save the order of visible columns */
2702 callback_args.visible_cols[visible_col_count] = i;
2704 /* Don't pad the last column. */
2705 if (i == last_visible_col)
2706 callback_args.col_widths[visible_col_count] = 0;
2707 else {
2708 callback_args.col_widths[visible_col_count] = (int) strlen(cf->cinfo.columns[i].col_title);
2709 data_width = get_column_char_width(get_column_format(i));
2710 if (data_width > callback_args.col_widths[visible_col_count])
2711 callback_args.col_widths[visible_col_count] = data_width;
2714 /* Find the length of the string for this column. */
2715 column_len = (int) strlen(cf->cinfo.columns[i].col_title);
2716 if (callback_args.col_widths[visible_col_count] > column_len)
2717 column_len = callback_args.col_widths[visible_col_count];
2719 /* Make sure there's room in the line buffer for the column; if not,
2720 double its length. */
2721 line_len += column_len + 1; /* "+1" for space */
2722 if (line_len > callback_args.header_line_buf_len) {
2723 cp_off = (int) (cp - callback_args.header_line_buf);
2724 callback_args.header_line_buf_len = 2 * line_len;
2725 callback_args.header_line_buf = (char *)g_realloc(callback_args.header_line_buf,
2726 callback_args.header_line_buf_len + 1);
2727 cp = callback_args.header_line_buf + cp_off;
2730 /* Right-justify the packet number column. */
2731 /* if (cf->cinfo.col_fmt[i] == COL_NUMBER || cf->cinfo.col_fmt[i] == COL_NUMBER_DIS)
2732 snprintf(cp, column_len+1, "%*s", callback_args.col_widths[visible_col_count], cf->cinfo.columns[i].col_title);
2733 else*/
2734 snprintf(cp, column_len+1, "%-*s", callback_args.col_widths[visible_col_count], cf->cinfo.columns[i].col_title);
2735 cp += column_len;
2736 if (i != cf->cinfo.num_cols - 1)
2737 *cp++ = ' ';
2739 visible_col_count++;
2741 *cp = '\0';
2743 /* Now start out the main line buffer with the same length as the
2744 header line buffer. */
2745 callback_args.line_buf_len = callback_args.header_line_buf_len;
2746 callback_args.line_buf = (char *)g_malloc(callback_args.line_buf_len + 1);
2747 } /* if (print_summary) */
2749 /* Create the protocol tree, and make it visible, if we're printing
2750 the dissection or the hex data.
2751 XXX - do we need it if we're just printing the hex data? */
2752 proto_tree_needed =
2753 callback_args.print_args->print_dissections != print_dissections_none ||
2754 callback_args.print_args->print_hex ||
2755 have_custom_cols(&cf->cinfo) || have_field_extractors();
2756 epan_dissect_init(&callback_args.edt, cf->epan, proto_tree_needed, proto_tree_needed);
2758 /* Iterate through the list of packets, printing the packets we were
2759 told to print. */
2760 ret = process_specified_records(cf, &print_args->range, "Printing",
2761 "selected packets", true, print_packet,
2762 &callback_args, show_progress_bar);
2763 epan_dissect_cleanup(&callback_args.edt);
2764 g_free(callback_args.header_line_buf);
2765 g_free(callback_args.line_buf);
2766 g_free(callback_args.col_widths);
2767 g_free(callback_args.visible_cols);
2769 switch (ret) {
2771 case PSP_FINISHED:
2772 /* Completed successfully. */
2773 break;
2775 case PSP_STOPPED:
2776 /* Well, the user decided to abort the printing.
2778 XXX - note that what got generated before they did that
2779 will get printed if we're piping to a print program; we'd
2780 have to write to a file and then hand that to the print
2781 program to make it actually not print anything. */
2782 break;
2784 case PSP_FAILED:
2785 /* Error while printing.
2787 XXX - note that what got generated before they did that
2788 will get printed if we're piping to a print program; we'd
2789 have to write to a file and then hand that to the print
2790 program to make it actually not print anything. */
2791 destroy_print_stream(print_args->stream);
2792 return CF_PRINT_WRITE_ERROR;
2795 if (!print_finale(print_args->stream)) {
2796 destroy_print_stream(print_args->stream);
2797 return CF_PRINT_WRITE_ERROR;
2800 if (!destroy_print_stream(print_args->stream))
2801 return CF_PRINT_WRITE_ERROR;
2803 return CF_PRINT_OK;
2806 typedef struct {
2807 FILE *fh;
2808 epan_dissect_t edt;
2809 print_args_t *print_args;
2810 json_dumper jdumper;
2811 } write_packet_callback_args_t;
2813 static bool
2814 write_pdml_packet(capture_file *cf, frame_data *fdata, wtap_rec *rec,
2815 void *argsp)
2817 write_packet_callback_args_t *args = (write_packet_callback_args_t *)argsp;
2819 /* Create the protocol tree, but don't fill in the column information. */
2820 epan_dissect_run(&args->edt, cf->cd_t, rec, fdata, NULL);
2822 /* Write out the information in that tree. */
2823 write_pdml_proto_tree(NULL, &args->edt, &cf->cinfo, args->fh, false);
2825 epan_dissect_reset(&args->edt);
2827 return !ferror(args->fh);
2830 cf_print_status_t
2831 cf_write_pdml_packets(capture_file *cf, print_args_t *print_args)
2833 write_packet_callback_args_t callback_args;
2834 FILE *fh;
2835 psp_return_t ret;
2837 fh = ws_fopen(print_args->file, "w");
2838 if (fh == NULL)
2839 return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
2841 write_pdml_preamble(fh, cf->filename);
2842 if (ferror(fh)) {
2843 fclose(fh);
2844 return CF_PRINT_WRITE_ERROR;
2847 callback_args.fh = fh;
2848 callback_args.print_args = print_args;
2849 epan_dissect_init(&callback_args.edt, cf->epan, true, true);
2851 /* Iterate through the list of packets, printing the packets we were
2852 told to print. */
2853 ret = process_specified_records(cf, &print_args->range, "Writing PDML",
2854 "selected packets", true,
2855 write_pdml_packet, &callback_args, true);
2857 epan_dissect_cleanup(&callback_args.edt);
2859 switch (ret) {
2861 case PSP_FINISHED:
2862 /* Completed successfully. */
2863 break;
2865 case PSP_STOPPED:
2866 /* Well, the user decided to abort the printing. */
2867 break;
2869 case PSP_FAILED:
2870 /* Error while printing. */
2871 fclose(fh);
2872 return CF_PRINT_WRITE_ERROR;
2875 write_pdml_finale(fh);
2876 if (ferror(fh)) {
2877 fclose(fh);
2878 return CF_PRINT_WRITE_ERROR;
2881 /* XXX - check for an error */
2882 fclose(fh);
2884 return CF_PRINT_OK;
2887 static bool
2888 write_psml_packet(capture_file *cf, frame_data *fdata, wtap_rec *rec,
2889 void *argsp)
2891 write_packet_callback_args_t *args = (write_packet_callback_args_t *)argsp;
2893 /* Fill in the column information */
2894 col_custom_prime_edt(&args->edt, &cf->cinfo);
2895 epan_dissect_run(&args->edt, cf->cd_t, rec, fdata, &cf->cinfo);
2896 epan_dissect_fill_in_columns(&args->edt, false, true);
2898 /* Write out the column information. */
2899 write_psml_columns(&args->edt, args->fh, false);
2901 epan_dissect_reset(&args->edt);
2903 return !ferror(args->fh);
2906 cf_print_status_t
2907 cf_write_psml_packets(capture_file *cf, print_args_t *print_args)
2909 write_packet_callback_args_t callback_args;
2910 FILE *fh;
2911 psp_return_t ret;
2913 bool proto_tree_needed;
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_psml_preamble(&cf->cinfo, fh);
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;
2928 /* Fill in the column information, only create the protocol tree
2929 if having custom columns or field extractors. */
2930 proto_tree_needed = have_custom_cols(&cf->cinfo) || have_field_extractors();
2931 epan_dissect_init(&callback_args.edt, cf->epan, proto_tree_needed, proto_tree_needed);
2933 /* Iterate through the list of packets, printing the packets we were
2934 told to print. */
2935 ret = process_specified_records(cf, &print_args->range, "Writing PSML",
2936 "selected packets", true,
2937 write_psml_packet, &callback_args, true);
2939 epan_dissect_cleanup(&callback_args.edt);
2941 switch (ret) {
2943 case PSP_FINISHED:
2944 /* Completed successfully. */
2945 break;
2947 case PSP_STOPPED:
2948 /* Well, the user decided to abort the printing. */
2949 break;
2951 case PSP_FAILED:
2952 /* Error while printing. */
2953 fclose(fh);
2954 return CF_PRINT_WRITE_ERROR;
2957 write_psml_finale(fh);
2958 if (ferror(fh)) {
2959 fclose(fh);
2960 return CF_PRINT_WRITE_ERROR;
2963 /* XXX - check for an error */
2964 fclose(fh);
2966 return CF_PRINT_OK;
2969 static bool
2970 write_csv_packet(capture_file *cf, frame_data *fdata, wtap_rec *rec,
2971 void *argsp)
2973 write_packet_callback_args_t *args = (write_packet_callback_args_t *)argsp;
2975 col_custom_prime_edt(&args->edt, &cf->cinfo);
2976 epan_dissect_run(&args->edt, cf->cd_t, rec, fdata, &cf->cinfo);
2977 epan_dissect_fill_in_columns(&args->edt, false, true);
2979 /* Write out the column information. */
2980 write_csv_columns(&args->edt, args->fh);
2982 epan_dissect_reset(&args->edt);
2984 return !ferror(args->fh);
2987 cf_print_status_t
2988 cf_write_csv_packets(capture_file *cf, print_args_t *print_args)
2990 write_packet_callback_args_t callback_args;
2991 bool proto_tree_needed;
2992 FILE *fh;
2993 psp_return_t ret;
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_csv_column_titles(&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 /* only create the protocol tree if having custom columns or field extractors. */
3009 proto_tree_needed = have_custom_cols(&cf->cinfo) || have_field_extractors();
3010 epan_dissect_init(&callback_args.edt, cf->epan, proto_tree_needed, proto_tree_needed);
3012 /* Iterate through the list of packets, printing the packets we were
3013 told to print. */
3014 ret = process_specified_records(cf, &print_args->range, "Writing CSV",
3015 "selected packets", true,
3016 write_csv_packet, &callback_args, true);
3018 epan_dissect_cleanup(&callback_args.edt);
3020 switch (ret) {
3022 case PSP_FINISHED:
3023 /* Completed successfully. */
3024 break;
3026 case PSP_STOPPED:
3027 /* Well, the user decided to abort the printing. */
3028 break;
3030 case PSP_FAILED:
3031 /* Error while printing. */
3032 fclose(fh);
3033 return CF_PRINT_WRITE_ERROR;
3036 /* XXX - check for an error */
3037 fclose(fh);
3039 return CF_PRINT_OK;
3042 static bool
3043 carrays_write_packet(capture_file *cf, frame_data *fdata, wtap_rec *rec,
3044 void *argsp)
3046 write_packet_callback_args_t *args = (write_packet_callback_args_t *)argsp;
3048 epan_dissect_run(&args->edt, cf->cd_t, rec, fdata, NULL);
3049 write_carrays_hex_data(fdata->num, args->fh, &args->edt);
3050 epan_dissect_reset(&args->edt);
3052 return !ferror(args->fh);
3055 cf_print_status_t
3056 cf_write_carrays_packets(capture_file *cf, print_args_t *print_args)
3058 write_packet_callback_args_t callback_args;
3059 FILE *fh;
3060 psp_return_t ret;
3062 fh = ws_fopen(print_args->file, "w");
3064 if (fh == NULL)
3065 return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
3067 if (ferror(fh)) {
3068 fclose(fh);
3069 return CF_PRINT_WRITE_ERROR;
3072 callback_args.fh = fh;
3073 callback_args.print_args = print_args;
3074 epan_dissect_init(&callback_args.edt, cf->epan, true, true);
3076 /* Iterate through the list of packets, printing the packets we were
3077 told to print. */
3078 ret = process_specified_records(cf, &print_args->range,
3079 "Writing C Arrays",
3080 "selected packets", true,
3081 carrays_write_packet, &callback_args, true);
3083 epan_dissect_cleanup(&callback_args.edt);
3085 switch (ret) {
3086 case PSP_FINISHED:
3087 /* Completed successfully. */
3088 break;
3089 case PSP_STOPPED:
3090 /* Well, the user decided to abort the printing. */
3091 break;
3092 case PSP_FAILED:
3093 /* Error while printing. */
3094 fclose(fh);
3095 return CF_PRINT_WRITE_ERROR;
3098 fclose(fh);
3099 return CF_PRINT_OK;
3102 static bool
3103 write_json_packet(capture_file *cf, frame_data *fdata, wtap_rec *rec,
3104 void *argsp)
3106 write_packet_callback_args_t *args = (write_packet_callback_args_t *)argsp;
3108 /* Create the protocol tree, but don't fill in the column information. */
3109 epan_dissect_run(&args->edt, cf->cd_t, rec, fdata, NULL);
3111 /* Write out the information in that tree. */
3112 write_json_proto_tree(NULL, args->print_args->print_dissections,
3113 args->print_args->print_hex,
3114 &args->edt, &cf->cinfo, proto_node_group_children_by_unique,
3115 &args->jdumper);
3117 epan_dissect_reset(&args->edt);
3119 return !ferror(args->fh);
3122 cf_print_status_t
3123 cf_write_json_packets(capture_file *cf, print_args_t *print_args)
3125 write_packet_callback_args_t callback_args;
3126 FILE *fh;
3127 psp_return_t ret;
3129 fh = ws_fopen(print_args->file, "w");
3130 if (fh == NULL)
3131 return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
3133 callback_args.jdumper = write_json_preamble(fh);
3134 if (ferror(fh)) {
3135 fclose(fh);
3136 return CF_PRINT_WRITE_ERROR;
3139 callback_args.fh = fh;
3140 callback_args.print_args = print_args;
3141 epan_dissect_init(&callback_args.edt, cf->epan, true, true);
3143 /* Iterate through the list of packets, printing the packets we were
3144 told to print. */
3145 ret = process_specified_records(cf, &print_args->range, "Writing JSON",
3146 "selected packets", true,
3147 write_json_packet, &callback_args, true);
3149 epan_dissect_cleanup(&callback_args.edt);
3151 switch (ret) {
3153 case PSP_FINISHED:
3154 /* Completed successfully. */
3155 break;
3157 case PSP_STOPPED:
3158 /* Well, the user decided to abort the printing. */
3159 break;
3161 case PSP_FAILED:
3162 /* Error while printing. */
3163 fclose(fh);
3164 return CF_PRINT_WRITE_ERROR;
3167 write_json_finale(&callback_args.jdumper);
3168 if (ferror(fh)) {
3169 fclose(fh);
3170 return CF_PRINT_WRITE_ERROR;
3173 /* XXX - check for an error */
3174 fclose(fh);
3176 return CF_PRINT_OK;
3179 bool
3180 cf_find_packet_protocol_tree(capture_file *cf, const char *string,
3181 search_direction dir, bool multiple)
3183 match_data mdata;
3185 mdata.frame_matched = false;
3186 mdata.halt = false;
3187 mdata.string = string;
3188 mdata.string_len = strlen(string);
3189 mdata.cf = cf;
3190 mdata.prev_finfo = cf->finfo_selected;
3191 if (multiple && cf->finfo_selected && cf->edt) {
3192 if (dir == SD_FORWARD) {
3193 proto_tree_children_foreach(cf->edt->tree, match_subtree_text, &mdata);
3194 } else {
3195 proto_tree_children_foreach(cf->edt->tree, match_subtree_text_reverse, &mdata);
3197 if (mdata.frame_matched) {
3198 packet_list_select_finfo(mdata.finfo);
3199 return true;
3202 return find_packet(cf, match_protocol_tree, &mdata, dir, true);
3205 field_info*
3206 cf_find_string_protocol_tree(capture_file *cf, proto_tree *tree)
3208 match_data mdata;
3209 mdata.frame_matched = false;
3210 mdata.halt = false;
3211 mdata.string = convert_string_case(cf->sfilter, cf->case_type);
3212 mdata.string_len = strlen(mdata.string);
3213 mdata.cf = cf;
3214 mdata.prev_finfo = NULL;
3215 /* Iterate through all the nodes looking for matching text */
3216 if (cf->dir == SD_FORWARD) {
3217 proto_tree_children_foreach(tree, match_subtree_text, &mdata);
3218 } else {
3219 proto_tree_children_foreach(tree, match_subtree_text_reverse, &mdata);
3221 g_free((char *)mdata.string);
3222 return mdata.frame_matched ? mdata.finfo : NULL;
3225 static match_result
3226 match_protocol_tree(capture_file *cf, frame_data *fdata,
3227 wtap_rec *rec, void *criterion)
3229 match_data *mdata = (match_data *)criterion;
3230 epan_dissect_t edt;
3232 /* Load the frame's data. */
3233 if (!cf_read_record(cf, fdata, rec)) {
3234 /* Attempt to get the packet failed. */
3235 return MR_ERROR;
3238 /* Construct the protocol tree, including the displayed text */
3239 epan_dissect_init(&edt, cf->epan, true, true);
3240 /* We don't need the column information */
3241 epan_dissect_run(&edt, cf->cd_t, rec, fdata, NULL);
3243 /* Iterate through all the nodes, seeing if they have text that matches. */
3244 mdata->cf = cf;
3245 mdata->frame_matched = false;
3246 mdata->halt = false;
3247 mdata->prev_finfo = NULL;
3248 /* We don't care about the direction here, because we're just looking
3249 * for one match and we'll destroy this tree anyway. (We find the actual
3250 * field later in PacketList::selectionChanged().) Forwards is faster.
3252 proto_tree_children_foreach(edt.tree, match_subtree_text, mdata);
3253 epan_dissect_cleanup(&edt);
3254 return mdata->frame_matched ? MR_MATCHED : MR_NOTMATCHED;
3257 static void
3258 match_subtree_text(proto_node *node, void *data)
3260 match_data *mdata = (match_data *) data;
3261 const char *string = mdata->string;
3262 size_t string_len = mdata->string_len;
3263 capture_file *cf = mdata->cf;
3264 field_info *fi = PNODE_FINFO(node);
3265 char label_str[ITEM_LABEL_LENGTH];
3266 char *label_ptr;
3267 size_t label_len;
3268 uint32_t i, i_restart;
3269 uint8_t c_char;
3270 size_t c_match = 0;
3272 /* dissection with an invisible proto tree? */
3273 ws_assert(fi);
3275 if (mdata->frame_matched) {
3276 /* We already had a match; don't bother doing any more work. */
3277 return;
3280 /* Don't match invisible entries. */
3281 if (proto_item_is_hidden(node))
3282 return;
3284 if (mdata->prev_finfo) {
3285 /* Haven't found the old match, so don't match this node. */
3286 if (fi == mdata->prev_finfo) {
3287 /* Found the old match, look for the next one after this. */
3288 mdata->prev_finfo = NULL;
3290 } else {
3291 /* was a free format label produced? */
3292 if (fi->rep) {
3293 label_ptr = fi->rep->representation;
3294 } else {
3295 /* no, make a generic label */
3296 label_ptr = label_str;
3297 proto_item_fill_label(fi, label_str, NULL);
3300 if (cf->regex) {
3301 if (ws_regex_matches(cf->regex, label_ptr)) {
3302 mdata->frame_matched = true;
3303 mdata->finfo = fi;
3304 return;
3306 } else if (cf->case_type) {
3307 /* Case insensitive match */
3308 label_len = strlen(label_ptr);
3309 i_restart = 0;
3310 for (i = 0; i < label_len; i++) {
3311 if (i_restart == 0 && c_match == 0 && (label_len - i < string_len))
3312 break;
3313 c_char = label_ptr[i];
3314 c_char = g_ascii_toupper(c_char);
3315 /* If c_match is non-zero, save candidate for retrying full match. */
3316 if (c_match > 0 && i_restart == 0 && c_char == string[0])
3317 i_restart = i;
3318 if (c_char == string[c_match]) {
3319 c_match++;
3320 if (c_match == string_len) {
3321 mdata->frame_matched = true;
3322 mdata->finfo = fi;
3323 /* No need to look further; we have a match */
3324 return;
3326 } else if (i_restart) {
3327 i = i_restart;
3328 c_match = 1;
3329 i_restart = 0;
3330 } else
3331 c_match = 0;
3333 } else if (strstr(label_ptr, string) != NULL) {
3334 /* Case sensitive match */
3335 mdata->frame_matched = true;
3336 mdata->finfo = fi;
3337 return;
3341 /* Recurse into the subtree, if it exists */
3342 if (node->first_child != NULL)
3343 proto_tree_children_foreach(node, match_subtree_text, mdata);
3346 static void
3347 match_subtree_text_reverse(proto_node *node, void *data)
3349 match_data *mdata = (match_data *) data;
3350 const char *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 char label_str[ITEM_LABEL_LENGTH];
3355 char *label_ptr;
3356 size_t label_len;
3357 uint32_t i, i_restart;
3358 uint8_t c_char;
3359 size_t c_match = 0;
3361 /* dissection with an invisible proto tree? */
3362 ws_assert(fi);
3364 /* We don't have an easy way to search backwards in the tree
3365 * (see also, proto_find_field_from_offset()) because we don't
3366 * have a previous node pointer, so we search backwards by
3367 * searching forwards, only stopping if we see the old match
3368 * (if we have one).
3371 if (mdata->halt) {
3372 return;
3375 /* Don't match invisible entries. */
3376 if (proto_item_is_hidden(node))
3377 return;
3379 if (mdata->prev_finfo && fi == mdata->prev_finfo) {
3380 /* Found the old match, use the previous match. */
3381 mdata->halt = true;
3382 return;
3385 /* was a free format label produced? */
3386 if (fi->rep) {
3387 label_ptr = fi->rep->representation;
3388 } else {
3389 /* no, make a generic label */
3390 label_ptr = label_str;
3391 proto_item_fill_label(fi, label_str, NULL);
3394 if (cf->regex) {
3395 if (ws_regex_matches(cf->regex, label_ptr)) {
3396 mdata->frame_matched = true;
3397 mdata->finfo = fi;
3399 } else if (cf->case_type) {
3400 /* Case insensitive match */
3401 label_len = strlen(label_ptr);
3402 i_restart = 0;
3403 for (i = 0; i < label_len; i++) {
3404 if (i_restart == 0 && c_match == 0 && (label_len - i < string_len))
3405 break;
3406 c_char = label_ptr[i];
3407 c_char = g_ascii_toupper(c_char);
3408 /* If c_match is non-zero, save candidate for retrying full match. */
3409 if (c_match > 0 && i_restart == 0 && c_char == string[0])
3410 i_restart = i;
3411 if (c_char == string[c_match]) {
3412 c_match++;
3413 if (c_match == string_len) {
3414 mdata->frame_matched = true;
3415 mdata->finfo = fi;
3416 break;
3418 } else if (i_restart) {
3419 i = i_restart;
3420 c_match = 1;
3421 i_restart = 0;
3422 } else
3423 c_match = 0;
3425 } else if (strstr(label_ptr, string) != NULL) {
3426 /* Case sensitive match */
3427 mdata->frame_matched = true;
3428 mdata->finfo = fi;
3431 /* Recurse into the subtree, if it exists */
3432 if (node->first_child != NULL)
3433 proto_tree_children_foreach(node, match_subtree_text_reverse, mdata);
3436 bool
3437 cf_find_packet_summary_line(capture_file *cf, const char *string,
3438 search_direction dir)
3440 match_data mdata;
3442 mdata.string = string;
3443 mdata.string_len = strlen(string);
3444 return find_packet(cf, match_summary_line, &mdata, dir, true);
3447 static match_result
3448 match_summary_line(capture_file *cf, frame_data *fdata,
3449 wtap_rec *rec, void *criterion)
3451 match_data *mdata = (match_data *)criterion;
3452 const char *string = mdata->string;
3453 size_t string_len = mdata->string_len;
3454 epan_dissect_t edt;
3455 const char *info_column;
3456 size_t info_column_len;
3457 match_result result = MR_NOTMATCHED;
3458 int colx;
3459 uint32_t i, i_restart;
3460 uint8_t c_char;
3461 size_t c_match = 0;
3463 /* Load the frame's data. */
3464 if (!cf_read_record(cf, fdata, rec)) {
3465 /* Attempt to get the packet failed. */
3466 return MR_ERROR;
3469 /* Don't bother constructing the protocol tree */
3470 epan_dissect_init(&edt, cf->epan, false, false);
3471 /* Get the column information */
3472 epan_dissect_run(&edt, cf->cd_t, rec, fdata, &cf->cinfo);
3474 /* Find the Info column */
3475 for (colx = 0; colx < cf->cinfo.num_cols; colx++) {
3476 if (cf->cinfo.columns[colx].fmt_matx[COL_INFO]) {
3477 /* Found it. See if we match. */
3478 info_column = get_column_text(edt.pi.cinfo, colx);
3479 info_column_len = strlen(info_column);
3480 if (cf->regex) {
3481 if (ws_regex_matches(cf->regex, info_column)) {
3482 result = MR_MATCHED;
3483 break;
3485 } else if (cf->case_type) {
3486 /* Case insensitive match */
3487 i_restart = 0;
3488 for (i = 0; i < info_column_len; i++) {
3489 if (i_restart == 0 && c_match == 0 && (info_column_len - i < string_len))
3490 break;
3491 c_char = info_column[i];
3492 c_char = g_ascii_toupper(c_char);
3493 /* If c_match is non-zero, save candidate for retrying full match. */
3494 if (c_match > 0 && i_restart == 0 && c_char == string[0])
3495 i_restart = i;
3496 if (c_char == string[c_match]) {
3497 c_match++;
3498 if (c_match == string_len) {
3499 result = MR_MATCHED;
3500 break;
3502 } else if (i_restart) {
3503 i = i_restart;
3504 c_match = 1;
3505 i_restart = 0;
3506 } else
3507 c_match = 0;
3509 } else if (strstr(info_column, string) != NULL) {
3510 /* Case sensitive match */
3511 result = MR_MATCHED;
3513 break;
3516 epan_dissect_cleanup(&edt);
3517 return result;
3520 typedef struct {
3521 const uint8_t *data;
3522 size_t data_len;
3523 ws_mempbrk_pattern *pattern;
3524 } cbs_t; /* "Counted byte string" */
3528 * The current match_* routines only support ASCII case insensitivity and don't
3529 * convert UTF-8 inputs to UTF-16 for matching. The UTF-16 support just
3530 * interleaves with \0 bytes, which works for 7 bit ASCII.
3532 * We could modify them to use the GLib Unicode routines or the International
3533 * Components for Unicode library but it's not apparent that we could do so
3534 * without consuming a lot more CPU and memory or that searching would be
3535 * significantly better.
3537 * XXX: We could test the search string to see if it's all ASCII, and if not
3538 * use Unicode aware routines for case insensitive searches or any UTF-16
3539 * search.
3542 bool
3543 cf_find_packet_data(capture_file *cf, const uint8_t *string, size_t string_size,
3544 search_direction dir, bool multiple)
3546 cbs_t info;
3547 uint8_t needles[3];
3548 ws_mempbrk_pattern pattern = {0};
3549 ws_match_function match_function;
3551 info.data = string;
3552 info.data_len = string_size;
3554 /* Regex, String or hex search? */
3555 if (cf->regex) {
3556 /* Regular Expression search */
3557 match_function = (dir == SD_FORWARD) ? match_regex : match_regex_reverse;
3558 } else if (cf->string) {
3559 /* String search - what type of string? */
3560 if (cf->case_type) {
3561 needles[0] = string[0];
3562 needles[1] = g_ascii_tolower(needles[0]);
3563 needles[2] = '\0';
3564 ws_mempbrk_compile(&pattern, needles);
3565 info.pattern = &pattern;
3566 switch (cf->scs_type) {
3568 case SCS_NARROW_AND_WIDE:
3569 match_function = (dir == SD_FORWARD) ? match_narrow_and_wide_case : match_narrow_and_wide_case_reverse;
3570 break;
3572 case SCS_NARROW:
3573 match_function = (dir == SD_FORWARD) ? match_narrow_case : match_narrow_case_reverse;
3574 break;
3576 case SCS_WIDE:
3577 match_function = (dir == SD_FORWARD) ? match_wide_case : match_wide_case_reverse;
3578 break;
3580 default:
3581 ws_assert_not_reached();
3582 return false;
3585 } else {
3586 switch (cf->scs_type) {
3588 case SCS_NARROW_AND_WIDE:
3589 match_function = (dir == SD_FORWARD) ? match_narrow_and_wide : match_narrow_and_wide_reverse;
3590 break;
3592 case SCS_NARROW:
3593 /* Narrow, case-sensitive match is the same as looking
3594 * for a converted hexstring. */
3595 match_function = (dir == SD_FORWARD) ? match_binary : match_binary_reverse;
3596 break;
3598 case SCS_WIDE:
3599 match_function = (dir == SD_FORWARD) ? match_wide : match_wide_reverse;
3600 break;
3602 default:
3603 ws_assert_not_reached();
3604 return false;
3607 } else {
3608 match_function = (dir == SD_FORWARD) ? match_binary : match_binary_reverse;
3611 if (multiple && cf->current_frame && (cf->search_pos || cf->search_len)) {
3612 /* Use the current frame (this will perform the equivalent of
3613 * cf_read_current_record() in match_function).
3615 if (match_function(cf, cf->current_frame, &cf->rec, &info)) {
3616 cf->search_in_progress = true;
3617 if (cf->edt) {
3618 field_info *fi = NULL;
3619 /* The regex match can match an empty string. */
3620 if (cf->search_len) {
3621 fi = proto_find_field_from_offset(cf->edt->tree, cf->search_pos + cf->search_len - 1, cf->edt->tvb);
3623 packet_list_select_finfo(fi);
3624 } else {
3625 packet_list_select_row_from_data(cf->current_frame);
3627 cf->search_in_progress = false;
3628 return true;
3631 cf->search_pos = 0; /* Reset the position */
3632 cf->search_len = 0; /* Reset length */
3633 return find_packet(cf, match_function, &info, dir, true);
3636 static match_result
3637 match_narrow_and_wide(capture_file *cf, frame_data *fdata,
3638 wtap_rec *rec, void *criterion)
3640 cbs_t *info = (cbs_t *)criterion;
3641 const uint8_t *ascii_text = info->data;
3642 size_t textlen = info->data_len;
3643 match_result result;
3644 uint32_t buf_len;
3645 const uint8_t *pd, *buf_start, *buf_end;
3646 uint32_t i;
3647 uint8_t c_char;
3648 size_t c_match = 0;
3650 /* Load the frame's data. */
3651 if (!cf_read_record(cf, fdata, rec)) {
3652 /* Attempt to get the packet failed. */
3653 return MR_ERROR;
3656 result = MR_NOTMATCHED;
3657 buf_len = fdata->cap_len;
3658 buf_start = ws_buffer_start_ptr(&rec->data);
3659 buf_end = buf_start + buf_len;
3660 pd = buf_start;
3661 if (cf->search_len || cf->search_pos) {
3662 /* we want to start searching one byte past the previous match start */
3663 pd += cf->search_pos + 1;
3665 for (; pd < buf_end; pd++) {
3666 pd = (uint8_t *)memchr(pd, ascii_text[0], buf_end - pd);
3667 if (pd == NULL) break;
3668 /* Try narrow match at this start location */
3669 c_match = 0;
3670 for (i = 0; pd + i < buf_end; i++) {
3671 c_char = pd[i];
3672 if (c_char == ascii_text[c_match]) {
3673 c_match++;
3674 if (c_match == textlen) {
3675 result = MR_MATCHED;
3676 /* Save position and length for highlighting the field. */
3677 cf->search_pos = (uint32_t)(pd - buf_start);
3678 cf->search_len = (uint32_t)(i + 1);
3679 goto done;
3681 } else {
3682 break;
3686 /* Now try wide match at the same start location. */
3687 c_match = 0;
3688 for (i = 0; pd + i < buf_end; i++) {
3689 c_char = pd[i];
3690 if (c_char == ascii_text[c_match]) {
3691 c_match++;
3692 if (c_match == textlen) {
3693 result = MR_MATCHED;
3694 /* Save position and length for highlighting the field. */
3695 cf->search_pos = (uint32_t)(pd - buf_start);
3696 cf->search_len = (uint32_t)(i + 1);
3697 goto done;
3699 i++;
3700 if (pd + i >= buf_end || pd[i] != '\0') break;
3701 } else {
3702 break;
3707 done:
3708 return result;
3711 static match_result
3712 match_narrow_and_wide_reverse(capture_file *cf, frame_data *fdata,
3713 wtap_rec *rec, void *criterion)
3715 cbs_t *info = (cbs_t *)criterion;
3716 const uint8_t *ascii_text = info->data;
3717 size_t textlen = info->data_len;
3718 match_result result;
3719 uint32_t buf_len;
3720 const uint8_t *pd, *buf_start, *buf_end;
3721 uint32_t i;
3722 uint8_t c_char;
3723 size_t c_match = 0;
3725 /* Load the frame's data. */
3726 if (!cf_read_record(cf, fdata, rec)) {
3727 /* Attempt to get the packet failed. */
3728 return MR_ERROR;
3731 result = MR_NOTMATCHED;
3732 /* Has to be room to hold the sought data. */
3733 if (textlen > fdata->cap_len) {
3734 return result;
3736 buf_len = fdata->cap_len;
3737 buf_start = ws_buffer_start_ptr(&rec->data);
3738 buf_end = buf_start + buf_len;
3739 pd = buf_end - textlen;
3740 if (cf->search_len || cf->search_pos) {
3741 /* we want to start searching one byte before the previous match start */
3742 pd = buf_start + cf->search_pos - 1;
3744 for (; pd < buf_end; pd++) {
3745 pd = (uint8_t *)ws_memrchr(buf_start, ascii_text[0], pd - buf_start + 1);
3746 if (pd == NULL) break;
3747 /* Try narrow match at this start location */
3748 c_match = 0;
3749 for (i = 0; pd + i < buf_end; i++) {
3750 c_char = pd[i];
3751 if (c_char == ascii_text[c_match]) {
3752 c_match++;
3753 if (c_match == textlen) {
3754 result = MR_MATCHED;
3755 /* Save position and length for highlighting the field. */
3756 cf->search_pos = (uint32_t)(pd - buf_start);
3757 cf->search_len = (uint32_t)(i + 1);
3758 goto done;
3760 } else {
3761 break;
3765 /* Now try wide match at the same start location. */
3766 c_match = 0;
3767 for (i = 0; pd + i < buf_end; i++) {
3768 c_char = pd[i];
3769 if (c_char == ascii_text[c_match]) {
3770 c_match++;
3771 if (c_match == textlen) {
3772 result = MR_MATCHED;
3773 /* Save position and length for highlighting the field. */
3774 cf->search_pos = (uint32_t)(pd - buf_start);
3775 cf->search_len = (uint32_t)(i + 1);
3776 goto done;
3778 i++;
3779 if (pd + i >= buf_end || pd[i] != '\0') break;
3780 } else {
3781 break;
3786 done:
3787 return result;
3790 /* Case insensitive match */
3791 static match_result
3792 match_narrow_and_wide_case(capture_file *cf, frame_data *fdata,
3793 wtap_rec *rec, void *criterion)
3795 cbs_t *info = (cbs_t *)criterion;
3796 const uint8_t *ascii_text = info->data;
3797 size_t textlen = info->data_len;
3798 ws_mempbrk_pattern *pattern = info->pattern;
3799 match_result result;
3800 uint32_t buf_len;
3801 const uint8_t *pd, *buf_start, *buf_end;
3802 uint32_t i;
3803 uint8_t c_char;
3804 size_t c_match = 0;
3806 /* Load the frame's data. */
3807 if (!cf_read_record(cf, fdata, rec)) {
3808 /* Attempt to get the packet failed. */
3809 return MR_ERROR;
3812 ws_assert(pattern != NULL);
3814 result = MR_NOTMATCHED;
3815 buf_len = fdata->cap_len;
3816 buf_start = ws_buffer_start_ptr(&rec->data);
3817 buf_end = buf_start + buf_len;
3818 pd = buf_start;
3819 if (cf->search_len || cf->search_pos) {
3820 /* we want to start searching one byte past the previous match start */
3821 pd += cf->search_pos + 1;
3823 for (; pd < buf_end; pd++) {
3824 pd = (uint8_t *)ws_mempbrk_exec(pd, buf_end - pd, pattern, &c_char);
3825 if (pd == NULL) break;
3826 /* Try narrow match at this start location */
3827 c_match = 0;
3828 for (i = 0; pd + i < buf_end; i++) {
3829 c_char = g_ascii_toupper(pd[i]);
3830 if (c_char == ascii_text[c_match]) {
3831 c_match++;
3832 if (c_match == textlen) {
3833 result = MR_MATCHED;
3834 /* Save position and length for highlighting the field. */
3835 cf->search_pos = (uint32_t)(pd - buf_start);
3836 cf->search_len = (uint32_t)(i + 1);
3837 goto done;
3839 } else {
3840 break;
3844 /* Now try wide match at the same start location. */
3845 c_match = 0;
3846 for (i = 0; pd + i < buf_end; i++) {
3847 c_char = g_ascii_toupper(pd[i]);
3848 if (c_char == ascii_text[c_match]) {
3849 c_match++;
3850 if (c_match == textlen) {
3851 result = MR_MATCHED;
3852 /* Save position and length for highlighting the field. */
3853 cf->search_pos = (uint32_t)(pd - buf_start);
3854 cf->search_len = (uint32_t)(i + 1);
3855 goto done;
3857 i++;
3858 if (pd + i >= buf_end || pd[i] != '\0') break;
3859 } else {
3860 break;
3865 done:
3866 return result;
3869 static match_result
3870 match_narrow_and_wide_case_reverse(capture_file *cf, frame_data *fdata,
3871 wtap_rec *rec, void *criterion)
3873 cbs_t *info = (cbs_t *)criterion;
3874 const uint8_t *ascii_text = info->data;
3875 size_t textlen = info->data_len;
3876 ws_mempbrk_pattern *pattern = info->pattern;
3877 match_result result;
3878 uint32_t buf_len;
3879 const uint8_t *pd, *buf_start, *buf_end;
3880 uint32_t i;
3881 uint8_t c_char;
3882 size_t c_match = 0;
3884 /* Load the frame's data. */
3885 if (!cf_read_record(cf, fdata, rec)) {
3886 /* Attempt to get the packet failed. */
3887 return MR_ERROR;
3890 ws_assert(pattern != NULL);
3892 result = MR_NOTMATCHED;
3893 /* Has to be room to hold the sought data. */
3894 if (textlen > fdata->cap_len) {
3895 return result;
3897 buf_len = fdata->cap_len;
3898 buf_start = ws_buffer_start_ptr(&rec->data);
3899 buf_end = buf_start + buf_len;
3900 pd = buf_end - textlen;
3901 if (cf->search_len || cf->search_pos) {
3902 /* we want to start searching one byte before the previous match start */
3903 pd = buf_start + cf->search_pos - 1;
3905 for (; pd >= buf_start; pd--) {
3906 pd = (uint8_t *)ws_memrpbrk_exec(buf_start, pd - buf_start + 1, pattern, &c_char);
3907 if (pd == NULL) break;
3908 /* Try narrow match at this start location */
3909 c_match = 0;
3910 for (i = 0; pd + i < buf_end; i++) {
3911 c_char = g_ascii_toupper(pd[i]);
3912 if (c_char == ascii_text[c_match]) {
3913 c_match++;
3914 if (c_match == textlen) {
3915 result = MR_MATCHED;
3916 /* Save position and length for highlighting the field. */
3917 cf->search_pos = (uint32_t)(pd - buf_start);
3918 cf->search_len = (uint32_t)(i + 1);
3919 goto done;
3921 } else {
3922 break;
3926 /* Now try wide match at the same start location. */
3927 c_match = 0;
3928 for (i = 0; pd + i < buf_end; i++) {
3929 c_char = g_ascii_toupper(pd[i]);
3930 if (c_char == ascii_text[c_match]) {
3931 c_match++;
3932 if (c_match == textlen) {
3933 result = MR_MATCHED;
3934 /* Save position and length for highlighting the field. */
3935 cf->search_pos = (uint32_t)(pd - buf_start);
3936 cf->search_len = (uint32_t)(i + 1);
3937 goto done;
3939 i++;
3940 if (pd + i >= buf_end || pd[i] != '\0') break;
3941 } else {
3942 break;
3947 done:
3948 return result;
3951 /* Case insensitive match */
3952 static match_result
3953 match_narrow_case(capture_file *cf, frame_data *fdata,
3954 wtap_rec *rec, void *criterion)
3956 cbs_t *info = (cbs_t *)criterion;
3957 const uint8_t *ascii_text = info->data;
3958 size_t textlen = info->data_len;
3959 ws_mempbrk_pattern *pattern = info->pattern;
3960 match_result result;
3961 uint32_t buf_len;
3962 const uint8_t *pd, *buf_start, *buf_end;
3963 uint32_t i;
3964 uint8_t c_char;
3965 size_t c_match = 0;
3967 /* Load the frame's data. */
3968 if (!cf_read_record(cf, fdata, rec)) {
3969 /* Attempt to get the packet failed. */
3970 return MR_ERROR;
3973 ws_assert(pattern != NULL);
3975 result = MR_NOTMATCHED;
3976 buf_len = fdata->cap_len;
3977 buf_start = ws_buffer_start_ptr(&rec->data);
3978 buf_end = buf_start + buf_len;
3979 pd = buf_start;
3980 if (cf->search_len || cf->search_pos) {
3981 /* we want to start searching one byte past the previous match start */
3982 pd += cf->search_pos + 1;
3984 for (; pd < buf_end; pd++) {
3985 pd = (uint8_t *)ws_mempbrk_exec(pd, buf_end - pd, pattern, &c_char);
3986 if (pd == NULL) break;
3987 c_match = 0;
3988 for (i = 0; pd + i < buf_end; i++) {
3989 c_char = g_ascii_toupper(pd[i]);
3990 if (c_char == ascii_text[c_match]) {
3991 c_match++;
3992 if (c_match == textlen) {
3993 /* Save position and length for highlighting the field. */
3994 result = MR_MATCHED;
3995 cf->search_pos = (uint32_t)(pd - buf_start);
3996 cf->search_len = (uint32_t)(i + 1);
3997 goto done;
3999 } else {
4000 break;
4005 done:
4006 return result;
4009 static match_result
4010 match_narrow_case_reverse(capture_file *cf, frame_data *fdata,
4011 wtap_rec *rec, void *criterion)
4013 cbs_t *info = (cbs_t *)criterion;
4014 const uint8_t *ascii_text = info->data;
4015 size_t textlen = info->data_len;
4016 ws_mempbrk_pattern *pattern = info->pattern;
4017 match_result result;
4018 uint32_t buf_len;
4019 const uint8_t *pd, *buf_start, *buf_end;
4020 uint32_t i;
4021 uint8_t c_char;
4022 size_t c_match = 0;
4024 /* Load the frame's data. */
4025 if (!cf_read_record(cf, fdata, rec)) {
4026 /* Attempt to get the packet failed. */
4027 return MR_ERROR;
4030 ws_assert(pattern != NULL);
4032 result = MR_NOTMATCHED;
4033 /* Has to be room to hold the sought data. */
4034 if (textlen > fdata->cap_len) {
4035 return result;
4037 buf_len = fdata->cap_len;
4038 buf_start = ws_buffer_start_ptr(&rec->data);
4039 buf_end = buf_start + buf_len;
4040 pd = buf_end - textlen;
4041 if (cf->search_len || cf->search_pos) {
4042 /* we want to start searching one byte before the previous match start */
4043 pd = buf_start + cf->search_pos - 1;
4045 for (; pd >= buf_start; pd--) {
4046 pd = (uint8_t *)ws_memrpbrk_exec(buf_start, pd - buf_start + 1, pattern, &c_char);
4047 if (pd == NULL) break;
4048 c_match = 0;
4049 for (i = 0; pd + i < buf_end; i++) {
4050 c_char = g_ascii_toupper(pd[i]);
4051 if (c_char == ascii_text[c_match]) {
4052 c_match++;
4053 if (c_match == textlen) {
4054 /* Save position and length for highlighting the field. */
4055 result = MR_MATCHED;
4056 cf->search_pos = (uint32_t)(pd - buf_start);
4057 cf->search_len = (uint32_t)(i + 1);
4058 goto done;
4060 } else {
4061 break;
4066 done:
4067 return result;
4070 static match_result
4071 match_wide(capture_file *cf, frame_data *fdata,
4072 wtap_rec *rec, void *criterion)
4074 cbs_t *info = (cbs_t *)criterion;
4075 const uint8_t *ascii_text = info->data;
4076 size_t textlen = info->data_len;
4077 match_result result;
4078 uint32_t buf_len;
4079 const uint8_t *pd, *buf_start, *buf_end;
4080 uint32_t i;
4081 uint8_t c_char;
4082 size_t c_match = 0;
4084 /* Load the frame's data. */
4085 if (!cf_read_record(cf, fdata, rec)) {
4086 /* Attempt to get the packet failed. */
4087 return MR_ERROR;
4090 result = MR_NOTMATCHED;
4091 buf_len = fdata->cap_len;
4092 buf_start = ws_buffer_start_ptr(&rec->data);
4093 buf_end = buf_start + buf_len;
4094 pd = buf_start;
4095 if (cf->search_len || cf->search_pos) {
4096 /* we want to start searching one byte past the previous match start */
4097 pd += cf->search_pos + 1;
4099 for (; pd < buf_end; pd++) {
4100 pd = (uint8_t *)memchr(pd, ascii_text[0], buf_end - pd);
4101 if (pd == NULL) break;
4102 c_match = 0;
4103 for (i = 0; pd + i < buf_end; i++) {
4104 c_char = pd[i];
4105 if (c_char == ascii_text[c_match]) {
4106 c_match++;
4107 if (c_match == textlen) {
4108 result = MR_MATCHED;
4109 /* Save position and length for highlighting the field. */
4110 cf->search_pos = (uint32_t)(pd - buf_start);
4111 cf->search_len = (uint32_t)(i + 1);
4112 goto done;
4114 i++;
4115 if (pd + i >= buf_end || pd[i] != '\0') break;
4116 } else {
4117 break;
4122 done:
4123 return result;
4126 static match_result
4127 match_wide_reverse(capture_file *cf, frame_data *fdata,
4128 wtap_rec *rec, void *criterion)
4130 cbs_t *info = (cbs_t *)criterion;
4131 const uint8_t *ascii_text = info->data;
4132 size_t textlen = info->data_len;
4133 match_result result;
4134 uint32_t buf_len;
4135 const uint8_t *pd, *buf_start, *buf_end;
4136 uint32_t i;
4137 uint8_t c_char;
4138 size_t c_match = 0;
4140 /* Load the frame's data. */
4141 if (!cf_read_record(cf, fdata, rec)) {
4142 /* Attempt to get the packet failed. */
4143 return MR_ERROR;
4146 result = MR_NOTMATCHED;
4147 /* Has to be room to hold the sought data. */
4148 if (textlen > fdata->cap_len) {
4149 return result;
4151 buf_len = fdata->cap_len;
4152 buf_start = ws_buffer_start_ptr(&rec->data);
4153 buf_end = buf_start + buf_len;
4154 pd = buf_end - textlen;
4155 if (cf->search_len || cf->search_pos) {
4156 /* we want to start searching one byte before the previous match start */
4157 pd = buf_start + cf->search_pos - 1;
4159 for (; pd < buf_end; pd++) {
4160 pd = (uint8_t *)ws_memrchr(buf_start, ascii_text[0], pd - buf_start + 1);
4161 if (pd == NULL) break;
4162 c_match = 0;
4163 for (i = 0; pd + i < buf_end; i++) {
4164 c_char = pd[i];
4165 if (c_char == ascii_text[c_match]) {
4166 c_match++;
4167 if (c_match == textlen) {
4168 result = MR_MATCHED;
4169 /* Save position and length for highlighting the field. */
4170 cf->search_pos = (uint32_t)(pd - buf_start);
4171 cf->search_len = (uint32_t)(i + 1);
4172 goto done;
4174 i++;
4175 if (pd + i >= buf_end || pd[i] != '\0') break;
4176 } else {
4177 break;
4182 done:
4183 return result;
4186 /* Case insensitive match */
4187 static match_result
4188 match_wide_case(capture_file *cf, frame_data *fdata,
4189 wtap_rec *rec, void *criterion)
4191 cbs_t *info = (cbs_t *)criterion;
4192 const uint8_t *ascii_text = info->data;
4193 size_t textlen = info->data_len;
4194 ws_mempbrk_pattern *pattern = info->pattern;
4195 match_result result;
4196 uint32_t buf_len;
4197 const uint8_t *pd, *buf_start, *buf_end;
4198 uint32_t i;
4199 uint8_t c_char;
4200 size_t c_match = 0;
4202 /* Load the frame's data. */
4203 if (!cf_read_record(cf, fdata, rec)) {
4204 /* Attempt to get the packet failed. */
4205 return MR_ERROR;
4208 ws_assert(pattern != NULL);
4210 result = MR_NOTMATCHED;
4211 buf_len = fdata->cap_len;
4212 buf_start = ws_buffer_start_ptr(&rec->data);
4213 buf_end = buf_start + buf_len;
4214 pd = buf_start;
4215 if (cf->search_len || cf->search_pos) {
4216 /* we want to start searching one byte past the previous match start */
4217 pd += cf->search_pos + 1;
4219 for (; pd < buf_end; pd++) {
4220 pd = (uint8_t *)ws_mempbrk_exec(pd, buf_end - pd, pattern, &c_char);
4221 if (pd == NULL) break;
4222 c_match = 0;
4223 for (i = 0; pd + i < buf_end; i++) {
4224 c_char = g_ascii_toupper(pd[i]);
4225 if (c_char == ascii_text[c_match]) {
4226 c_match++;
4227 if (c_match == textlen) {
4228 result = MR_MATCHED;
4229 /* Save position and length for highlighting the field. */
4230 cf->search_pos = (uint32_t)(pd - buf_start);
4231 cf->search_len = (uint32_t)(i + 1);
4232 goto done;
4234 i++;
4235 if (pd + i >= buf_end || pd[i] != '\0') break;
4236 } else {
4237 break;
4242 done:
4243 return result;
4246 /* Case insensitive match */
4247 static match_result
4248 match_wide_case_reverse(capture_file *cf, frame_data *fdata,
4249 wtap_rec *rec, void *criterion)
4251 cbs_t *info = (cbs_t *)criterion;
4252 const uint8_t *ascii_text = info->data;
4253 size_t textlen = info->data_len;
4254 ws_mempbrk_pattern *pattern = info->pattern;
4255 match_result result;
4256 uint32_t buf_len;
4257 const uint8_t *pd, *buf_start, *buf_end;
4258 uint32_t i;
4259 uint8_t c_char;
4260 size_t c_match = 0;
4262 /* Load the frame's data. */
4263 if (!cf_read_record(cf, fdata, rec)) {
4264 /* Attempt to get the packet failed. */
4265 return MR_ERROR;
4268 ws_assert(pattern != NULL);
4270 result = MR_NOTMATCHED;
4271 /* Has to be room to hold the sought data. */
4272 if (textlen > fdata->cap_len) {
4273 return result;
4275 buf_len = fdata->cap_len;
4276 buf_start = ws_buffer_start_ptr(&rec->data);
4277 buf_end = buf_start + buf_len;
4278 pd = buf_end - textlen;
4279 if (cf->search_len || cf->search_pos) {
4280 /* we want to start searching one byte before the previous match start */
4281 pd = buf_start + cf->search_pos - 1;
4283 for (; pd >= buf_start; pd--) {
4284 pd = (uint8_t *)ws_memrpbrk_exec(buf_start, pd - buf_start + 1, pattern, &c_char);
4285 if (pd == NULL) break;
4286 c_match = 0;
4287 for (i = 0; pd + i < buf_end; i++) {
4288 c_char = g_ascii_toupper(pd[i]);
4289 if (c_char == ascii_text[c_match]) {
4290 c_match++;
4291 if (c_match == textlen) {
4292 result = MR_MATCHED;
4293 /* Save position and length for highlighting the field. */
4294 cf->search_pos = (uint32_t)(pd - buf_start);
4295 cf->search_len = (uint32_t)(i + 1);
4296 goto done;
4298 i++;
4299 if (pd + i >= buf_end || pd[i] != '\0') break;
4300 } else {
4301 break;
4306 done:
4307 return result;
4310 static match_result
4311 match_binary(capture_file *cf, frame_data *fdata,
4312 wtap_rec *rec, void *criterion)
4314 cbs_t *info = (cbs_t *)criterion;
4315 size_t datalen = info->data_len;
4316 match_result result;
4317 const uint8_t *pd = NULL, *buf_start;
4319 /* Load the frame's data. */
4320 if (!cf_read_record(cf, fdata, rec)) {
4321 /* Attempt to get the packet failed. */
4322 return MR_ERROR;
4325 result = MR_NOTMATCHED;
4326 buf_start = ws_buffer_start_ptr(&rec->data);
4327 size_t offset = 0;
4328 if (cf->search_len || cf->search_pos) {
4329 /* we want to start searching one byte past the previous match start */
4330 offset = cf->search_pos + 1;
4332 if (offset < fdata->cap_len) {
4333 pd = ws_memmem(buf_start + offset, fdata->cap_len - offset, info->data, datalen);
4335 if (pd != NULL) {
4336 result = MR_MATCHED;
4337 /* Save position and length for highlighting the field. */
4338 cf->search_pos = (uint32_t)(pd - buf_start);
4339 cf->search_len = (uint32_t)datalen;
4342 return result;
4345 static match_result
4346 match_binary_reverse(capture_file *cf, frame_data *fdata,
4347 wtap_rec *rec, void *criterion)
4349 cbs_t *info = (cbs_t *)criterion;
4350 size_t datalen = info->data_len;
4351 match_result result;
4352 const uint8_t *pd = NULL, *buf_start;
4354 /* Load the frame's data. */
4355 if (!cf_read_record(cf, fdata, rec)) {
4356 /* Attempt to get the packet failed. */
4357 return MR_ERROR;
4360 result = MR_NOTMATCHED;
4361 buf_start = ws_buffer_start_ptr(&rec->data);
4362 /* Has to be room to hold the sought data. */
4363 if (datalen > fdata->cap_len) {
4364 return result;
4366 pd = buf_start + fdata->cap_len - datalen;
4367 if (cf->search_len || cf->search_pos) {
4368 /* we want to start searching one byte before the previous match start */
4369 pd = buf_start + cf->search_pos - 1;
4371 for (; pd >= buf_start; pd--) {
4372 pd = (uint8_t *)ws_memrchr(buf_start, info->data[0], pd - buf_start + 1);
4373 if (pd == NULL) break;
4374 if (memcmp(pd, info->data, datalen) == 0) {
4375 result = MR_MATCHED;
4376 /* Save position and length for highlighting the field. */
4377 cf->search_pos = (uint32_t)(pd - buf_start);
4378 cf->search_len = (uint32_t)datalen;
4379 break;
4383 return result;
4386 static match_result
4387 match_regex(capture_file *cf, frame_data *fdata,
4388 wtap_rec *rec, void *criterion _U_)
4390 match_result result = MR_NOTMATCHED;
4391 size_t result_pos[2] = {0, 0};
4393 /* Load the frame's data. */
4394 if (!cf_read_record(cf, fdata, rec)) {
4395 /* Attempt to get the packet failed. */
4396 return MR_ERROR;
4399 size_t offset = 0;
4400 if (cf->search_len || cf->search_pos) {
4401 /* we want to start searching one byte past the previous match start */
4402 offset = cf->search_pos + 1;
4404 if (offset < fdata->cap_len) {
4405 if (ws_regex_matches_pos(cf->regex,
4406 (const char *)ws_buffer_start_ptr(&rec->data),
4407 fdata->cap_len, offset,
4408 result_pos)) {
4409 //TODO: A chosen regex can match the empty string (zero length)
4410 // which doesn't make a lot of sense for searching the packet bytes.
4411 // Should we search with the PCRE2_NOTEMPTY option?
4412 //TODO: Fix cast.
4413 /* Save position and length for highlighting the field. */
4414 cf->search_pos = (uint32_t)(result_pos[0]);
4415 cf->search_len = (uint32_t)(result_pos[1] - result_pos[0]);
4416 result = MR_MATCHED;
4419 return result;
4422 static match_result
4423 match_regex_reverse(capture_file *cf, frame_data *fdata,
4424 wtap_rec *rec, void *criterion _U_)
4426 match_result result = MR_NOTMATCHED;
4427 size_t result_pos[2] = {0, 0};
4429 /* Load the frame's data. */
4430 if (!cf_read_record(cf, fdata, rec)) {
4431 /* Attempt to get the packet failed. */
4432 return MR_ERROR;
4435 size_t offset = fdata->cap_len - 1;
4436 if (cf->search_pos) {
4437 /* we want to start searching one byte before the previous match */
4438 offset = cf->search_pos - 1;
4440 for (; offset > 0; offset--) {
4441 if (ws_regex_matches_pos(cf->regex,
4442 (const char *)ws_buffer_start_ptr(&rec->data),
4443 fdata->cap_len, offset,
4444 result_pos)) {
4445 //TODO: A chosen regex can match the empty string (zero length)
4446 // which doesn't make a lot of sense for searching the packet bytes.
4447 // Should we search with the PCRE2_NOTEMPTY option?
4448 //TODO: Fix cast.
4449 /* Save position and length for highlighting the field. */
4450 cf->search_pos = (uint32_t)(result_pos[0]);
4451 cf->search_len = (uint32_t)(result_pos[1] - result_pos[0]);
4452 result = MR_MATCHED;
4453 break;
4456 return result;
4459 bool
4460 cf_find_packet_dfilter(capture_file *cf, dfilter_t *sfcode,
4461 search_direction dir, bool start_current)
4463 return find_packet(cf, match_dfilter, sfcode, dir, start_current);
4466 bool
4467 cf_find_packet_dfilter_string(capture_file *cf, const char *filter,
4468 search_direction dir)
4470 dfilter_t *sfcode;
4471 bool result;
4473 if (!dfilter_compile(filter, &sfcode, NULL)) {
4475 * XXX - this shouldn't happen, as the filter string is machine
4476 * generated
4478 return false;
4480 if (sfcode == NULL) {
4482 * XXX - this shouldn't happen, as the filter string is machine
4483 * generated.
4485 return false;
4487 result = find_packet(cf, match_dfilter, sfcode, dir, true);
4488 dfilter_free(sfcode);
4489 return result;
4492 static match_result
4493 match_dfilter(capture_file *cf, frame_data *fdata, wtap_rec *rec,
4494 void *criterion)
4496 dfilter_t *sfcode = (dfilter_t *)criterion;
4497 epan_dissect_t edt;
4498 match_result result;
4500 /* Load the frame's data. */
4501 if (!cf_read_record(cf, fdata, rec)) {
4502 /* Attempt to get the packet failed. */
4503 return MR_ERROR;
4506 epan_dissect_init(&edt, cf->epan, true, false);
4507 epan_dissect_prime_with_dfilter(&edt, sfcode);
4508 epan_dissect_run(&edt, cf->cd_t, rec, fdata, NULL);
4509 result = dfilter_apply_edt(sfcode, &edt) ? MR_MATCHED : MR_NOTMATCHED;
4510 epan_dissect_cleanup(&edt);
4511 return result;
4514 bool
4515 cf_find_packet_marked(capture_file *cf, search_direction dir)
4517 return find_packet(cf, match_marked, NULL, dir, true);
4520 static match_result
4521 match_marked(capture_file *cf _U_, frame_data *fdata, wtap_rec *rec _U_,
4522 void *criterion _U_)
4524 return fdata->marked ? MR_MATCHED : MR_NOTMATCHED;
4527 bool
4528 cf_find_packet_time_reference(capture_file *cf, search_direction dir)
4530 return find_packet(cf, match_time_reference, NULL, dir, true);
4533 static match_result
4534 match_time_reference(capture_file *cf _U_, frame_data *fdata, wtap_rec *rec _U_,
4535 void *criterion _U_)
4537 return fdata->ref_time ? MR_MATCHED : MR_NOTMATCHED;
4540 static bool
4541 find_packet(capture_file *cf, ws_match_function match_function,
4542 void *criterion, search_direction dir, bool start_current)
4544 frame_data *start_fd;
4545 uint32_t framenum;
4546 uint32_t prev_framenum;
4547 frame_data *fdata;
4548 wtap_rec rec;
4549 frame_data *new_fd = NULL;
4550 progdlg_t *progbar = NULL;
4551 GTimer *prog_timer = g_timer_new();
4552 int count;
4553 bool wrap = prefs.gui_find_wrap;
4554 bool succeeded;
4555 float progbar_val;
4556 char status_str[100];
4557 match_result result;
4559 wtap_rec_init(&rec, 1514);
4561 start_fd = start_current ? cf->current_frame : NULL;
4562 if (start_fd != NULL) {
4563 prev_framenum = start_fd->num;
4564 } else {
4565 prev_framenum = 0; /* No start packet selected. */
4566 wrap = false;
4569 /* Iterate through the list of packets, starting at the packet we've
4570 picked, calling a routine to run the filter on the packet, see if
4571 it matches, and stop if so. */
4572 count = 0;
4573 framenum = prev_framenum;
4574 if (framenum == 0 && dir == SD_BACKWARD) {
4575 /* If we have no start packet selected, and we're going backwards,
4576 * start at the end (even if wrap is off.)
4578 framenum = cf->count + 1;
4581 g_timer_start(prog_timer);
4582 /* Progress so far. */
4583 progbar_val = 0.0f;
4585 cf->stop_flag = false;
4587 for (;;) {
4588 /* Create the progress bar if necessary.
4589 We check on every iteration of the loop, so that it takes no
4590 longer than the standard time to create it (otherwise, for a
4591 large file, we might take considerably longer than that standard
4592 time in order to get to the next progress bar step). */
4593 if (progbar == NULL)
4594 progbar = delayed_create_progress_dlg(cf->window, NULL, NULL,
4595 false, &cf->stop_flag, progbar_val);
4598 * Update the progress bar, but do it only after PROGBAR_UPDATE_INTERVAL
4599 * has elapsed. Calling update_progress_dlg and packets_bar_update will
4600 * likely trigger UI paint events, which might take a while depending on
4601 * the platform and display. Reset our timer *after* painting.
4603 if (g_timer_elapsed(prog_timer, NULL) > PROGBAR_UPDATE_INTERVAL) {
4604 /* let's not divide by zero. I should never be started
4605 * with count == 0, so let's assert that
4607 ws_assert(cf->count > 0);
4609 progbar_val = (float) count / cf->count;
4611 snprintf(status_str, sizeof(status_str),
4612 "%4u of %u packets", count, cf->count);
4613 update_progress_dlg(progbar, progbar_val, status_str);
4615 g_timer_start(prog_timer);
4618 if (cf->stop_flag) {
4619 /* Well, the user decided to abort the search. Go back to the
4620 frame where we started.
4621 XXX - This ends up selecting the start packet and reporting
4622 "success". Perhaps new_fd should stay NULL? */
4623 new_fd = start_fd;
4624 break;
4627 /* Go past the current frame. */
4628 if (dir == SD_BACKWARD) {
4629 /* Go on to the previous frame. */
4630 if (framenum <= 1) {
4632 * XXX - other apps have a bit more of a detailed message
4633 * for this, and instead of offering "OK" and "Cancel",
4634 * they offer things such as "Continue" and "Cancel";
4635 * we need an API for popping up alert boxes with
4636 * {Verb} and "Cancel".
4639 if (wrap) {
4640 statusbar_push_temporary_msg("Search reached the beginning. Continuing at end.");
4641 framenum = cf->count; /* wrap around */
4642 wrap = false;
4643 } else {
4644 statusbar_push_temporary_msg("Search reached the beginning.");
4645 framenum = prev_framenum; /* stay on previous packet */
4647 } else
4648 framenum--;
4649 } else {
4650 /* Go on to the next frame. */
4651 if (framenum == cf->count) {
4652 if (wrap) {
4653 statusbar_push_temporary_msg("Search reached the end. Continuing at beginning.");
4654 framenum = 1; /* wrap around */
4655 wrap = false;
4656 } else {
4657 statusbar_push_temporary_msg("Search reached the end.");
4658 framenum = prev_framenum; /* stay on previous packet */
4660 } else
4661 framenum++;
4664 fdata = frame_data_sequence_find(cf->provider.frames, framenum);
4665 count++;
4667 /* Is this packet in the display? */
4668 if (fdata && fdata->passed_dfilter) {
4669 /* Yes. Does it match the search criterion? */
4670 result = (*match_function)(cf, fdata, &rec, criterion);
4671 if (result == MR_ERROR) {
4672 /* Error; our caller has reported the error. Go back to the frame
4673 where we started.
4674 XXX - This ends up selecting the start packet and reporting
4675 "success." Perhaps new_fd should stay NULL? */
4676 new_fd = start_fd;
4677 break;
4678 } else if (result == MR_MATCHED) {
4679 /* Yes. Go to the new frame. */
4680 new_fd = fdata;
4681 break;
4683 wtap_rec_reset(&rec);
4686 if (fdata == start_fd) {
4687 /* We're back to the frame we were on originally, and that frame
4688 doesn't match the search filter. The search failed. */
4689 break;
4693 /* We're done scanning the packets; destroy the progress bar if it
4694 was created. */
4695 if (progbar != NULL)
4696 destroy_progress_dlg(progbar);
4697 g_timer_destroy(prog_timer);
4699 if (new_fd != NULL) {
4700 /* We found a frame that's displayed and that matches.
4701 Try to find and select the packet summary list row for that frame. */
4702 bool found_row;
4704 cf->search_in_progress = true;
4705 found_row = packet_list_select_row_from_data(new_fd);
4706 cf->search_in_progress = false;
4707 if (!found_row) {
4708 /* We didn't find a row corresponding to this frame.
4709 This means that the frame isn't being displayed currently,
4710 so we can't select it. */
4711 cf->search_pos = 0; /* Reset the position */
4712 cf->search_len = 0; /* Reset length */
4713 simple_message_box(ESD_TYPE_INFO, NULL,
4714 "The capture file is probably not fully dissected.",
4715 "End of capture exceeded.");
4716 succeeded = false; /* The search succeeded but we didn't find the row */
4717 } else
4718 succeeded = true; /* The search succeeded and we found the row */
4719 } else
4720 succeeded = false; /* The search failed */
4721 wtap_rec_cleanup(&rec);
4722 return succeeded;
4725 bool
4726 cf_goto_frame(capture_file *cf, unsigned fnumber, bool exact)
4728 frame_data *fdata;
4730 if (cf == NULL || cf->provider.frames == NULL) {
4731 /* we don't have a loaded capture file - fix for bugs 11810 & 11989 */
4732 statusbar_push_temporary_msg("There is no file loaded");
4733 return false; /* we failed to go to that packet */
4736 fdata = frame_data_sequence_find(cf->provider.frames, fnumber);
4738 if (fdata == NULL) {
4739 /* we didn't find a packet with that packet number */
4740 statusbar_push_temporary_msg("There is no packet number %u.", fnumber);
4741 return false; /* we failed to go to that packet */
4743 if (!fdata->passed_dfilter) {
4744 /* that packet currently isn't displayed */
4745 /* XXX - add it to the set of displayed packets? */
4746 if (cf->first_displayed == 0 || exact) {
4747 /* We only want that exact frame, or no frames are displayed. */
4748 statusbar_push_temporary_msg("Packet number %u isn't displayed.", fnumber);
4749 return false; /* we failed to go to that packet */
4751 if (fdata->prev_dis_num == 0) {
4752 /* There is no previous displayed frame, so this frame is
4753 * before the first displayed frame. Go to the first line,
4754 * which is the closest frame.
4756 fdata = NULL; /* This will select the first row. */
4757 statusbar_push_temporary_msg("Packet number %u isn't displayed, going to the first displayed packet, %u.", fnumber, cf->first_displayed);
4758 } else {
4759 uint32_t delta = fnumber - fdata->prev_dis_num;
4760 /* The next displayed frame might be closer, we can do an
4761 * O(log n) binary search for the earliest displayed frame
4762 * in the open interval (fnumber, fnumber + delta).
4764 * This is possibly overkill, we could just go to the previous
4765 * displayed frame.
4767 frame_data *fdata2;
4768 uint32_t lower_bound = fnumber + 1;
4769 uint32_t upper_bound = fnumber + delta - 1;
4770 bool found = false;
4771 while (lower_bound <= upper_bound) {
4772 uint32_t middle = (lower_bound + upper_bound) / 2;
4773 fdata2 = frame_data_sequence_find(cf->provider.frames, middle);
4774 if (fdata2 == NULL) {
4775 /* We don't have a frame of that number, so search before it. */
4776 upper_bound = middle - 1;
4777 continue;
4779 /* We have a frame of that number. What's the displayed
4780 * frame before it? */
4781 if (fdata2->prev_dis_num > fnumber) {
4782 /* The previous frame that passed the filter is also after
4783 * our target, so our answer is no later than that.
4785 upper_bound = fdata2->prev_dis_num;
4786 } else {
4787 /* The previous displayed frame is before fnumber.
4788 * (We already know fnumber itself is not displayed.)
4789 * Is this frame itself displayed?
4791 if (fdata2->passed_dfilter) {
4792 /* Yes. So this is our answer. */
4793 found = true;
4794 break;
4796 /* No. So our answer, if any, is after this frame. */
4797 lower_bound = middle + 1;
4800 if (found) {
4801 fdata = fdata2;
4802 statusbar_push_temporary_msg("Packet number %u isn't displayed, going to the next displayed packet, %u.", fnumber, fdata->num);
4803 } else {
4804 statusbar_push_temporary_msg("Packet number %u isn't displayed, going to the previous displayed packet, %u.", fnumber, fdata->prev_dis_num);
4805 fdata = frame_data_sequence_find(cf->provider.frames, fdata->prev_dis_num);
4810 if (!packet_list_select_row_from_data(fdata)) {
4811 /* We didn't find a row corresponding to this frame.
4812 This means that the frame isn't being displayed currently,
4813 so we can't select it. */
4814 simple_message_box(ESD_TYPE_INFO, NULL,
4815 "The capture file is probably not fully dissected.",
4816 "End of capture exceeded.");
4817 return false;
4819 return true; /* we got to that packet */
4823 * Go to frame specified by currently selected protocol tree item.
4825 bool
4826 cf_goto_framenum(capture_file *cf)
4828 const header_field_info *hfinfo;
4829 uint32_t framenum;
4831 if (cf->finfo_selected) {
4832 hfinfo = cf->finfo_selected->hfinfo;
4833 ws_assert(hfinfo);
4834 if (hfinfo->type == FT_FRAMENUM) {
4835 framenum = fvalue_get_uinteger(cf->finfo_selected->value);
4836 if (framenum != 0) {
4837 /* We probably only want to go to the exact match,
4838 * even though "Go to Previous Packet in History" exists.
4840 return cf_goto_frame(cf, framenum, true);
4845 return false;
4848 /* Select the packet on a given row. */
4849 void
4850 cf_select_packet(capture_file *cf, frame_data *fdata)
4852 epan_dissect_t *old_edt;
4854 /* check the frame data struct pointer for this frame */
4855 if (fdata == NULL) {
4856 return;
4859 /* Get the data in that frame. */
4860 if (!cf_read_record(cf, fdata, &cf->rec)) {
4861 return;
4864 /* Record that this frame is the current frame. */
4865 cf->current_frame = fdata;
4868 * The change to defer freeing the current epan_dissect_t was in
4869 * commit a2bb94c3b33d53f42534aceb7cc67aab1d1fb1f9; to quote
4870 * that commit's comment:
4872 * Clear GtkTreeStore before freeing edt
4874 * When building current data for packet details treeview we store two
4875 * things.
4876 * - Generated string with item label
4877 * - Pointer to node field_info structure
4879 * After epan_dissect_{free, cleanup} pointer to field_info node is no
4880 * longer valid so we should clear GtkTreeStore before freeing.
4882 * XXX - we're no longer using GTK+; is there a way to ensure that
4883 * *nothing* refers to any of the current frame information before
4884 * we replace it?
4886 old_edt = cf->edt;
4887 /* Create the logical protocol tree. */
4888 /* We don't need the columns here. */
4889 cf->edt = epan_dissect_new(cf->epan, true, true);
4891 tap_build_interesting(cf->edt);
4892 epan_dissect_run(cf->edt, cf->cd_t, &cf->rec, cf->current_frame, NULL);
4894 if (old_edt != NULL)
4895 epan_dissect_free(old_edt);
4898 /* Unselect the selected packet, if any. */
4899 void
4900 cf_unselect_packet(capture_file *cf)
4902 epan_dissect_t *old_edt = cf->edt;
4905 * See the comment in cf_select_packet() about deferring the freeing
4906 * of the old cf->edt.
4908 cf->edt = NULL;
4910 /* No packet is selected. */
4911 cf->current_frame = NULL;
4913 /* Destroy the epan_dissect_t for the unselected packet. */
4914 if (old_edt != NULL)
4915 epan_dissect_free(old_edt);
4919 * Mark a particular frame.
4921 void
4922 cf_mark_frame(capture_file *cf, frame_data *frame)
4924 if (! frame->marked) {
4925 frame->marked = true;
4926 if (cf->count > cf->marked_count)
4927 cf->marked_count++;
4932 * Unmark a particular frame.
4934 void
4935 cf_unmark_frame(capture_file *cf, frame_data *frame)
4937 if (frame->marked) {
4938 frame->marked = false;
4939 if (cf->marked_count > 0)
4940 cf->marked_count--;
4945 * Ignore a particular frame.
4947 void
4948 cf_ignore_frame(capture_file *cf, frame_data *frame)
4950 if (! frame->ignored) {
4951 frame->ignored = true;
4952 if (cf->count > cf->ignored_count)
4953 cf->ignored_count++;
4958 * Un-ignore a particular frame.
4960 void
4961 cf_unignore_frame(capture_file *cf, frame_data *frame)
4963 if (frame->ignored) {
4964 frame->ignored = false;
4965 if (cf->ignored_count > 0)
4966 cf->ignored_count--;
4971 * Modify the section comment.
4973 void
4974 cf_update_section_comment(capture_file *cf, char *comment)
4976 wtap_block_t shb_inf;
4977 char *shb_comment;
4979 /* Get the first SHB. */
4980 /* XXX - support multiple SHBs */
4981 shb_inf = wtap_file_get_shb(cf->provider.wth, 0);
4983 /* Get the first comment from the SHB. */
4984 /* XXX - support multiple comments */
4985 if (wtap_block_get_nth_string_option_value(shb_inf, OPT_COMMENT, 0, &shb_comment) != WTAP_OPTTYPE_SUCCESS) {
4986 /* There's no comment - add one. */
4987 wtap_block_add_string_option(shb_inf, OPT_COMMENT, comment, strlen(comment));
4988 } else {
4989 /* See if the comment has changed or not */
4990 if (strcmp(shb_comment, comment) == 0) {
4991 g_free(comment);
4992 return;
4995 /* The comment has changed, let's update it */
4996 wtap_block_set_nth_string_option_value(shb_inf, OPT_COMMENT, 0, comment, strlen(comment));
4998 /* Mark the file as having unsaved changes */
4999 cf->unsaved_changes = true;
5003 * Modify the section comments for a given section.
5005 void
5006 cf_update_section_comments(capture_file *cf, unsigned shb_idx, char **comments)
5008 wtap_block_t shb_inf;
5009 char *shb_comment;
5011 shb_inf = wtap_file_get_shb(cf->provider.wth, shb_idx);
5012 if (shb_inf == NULL) {
5013 /* Shouldn't happen. XXX: Report it if it does? */
5014 return;
5017 unsigned n_comments = g_strv_length(comments);
5018 unsigned i;
5019 char* comment;
5021 for (i = 0; i < n_comments; i++) {
5022 comment = comments[i];
5023 if (wtap_block_get_nth_string_option_value(shb_inf, OPT_COMMENT, i, &shb_comment) != WTAP_OPTTYPE_SUCCESS) {
5024 /* There's no comment - add one. */
5025 wtap_block_add_string_option_owned(shb_inf, OPT_COMMENT, comment);
5026 cf->unsaved_changes = true;
5027 } else {
5028 /* See if the comment has changed or not */
5029 if (strcmp(shb_comment, comment) != 0) {
5030 /* The comment has changed, let's update it */
5031 wtap_block_set_nth_string_option_value(shb_inf, OPT_COMMENT, 0, comment, strlen(comment));
5032 cf->unsaved_changes = true;
5034 g_free(comment);
5037 /* We either transferred ownership of the comments or freed them
5038 * above, so free the array of strings but not the strings themselves. */
5039 g_free(comments);
5041 /* If there are extra old comments, remove them. Start at the end. */
5042 for (i = wtap_block_count_option(shb_inf, OPT_COMMENT); i > n_comments; i--) {
5043 wtap_block_remove_nth_option_instance(shb_inf, OPT_COMMENT, i - 1);
5044 cf->unsaved_changes = true;
5049 * Get the packet block for a packet (record).
5050 * If the block has been edited, it returns the result of the edit,
5051 * otherwise it returns the block from the file.
5052 * NB. Caller must wtap_block_unref() the result when done.
5054 wtap_block_t
5055 cf_get_packet_block(capture_file *cf, const frame_data *fd)
5057 /* If this block has been modified, fetch the modified version */
5058 if (fd->has_modified_block)
5059 return wtap_block_ref(cap_file_provider_get_modified_block(&cf->provider, fd));
5060 else {
5061 wtap_rec rec; /* Record information */
5062 wtap_block_t block;
5064 /* fetch record block */
5065 wtap_rec_init(&rec, 1514);
5067 if (!cf_read_record(cf, fd, &rec))
5068 { /* XXX, what we can do here? */ }
5070 /* rec.block is owned by the record, steal it before it is gone. */
5071 block = wtap_block_ref(rec.block);
5073 wtap_rec_cleanup(&rec);
5074 return block;
5079 * Update(replace) the block on a capture from a frame
5081 bool
5082 cf_set_modified_block(capture_file *cf, frame_data *fd, const wtap_block_t new_block)
5084 wtap_block_t pkt_block = cf_get_packet_block(cf, fd);
5086 /* It's possible to further modify the modified block "in place" by doing
5087 * a call to cf_get_packet_block() that returns an already created modified
5088 * block, modifying that, and calling this function.
5089 * If the caller did that, then the block pointers will be equal.
5091 if (pkt_block == new_block) {
5092 /* No need to save anything here, the caller changes went right
5093 * onto the block.
5094 * Unfortunately we don't have a way to know how many comments were
5095 * in the block before the caller modified it, so tell the caller
5096 * it is its responsibility to update the comment count.
5098 return false;
5100 else {
5101 if (pkt_block)
5102 cf->packet_comment_count -= wtap_block_count_option(pkt_block, OPT_COMMENT);
5104 if (new_block)
5105 cf->packet_comment_count += wtap_block_count_option(new_block, OPT_COMMENT);
5107 cap_file_provider_set_modified_block(&cf->provider, fd, new_block);
5109 expert_update_comment_count(cf->packet_comment_count);
5112 /* Either way, we have unsaved changes. */
5113 wtap_block_unref(pkt_block);
5114 cf->unsaved_changes = true;
5115 return true;
5119 * What types of comments does this capture file have?
5121 uint32_t
5122 cf_comment_types(capture_file *cf)
5124 uint32_t comment_types = 0;
5127 * Does this file have any sections with at least one comment?
5129 for (unsigned section_number = 0;
5130 section_number < wtap_file_get_num_shbs(cf->provider.wth);
5131 section_number++) {
5132 wtap_block_t shb_inf;
5133 char *shb_comment;
5135 shb_inf = wtap_file_get_shb(cf->provider.wth, section_number);
5137 /* Try to get the first comment from that SHB. */
5138 if (wtap_block_get_nth_string_option_value(shb_inf, OPT_COMMENT, 0,
5139 &shb_comment) == WTAP_OPTTYPE_SUCCESS) {
5140 /* We succeeded, so this file has at least one section comment. */
5141 comment_types |= WTAP_COMMENT_PER_SECTION;
5143 /* We don't need to search any more. */
5144 break;
5147 if (cf->packet_comment_count != 0)
5148 comment_types |= WTAP_COMMENT_PER_PACKET;
5149 return comment_types;
5153 * Add a resolved address to this file's list of resolved addresses.
5155 bool
5156 cf_add_ip_name_from_string(capture_file *cf, const char *addr, const char *name)
5159 * XXX - support multiple resolved address lists, and add to the one
5160 * attached to this file?
5162 if (!add_ip_name_from_string(addr, name))
5163 return false;
5165 /* OK, we have unsaved changes. */
5166 cf->unsaved_changes = true;
5167 return true;
5170 typedef struct {
5171 wtap_dumper *pdh;
5172 const char *fname;
5173 int file_type;
5174 bool export;
5175 } save_callback_args_t;
5178 * Save a capture to a file, in a particular format, saving either
5179 * all packets, all currently-displayed packets, or all marked packets.
5181 * Returns true if it succeeds, false otherwise; if it fails, it pops
5182 * up a message box for the failure.
5184 static bool
5185 save_record(capture_file *cf, frame_data *fdata, wtap_rec *rec, void *argsp)
5187 save_callback_args_t *args = (save_callback_args_t *)argsp;
5188 wtap_rec new_rec;
5189 int err;
5190 char *err_info;
5191 wtap_block_t pkt_block;
5193 /* Copy the record information from what was read in from the file. */
5194 new_rec = *rec;
5196 /* Make changes based on anything that the user has done but that
5197 hasn't been saved yet. */
5198 if (fdata->has_modified_block)
5199 pkt_block = cap_file_provider_get_modified_block(&cf->provider, fdata);
5200 else
5201 pkt_block = rec->block;
5202 new_rec.block = pkt_block;
5203 new_rec.block_was_modified = fdata->has_modified_block ? true : false;
5205 if (!nstime_is_zero(&fdata->shift_offset)) {
5206 if (new_rec.presence_flags & WTAP_HAS_TS) {
5207 nstime_add(&new_rec.ts, &fdata->shift_offset);
5211 /* and save the packet */
5212 if (!wtap_dump(args->pdh, &new_rec, ws_buffer_start_ptr(&rec->data), &err, &err_info)) {
5213 report_cfile_write_failure(NULL, args->fname, err, err_info, fdata->num,
5214 args->file_type);
5215 return false;
5218 /* If we are saving (i.e., replacing the current file with the one we're
5219 * writing), then update the frame data to clear the shift offset.
5220 * This keeps us from having to re-read the entire file.
5221 * We could do this in rescan_file(), but
5222 * 1) Ideally we shouldn't have to call rescan_file if all we're doing
5223 * is changing the timestamps, since that shouldn't change the offsets.
5224 * 2) The long term goal is to try to do the offset adjustment here
5225 * instead of using rescan_file, which should be faster (#1257).
5227 * If we're exporting to a different file, then don't do that.
5229 if (!args->export && new_rec.presence_flags & WTAP_HAS_TS) {
5230 nstime_set_zero(&fdata->shift_offset);
5233 return true;
5237 * Can this capture file be written out in any format using Wiretap
5238 * rather than by copying the raw data?
5240 bool
5241 cf_can_write_with_wiretap(capture_file *cf)
5243 /* We don't care whether we support the comments in this file or not;
5244 if we can't, we'll offer the user the option of discarding the
5245 comments. */
5246 return wtap_dump_can_write(cf->linktypes, 0);
5250 * Should we let the user do a save?
5252 * We should if:
5254 * the file has unsaved changes, and we can save it in some
5255 * format through Wiretap
5257 * or
5259 * the file is a temporary file and has no unsaved changes (so
5260 * that "saving" it just means copying it).
5262 * XXX - we shouldn't allow files to be edited if they can't be saved,
5263 * so cf->unsaved_changes should be true only if the file can be saved.
5265 * We don't care whether we support the comments in this file or not;
5266 * if we can't, we'll offer the user the option of discarding the
5267 * comments.
5269 bool
5270 cf_can_save(capture_file *cf)
5272 if (cf->unsaved_changes && wtap_dump_can_write(cf->linktypes, 0)) {
5273 /* Saved changes, and we can write it out with Wiretap. */
5274 return true;
5277 if (cf->is_tempfile && !cf->unsaved_changes) {
5279 * Temporary file with no unsaved changes, so we can just do a
5280 * raw binary copy.
5282 return true;
5285 /* Nothing to save. */
5286 return false;
5290 * Should we let the user do a "save as"?
5292 * That's true if:
5294 * we can save it in some format through Wiretap
5296 * or
5298 * the file is a temporary file and has no unsaved changes (so
5299 * that "saving" it just means copying it).
5301 * XXX - we shouldn't allow files to be edited if they can't be saved,
5302 * so cf->unsaved_changes should be true only if the file can be saved.
5304 * We don't care whether we support the comments in this file or not;
5305 * if we can't, we'll offer the user the option of discarding the
5306 * comments.
5308 bool
5309 cf_can_save_as(capture_file *cf)
5311 if (wtap_dump_can_write(cf->linktypes, 0)) {
5312 /* We can write it out with Wiretap. */
5313 return true;
5316 if (cf->is_tempfile && !cf->unsaved_changes) {
5318 * Temporary file with no unsaved changes, so we can just do a
5319 * raw binary copy.
5321 return true;
5324 /* Nothing to save. */
5325 return false;
5329 * Does this file have unsaved data?
5331 bool
5332 cf_has_unsaved_data(capture_file *cf)
5335 * If this is a temporary file, or a file with unsaved changes, it
5336 * has unsaved data.
5338 return (cf->is_tempfile && cf->count>0) || cf->unsaved_changes;
5342 * Quick scan to find packet offsets.
5344 static cf_read_status_t
5345 rescan_file(capture_file *cf, const char *fname, bool is_tempfile)
5347 wtap_rec rec;
5348 int err;
5349 char *err_info;
5350 char *name_ptr;
5351 int64_t data_offset;
5352 progdlg_t *progbar = NULL;
5353 GTimer *prog_timer = g_timer_new();
5354 int64_t size;
5355 float progbar_val;
5356 int64_t start_time;
5357 char status_str[100];
5358 uint32_t framenum;
5359 frame_data *fdata;
5361 /* Close the old handle. */
5362 wtap_close(cf->provider.wth);
5364 /* Open the new file. */
5365 /* XXX: this will go through all open_routines for a matching one. But right
5366 now rescan_file() is only used when a file is being saved to a different
5367 format than the original, and the user is not given a choice of which
5368 reader to use (only which format to save it in), so doing this makes
5369 sense for now. (XXX: Now it is also used when saving a changed file,
5370 e.g. comments or time-shifted frames.) */
5371 cf->provider.wth = wtap_open_offline(fname, WTAP_TYPE_AUTO, &err, &err_info, true);
5372 if (cf->provider.wth == NULL) {
5373 report_cfile_open_failure(fname, err, err_info);
5374 return CF_READ_ERROR;
5377 /* We're scanning a file whose contents should be the same as what
5378 we had before, so we don't discard dissection state etc.. */
5379 cf->f_datalen = 0;
5381 /* Set the file name because we need it to set the follow stream filter.
5382 XXX - is that still true? We need it for other reasons, though,
5383 in any case. */
5384 if (cf->filename != NULL) {
5385 g_free(cf->filename);
5387 cf->filename = g_strdup(fname);
5389 /* Indicate whether it's a permanent or temporary file. */
5390 cf->is_tempfile = is_tempfile;
5392 /* No user changes yet. */
5393 cf->unsaved_changes = false;
5395 /* Record the file's type and compression type. */
5396 cf->cd_t = wtap_file_type_subtype(cf->provider.wth);
5397 cf->compression_type = wtap_get_compression_type(cf->provider.wth);
5398 if (cf->linktypes != NULL) {
5399 g_array_free(cf->linktypes, TRUE);
5401 cf->linktypes = g_array_sized_new(FALSE, FALSE, (unsigned) sizeof(int), 1);
5403 cf->snap = wtap_snapshot_length(cf->provider.wth);
5405 name_ptr = g_filename_display_basename(cf->filename);
5407 cf_callback_invoke(cf_cb_file_rescan_started, cf);
5409 /* Find the size of the file. */
5410 size = wtap_file_size(cf->provider.wth, NULL);
5412 g_timer_start(prog_timer);
5414 cf->stop_flag = false;
5415 start_time = g_get_monotonic_time();
5417 framenum = 0;
5418 wtap_rec_init(&rec, 1514);
5419 while ((wtap_read(cf->provider.wth, &rec, &err, &err_info,
5420 &data_offset))) {
5421 framenum++;
5422 fdata = frame_data_sequence_find(cf->provider.frames, framenum);
5423 if (G_LIKELY(fdata != NULL)) {
5424 fdata->file_off = data_offset;
5426 if (size >= 0) {
5427 cf->f_datalen = wtap_read_so_far(cf->provider.wth);
5429 /* Create the progress bar if necessary. */
5430 if (progress_is_slow(progbar, prog_timer, size, cf->f_datalen)) {
5431 progbar_val = calc_progbar_val(cf, size, cf->f_datalen, status_str, sizeof(status_str));
5432 progbar = delayed_create_progress_dlg(cf->window, NULL, NULL,
5433 true, &cf->stop_flag, progbar_val);
5437 * Update the progress bar, but do it only after PROGBAR_UPDATE_INTERVAL
5438 * has elapsed. Calling update_progress_dlg and packets_bar_update will
5439 * likely trigger UI paint events, which might take a while depending on
5440 * the platform and display. Reset our timer *after* painting.
5442 if (progbar && g_timer_elapsed(prog_timer, NULL) > PROGBAR_UPDATE_INTERVAL) {
5443 progbar_val = calc_progbar_val(cf, size, cf->f_datalen, status_str, sizeof(status_str));
5444 /* update the packet bar content on the first run or frequently on very large files */
5445 update_progress_dlg(progbar, progbar_val, status_str);
5446 compute_elapsed(cf, start_time);
5447 packets_bar_update();
5448 g_timer_start(prog_timer);
5452 if (cf->stop_flag) {
5453 /* Well, the user decided to abort the rescan. Sadly, as this
5454 isn't a reread, recovering is difficult, so we'll just
5455 close the current capture. */
5456 break;
5459 /* Add this packet's link-layer encapsulation type to cf->linktypes, if
5460 it's not already there.
5461 XXX - yes, this is O(N), so if every packet had a different
5462 link-layer encapsulation type, it'd be O(N^2) to read the file, but
5463 there are probably going to be a small number of encapsulation types
5464 in a file. */
5465 if (rec.rec_type == REC_TYPE_PACKET) {
5466 cf_add_encapsulation_type(cf, rec.rec_header.packet_header.pkt_encap);
5468 wtap_rec_reset(&rec);
5470 wtap_rec_cleanup(&rec);
5472 /* Free the display name */
5473 g_free(name_ptr);
5475 /* We're done reading the file; destroy the progress bar if it was created. */
5476 if (progbar != NULL)
5477 destroy_progress_dlg(progbar);
5478 g_timer_destroy(prog_timer);
5480 /* We're done reading sequentially through the file. */
5481 cf->state = FILE_READ_DONE;
5483 /* Close the sequential I/O side, to free up memory it requires. */
5484 wtap_sequential_close(cf->provider.wth);
5486 /* compute the time it took to load the file */
5487 compute_elapsed(cf, start_time);
5489 /* Set the file encapsulation type now; we don't know what it is until
5490 we've looked at all the packets, as we don't know until then whether
5491 there's more than one type (and thus whether it's
5492 WTAP_ENCAP_PER_PACKET). */
5493 cf->lnk_t = wtap_file_encap(cf->provider.wth);
5495 cf_callback_invoke(cf_cb_file_rescan_finished, cf);
5497 if (cf->stop_flag) {
5498 /* Our caller will give up at this point. */
5499 return CF_READ_ABORTED;
5502 if (err != 0) {
5503 /* Put up a message box noting that the read failed somewhere along
5504 the line. Don't throw out the stuff we managed to read, though,
5505 if any. */
5506 report_cfile_read_failure(NULL, err, err_info);
5507 return CF_READ_ERROR;
5508 } else
5509 return CF_READ_OK;
5512 cf_write_status_t
5513 cf_save_records(capture_file *cf, const char *fname, unsigned save_format,
5514 wtap_compression_type compression_type,
5515 bool discard_comments, bool dont_reopen)
5517 char *err_info = "Unknown error";
5518 char *fname_new = NULL;
5519 wtap_dumper *pdh;
5520 frame_data *fdata;
5521 addrinfo_lists_t *addr_lists;
5522 unsigned framenum;
5523 int err;
5524 enum {
5525 SAVE_WITH_MOVE,
5526 SAVE_WITH_COPY,
5527 SAVE_WITH_WTAP
5528 } how_to_save;
5529 save_callback_args_t callback_args;
5530 callback_args.export = false;
5531 bool needs_reload = false;
5533 /* XXX caller should avoid saving the file while a read is pending
5534 * (e.g. by delaying the save action) */
5535 if (cf->read_lock) {
5536 ws_warning("cf_save_records(\"%s\") while the file is being read, potential crash ahead", fname);
5539 cf_callback_invoke(cf_cb_file_save_started, (void *)fname);
5541 addr_lists = get_addrinfo_list();
5543 if (save_format == cf->cd_t && compression_type == cf->compression_type
5544 && !discard_comments && !cf->unsaved_changes
5545 && (wtap_addrinfo_list_empty(addr_lists) || wtap_file_type_subtype_supports_block(save_format, WTAP_BLOCK_NAME_RESOLUTION) == BLOCK_NOT_SUPPORTED)) {
5546 /* We're saving in the format it's already in, and we're not discarding
5547 comments, and there are no changes we have in memory that aren't saved
5548 to the file, and we have no name resolution information to write or
5549 the file format we're saving in doesn't support writing name
5550 resolution information, so we can just move or copy the raw data. */
5552 if (cf->is_tempfile) {
5553 /* The file being saved is a temporary file from a live
5554 capture, so it doesn't need to stay around under that name;
5555 first, try renaming the capture buffer file to the new name.
5556 This acts as a "safe save", in that, if the file already
5557 exists, the existing file will be removed only if the rename
5558 succeeds.
5560 Sadly, on Windows, as we have the current capture file
5561 open, even MoveFileEx() with MOVEFILE_REPLACE_EXISTING
5562 (to cause the rename to remove an existing target), as
5563 done by ws_stdio_rename() (ws_rename() is #defined to
5564 be ws_stdio_rename() on Windows) will fail.
5566 According to the MSDN documentation for CreateFile(), if,
5567 when we open a capture file, we were to directly do a CreateFile(),
5568 opening with FILE_SHARE_DELETE|FILE_SHARE_READ, and then
5569 convert it to a file descriptor with _open_osfhandle(),
5570 that would allow the file to be renamed out from under us.
5572 However, that doesn't work in practice. Perhaps the problem
5573 is that the process doing the rename is the process that
5574 has the file open. */
5575 #ifndef _WIN32
5576 if (ws_rename(cf->filename, fname) == 0) {
5577 /* That succeeded - there's no need to copy the source file. */
5578 how_to_save = SAVE_WITH_MOVE;
5579 } else {
5580 if (errno == EXDEV) {
5581 /* They're on different file systems, so we have to copy the
5582 file. */
5583 how_to_save = SAVE_WITH_COPY;
5584 } else {
5585 /* The rename failed, but not because they're on different
5586 file systems - put up an error message. (Or should we
5587 just punt and try to copy? The only reason why I'd
5588 expect the rename to fail and the copy to succeed would
5589 be if we didn't have permission to remove the file from
5590 the temporary directory, and that might be fixable - but
5591 is it worth requiring the user to go off and fix it?) */
5592 report_rename_failure(cf->filename, fname, errno);
5593 goto fail;
5596 #else
5597 /* Windows - copy the file to its new location. */
5598 how_to_save = SAVE_WITH_COPY;
5599 #endif
5600 } else {
5601 /* It's a permanent file, so we should copy it, and not remove the
5602 original. */
5603 how_to_save = SAVE_WITH_COPY;
5606 if (how_to_save == SAVE_WITH_COPY) {
5607 /* Copy the file, if we haven't moved it. If we're overwriting
5608 an existing file, we do it with a "safe save", by writing
5609 to a new file and, if the write succeeds, renaming the
5610 new file on top of the old file. */
5611 if (file_exists(fname)) {
5612 fname_new = ws_strdup_printf("%s~", fname);
5613 if (!copy_file_binary_mode(cf->filename, fname_new))
5614 goto fail;
5615 } else {
5616 if (!copy_file_binary_mode(cf->filename, fname))
5617 goto fail;
5620 } else {
5621 /* Either we're saving in a different format or we're saving changes,
5622 such as added, modified, or removed comments, that haven't yet
5623 been written to the underlying file; we can't do that by copying
5624 or moving the capture file, we have to do it by writing the packets
5625 out in Wiretap. */
5627 wtap_dump_params params;
5628 int encap;
5630 how_to_save = SAVE_WITH_WTAP;
5631 wtap_dump_params_init(&params, cf->provider.wth);
5633 /* Determine what file encapsulation type we should use. */
5634 encap = wtap_dump_required_file_encap_type(cf->linktypes);
5635 params.encap = encap;
5637 /* Use the snaplen from cf (XXX - does wtap_dump_params_init handle that?) */
5638 params.snaplen = cf->snap;
5640 if (file_exists(fname)) {
5641 /* We're overwriting an existing file; write out to a new file,
5642 and, if that succeeds, rename the new file on top of the
5643 old file. That makes this a "safe save", so that we don't
5644 lose the old file if we have a problem writing out the new
5645 file. (If the existing file is the current capture file,
5646 we *HAVE* to do that, otherwise we're overwriting the file
5647 from which we're reading the packets that we're writing!) */
5648 fname_new = ws_strdup_printf("%s~", fname);
5649 pdh = wtap_dump_open(fname_new, save_format, compression_type, &params,
5650 &err, &err_info);
5651 } else {
5652 pdh = wtap_dump_open(fname, save_format, compression_type, &params,
5653 &err, &err_info);
5655 /* XXX idb_inf is documented to be used until wtap_dump_close. */
5656 g_free(params.idb_inf);
5657 params.idb_inf = NULL;
5659 if (pdh == NULL) {
5660 report_cfile_dump_open_failure(fname, err, err_info, save_format);
5661 goto fail;
5664 /* Add address resolution */
5665 wtap_dump_set_addrinfo_list(pdh, addr_lists);
5667 /* Iterate through the list of packets, processing all the packets. */
5668 callback_args.pdh = pdh;
5669 callback_args.fname = fname;
5670 callback_args.file_type = save_format;
5671 switch (process_specified_records(cf, NULL, "Saving", "packets",
5672 true, save_record, &callback_args, true)) {
5674 case PSP_FINISHED:
5675 /* Completed successfully. */
5676 break;
5678 case PSP_STOPPED:
5679 /* The user decided to abort the saving.
5680 If we're writing to a temporary file, remove it.
5681 XXX - should we do so even if we're not writing to a
5682 temporary file? */
5683 wtap_dump_close(pdh, NULL, &err, &err_info);
5684 if (fname_new != NULL)
5685 ws_unlink(fname_new);
5686 cf_callback_invoke(cf_cb_file_save_stopped, NULL);
5687 wtap_dump_params_cleanup(&params);
5688 return CF_WRITE_ABORTED;
5690 case PSP_FAILED:
5691 /* Error while saving.
5692 If we're writing to a temporary file, remove it. */
5693 if (fname_new != NULL)
5694 ws_unlink(fname_new);
5695 wtap_dump_close(pdh, NULL, &err, &err_info);
5696 wtap_dump_params_cleanup(&params);
5697 goto fail;
5700 if (!wtap_dump_close(pdh, &needs_reload, &err, &err_info)) {
5701 report_cfile_close_failure(fname, err, err_info);
5702 wtap_dump_params_cleanup(&params);
5703 goto fail;
5706 wtap_dump_params_cleanup(&params);
5709 if (fname_new != NULL) {
5710 /* We wrote out to fname_new, and should rename it on top of
5711 fname. fname_new is now closed, so that should be possible even
5712 on Windows. However, on Windows, we first need to close whatever
5713 file descriptors we have open for fname. */
5714 #ifdef _WIN32
5715 wtap_fdclose(cf->provider.wth);
5716 #endif
5717 /* Now do the rename. */
5718 if (ws_rename(fname_new, fname) == -1) {
5719 /* Well, the rename failed. */
5720 report_rename_failure(fname_new, fname, errno);
5721 #ifdef _WIN32
5722 /* Attempt to reopen the random file descriptor using the
5723 current file's filename. (At this point, the sequential
5724 file descriptor is closed.) */
5725 if (!wtap_fdreopen(cf->provider.wth, cf->filename, &err)) {
5726 /* Oh, well, we're screwed. */
5727 report_cfile_open_failure(cf->filename, err, NULL);
5729 #endif
5730 goto fail;
5732 g_free(fname_new);
5735 /* If this was a temporary file, and we didn't do the save by doing
5736 a move, so the tempoary file is still around under its old name,
5737 remove it. */
5738 if (cf->is_tempfile && how_to_save != SAVE_WITH_MOVE) {
5739 /* If this fails, there's not much we can do, so just ignore errors. */
5740 ws_unlink(cf->filename);
5743 cf_callback_invoke(cf_cb_file_save_finished, NULL);
5744 cf->unsaved_changes = false;
5746 if (!dont_reopen) {
5747 switch (how_to_save) {
5749 case SAVE_WITH_MOVE:
5750 /* We just moved the file, so the wtap structure refers to the
5751 new file, and all the information other than the filename
5752 and the "is temporary" status applies to the new file; just
5753 update that. */
5754 g_free(cf->filename);
5755 cf->filename = g_strdup(fname);
5756 cf->is_tempfile = false;
5757 cf_callback_invoke(cf_cb_file_fast_save_finished, cf);
5758 break;
5760 case SAVE_WITH_COPY:
5761 /* We just copied the file, so all the information other than
5762 the file descriptors, the filename, and the "is temporary"
5763 status applies to the new file; just update that. */
5764 wtap_fdclose(cf->provider.wth);
5765 /* Attempt to reopen the random file descriptor using the
5766 new file's filename. (At this point, the sequential
5767 file descriptor is closed.) */
5768 if (!wtap_fdreopen(cf->provider.wth, fname, &err)) {
5769 report_cfile_open_failure(fname, err, err_info);
5770 cf_close(cf);
5771 } else {
5772 g_free(cf->filename);
5773 cf->filename = g_strdup(fname);
5774 cf->is_tempfile = false;
5776 cf_callback_invoke(cf_cb_file_fast_save_finished, cf);
5777 break;
5779 case SAVE_WITH_WTAP:
5780 /* Open and read the file we saved to.
5782 XXX - this is somewhat of a waste; we already have the
5783 packets, all this gets us is updated file type information
5784 (which we could just stuff into "cf"), and having the new
5785 file be the one we have opened and from which we're reading
5786 the data, and it means we have to spend time opening and
5787 reading the file, which could be a significant amount of
5788 time if the file is large.
5790 If the capture-file-writing code were to return the
5791 seek offset of each packet it writes, we could save that
5792 in the frame_data structure for the frame, and just open
5793 the file without reading it again...
5795 ...as long as, for gzipped files, the process of writing
5796 out the file *also* generates the information needed to
5797 support fast random access to the compressed file. */
5798 /* rescan_file will cause us to try all open_routines, so
5799 reset cfile's open_type */
5800 cf->open_type = WTAP_TYPE_AUTO;
5801 /* There are cases when SAVE_WITH_WTAP can result in new packets
5802 being written to the file, e.g ERF records
5803 In that case, we need to reload the whole file */
5804 if(needs_reload) {
5805 if (cf_open(cf, fname, WTAP_TYPE_AUTO, false, &err) == CF_OK) {
5806 if (cf_read(cf, /*reloading=*/true) != CF_READ_OK) {
5807 /* The rescan failed; just close the file. Either
5808 a dialog was popped up for the failure, so the
5809 user knows what happened, or they stopped the
5810 rescan, in which case they know what happened. */
5811 /* XXX: This is inconsistent with normal open/reload behaviour. */
5812 cf_close(cf);
5816 else {
5817 if (rescan_file(cf, fname, false) != CF_READ_OK) {
5818 /* The rescan failed; just close the file. Either
5819 a dialog was popped up for the failure, so the
5820 user knows what happened, or they stopped the
5821 rescan, in which case they know what happened. */
5822 cf_close(cf);
5825 break;
5828 /* If we were told to discard the comments, do so. */
5829 if (discard_comments) {
5830 /* Remove SHB comment, if any. */
5831 wtap_write_shb_comment(cf->provider.wth, NULL);
5833 /* remove all user comments */
5834 for (framenum = 1; framenum <= cf->count; framenum++) {
5835 fdata = frame_data_sequence_find(cf->provider.frames, framenum);
5837 // XXX: This also ignores non-comment options like verdict
5838 fdata->has_modified_block = false;
5841 if (cf->provider.frames_modified_blocks) {
5842 g_tree_destroy(cf->provider.frames_modified_blocks);
5843 cf->provider.frames_modified_blocks = NULL;
5846 cf->packet_comment_count = 0;
5849 return CF_WRITE_OK;
5851 fail:
5852 if (fname_new != NULL) {
5853 /* We were trying to write to a temporary file; get rid of it if it
5854 exists. (We don't care whether this fails, as, if it fails,
5855 there's not much we can do about it. I guess if it failed for
5856 a reason other than "it doesn't exist", we could report an
5857 error, so the user knows there's a junk file that they might
5858 want to clean up.) */
5859 ws_unlink(fname_new);
5860 g_free(fname_new);
5862 cf_callback_invoke(cf_cb_file_save_failed, NULL);
5863 return CF_WRITE_ERROR;
5866 cf_write_status_t
5867 cf_export_specified_packets(capture_file *cf, const char *fname,
5868 packet_range_t *range, unsigned save_format,
5869 wtap_compression_type compression_type)
5871 char *fname_new = NULL;
5872 int err;
5873 char *err_info;
5874 wtap_dumper *pdh;
5875 save_callback_args_t callback_args;
5876 wtap_dump_params params;
5877 int encap;
5879 callback_args.export = true;
5880 packet_range_process_init(range);
5882 /* We're writing out specified packets from the specified capture
5883 file to another file. Even if all captured packets are to be
5884 written, don't special-case the operation - read each packet
5885 and then write it out if it's one of the specified ones. */
5887 wtap_dump_params_init(&params, cf->provider.wth);
5889 /* Determine what file encapsulation type we should use. */
5890 encap = wtap_dump_required_file_encap_type(cf->linktypes);
5891 params.encap = encap;
5893 /* Use the snaplen from cf (XXX - does wtap_dump_params_init handle that?) */
5894 params.snaplen = cf->snap;
5896 if (file_exists(fname)) {
5897 /* We're overwriting an existing file; write out to a new file,
5898 and, if that succeeds, rename the new file on top of the
5899 old file. That makes this a "safe save", so that we don't
5900 lose the old file if we have a problem writing out the new
5901 file. (If the existing file is the current capture file,
5902 we *HAVE* to do that, otherwise we're overwriting the file
5903 from which we're reading the packets that we're writing!) */
5904 fname_new = ws_strdup_printf("%s~", fname);
5905 pdh = wtap_dump_open(fname_new, save_format, compression_type, &params,
5906 &err, &err_info);
5907 } else {
5908 pdh = wtap_dump_open(fname, save_format, compression_type, &params,
5909 &err, &err_info);
5911 /* XXX idb_inf is documented to be used until wtap_dump_close. */
5912 g_free(params.idb_inf);
5913 params.idb_inf = NULL;
5915 if (pdh == NULL) {
5916 report_cfile_dump_open_failure(fname, err, err_info, save_format);
5917 goto fail;
5920 /* Add address resolution */
5921 wtap_dump_set_addrinfo_list(pdh, get_addrinfo_list());
5923 /* Iterate through the list of packets, processing the packets we were
5924 told to process.
5926 XXX - we've already called "packet_range_process_init(range)", but
5927 "process_specified_records()" will do it again. Fortunately,
5928 that's harmless in this case, as we haven't done anything to
5929 "range" since we initialized it. */
5930 callback_args.pdh = pdh;
5931 callback_args.fname = fname;
5932 callback_args.file_type = save_format;
5933 switch (process_specified_records(cf, range, "Writing", "specified records",
5934 true, save_record, &callback_args, true)) {
5936 case PSP_FINISHED:
5937 /* Completed successfully. */
5938 break;
5940 case PSP_STOPPED:
5941 /* The user decided to abort the saving.
5942 If we're writing to a temporary file, remove it.
5943 XXX - should we do so even if we're not writing to a
5944 temporary file? */
5945 wtap_dump_close(pdh, NULL, &err, &err_info);
5946 if (fname_new != NULL) {
5947 ws_unlink(fname_new);
5948 g_free(fname_new);
5950 wtap_dump_params_cleanup(&params);
5952 return CF_WRITE_ABORTED;
5954 case PSP_FAILED:
5955 /* Error while saving. */
5956 wtap_dump_close(pdh, NULL, &err, &err_info);
5958 * We don't report any error from closing; the error that caused
5959 * process_specified_records() to fail has already been reported.
5961 goto fail;
5964 if (!wtap_dump_close(pdh, NULL, &err, &err_info)) {
5965 report_cfile_close_failure(fname, err, err_info);
5966 goto fail;
5969 if (fname_new != NULL) {
5970 /* We wrote out to fname_new, and should rename it on top of
5971 fname; fname is now closed, so that should be possible even
5972 on Windows. Do the rename. */
5973 if (ws_rename(fname_new, fname) == -1) {
5974 /* Well, the rename failed. */
5975 report_rename_failure(fname_new, fname, errno);
5976 goto fail;
5978 g_free(fname_new);
5980 wtap_dump_params_cleanup(&params);
5982 return CF_WRITE_OK;
5984 fail:
5985 if (fname_new != NULL) {
5986 /* We were trying to write to a temporary file; get rid of it if it
5987 exists. (We don't care whether this fails, as, if it fails,
5988 there's not much we can do about it. I guess if it failed for
5989 a reason other than "it doesn't exist", we could report an
5990 error, so the user knows there's a junk file that they might
5991 want to clean up.) */
5992 ws_unlink(fname_new);
5993 g_free(fname_new);
5995 wtap_dump_params_cleanup(&params);
5997 return CF_WRITE_ERROR;
6000 /* Reload the current capture file. */
6001 cf_status_t
6002 cf_reload(capture_file *cf)
6004 char *filename;
6005 bool is_tempfile;
6006 cf_status_t cf_status = CF_OK;
6007 int err;
6009 if (cf->read_lock) {
6010 ws_warning("Failing cf_reload(\"%s\") since a read is in progress", cf->filename);
6011 return CF_ERROR;
6014 /* If the file could be opened, "cf_open()" calls "cf_close()"
6015 to get rid of state for the old capture file before filling in state
6016 for the new capture file. "cf_close()" will remove the file if
6017 it's a temporary file; we don't want that to happen (for one thing,
6018 it'd prevent subsequent reopens from working). Remember whether it's
6019 a temporary file, mark it as not being a temporary file, and then
6020 reopen it as the type of file it was.
6022 Also, "cf_close()" will free "cf->filename", so we must make
6023 a copy of it first. */
6024 filename = g_strdup(cf->filename);
6025 is_tempfile = cf->is_tempfile;
6026 cf->is_tempfile = false;
6027 if (cf_open(cf, filename, cf->open_type, is_tempfile, &err) == CF_OK) {
6028 switch (cf_read(cf, /*reloading=*/true)) {
6030 case CF_READ_OK:
6031 case CF_READ_ERROR:
6032 /* Just because we got an error, that doesn't mean we were unable
6033 to read any of the file; we handle what we could get from the
6034 file. */
6035 break;
6037 case CF_READ_ABORTED:
6038 /* The user bailed out of re-reading the capture file; the
6039 capture file has been closed. */
6040 break;
6042 } else {
6043 /* The open failed, so "cf->is_tempfile" wasn't set to "is_tempfile".
6044 Instead, the file was left open, so we should restore "cf->is_tempfile"
6045 ourselves.
6047 XXX - change the menu? Presumably "cf_open()" will do that;
6048 make sure it does! */
6049 cf->is_tempfile = is_tempfile;
6050 cf_status = CF_ERROR;
6052 /* "cf_open()" made a copy of the file name we handed it, so
6053 we should free up our copy. */
6054 g_free(filename);
6055 return cf_status;