TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags
[wireshark-sm.git] / file.c
blobf632db05792f3bd96da2ae5150f1926b631fdeca
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, Buffer *buf,
76 dfilter_t *dfcode, 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 *, Buffer *, void *);
88 static match_result match_protocol_tree(capture_file *cf, frame_data *fdata,
89 wtap_rec *, Buffer *, 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 *, Buffer *, void *criterion);
94 static match_result match_narrow_and_wide(capture_file *cf, frame_data *fdata,
95 wtap_rec *, Buffer *, void *criterion);
96 static match_result match_narrow_and_wide_reverse(capture_file *cf, frame_data *fdata,
97 wtap_rec *, Buffer *, void *criterion);
98 static match_result match_narrow_and_wide_case(capture_file *cf, frame_data *fdata,
99 wtap_rec *, Buffer *, void *criterion);
100 static match_result match_narrow_and_wide_case_reverse(capture_file *cf, frame_data *fdata,
101 wtap_rec *, Buffer *, void *criterion);
102 static match_result match_narrow_case(capture_file *cf, frame_data *fdata,
103 wtap_rec *, Buffer *, void *criterion);
104 static match_result match_narrow_case_reverse(capture_file *cf, frame_data *fdata,
105 wtap_rec *, Buffer *, void *criterion);
106 static match_result match_wide(capture_file *cf, frame_data *fdata,
107 wtap_rec *, Buffer *, void *criterion);
108 static match_result match_wide_reverse(capture_file *cf, frame_data *fdata,
109 wtap_rec *, Buffer *, void *criterion);
110 static match_result match_wide_case(capture_file *cf, frame_data *fdata,
111 wtap_rec *, Buffer *, void *criterion);
112 static match_result match_wide_case_reverse(capture_file *cf, frame_data *fdata,
113 wtap_rec *, Buffer *, void *criterion);
114 static match_result match_binary(capture_file *cf, frame_data *fdata,
115 wtap_rec *, Buffer *, void *criterion);
116 static match_result match_binary_reverse(capture_file *cf, frame_data *fdata,
117 wtap_rec *, Buffer *, void *criterion);
118 static match_result match_regex(capture_file *cf, frame_data *fdata,
119 wtap_rec *, Buffer *, void *criterion);
120 static match_result match_regex_reverse(capture_file *cf, frame_data *fdata,
121 wtap_rec *, Buffer *, void *criterion);
122 static match_result match_dfilter(capture_file *cf, frame_data *fdata,
123 wtap_rec *, Buffer *, void *criterion);
124 static match_result match_marked(capture_file *cf, frame_data *fdata,
125 wtap_rec *, Buffer *, void *criterion);
126 static match_result match_time_reference(capture_file *cf, frame_data *fdata,
127 wtap_rec *, Buffer *, 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 metadata. */
255 wtap_rec_init(&cf->rec);
257 /* XXX - we really want to initialize this after we've read all
258 the packets, so we know how much we'll ultimately need. */
259 ws_buffer_init(&cf->buf, 1514);
261 /* We're about to start reading the file. */
262 cf->state = FILE_READ_IN_PROGRESS;
264 /* If there was a pending redissection for the old file (there
265 * shouldn't be), clear it. cf_close() should have failed if the
266 * old file's read lock was held, but it doesn't hurt to clear it. */
267 cf->read_lock = false;
268 cf->redissection_queued = RESCAN_NONE;
270 cf->provider.wth = wth;
271 cf->f_datalen = 0;
273 /* Set the file name because we need it to set the follow stream filter.
274 XXX - is that still true? We need it for other reasons, though,
275 in any case. */
276 cf->filename = g_strdup(fname);
278 /* Indicate whether it's a permanent or temporary file. */
279 cf->is_tempfile = is_tempfile;
281 /* No user changes yet. */
282 cf->unsaved_changes = false;
284 cf->computed_elapsed = 0;
286 cf->cd_t = wtap_file_type_subtype(cf->provider.wth);
287 cf->open_type = type;
288 cf->linktypes = g_array_sized_new(FALSE, FALSE, (unsigned) sizeof(int), 1);
289 cf->count = 0;
290 cf->packet_comment_count = 0;
291 cf->displayed_count = 0;
292 cf->marked_count = 0;
293 cf->ignored_count = 0;
294 cf->ref_time_count = 0;
295 cf->drops_known = false;
296 cf->drops = 0;
297 cf->snap = wtap_snapshot_length(cf->provider.wth);
299 /* Allocate a frame_data_sequence for the frames in this file */
300 cf->provider.frames = new_frame_data_sequence();
302 nstime_set_zero(&cf->elapsed_time);
303 cf->provider.ref = NULL;
304 cf->provider.prev_dis = NULL;
305 cf->provider.prev_cap = NULL;
306 cf->cum_bytes = 0;
308 /* Create new epan session for dissection.
309 * (The old one was freed in cf_close().)
311 cf->epan = ws_epan_new(cf);
313 packet_list_queue_draw();
314 cf_callback_invoke(cf_cb_file_opened, cf);
316 wtap_set_cb_new_ipv4(cf->provider.wth, add_ipv4_name);
317 wtap_set_cb_new_ipv6(cf->provider.wth, (wtap_new_ipv6_callback_t) add_ipv6_name);
318 wtap_set_cb_new_secrets(cf->provider.wth, secrets_wtap_callback);
320 return CF_OK;
322 fail:
323 report_cfile_open_failure(fname, *err, err_info);
324 return CF_ERROR;
328 * Add an encapsulation type to cf->linktypes.
330 static void
331 cf_add_encapsulation_type(capture_file *cf, int encap)
333 unsigned i;
335 for (i = 0; i < cf->linktypes->len; i++) {
336 if (g_array_index(cf->linktypes, int, i) == encap)
337 return; /* it's already there */
339 /* It's not already there - add it. */
340 g_array_append_val(cf->linktypes, encap);
343 /* Reset everything to a pristine state */
344 void
345 cf_close(capture_file *cf)
347 cf->stop_flag = false;
348 if (cf->state == FILE_CLOSED || cf->state == FILE_READ_PENDING)
349 return; /* Nothing to do */
351 /* Die if we're in the middle of reading a file. */
352 ws_assert(cf->state != FILE_READ_IN_PROGRESS);
353 ws_assert(!cf->read_lock);
355 cf_callback_invoke(cf_cb_file_closing, cf);
357 /* close things, if not already closed before */
358 color_filters_cleanup();
360 if (cf->provider.wth) {
361 wtap_close(cf->provider.wth);
362 cf->provider.wth = NULL;
364 /* We have no file open... */
365 if (cf->filename != NULL) {
366 /* If it's a temporary file, remove it. */
367 if (cf->is_tempfile)
368 ws_unlink(cf->filename);
369 g_free(cf->filename);
370 cf->filename = NULL;
372 /* ...which means we have no changes to that file to save. */
373 cf->unsaved_changes = false;
375 /* no open_routine type */
376 cf->open_type = WTAP_TYPE_AUTO;
378 /* Clean up the record metadata. */
379 wtap_rec_cleanup(&cf->rec);
381 /* Clear the packet list. */
382 packet_list_freeze();
383 packet_list_clear();
384 packet_list_thaw();
386 /* Free up the packet buffer. */
387 ws_buffer_free(&cf->buf);
389 dfilter_free(cf->rfcode);
390 cf->rfcode = NULL;
391 if (cf->provider.frames != NULL) {
392 free_frame_data_sequence(cf->provider.frames);
393 cf->provider.frames = NULL;
395 if (cf->provider.frames_modified_blocks) {
396 g_tree_destroy(cf->provider.frames_modified_blocks);
397 cf->provider.frames_modified_blocks = NULL;
399 cf_unselect_packet(cf); /* nothing to select */
400 cf->first_displayed = 0;
401 cf->last_displayed = 0;
403 /* No frames, no frame selected, no field in that frame selected. */
404 cf->count = 0;
405 cf->current_frame = NULL;
406 cf->finfo_selected = NULL;
408 /* No frame link-layer types, either. */
409 if (cf->linktypes != NULL) {
410 g_array_free(cf->linktypes, TRUE);
411 cf->linktypes = NULL;
414 cf->f_datalen = 0;
415 nstime_set_zero(&cf->elapsed_time);
417 reset_tap_listeners();
419 epan_free(cf->epan);
420 cf->epan = NULL;
422 /* We have no file open. */
423 cf->state = FILE_CLOSED;
425 cf_callback_invoke(cf_cb_file_closed, cf);
429 * true if the progress dialog doesn't exist and it looks like we'll
430 * take > PROGBAR_SHOW_DELAY (500ms) to load, false otherwise.
432 static inline bool
433 progress_is_slow(progdlg_t *progdlg, GTimer *prog_timer, int64_t size, int64_t pos)
435 double elapsed;
437 if (progdlg) return false;
438 elapsed = g_timer_elapsed(prog_timer, NULL);
439 /* This only gets checked between reading records, which doesn't help if
440 * a single record takes a very long time, e.g., the first TLS packet if
441 * the SSLKEYLOGFILE is very large. (#17051) */
442 if ((elapsed * 2 > PROGBAR_SHOW_DELAY && (size / pos) >= 2) /* It looks like we're going to be slow. */
443 || elapsed > PROGBAR_SHOW_DELAY) { /* We are indeed slow. */
444 return true;
446 return false;
449 static float
450 calc_progbar_val(capture_file *cf, int64_t size, int64_t file_pos, char *status_str, unsigned long status_size)
452 float progbar_val;
454 progbar_val = (float) file_pos / (float) size;
455 if (progbar_val > 1.0) {
457 /* The file probably grew while we were reading it.
458 * Update file size, and try again.
460 size = wtap_file_size(cf->provider.wth, NULL);
462 if (size >= 0)
463 progbar_val = (float) file_pos / (float) size;
465 /* If it's still > 1, either "wtap_file_size()" failed (in which
466 * case there's not much we can do about it), or the file
467 * *shrank* (in which case there's not much we can do about
468 * it); just clip the progress value at 1.0.
470 if (progbar_val > 1.0f)
471 progbar_val = 1.0f;
474 snprintf(status_str, status_size,
475 "%" PRId64 "KB of %" PRId64 "KB",
476 file_pos / 1024, size / 1024);
478 return progbar_val;
481 cf_read_status_t
482 cf_read(capture_file *cf, bool reloading)
484 int err = 0;
485 char *err_info = NULL;
486 volatile bool too_many_records = false;
487 char *name_ptr;
488 progdlg_t *volatile progbar = NULL;
489 GTimer *prog_timer = g_timer_new();
490 int64_t size;
491 int64_t start_time;
492 epan_dissect_t edt;
493 wtap_rec rec;
494 Buffer buf;
495 dfilter_t *dfcode = NULL;
496 column_info *cinfo;
497 volatile bool create_proto_tree;
498 unsigned tap_flags;
499 bool compiled _U_;
500 volatile bool is_read_aborted = false;
502 /* The update_progress_dlg call below might end up accepting a user request to
503 * trigger redissection/rescans which can modify/destroy the dissection
504 * context ("cf->epan"). That condition should be prevented by callers, but in
505 * case it occurs let's fail gracefully.
507 if (cf->read_lock) {
508 ws_warning("Failing due to recursive cf_read(\"%s\", %d) call!",
509 cf->filename, reloading);
510 return CF_READ_ERROR;
512 /* This is a full dissection, so clear any pending request for one. */
513 cf->redissection_queued = RESCAN_NONE;
514 cf->read_lock = true;
516 /* Compile the current display filter.
517 * The code it compiles to might have changed, e.g. if a display
518 * filter macro used has changed.
520 * We assume this will not fail since cf->dfilter is only set in
521 * cf_filter IFF the filter was valid.
522 * XXX - This is not necessarily true, if the filter has a FT_IPv4
523 * or FT_IPv6 field compared to a resolved hostname in it, because
524 * we do a new host lookup, and that *could* timeout this time
525 * (though with the read lock above we shouldn't have many lookups at
526 * once, reducing the chances of that)... (#19612)
528 if (cf->dfilter) {
529 compiled = dfilter_compile(cf->dfilter, &dfcode, NULL);
530 ws_assert(compiled && dfcode);
533 dfilter_free(cf->dfcode);
534 cf->dfcode = dfcode;
536 /* The compiled dfilter might have a field reference; recompiling it
537 * means that the field references won't match anything. That's what
538 * we want since this is a new sequential read and we don't have
539 * a selected frame with a tree. (Will taps with filters with display
540 * references also have cleared display references?)
543 /* Get the union of the flags for all tap listeners. */
544 tap_flags = union_of_tap_listener_flags();
547 * Determine whether we need to create a protocol tree.
548 * We do if:
550 * we're going to apply a display filter;
552 * one of the tap listeners is going to apply a filter;
554 * one of the tap listeners requires a protocol tree;
556 * a postdissector wants field values or protocols on
557 * the first pass.
559 create_proto_tree =
560 (cf->dfcode != NULL || have_filtering_tap_listeners() ||
561 (tap_flags & TL_REQUIRES_PROTO_TREE) || postdissectors_want_hfids());
563 reset_tap_listeners();
565 name_ptr = g_filename_display_basename(cf->filename);
567 if (reloading)
568 cf_callback_invoke(cf_cb_file_reload_started, cf);
569 else
570 cf_callback_invoke(cf_cb_file_read_started, cf);
572 /* Record the file's compression type.
573 XXX - do we know this at open time? */
574 cf->compression_type = wtap_get_compression_type(cf->provider.wth);
576 /* The packet list window will be empty until the file is completely loaded */
577 packet_list_freeze();
579 cf->stop_flag = false;
580 start_time = g_get_monotonic_time();
582 epan_dissect_init(&edt, cf->epan, create_proto_tree, false);
584 /* If the display filter or any tap listeners require the columns,
585 * construct them. */
586 cinfo = (tap_listeners_require_columns() ||
587 dfilter_requires_columns(cf->dfcode)) ? &cf->cinfo : NULL;
589 /* Find the size of the file. */
590 size = wtap_file_size(cf->provider.wth, NULL);
592 /* If we are to ignore duplicate frames, we need a container to store
593 * hashes frame contents */
594 fifo_string_cache_t frame_dup_cache;
595 GChecksum *volatile cksum = NULL;
597 if (prefs.ignore_dup_frames) {
598 fifo_string_cache_init(&frame_dup_cache, prefs.ignore_dup_frames_cache_entries, g_free);
599 cksum = g_checksum_new(G_CHECKSUM_SHA256);
602 g_timer_start(prog_timer);
604 wtap_rec_init(&rec);
605 ws_buffer_init(&buf, 1514);
607 TRY {
608 int64_t file_pos;
609 int64_t data_offset;
611 float progbar_val;
612 char status_str[100];
614 while ((wtap_read(cf->provider.wth, &rec, &buf, &err, &err_info,
615 &data_offset))) {
616 if (size >= 0) {
617 if (cf->count == max_records) {
619 * Quit if we've already read the maximum number of
620 * records allowed.
622 too_many_records = true;
623 break;
625 file_pos = wtap_read_so_far(cf->provider.wth);
627 /* Create the progress bar if necessary. */
628 if (progress_is_slow(progbar, prog_timer, size, file_pos)) {
629 progbar_val = calc_progbar_val(cf, size, file_pos, status_str, sizeof(status_str));
630 progbar = delayed_create_progress_dlg(cf->window, NULL, NULL, true,
631 &cf->stop_flag, progbar_val);
635 * Update the progress bar, but do it only after
636 * PROGBAR_UPDATE_INTERVAL has elapsed. Calling update_progress_dlg
637 * and packets_bar_update will likely trigger UI paint events, which
638 * might take a while depending on the platform and display. Reset
639 * our timer *after* painting.
641 if (progbar && g_timer_elapsed(prog_timer, NULL) > PROGBAR_UPDATE_INTERVAL) {
642 progbar_val = calc_progbar_val(cf, size, file_pos, status_str, sizeof(status_str));
643 /* update the packet bar content on the first run or frequently on very large files */
644 update_progress_dlg(progbar, progbar_val, status_str);
645 compute_elapsed(cf, start_time);
646 packets_bar_update();
647 g_timer_start(prog_timer);
650 * The previous GUI triggers should not have destroyed the running
651 * session. If that did happen, it could blow up when read_record tries
652 * to use the destroyed edt.session, so detect it right here.
654 ws_assert(edt.session == cf->epan);
657 if (cf->state == FILE_READ_ABORTED) {
658 /* Well, the user decided to exit Wireshark. Break out of the
659 loop, and let the code below (which is called even if there
660 aren't any packets left to read) exit. */
661 is_read_aborted = true;
662 break;
664 if (cf->stop_flag) {
665 /* Well, the user decided to abort the read. He/She will be warned and
666 it might be enough for him/her to work with the already loaded
667 packets.
668 This is especially true for very large capture files, where you don't
669 want to wait loading the whole file (which may last minutes or even
670 hours even on fast machines) just to see that it was the wrong file. */
671 break;
673 read_record(cf, &rec, &buf, cf->dfcode, &edt, cinfo, data_offset, &frame_dup_cache, cksum);
674 wtap_rec_reset(&rec);
677 CATCH(OutOfMemoryError) {
678 simple_message_box(ESD_TYPE_ERROR, NULL,
679 "More information and workarounds can be found at\n"
680 WS_WIKI_URL("KnownBugs/OutOfMemory"),
681 "Sorry, but Wireshark has run out of memory and has to terminate now.");
682 #if 0
683 /* Could we close the current capture and free up memory from that? */
684 #else
685 /* we have to terminate, as we cannot recover from the memory error */
686 exit(1);
687 #endif
689 ENDTRY;
691 // If we're ignoring duplicate frames, clear the data structures.
692 // We really could look at prefs.ignore_dup_frames here, but it's even
693 // safer to check if we had allocated 'cksum'.
694 if (cksum != NULL) {
695 fifo_string_cache_free(&frame_dup_cache);
696 g_checksum_free(cksum);
699 /* We're done reading sequentially through the file. */
700 cf->state = FILE_READ_DONE;
702 /* Destroy the progress bar if it was created. */
703 if (progbar != NULL)
704 destroy_progress_dlg(progbar);
705 g_timer_destroy(prog_timer);
707 /* Free the display name */
708 g_free(name_ptr);
710 epan_dissect_cleanup(&edt);
711 wtap_rec_cleanup(&rec);
712 ws_buffer_free(&buf);
714 /* Close the sequential I/O side, to free up memory it requires. */
715 wtap_sequential_close(cf->provider.wth);
717 /* Allow the protocol dissectors to free up memory that they
718 * don't need after the sequential run-through of the packets. */
719 postseq_cleanup_all_protocols();
721 /* compute the time it took to load the file */
722 compute_elapsed(cf, start_time);
724 /* Set the file encapsulation type now; we don't know what it is until
725 we've looked at all the packets, as we don't know until then whether
726 there's more than one type (and thus whether it's
727 WTAP_ENCAP_PER_PACKET). */
728 cf->lnk_t = wtap_file_encap(cf->provider.wth);
730 cf->current_frame = frame_data_sequence_find(cf->provider.frames, cf->first_displayed);
732 packet_list_thaw();
734 /* It is safe again to execute redissections or sort. */
735 ws_assert(cf->read_lock);
736 cf->read_lock = false;
738 if (reloading)
739 cf_callback_invoke(cf_cb_file_reload_finished, cf);
740 else
741 cf_callback_invoke(cf_cb_file_read_finished, cf);
743 /* If we have any displayed packets to select, select the first of those
744 packets by making the first row the selected row. */
745 if (cf->first_displayed != 0) {
746 packet_list_select_row_from_data(NULL);
749 if (is_read_aborted) {
751 * Well, the user decided to exit Wireshark while reading this *offline*
752 * capture file (Live captures are handled by something like
753 * cf_continue_tail). Clean up accordingly.
755 cf_close(cf);
756 cf->redissection_queued = RESCAN_NONE;
757 return CF_READ_ABORTED;
760 if (cf->redissection_queued != RESCAN_NONE) {
761 /* Redissection was queued up. Clear the request and perform it now. */
762 bool redissect = cf->redissection_queued == RESCAN_REDISSECT;
763 rescan_packets(cf, NULL, NULL, redissect);
766 if (cf->stop_flag) {
767 simple_message_box(ESD_TYPE_WARN, NULL,
768 "The remaining packets in the file were discarded.\n"
769 "\n"
770 "As a lot of packets from the original file will be missing,\n"
771 "remember to be careful when saving the current content to a file.\n",
772 "File loading was cancelled.");
773 return CF_READ_ERROR;
776 if (err != 0) {
777 /* Put up a message box noting that the read failed somewhere along
778 the line. Don't throw out the stuff we managed to read, though,
779 if any. */
780 report_cfile_read_failure(NULL, err, err_info);
781 return CF_READ_ERROR;
782 } else if (too_many_records) {
783 simple_message_box(ESD_TYPE_WARN, NULL,
784 "The remaining packets in the file were discarded.\n"
785 "\n"
786 "As a lot of packets from the original file will be missing,\n"
787 "remember to be careful when saving the current content to a file.\n"
788 "\n"
789 "The command-line utility editcap can be used to split "
790 "the file into multiple smaller files",
791 "The file contains more records than the maximum "
792 "supported number of records, %u.", max_records);
793 return CF_READ_ERROR;
794 } else
795 return CF_READ_OK;
798 #ifdef HAVE_LIBPCAP
799 cf_read_status_t
800 cf_continue_tail(capture_file *cf, volatile int to_read, wtap_rec *rec,
801 Buffer *buf, int *err, fifo_string_cache_t *frame_dup_cache, GChecksum *frame_cksum)
803 char *err_info;
804 volatile int newly_displayed_packets = 0;
805 epan_dissect_t edt;
806 bool create_proto_tree;
807 unsigned tap_flags;
809 /* Don't compile the current display filter. The current display filter
810 * text might compile to different code than when the capture started:
812 * If it has a IP address resolved name, calling get_host_ipaddr every
813 * time new packets arrive can mean a *lot* of gethostbyname calls
814 * in flight at once, eventually leading to a timeout (#19612).
815 * addr_resolv.c says that ares_gethostbyname is "usually interactive",
816 * unlike ares_gethostbyaddr (used in dissection), and violating that
817 * expectation is bad.
819 * If it has a display filter macro, the definition might have changed.
821 * If it has a field reference, the selected frame / current proto tree
822 * might have changed, and we don't have the old one. If we recompile,
823 * we can't set the field references to the old values.
825 * For a rescan, redissection, reload, retap, or opening a new file, we
826 * want to compile. What about here, when new frames have arrived in a live
827 * capture? We might be able to cache the host lookup, and a user might want
828 * the new display filter macro definition, but the user almost surely wants
829 * the field references to refer to values from the proto tree when the
830 * filter was applied, not whatever it happens to be now if the user has
831 * clicked on a different packet.
833 * To get the new compiled filter, the user should refilter.
836 /* Get the union of the flags for all tap listeners. */
837 tap_flags = union_of_tap_listener_flags();
840 * Determine whether we need to create a protocol tree.
841 * We do if:
843 * we're going to apply a display filter;
845 * one of the tap listeners is going to apply a filter;
847 * one of the tap listeners requires a protocol tree;
849 * a postdissector wants field values or protocols on
850 * the first pass.
852 create_proto_tree =
853 (cf->dfcode != NULL || have_filtering_tap_listeners() ||
854 (tap_flags & TL_REQUIRES_PROTO_TREE) || postdissectors_want_hfids());
856 *err = 0;
858 /* Don't freeze/thaw the list when doing live capture */
859 /*packet_list_freeze();*/
861 epan_dissect_init(&edt, cf->epan, create_proto_tree, false);
863 TRY {
864 int64_t data_offset = 0;
865 column_info *cinfo;
867 /* If the display filter or any tap listeners require the columns,
868 * construct them. */
869 cinfo = (tap_listeners_require_columns() ||
870 dfilter_requires_columns(cf->dfcode)) ? &cf->cinfo : NULL;
872 while (to_read != 0) {
873 wtap_cleareof(cf->provider.wth);
874 if (!wtap_read(cf->provider.wth, rec, buf, err, &err_info,
875 &data_offset)) {
876 break;
878 if (cf->state == FILE_READ_ABORTED) {
879 /* Well, the user decided to exit Wireshark. Break out of the
880 loop, and let the code below (which is called even if there
881 aren't any packets left to read) exit. */
882 break;
884 if (read_record(cf, rec, buf, cf->dfcode, &edt, cinfo, data_offset, frame_dup_cache, frame_cksum)) {
885 newly_displayed_packets++;
887 to_read--;
889 wtap_rec_reset(rec);
891 CATCH(OutOfMemoryError) {
892 simple_message_box(ESD_TYPE_ERROR, NULL,
893 "More information and workarounds can be found at\n"
894 WS_WIKI_URL("KnownBugs/OutOfMemory"),
895 "Sorry, but Wireshark has run out of memory and has to terminate now.");
896 #if 0
897 /* Could we close the current capture and free up memory from that? */
898 return CF_READ_ABORTED;
899 #else
900 /* we have to terminate, as we cannot recover from the memory error */
901 exit(1);
902 #endif
904 ENDTRY;
906 /* Update the file encapsulation; it might have changed based on the
907 packets we've read. */
908 cf->lnk_t = wtap_file_encap(cf->provider.wth);
910 epan_dissect_cleanup(&edt);
912 /* Don't freeze/thaw the list when doing live capture */
913 /*packet_list_thaw();*/
914 /* With the new packet list the first packet
915 * isn't automatically selected.
917 if (!cf->current_frame && !packet_list_multi_select_active())
918 packet_list_select_row_from_data(NULL);
920 if (cf->state == FILE_READ_ABORTED) {
921 /* Well, the user decided to exit Wireshark. Return CF_READ_ABORTED
922 so that our caller can kill off the capture child process;
923 this will cause an EOF on the pipe from the child, so
924 "cf_finish_tail()" will be called, and it will clean up
925 and exit. */
926 return CF_READ_ABORTED;
927 } else if (*err != 0) {
928 /* We got an error reading the capture file.
929 XXX - pop up a dialog box instead? */
930 if (err_info != NULL) {
931 ws_warning("Error \"%s\" while reading \"%s\" (\"%s\")",
932 wtap_strerror(*err), cf->filename, err_info);
933 g_free(err_info);
934 } else {
935 ws_warning("Error \"%s\" while reading \"%s\"",
936 wtap_strerror(*err), cf->filename);
938 return CF_READ_ERROR;
939 } else
940 return CF_READ_OK;
943 void
944 cf_fake_continue_tail(capture_file *cf)
946 if (cf->state == FILE_CLOSED) {
947 cf->state = FILE_READ_PENDING;
951 cf_read_status_t
952 cf_finish_tail(capture_file *cf, wtap_rec *rec, Buffer *buf, int *err,
953 fifo_string_cache_t *frame_dup_cache, GChecksum *frame_cksum)
955 char *err_info;
956 int64_t data_offset;
957 column_info *cinfo;
958 epan_dissect_t edt;
959 bool create_proto_tree;
960 unsigned tap_flags;
962 /* All the comments above in cf_continue_tail apply regarding the
963 * current display filter.
966 /* Get the union of the flags for all tap listeners. */
967 tap_flags = union_of_tap_listener_flags();
969 /* If the display filter or any tap listeners require the columns,
970 * construct them. */
971 cinfo = (tap_listeners_require_columns() ||
972 dfilter_requires_columns(cf->dfcode)) ? &cf->cinfo : NULL;
975 * Determine whether we need to create a protocol tree.
976 * We do if:
978 * we're going to apply a display filter;
980 * one of the tap listeners is going to apply a filter;
982 * one of the tap listeners requires a protocol tree;
984 * a postdissector wants field values or protocols on
985 * the first pass.
987 create_proto_tree =
988 (cf->dfcode != NULL || have_filtering_tap_listeners() ||
989 (tap_flags & TL_REQUIRES_PROTO_TREE) || postdissectors_want_hfids());
991 if (cf->provider.wth == NULL) {
992 cf_close(cf);
993 return CF_READ_ERROR;
996 /* Don't freeze/thaw the list when doing live capture */
997 /*packet_list_freeze();*/
999 epan_dissect_init(&edt, cf->epan, create_proto_tree, false);
1001 while ((wtap_read(cf->provider.wth, rec, buf, err, &err_info, &data_offset))) {
1002 if (cf->state == FILE_READ_ABORTED) {
1003 /* Well, the user decided to abort the read. Break out of the
1004 loop, and let the code below (which is called even if there
1005 aren't any packets left to read) exit. */
1006 break;
1008 read_record(cf, rec, buf, cf->dfcode, &edt, cinfo, data_offset, frame_dup_cache, frame_cksum);
1009 wtap_rec_reset(rec);
1012 epan_dissect_cleanup(&edt);
1014 /* Don't freeze/thaw the list when doing live capture */
1015 /*packet_list_thaw();*/
1017 if (cf->state == FILE_READ_ABORTED) {
1018 /* Well, the user decided to abort the read. We're only called
1019 when the child capture process closes the pipe to us (meaning
1020 it's probably exited), so we can just close the capture
1021 file; we return CF_READ_ABORTED so our caller can do whatever
1022 is appropriate when that happens. */
1023 cf_close(cf);
1024 return CF_READ_ABORTED;
1027 /* We're done reading sequentially through the file. */
1028 cf->state = FILE_READ_DONE;
1030 /* We're done reading sequentially through the file; close the
1031 sequential I/O side, to free up memory it requires. */
1032 wtap_sequential_close(cf->provider.wth);
1034 /* Allow the protocol dissectors to free up memory that they
1035 * don't need after the sequential run-through of the packets. */
1036 postseq_cleanup_all_protocols();
1038 /* Update the file encapsulation; it might have changed based on the
1039 packets we've read. */
1040 cf->lnk_t = wtap_file_encap(cf->provider.wth);
1042 /* Update the details in the file-set dialog, as the capture file
1043 * has likely grown since we first stat-ed it */
1044 fileset_update_file(cf->filename);
1046 if (*err != 0) {
1047 /* We got an error reading the capture file.
1048 XXX - pop up a dialog box? */
1049 if (err_info != NULL) {
1050 ws_warning("Error \"%s\" while reading \"%s\" (\"%s\")",
1051 wtap_strerror(*err), cf->filename, err_info);
1052 g_free(err_info);
1053 } else {
1054 ws_warning("Error \"%s\" while reading \"%s\"",
1055 wtap_strerror(*err), cf->filename);
1057 return CF_READ_ERROR;
1058 } else {
1059 return CF_READ_OK;
1062 #endif /* HAVE_LIBPCAP */
1064 char *
1065 cf_get_display_name(capture_file *cf)
1067 char *displayname;
1069 /* Return a name to use in displays */
1070 if (!cf->is_tempfile) {
1071 /* Get the last component of the file name, and use that. */
1072 if (cf->filename) {
1073 displayname = g_filename_display_basename(cf->filename);
1074 } else {
1075 displayname=g_strdup("(No file)");
1077 } else {
1078 /* The file we read is a temporary file from a live capture or
1079 a merge operation; we don't mention its name, but, if it's
1080 from a capture, give the source of the capture. */
1081 if (cf->source) {
1082 displayname = g_strdup(cf->source);
1083 } else {
1084 displayname = g_strdup("(Untitled)");
1087 return displayname;
1090 char *
1091 cf_get_basename(capture_file *cf)
1093 char *displayname;
1095 /* Return a name to use in the GUI for the basename for files to
1096 which we save statistics */
1097 if (!cf->is_tempfile) {
1098 /* Get the last component of the file name, and use that. */
1099 if (cf->filename) {
1100 displayname = g_filename_display_basename(cf->filename);
1102 /* If the file name ends with any extension that corresponds
1103 to a file type we support - including compressed versions
1104 of those files - strip it off. */
1105 size_t displayname_len = strlen(displayname);
1106 GSList *extensions = wtap_get_all_file_extensions_list();
1107 GSList *suffix;
1108 for (suffix = extensions; suffix != NULL; suffix = g_slist_next(suffix)) {
1109 /* Does the file name end with that extension? */
1110 const char *extension = (char *)suffix->data;
1111 size_t extension_len = strlen(extension);
1112 if (displayname_len > extension_len &&
1113 displayname[displayname_len - extension_len - 1] == '.' &&
1114 strcmp(&displayname[displayname_len - extension_len], extension) == 0) {
1115 /* Yes. Strip the extension off, and return the result. */
1116 displayname[displayname_len - extension_len - 1] = '\0';
1117 break;
1120 wtap_free_extensions_list(extensions);
1121 } else {
1122 displayname=g_strdup("");
1124 } else {
1125 /* The file we read is a temporary file from a live capture or
1126 a merge operation; we don't mention its name, but, if it's
1127 from a capture, give the source of the capture. */
1128 if (cf->source) {
1129 displayname = g_strdup(cf->source);
1130 } else {
1131 displayname = g_strdup("");
1134 return displayname;
1137 void
1138 cf_set_tempfile_source(capture_file *cf, char *source)
1140 if (cf->source) {
1141 g_free(cf->source);
1144 if (source) {
1145 cf->source = g_strdup(source);
1146 } else {
1147 cf->source = g_strdup("");
1151 const char *
1152 cf_get_tempfile_source(capture_file *cf)
1154 if (!cf->source) {
1155 return "";
1158 return cf->source;
1161 /* XXX - use a macro instead? */
1163 cf_get_packet_count(capture_file *cf)
1165 return cf->count;
1168 /* XXX - use a macro instead? */
1169 bool
1170 cf_is_tempfile(capture_file *cf)
1172 return cf->is_tempfile;
1175 void
1176 cf_set_tempfile(capture_file *cf, bool is_tempfile)
1178 cf->is_tempfile = is_tempfile;
1182 /* XXX - use a macro instead? */
1183 void
1184 cf_set_drops_known(capture_file *cf, bool drops_known)
1186 cf->drops_known = drops_known;
1189 /* XXX - use a macro instead? */
1190 void
1191 cf_set_drops(capture_file *cf, uint32_t drops)
1193 cf->drops = drops;
1196 /* XXX - use a macro instead? */
1197 bool
1198 cf_get_drops_known(capture_file *cf)
1200 return cf->drops_known;
1203 /* XXX - use a macro instead? */
1204 uint32_t
1205 cf_get_drops(capture_file *cf)
1207 return cf->drops;
1210 void
1211 cf_set_rfcode(capture_file *cf, dfilter_t *rfcode)
1213 cf->rfcode = rfcode;
1216 static void
1217 add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
1218 epan_dissect_t *edt, dfilter_t *dfcode, column_info *cinfo,
1219 wtap_rec *rec, Buffer *buf, bool add_to_packet_list)
1221 frame_data_set_before_dissect(fdata, &cf->elapsed_time,
1222 &cf->provider.ref, cf->provider.prev_dis);
1223 cf->provider.prev_cap = fdata;
1225 if (dfcode != NULL) {
1226 epan_dissect_prime_with_dfilter(edt, dfcode);
1228 #if 0
1229 /* Prepare coloring rules, this ensures that display filter rules containing
1230 * frame.color_rule references are still processed.
1231 * TODO: actually detect that situation or maybe apply other optimizations? */
1232 if (edt->tree && color_filters_used()) {
1233 color_filters_prime_edt(edt);
1234 fdata->need_colorize = 1;
1236 #endif
1238 if (!fdata->visited) {
1239 /* This is the first pass, so prime the epan_dissect_t with the
1240 hfids postdissectors want on the first pass. */
1241 prime_epan_dissect_with_postdissector_wanted_hfids(edt);
1244 /* Initialize passed_dfilter here so that dissectors can hide packets. */
1245 /* XXX We might want to add a separate "visible" bit to frame_data instead. */
1246 fdata->passed_dfilter = 1;
1248 /* Dissect the frame. */
1249 epan_dissect_run_with_taps(edt, cf->cd_t, rec,
1250 ws_buffer_start_ptr(buf),
1251 fdata, cinfo);
1253 if (fdata->passed_dfilter && dfcode != NULL) {
1254 fdata->passed_dfilter = dfilter_apply_edt(dfcode, edt) ? 1 : 0;
1256 if (fdata->passed_dfilter && edt->pi.fd->dependent_frames) {
1257 /* This frame passed the display filter but it may depend on other
1258 * (potentially not displayed) frames. Find those frames and mark them
1259 * as depended upon.
1261 g_hash_table_foreach(edt->pi.fd->dependent_frames, find_and_mark_frame_depended_upon, cf->provider.frames);
1265 if (fdata->passed_dfilter || fdata->ref_time) {
1266 cf->displayed_count++;
1267 fdata->dis_num = cf->displayed_count;
1270 if (add_to_packet_list) {
1271 /* We fill the needed columns from new_packet_list */
1272 packet_list_append(cinfo, fdata);
1275 if (fdata->passed_dfilter || fdata->ref_time)
1277 frame_data_set_after_dissect(fdata, &cf->cum_bytes);
1278 /* The only way we use prev_dis is to get the time stamp of
1279 * the previous displayed frame, so ignore it if it doesn't
1280 * have a time stamp, because we're presumably interested in
1281 * the timestamp of the previously displayed frame with a
1282 * time. XXX: What if in the future we want to use the previously
1283 * displayed frame for something else, too?
1285 if (fdata->has_ts) {
1286 cf->provider.prev_dis = fdata;
1289 /* If we haven't yet seen the first frame, this is it. */
1290 if (cf->first_displayed == 0)
1291 cf->first_displayed = fdata->num;
1293 /* This is the last frame we've seen so far. */
1294 cf->last_displayed = fdata->num;
1297 epan_dissect_reset(edt);
1301 * Read in a new record.
1302 * Returns true if the packet was added to the packet (record) list,
1303 * false otherwise.
1305 static bool
1306 read_record(capture_file *cf, wtap_rec *rec, Buffer *buf, dfilter_t *dfcode,
1307 epan_dissect_t *edt, column_info *cinfo, int64_t offset,
1308 fifo_string_cache_t *frame_dup_cache, GChecksum *frame_cksum)
1310 frame_data fdlocal;
1311 frame_data *fdata;
1312 bool passed = true;
1313 bool added = false;
1314 const char *cksum_string;
1315 bool was_in_cache;
1317 /* Add this packet's link-layer encapsulation type to cf->linktypes, if
1318 it's not already there.
1319 XXX - yes, this is O(N), so if every packet had a different
1320 link-layer encapsulation type, it'd be O(N^2) to read the file, but
1321 there are probably going to be a small number of encapsulation types
1322 in a file. */
1323 if (rec->rec_type == REC_TYPE_PACKET) {
1324 cf_add_encapsulation_type(cf, rec->rec_header.packet_header.pkt_encap);
1327 /* The frame number of this packet, if we add it to the set of frames,
1328 would be one more than the count of frames in the file so far. */
1329 frame_data_init(&fdlocal, cf->count + 1, rec, offset, cf->cum_bytes);
1331 if (cf->rfcode) {
1332 epan_dissect_t rf_edt;
1333 column_info *rf_cinfo = NULL;
1335 epan_dissect_init(&rf_edt, cf->epan, true, false);
1336 epan_dissect_prime_with_dfilter(&rf_edt, cf->rfcode);
1337 if (dfilter_requires_columns(cf->rfcode)) {
1338 rf_cinfo = &cf->cinfo;
1340 epan_dissect_run(&rf_edt, cf->cd_t, rec,
1341 ws_buffer_start_ptr(buf),
1342 &fdlocal, rf_cinfo);
1343 passed = dfilter_apply_edt(cf->rfcode, &rf_edt);
1344 epan_dissect_cleanup(&rf_edt);
1347 if (passed) {
1348 added = true;
1350 /* This does a shallow copy of fdlocal, which is good enough. */
1351 fdata = frame_data_sequence_add(cf->provider.frames, &fdlocal);
1353 cf->count++;
1354 if (rec->block != NULL)
1355 cf->packet_comment_count += wtap_block_count_option(rec->block, OPT_COMMENT);
1356 cf->f_datalen = offset + fdlocal.cap_len;
1358 // Should we check if the frame data is a duplicate, and thus, ignore
1359 // this frame?
1360 if (frame_cksum != NULL && rec->rec_type == REC_TYPE_PACKET) {
1361 g_checksum_reset(frame_cksum);
1362 g_checksum_update(frame_cksum, ws_buffer_start_ptr(buf), ws_buffer_length(buf));
1363 cksum_string = g_strdup(g_checksum_get_string(frame_cksum));
1364 was_in_cache = fifo_string_cache_insert(frame_dup_cache, cksum_string);
1365 if (was_in_cache) {
1366 g_free((void *)cksum_string);
1367 fdata->ignored = true;
1368 cf->ignored_count++;
1372 /* When a redissection is in progress (or queued), do not process packets.
1373 * This will be done once all (new) packets have been scanned. */
1374 if (!cf->redissecting && cf->redissection_queued == RESCAN_NONE) {
1375 add_packet_to_packet_list(fdata, cf, edt, dfcode, cinfo, rec, buf, true);
1379 return added;
1383 typedef struct _callback_data_t {
1384 void * pd_window;
1385 int64_t f_len;
1386 progdlg_t *progbar;
1387 GTimer *prog_timer;
1388 bool stop_flag;
1389 } callback_data_t;
1392 static bool
1393 merge_callback(merge_event event, int num _U_,
1394 const merge_in_file_t in_files[], const unsigned in_file_count,
1395 void *data)
1397 unsigned i;
1398 callback_data_t *cb_data = (callback_data_t*) data;
1400 ws_assert(cb_data != NULL);
1402 switch (event) {
1404 case MERGE_EVENT_INPUT_FILES_OPENED:
1405 /* do nothing */
1406 break;
1408 case MERGE_EVENT_FRAME_TYPE_SELECTED:
1409 /* do nothing */
1410 break;
1412 case MERGE_EVENT_READY_TO_MERGE:
1413 /* Get the sum of the sizes of all the files. */
1414 for (i = 0; i < in_file_count; i++)
1415 cb_data->f_len += in_files[i].size;
1417 cb_data->prog_timer = g_timer_new();
1418 g_timer_start(cb_data->prog_timer);
1419 break;
1421 case MERGE_EVENT_RECORD_WAS_READ:
1423 /* Create the progress bar if necessary.
1424 We check on every iteration of the loop, so that it takes no
1425 longer than the standard time to create it (otherwise, for a
1426 large file, we might take considerably longer than that standard
1427 time in order to get to the next progress bar step). */
1428 if (cb_data->progbar == NULL) {
1429 cb_data->progbar = delayed_create_progress_dlg(cb_data->pd_window, NULL, NULL,
1430 false, &cb_data->stop_flag, 0.0f);
1434 * Update the progress bar, but do it only after
1435 * PROGBAR_UPDATE_INTERVAL has elapsed. Calling update_progress_dlg
1436 * and packets_bar_update will likely trigger UI paint events, which
1437 * might take a while depending on the platform and display. Reset
1438 * our timer *after* painting.
1440 if (g_timer_elapsed(cb_data->prog_timer, NULL) > PROGBAR_UPDATE_INTERVAL) {
1441 float progbar_val;
1442 int64_t file_pos = 0;
1443 /* Get the sum of the seek positions in all of the files. */
1444 for (i = 0; i < in_file_count; i++)
1445 file_pos += wtap_read_so_far(in_files[i].wth);
1447 progbar_val = (float) file_pos / (float) cb_data->f_len;
1448 if (progbar_val > 1.0f) {
1449 /* Some file probably grew while we were reading it.
1450 That "shouldn't happen", so we'll just clip the progress
1451 value at 1.0. */
1452 progbar_val = 1.0f;
1455 if (cb_data->progbar != NULL) {
1456 char status_str[100];
1457 snprintf(status_str, sizeof(status_str),
1458 "%" PRId64 "KB of %" PRId64 "KB",
1459 file_pos / 1024, cb_data->f_len / 1024);
1460 update_progress_dlg(cb_data->progbar, progbar_val, status_str);
1462 g_timer_start(cb_data->prog_timer);
1465 break;
1467 case MERGE_EVENT_DONE:
1468 /* We're done merging the files; destroy the progress bar if it was created. */
1469 if (cb_data->progbar != NULL)
1470 destroy_progress_dlg(cb_data->progbar);
1471 g_timer_destroy(cb_data->prog_timer);
1472 break;
1475 return cb_data->stop_flag;
1480 cf_status_t
1481 cf_merge_files_to_tempfile(void *pd_window, const char *temp_dir, char **out_filenamep,
1482 int in_file_count, const char *const *in_filenames,
1483 int file_type, bool do_append)
1485 bool status;
1486 merge_progress_callback_t cb;
1487 callback_data_t *cb_data = g_new0(callback_data_t, 1);
1489 /* prepare our callback routine */
1490 cb_data->pd_window = pd_window;
1491 cb.callback_func = merge_callback;
1492 cb.data = cb_data;
1494 cf_callback_invoke(cf_cb_file_merge_started, NULL);
1496 /* merge the files */
1497 status = merge_files_to_tempfile(temp_dir, out_filenamep, "wireshark", file_type,
1498 in_filenames,
1499 in_file_count, do_append,
1500 IDB_MERGE_MODE_ALL_SAME, 0 /* snaplen */,
1501 "Wireshark", &cb);
1503 g_free(cb.data);
1505 cf_callback_invoke(cf_cb_file_merge_finished, NULL);
1507 if (!status) {
1508 /* Callers aren't expected to treat an error or an explicit abort
1509 differently - the merge code puts up error dialogs itself, so
1510 they don't have to. */
1511 return CF_ERROR;
1512 } else
1513 return CF_OK;
1516 cf_status_t
1517 cf_filter_packets(capture_file *cf, char *dftext, bool force)
1519 const char *filter_new = dftext ? dftext : "";
1520 const char *filter_old = cf->dfilter ? cf->dfilter : "";
1521 dfilter_t *dfcode;
1522 df_error_t *df_err;
1524 /* if new filter equals old one, do nothing unless told to do so */
1525 /* XXX - The text can be the same without compiling to the same code.
1526 * (Macros, field references, etc.)
1528 if (!force && strcmp(filter_new, filter_old) == 0) {
1529 return CF_OK;
1532 dfcode=NULL;
1534 if (dftext == NULL) {
1535 /* The new filter is an empty filter (i.e., display all packets).
1536 * so leave dfcode==NULL
1538 } else {
1540 * We have a filter; make a copy of it (as we'll be saving it),
1541 * and try to compile it.
1543 dftext = g_strdup(dftext);
1544 if (!dfilter_compile(dftext, &dfcode, &df_err)) {
1545 /* The attempt failed; report an error. */
1546 simple_message_box(ESD_TYPE_ERROR, NULL,
1547 "See the help for a description of the display filter syntax.",
1548 "\"%s\" isn't a valid display filter: %s",
1549 dftext, df_err->msg);
1550 df_error_free(&df_err);
1551 g_free(dftext);
1552 return CF_ERROR;
1555 /* Was it empty? */
1556 if (dfcode == NULL) {
1557 /* Yes - free the filter text, and set it to null. */
1558 g_free(dftext);
1559 dftext = NULL;
1563 /* We have a valid filter. Replace the current filter. */
1564 g_free(cf->dfilter);
1565 cf->dfilter = dftext;
1567 /* We'll recompile this when the rescan starts, or in cf_read()
1568 * if no file is open currently. However, if no file is open and
1569 * we start a new capture, we want to use this rather than
1570 * recompiling in cf_continue_tail() */
1571 dfilter_free(cf->dfcode);
1572 cf->dfcode = dfcode;
1574 /* Now rescan the packet list, applying the new filter, but not
1575 * throwing away information constructed on a previous pass.
1576 * If a dissection is already in progress, queue it.
1578 if (cf->redissection_queued == RESCAN_NONE) {
1579 if (cf->read_lock) {
1580 cf->redissection_queued = RESCAN_SCAN;
1581 } else if (cf->state != FILE_CLOSED) {
1582 if (dftext == NULL) {
1583 rescan_packets(cf, "Resetting", "filter", false);
1584 } else {
1585 rescan_packets(cf, "Filtering", dftext, false);
1590 return CF_OK;
1593 void
1594 cf_redissect_packets(capture_file *cf)
1596 if (cf->read_lock || cf->redissection_queued == RESCAN_SCAN) {
1597 /* Dissection in progress, signal redissection rather than rescanning. That
1598 * would destroy the current (in-progress) dissection in "cf_read" which
1599 * will cause issues when "cf_read" tries to add packets to the list.
1600 * If a previous rescan was requested, "upgrade" it to a full redissection.
1602 cf->redissection_queued = RESCAN_REDISSECT;
1604 if (cf->redissection_queued != RESCAN_NONE) {
1605 /* Redissection is (already) queued, wait for "cf_read" to finish. */
1606 /* XXX - what if whatever set and later clears read_lock is *not*
1607 * cf_read, e.g. process_specified_records ? We need to handle a
1608 * queued redissection there too like we do in cf_read.
1610 return;
1613 if (cf->state != FILE_CLOSED) {
1614 /* Restart dissection in case no cf_read is pending. */
1615 rescan_packets(cf, "Reprocessing", "all packets", true);
1619 bool
1620 cf_read_record(capture_file *cf, const frame_data *fdata,
1621 wtap_rec *rec, Buffer *buf)
1623 int err;
1624 char *err_info;
1626 if (!wtap_seek_read(cf->provider.wth, fdata->file_off, rec, buf, &err, &err_info)) {
1627 report_cfile_read_failure(cf->filename, err, err_info);
1628 return false;
1630 return true;
1633 bool
1634 cf_read_record_no_alert(capture_file *cf, const frame_data *fdata,
1635 wtap_rec *rec, Buffer *buf)
1637 int err;
1638 char *err_info;
1640 if (!wtap_seek_read(cf->provider.wth, fdata->file_off, rec, buf, &err, &err_info)) {
1641 g_free(err_info);
1642 return false;
1644 return true;
1647 bool
1648 cf_read_current_record(capture_file *cf)
1650 return cf_read_record(cf, cf->current_frame, &cf->rec, &cf->buf);
1653 /* Rescan the list of packets, reconstructing the CList.
1655 "action" describes why we're doing this; it's used in the progress
1656 dialog box.
1658 "action_item" describes what we're doing; it's used in the progress
1659 dialog box.
1661 "redissect" is true if we need to make the dissectors reconstruct
1662 any state information they have (because a preference that affects
1663 some dissector has changed, meaning some dissector might construct
1664 its state differently from the way it was constructed the last time). */
1665 static void
1666 rescan_packets(capture_file *cf, const char *action, const char *action_item, bool redissect)
1668 /* Rescan packets new packet list */
1669 uint32_t framenum;
1670 frame_data *fdata;
1671 wtap_rec rec;
1672 Buffer buf;
1673 progdlg_t *progbar = NULL;
1674 GTimer *prog_timer = g_timer_new();
1675 int count;
1676 frame_data *selected_frame, *preceding_frame, *following_frame, *prev_frame;
1677 int selected_frame_num, preceding_frame_num, following_frame_num, prev_frame_num;
1678 bool selected_frame_seen;
1679 float progbar_val;
1680 int64_t start_time;
1681 char status_str[100];
1682 epan_dissect_t edt;
1683 dfilter_t *dfcode = NULL;
1684 column_info *cinfo;
1685 bool create_proto_tree;
1686 bool filtering_tap_listeners = false;
1687 unsigned tap_flags;
1688 bool add_to_packet_list = false;
1689 bool compiled _U_;
1690 uint32_t frames_count;
1691 rescan_type queued_rescan_type = RESCAN_NONE;
1693 if (cf->state == FILE_CLOSED || cf->state == FILE_READ_PENDING) {
1694 return;
1697 /* Rescan in progress, clear pending actions. */
1698 cf->redissection_queued = RESCAN_NONE;
1699 ws_assert(!cf->read_lock);
1700 cf->read_lock = true;
1702 wtap_rec_init(&rec);
1703 ws_buffer_init(&buf, 1514);
1705 /* Compile the current display filter.
1706 * The code it compiles to might have changed, e.g. if a display
1707 * filter macro used has changed.
1709 * We assume this will not fail since cf->dfilter is only set in
1710 * cf_filter IFF the filter was valid.
1711 * XXX - This is not necessarily true, if the filter has a FT_IPv4
1712 * or FT_IPv6 field compared to a resolved hostname in it, because
1713 * we do a new host lookup, and that *could* timeout this time
1714 * (though with the read lock above we shouldn't have many lookups at
1715 * once, reducing the chances of that)... (#19612)
1717 if (cf->dfilter) {
1718 compiled = dfilter_compile(cf->dfilter, &dfcode, NULL);
1719 ws_assert(compiled && dfcode);
1722 dfilter_free(cf->dfcode);
1723 cf->dfcode = dfcode;
1725 /* Do we have any tap listeners with filters? */
1726 filtering_tap_listeners = have_filtering_tap_listeners();
1728 /* Update references in filters (if any) for the protocol
1729 * tree corresponding to the currently selected frame in the GUI. */
1730 if (cf->edt != NULL && cf->edt->tree != NULL) {
1731 if (cf->dfcode)
1732 dfilter_load_field_references(cf->dfcode, cf->edt->tree);
1733 if (filtering_tap_listeners)
1734 tap_listeners_load_field_references(cf->edt);
1737 if (cf->dfcode != NULL) {
1738 dfilter_log_full(LOG_DOMAIN_DFILTER, LOG_LEVEL_NOISY, NULL, -1, NULL,
1739 cf->dfcode, "Rescanning packets with display filter");
1742 /* Get the union of the flags for all tap listeners. */
1743 tap_flags = union_of_tap_listener_flags();
1745 /* If the display filter or any tap listeners require the columns,
1746 * construct them. */
1747 cinfo = (tap_listeners_require_columns() ||
1748 dfilter_requires_columns(cf->dfcode)) ? &cf->cinfo : NULL;
1751 * Determine whether we need to create a protocol tree.
1752 * We do if:
1754 * we're going to apply a display filter;
1756 * one of the tap listeners is going to apply a filter;
1758 * one of the tap listeners requires a protocol tree;
1760 * we're redissecting and a postdissector wants field
1761 * values or protocols on the first pass.
1763 create_proto_tree =
1764 (cf->dfcode != NULL || filtering_tap_listeners ||
1765 (tap_flags & TL_REQUIRES_PROTO_TREE) ||
1766 (redissect && postdissectors_want_hfids()));
1768 reset_tap_listeners();
1769 /* Which frame, if any, is the currently selected frame?
1770 XXX - should the selected frame or the focus frame be the "current"
1771 frame, that frame being the one from which "Find Frame" searches
1772 start? */
1773 selected_frame = cf->current_frame;
1775 /* Mark frame num as not found */
1776 selected_frame_num = -1;
1778 /* Freeze the packet list while we redo it, so we don't get any
1779 screen updates while it happens. */
1780 packet_list_freeze();
1782 if (redissect) {
1783 /* We need to re-initialize all the state information that protocols
1784 keep, because some preference that controls a dissector has changed,
1785 which might cause the state information to be constructed differently
1786 by that dissector. */
1788 /* We might receive new packets while redissecting, and we don't
1789 want to dissect those before their time. */
1790 cf->redissecting = true;
1792 /* 'reset' dissection session */
1793 epan_free(cf->epan);
1794 if (cf->edt && cf->edt->pi.fd) {
1795 /* All pointers in "per frame proto data" for the currently selected
1796 packet are allocated in wmem_file_scope() and deallocated in epan_free().
1797 Free them here to avoid unintended usage in packet_list_clear(). */
1798 frame_data_destroy(cf->edt->pi.fd);
1800 cf->epan = ws_epan_new(cf);
1801 cf->cinfo.epan = cf->epan;
1803 /* A new Lua tap listener may be registered in lua_prime_all_fields()
1804 called via epan_new() / init_dissection() when reloading Lua plugins. */
1805 if (!create_proto_tree && have_filtering_tap_listeners()) {
1806 create_proto_tree = true;
1808 if (!cinfo && tap_listeners_require_columns()) {
1809 cinfo = &cf->cinfo;
1812 /* We need to redissect the packets so we have to discard our old
1813 * packet list store. */
1814 packet_list_clear();
1815 add_to_packet_list = true;
1818 /* We don't yet know which will be the first and last frames displayed. */
1819 cf->first_displayed = 0;
1820 cf->last_displayed = 0;
1822 /* We currently don't display any packets */
1823 cf->displayed_count = 0;
1825 /* Iterate through the list of frames. Call a routine for each frame
1826 to check whether it should be displayed and, if so, add it to
1827 the display list. */
1828 cf->provider.ref = NULL;
1829 cf->provider.prev_dis = NULL;
1830 cf->provider.prev_cap = NULL;
1831 cf->cum_bytes = 0;
1833 cf_callback_invoke(cf_cb_file_rescan_started, cf);
1835 g_timer_start(prog_timer);
1836 /* Count of packets at which we've looked. */
1837 count = 0;
1838 /* Progress so far. */
1839 progbar_val = 0.0f;
1841 cf->stop_flag = false;
1842 start_time = g_get_monotonic_time();
1844 /* no previous row yet */
1845 prev_frame_num = -1;
1846 prev_frame = NULL;
1848 preceding_frame_num = -1;
1849 preceding_frame = NULL;
1850 following_frame_num = -1;
1851 following_frame = NULL;
1853 selected_frame_seen = false;
1855 frames_count = cf->count;
1857 epan_dissect_init(&edt, cf->epan, create_proto_tree, false);
1859 if (redissect) {
1861 * Decryption secrets and name resolution blocks are read while
1862 * sequentially processing records and then passed to the dissector.
1863 * During redissection, the previous information is lost (see epan_free
1864 * above), but they are not read again from the file as only packet
1865 * records are re-read. Therefore reset the wtap secrets and name
1866 * resolution callbacks such that wtap resupplies the callbacks with
1867 * previously read information.
1869 wtap_set_cb_new_ipv4(cf->provider.wth, add_ipv4_name);
1870 wtap_set_cb_new_ipv6(cf->provider.wth, (wtap_new_ipv6_callback_t) add_ipv6_name);
1871 wtap_set_cb_new_secrets(cf->provider.wth, secrets_wtap_callback);
1874 for (framenum = 1; framenum <= frames_count; framenum++) {
1875 fdata = frame_data_sequence_find(cf->provider.frames, framenum);
1877 /* Create the progress bar if necessary.
1878 We check on every iteration of the loop, so that it takes no
1879 longer than the standard time to create it (otherwise, for a
1880 large file, we might take considerably longer than that standard
1881 time in order to get to the next progress bar step). */
1882 if (progbar == NULL)
1883 progbar = delayed_create_progress_dlg(cf->window, action, action_item, true,
1884 &cf->stop_flag,
1885 progbar_val);
1888 * Update the progress bar, but do it only after PROGBAR_UPDATE_INTERVAL
1889 * has elapsed. Calling update_progress_dlg and packets_bar_update will
1890 * likely trigger UI paint events, which might take a while depending on
1891 * the platform and display. Reset our timer *after* painting.
1893 if (g_timer_elapsed(prog_timer, NULL) > PROGBAR_UPDATE_INTERVAL) {
1894 /* let's not divide by zero. I should never be started
1895 * with count == 0, so let's assert that
1897 ws_assert(cf->count > 0);
1898 progbar_val = (float) count / frames_count;
1900 if (progbar != NULL) {
1901 snprintf(status_str, sizeof(status_str),
1902 "%4u of %u frames", count, frames_count);
1903 update_progress_dlg(progbar, progbar_val, status_str);
1906 g_timer_start(prog_timer);
1909 queued_rescan_type = cf->redissection_queued;
1910 if (queued_rescan_type != RESCAN_NONE) {
1911 /* A redissection was requested while an existing redissection was
1912 * pending. */
1913 break;
1916 if (cf->stop_flag) {
1917 /* Well, the user decided to abort the filtering. Just stop.
1919 XXX - go back to the previous filter? Users probably just
1920 want not to wait for a filtering operation to finish;
1921 unless we cancel by having no filter, reverting to the
1922 previous filter will probably be even more expensive than
1923 continuing the filtering, as it involves going back to the
1924 beginning and filtering, and even with no filter we currently
1925 have to re-generate the entire clist, which is also expensive.
1927 I'm not sure what Network Monitor does, but it doesn't appear
1928 to give you an unfiltered display if you cancel. */
1929 break;
1932 count++;
1934 if (redissect) {
1935 /* Since all state for the frame was destroyed, mark the frame
1936 * as not visited, free the GSList referring to the state
1937 * data (the per-frame data itself was freed by
1938 * "init_dissection()"), and null out the GSList pointer. */
1939 frame_data_reset(fdata);
1940 frames_count = cf->count;
1943 /* Frame dependencies from the previous dissection/filtering are no longer valid. */
1944 fdata->dependent_of_displayed = 0;
1946 if (!cf_read_record(cf, fdata, &rec, &buf))
1947 break; /* error reading the frame */
1949 /* If the previous frame is displayed, and we haven't yet seen the
1950 selected frame, remember that frame - it's the closest one we've
1951 yet seen before the selected frame. */
1952 if (prev_frame_num != -1 && !selected_frame_seen && prev_frame->passed_dfilter) {
1953 preceding_frame_num = prev_frame_num;
1954 preceding_frame = prev_frame;
1957 add_packet_to_packet_list(fdata, cf, &edt, cf->dfcode,
1958 cinfo, &rec, &buf,
1959 add_to_packet_list);
1961 /* If this frame is displayed, and this is the first frame we've
1962 seen displayed after the selected frame, remember this frame -
1963 it's the closest one we've yet seen at or after the selected
1964 frame. */
1965 if (fdata->passed_dfilter && selected_frame_seen && following_frame_num == -1) {
1966 following_frame_num = fdata->num;
1967 following_frame = fdata;
1969 if (fdata == selected_frame) {
1970 selected_frame_seen = true;
1971 if (fdata->passed_dfilter)
1972 selected_frame_num = fdata->num;
1975 /* Remember this frame - it'll be the previous frame
1976 on the next pass through the loop. */
1977 prev_frame_num = fdata->num;
1978 prev_frame = fdata;
1979 wtap_rec_reset(&rec);
1982 epan_dissect_cleanup(&edt);
1983 wtap_rec_cleanup(&rec);
1984 ws_buffer_free(&buf);
1986 /* We are done redissecting the packet list. */
1987 cf->redissecting = false;
1989 if (redissect) {
1990 frames_count = cf->count;
1991 /* Clear out what remains of the visited flags and per-frame data
1992 pointers.
1994 XXX - that may cause various forms of bogosity when dissecting
1995 these frames, as they won't have been seen by this sequential
1996 pass, but the only alternative I see is to keep scanning them
1997 even though the user requested that the scan stop, and that
1998 would leave the user stuck with an Wireshark grinding on
1999 until it finishes. Should we just stick them with that? */
2000 for (; framenum <= frames_count; framenum++) {
2001 fdata = frame_data_sequence_find(cf->provider.frames, framenum);
2002 frame_data_reset(fdata);
2006 /* We're done filtering the packets; destroy the progress bar if it
2007 was created. */
2008 if (progbar != NULL)
2009 destroy_progress_dlg(progbar);
2010 g_timer_destroy(prog_timer);
2012 /* Unfreeze the packet list. */
2013 if (!add_to_packet_list)
2014 packet_list_recreate_visible_rows();
2016 /* Compute the time it took to filter the file */
2017 compute_elapsed(cf, start_time);
2019 packet_list_thaw();
2021 /* It is safe again to execute redissections or sort. */
2022 ws_assert(cf->read_lock);
2023 cf->read_lock = false;
2025 cf_callback_invoke(cf_cb_file_rescan_finished, cf);
2027 if (selected_frame_num == -1) {
2028 /* The selected frame didn't pass the filter. */
2029 if (selected_frame == NULL) {
2030 /* That's because there *was* no selected frame. Make the first
2031 displayed frame the current frame. */
2032 selected_frame_num = 0;
2033 } else {
2034 /* Find the nearest displayed frame to the selected frame (whether
2035 it's before or after that frame) and make that the current frame.
2036 If the next and previous displayed frames are equidistant from the
2037 selected frame, choose the next one. */
2038 ws_assert(following_frame == NULL ||
2039 following_frame->num >= selected_frame->num);
2040 ws_assert(preceding_frame == NULL ||
2041 preceding_frame->num <= selected_frame->num);
2042 if (following_frame == NULL) {
2043 /* No frame after the selected frame passed the filter, so we
2044 have to select the last displayed frame before the selected
2045 frame. */
2046 selected_frame_num = preceding_frame_num;
2047 selected_frame = preceding_frame;
2048 } else if (preceding_frame == NULL) {
2049 /* No frame before the selected frame passed the filter, so we
2050 have to select the first displayed frame after the selected
2051 frame. */
2052 selected_frame_num = following_frame_num;
2053 selected_frame = following_frame;
2054 } else {
2055 /* Frames before and after the selected frame passed the filter, so
2056 we'll select the previous frame */
2057 selected_frame_num = preceding_frame_num;
2058 selected_frame = preceding_frame;
2063 if (selected_frame_num == -1) {
2064 /* There are no frames displayed at all. */
2065 cf_unselect_packet(cf);
2066 } else {
2067 /* Either the frame that was selected passed the filter, or we've
2068 found the nearest displayed frame to that frame. Select it, make
2069 it the focus row, and make it visible. */
2070 /* Set to invalid to force update of packet list and packet details */
2071 if (selected_frame_num == 0) {
2072 packet_list_select_row_from_data(NULL);
2073 }else{
2074 if (!packet_list_select_row_from_data(selected_frame)) {
2075 /* We didn't find a row corresponding to this frame.
2076 This means that the frame isn't being displayed currently,
2077 so we can't select it. */
2078 simple_message_box(ESD_TYPE_INFO, NULL,
2079 "The capture file is probably not fully dissected.",
2080 "End of capture exceeded.");
2085 /* If another rescan (due to dfilter change) or redissection (due to profile
2086 * change) was requested, the rescan above is aborted and restarted here. */
2087 if (queued_rescan_type != RESCAN_NONE) {
2088 redissect = redissect || queued_rescan_type == RESCAN_REDISSECT;
2089 rescan_packets(cf, "Reprocessing", "all packets", redissect);
2095 * Scan through all frame data and recalculate the ref time
2096 * without rereading the file.
2097 * XXX - do we need a progress bar or is this fast enough?
2099 void
2100 cf_reftime_packets(capture_file* cf)
2102 uint32_t framenum;
2103 frame_data *fdata;
2104 nstime_t rel_ts;
2106 cf->provider.ref = NULL;
2107 cf->provider.prev_dis = NULL;
2108 cf->cum_bytes = 0;
2110 for (framenum = 1; framenum <= cf->count; framenum++) {
2111 fdata = frame_data_sequence_find(cf->provider.frames, framenum);
2113 /* just add some value here until we know if it is being displayed or not */
2114 fdata->cum_bytes = cf->cum_bytes + fdata->pkt_len;
2117 * Timestamps
2120 if (fdata->has_ts) {
2121 /* If we don't have the time stamp of the first packet in the
2122 capture, it's because this is the first packet. Save the time
2123 stamp of this packet as the time stamp of the first packet. */
2124 if (cf->provider.ref == NULL)
2125 cf->provider.ref = fdata;
2126 /* if this frames is marked as a reference time frame, reset
2127 firstsec and firstusec to this frame */
2128 if (fdata->ref_time)
2129 cf->provider.ref = fdata;
2131 /* Get the time elapsed between the first packet and this one. */
2132 fdata->frame_ref_num = (fdata != cf->provider.ref) ? cf->provider.ref->num : 0;
2133 nstime_delta(&rel_ts, &fdata->abs_ts, &cf->provider.ref->abs_ts);
2135 /* If it's greater than the current elapsed time, set the elapsed
2136 time to it (we check for "greater than" so as not to be
2137 confused by time moving backwards). */
2138 if ((int32_t)cf->elapsed_time.secs < rel_ts.secs
2139 || ((int32_t)cf->elapsed_time.secs == rel_ts.secs && (int32_t)cf->elapsed_time.nsecs < rel_ts.nsecs)) {
2140 cf->elapsed_time = rel_ts;
2143 /* If this frame is displayed, get the time elapsed between the
2144 previous displayed packet and this packet. */
2145 /* XXX: What if in the future we want to use the previously
2146 * displayed frame for something else, too? Then we'd want
2147 * to store this frame as prev_dis even if it doesn't have a
2148 * timestamp. */
2149 if ( fdata->passed_dfilter ) {
2150 /* If we don't have the time stamp of the previous displayed
2151 packet, it's because this is the first displayed packet.
2152 Save the time stamp of this packet as the time stamp of
2153 the previous displayed packet. */
2154 if (cf->provider.prev_dis == NULL) {
2155 cf->provider.prev_dis = fdata;
2158 fdata->prev_dis_num = cf->provider.prev_dis->num;
2159 cf->provider.prev_dis = fdata;
2161 } else {
2162 /* If this frame doesn't have a timestamp, don't calculate
2163 anything with relative times. */
2164 /* However, if this frame is marked as a reference time frame,
2165 clear the reference frame so that the next frame with a
2166 timestamp becomes the reference frame. */
2167 if (fdata->ref_time) {
2168 cf->provider.ref = NULL;
2173 * Byte counts
2175 if ( (fdata->passed_dfilter) || (fdata->ref_time) ) {
2176 /* This frame either passed the display filter list or is marked as
2177 a time reference frame. All time reference frames are displayed
2178 even if they don't pass the display filter */
2179 if (fdata->ref_time) {
2180 /* if this was a TIME REF frame we should reset the cum_bytes field */
2181 cf->cum_bytes = fdata->pkt_len;
2182 fdata->cum_bytes = cf->cum_bytes;
2183 } else {
2184 /* increase cum_bytes with this packets length */
2185 cf->cum_bytes += fdata->pkt_len;
2191 typedef enum {
2192 PSP_FINISHED,
2193 PSP_STOPPED,
2194 PSP_FAILED
2195 } psp_return_t;
2197 static psp_return_t
2198 process_specified_records(capture_file *cf, packet_range_t *range,
2199 const char *string1, const char *string2, bool terminate_is_stop,
2200 bool (*callback)(capture_file *, frame_data *,
2201 wtap_rec *, Buffer *, void *),
2202 void *callback_args,
2203 bool show_progress_bar)
2205 uint32_t framenum;
2206 frame_data *fdata;
2207 wtap_rec rec;
2208 Buffer buf;
2209 psp_return_t ret = PSP_FINISHED;
2211 progdlg_t *progbar = NULL;
2212 GTimer *prog_timer = g_timer_new();
2213 int progbar_count;
2214 float progbar_val;
2215 char progbar_status_str[100];
2216 range_process_e process_this;
2218 wtap_rec_init(&rec);
2219 ws_buffer_init(&buf, 1514);
2221 g_timer_start(prog_timer);
2222 /* Count of packets at which we've looked. */
2223 progbar_count = 0;
2224 /* Progress so far. */
2225 progbar_val = 0.0f;
2227 /* XXX - It should be ok to have multiple readers, so long as nothing
2228 * frees the epan context, e.g. rescan_packets with redissect true,
2229 * or anything that closes the file (including reload and certain forms
2230 * of saving.) This is mostly to stop cf_save_records but should probably
2231 * be handled by callers in order to allow multiple readers (e.g.,
2232 * restarting taps after adding or changing one.) We should probably
2233 * make this a real reader-writer lock.
2235 if (cf->read_lock) {
2236 ws_warning("Failing due to nested process_specified_records(\"%s\") call!", cf->filename);
2237 return PSP_FAILED;
2239 cf->read_lock = true;
2241 cf->stop_flag = false;
2243 if (range != NULL)
2244 packet_range_process_init(range);
2246 /* Iterate through all the packets, printing the packets that
2247 were selected by the current display filter. */
2248 for (framenum = 1; framenum <= cf->count; framenum++) {
2249 fdata = frame_data_sequence_find(cf->provider.frames, framenum);
2251 /* Create the progress bar if necessary.
2252 We check on every iteration of the loop, so that it takes no
2253 longer than the standard time to create it (otherwise, for a
2254 large file, we might take considerably longer than that standard
2255 time in order to get to the next progress bar step). */
2256 if (show_progress_bar && progbar == NULL)
2257 progbar = delayed_create_progress_dlg(cf->window, string1, string2,
2258 terminate_is_stop,
2259 &cf->stop_flag,
2260 progbar_val);
2263 * Update the progress bar, but do it only after PROGBAR_UPDATE_INTERVAL
2264 * has elapsed. Calling update_progress_dlg and packets_bar_update will
2265 * likely trigger UI paint events, which might take a while depending on
2266 * the platform and display. Reset our timer *after* painting.
2268 if (progbar && g_timer_elapsed(prog_timer, NULL) > PROGBAR_UPDATE_INTERVAL) {
2269 /* let's not divide by zero. I should never be started
2270 * with count == 0, so let's assert that
2272 ws_assert(cf->count > 0);
2273 progbar_val = (float) progbar_count / cf->count;
2275 snprintf(progbar_status_str, sizeof(progbar_status_str),
2276 "%4u of %u packets", progbar_count, cf->count);
2277 update_progress_dlg(progbar, progbar_val, progbar_status_str);
2279 g_timer_start(prog_timer);
2282 if (cf->stop_flag) {
2283 /* Well, the user decided to abort the operation. Just stop,
2284 and arrange to return PSP_STOPPED to our caller, so they know
2285 it was stopped explicitly. */
2286 ret = PSP_STOPPED;
2287 break;
2290 progbar_count++;
2292 if (range != NULL) {
2293 /* do we have to process this packet? */
2294 process_this = packet_range_process_packet(range, fdata);
2295 if (process_this == range_process_next) {
2296 /* this packet uninteresting, continue with next one */
2297 continue;
2298 } else if (process_this == range_processing_finished) {
2299 /* all interesting packets processed, stop the loop */
2300 break;
2304 /* Get the packet */
2305 if (!cf_read_record(cf, fdata, &rec, &buf)) {
2306 /* Attempt to get the packet failed. */
2307 ret = PSP_FAILED;
2308 break;
2310 /* Process the packet */
2311 if (!callback(cf, fdata, &rec, &buf, callback_args)) {
2312 /* Callback failed. We assume it reported the error appropriately. */
2313 ret = PSP_FAILED;
2314 break;
2316 wtap_rec_reset(&rec);
2319 /* We're done printing the packets; destroy the progress bar if
2320 it was created. */
2321 if (progbar != NULL)
2322 destroy_progress_dlg(progbar);
2323 g_timer_destroy(prog_timer);
2325 ws_assert(cf->read_lock);
2326 cf->read_lock = false;
2328 wtap_rec_cleanup(&rec);
2329 ws_buffer_free(&buf);
2331 return ret;
2334 typedef struct {
2335 epan_dissect_t edt;
2336 column_info *cinfo;
2337 } retap_callback_args_t;
2339 static bool
2340 retap_packet(capture_file *cf, frame_data *fdata, wtap_rec *rec, Buffer *buf,
2341 void *argsp)
2343 retap_callback_args_t *args = (retap_callback_args_t *)argsp;
2345 epan_dissect_run_with_taps(&args->edt, cf->cd_t, rec,
2346 ws_buffer_start_ptr(buf),
2347 fdata, args->cinfo);
2348 epan_dissect_reset(&args->edt);
2350 return true;
2353 cf_read_status_t
2354 cf_retap_packets(capture_file *cf)
2356 packet_range_t range;
2357 retap_callback_args_t callback_args;
2358 bool create_proto_tree;
2359 bool filtering_tap_listeners;
2360 unsigned tap_flags;
2361 psp_return_t ret;
2363 /* Presumably the user closed the capture file. */
2364 if (cf == NULL) {
2365 return CF_READ_ABORTED;
2368 /* XXX - If cf->read_lock is true, process_specified_records will fail
2369 * due to a nested call. We fail here so that we don't reset the tap
2370 * listeners if this tap isn't going to succeed.
2372 if (cf->read_lock) {
2373 ws_warning("Failing due to nested process_specified_records(\"%s\") call!", cf->filename);
2374 return CF_READ_ERROR;
2377 cf_callback_invoke(cf_cb_file_retap_started, cf);
2379 /* Do we have any tap listeners with filters? */
2380 filtering_tap_listeners = have_filtering_tap_listeners();
2382 /* Update references in filters (if any) for the protocol
2383 * tree corresponding to the currently selected frame in the GUI. */
2384 /* XXX - What if we *don't* have a currently selected frame in the GUI,
2385 * but we did the last time we loaded field references? Then they'll
2386 * match something instead of nothing (unless they've been recompiled).
2387 * Should we have a way to clear the field references even with a NULL tree?
2389 if (cf->edt != NULL && cf->edt->tree != NULL) {
2390 if (filtering_tap_listeners)
2391 tap_listeners_load_field_references(cf->edt);
2394 /* Get the union of the flags for all tap listeners. */
2395 tap_flags = union_of_tap_listener_flags();
2397 /* If any tap listeners require the columns, construct them. */
2398 callback_args.cinfo = (tap_listeners_require_columns()) ? &cf->cinfo : NULL;
2401 * Determine whether we need to create a protocol tree.
2402 * We do if:
2404 * one of the tap listeners is going to apply a filter;
2406 * one of the tap listeners requires a protocol tree.
2408 create_proto_tree =
2409 (filtering_tap_listeners || (tap_flags & TL_REQUIRES_PROTO_TREE));
2411 /* Reset the tap listeners. */
2412 reset_tap_listeners();
2413 uint32_t count = cf->count;
2415 epan_dissect_init(&callback_args.edt, cf->epan, create_proto_tree, false);
2417 /* Iterate through the list of packets, dissecting all packets and
2418 re-running the taps. */
2419 packet_range_init(&range, cf);
2420 packet_range_process_init(&range);
2422 if (cf->state == FILE_READ_IN_PROGRESS) {
2423 /* We're not done with the sequential read of the file and might
2424 * add more frames while process_specified_records is going. We
2425 * don't want to tap new frames twice, so limit the range to the
2426 * frames already here.
2428 * cf_read sets read_lock so we don't tap in case of an offline
2429 * file, but cf_continue_tail and cf_finish_tail don't, and we
2430 * don't want them to, because tapping new packets in a live
2431 * capture is a common use case.
2433 * Note that most other users of process_specified_records (saving,
2434 * printing) do want to process new packets, unlike taps.
2436 if (count) {
2437 char* range_str = g_strdup_printf("-%u", count);
2438 packet_range_convert_str(&range, range_str);
2439 g_free(range_str);
2440 } else {
2441 /* range_t treats a missing number as meaning 1, not 0, and
2442 * reverses the order if backwards; thus the syntax -0 means
2443 * 0-1, so to only take zero packets we do this.
2445 packet_range_convert_str(&range, "0");
2447 range.process = range_process_user_range;
2450 ret = process_specified_records(cf, &range, "Recalculating statistics on",
2451 "all packets", true, retap_packet,
2452 &callback_args, true);
2454 packet_range_cleanup(&range);
2455 epan_dissect_cleanup(&callback_args.edt);
2457 cf_callback_invoke(cf_cb_file_retap_finished, cf);
2459 switch (ret) {
2460 case PSP_FINISHED:
2461 /* Completed successfully. */
2462 return CF_READ_OK;
2464 case PSP_STOPPED:
2465 /* Well, the user decided to abort the refiltering.
2466 Return CF_READ_ABORTED so our caller knows they did that. */
2467 return CF_READ_ABORTED;
2469 case PSP_FAILED:
2470 /* Error while retapping. */
2471 return CF_READ_ERROR;
2474 ws_assert_not_reached();
2475 return CF_READ_OK;
2478 typedef struct {
2479 print_args_t *print_args;
2480 bool print_header_line;
2481 char *header_line_buf;
2482 int header_line_buf_len;
2483 bool print_formfeed;
2484 bool print_separator;
2485 char *line_buf;
2486 int line_buf_len;
2487 int *col_widths;
2488 int num_visible_cols;
2489 int *visible_cols;
2490 epan_dissect_t edt;
2491 } print_callback_args_t;
2493 static bool
2494 print_packet(capture_file *cf, frame_data *fdata, wtap_rec *rec, Buffer *buf,
2495 void *argsp)
2497 print_callback_args_t *args = (print_callback_args_t *)argsp;
2498 int i;
2499 char *cp;
2500 int line_len;
2501 int column_len;
2502 int cp_off;
2503 char bookmark_name[9+10+1]; /* "__frameNNNNNNNNNN__\0" */
2504 char bookmark_title[6+10+1]; /* "Frame NNNNNNNNNN__\0" */
2505 col_item_t* col_item;
2506 const char* col_text;
2508 /* Fill in the column information if we're printing the summary
2509 information. */
2510 if (args->print_args->print_summary) {
2511 col_custom_prime_edt(&args->edt, &cf->cinfo);
2512 epan_dissect_run(&args->edt, cf->cd_t, rec,
2513 ws_buffer_start_ptr(buf),
2514 fdata, &cf->cinfo);
2515 epan_dissect_fill_in_columns(&args->edt, false, true);
2516 } else
2517 epan_dissect_run(&args->edt, cf->cd_t, rec,
2518 ws_buffer_start_ptr(buf),
2519 fdata, NULL);
2521 if (args->print_formfeed) {
2522 if (!new_page(args->print_args->stream))
2523 goto fail;
2526 * Print another header line if we print a packet summary on the
2527 * new page.
2529 if (args->print_args->print_col_headings)
2530 args->print_header_line = true;
2531 } else {
2532 if (args->print_separator) {
2533 if (!print_line(args->print_args->stream, 0, ""))
2534 goto fail;
2539 * We generate bookmarks, if the output format supports them.
2540 * The name is "__frameN__".
2542 snprintf(bookmark_name, sizeof bookmark_name, "__frame%u__", fdata->num);
2544 if (args->print_args->print_summary) {
2545 if (!args->print_args->print_col_headings)
2546 args->print_header_line = false;
2547 if (args->print_header_line) {
2548 if (!print_line(args->print_args->stream, 0, args->header_line_buf))
2549 goto fail;
2550 args->print_header_line = false; /* we might not need to print any more */
2552 cp = &args->line_buf[0];
2553 line_len = 0;
2554 for (i = 0; i < args->num_visible_cols; i++) {
2555 col_item = &cf->cinfo.columns[args->visible_cols[i]];
2556 col_text = get_column_text(&cf->cinfo, args->visible_cols[i]);
2557 /* Find the length of the string for this column. */
2558 column_len = (int) strlen(col_text);
2559 if (args->col_widths[i] > column_len)
2560 column_len = args->col_widths[i];
2562 /* Make sure there's room in the line buffer for the column; if not,
2563 double its length. */
2564 line_len += column_len + 1; /* "+1" for space */
2565 if (line_len > args->line_buf_len) {
2566 cp_off = (int) (cp - args->line_buf);
2567 args->line_buf_len = 2 * line_len;
2568 args->line_buf = (char *)g_realloc(args->line_buf, args->line_buf_len + 1);
2569 cp = args->line_buf + cp_off;
2572 /* Right-justify the packet number column. */
2573 if (col_item->col_fmt == COL_NUMBER || col_item->col_fmt == COL_NUMBER_DIS)
2574 snprintf(cp, column_len+1, "%*s", args->col_widths[i], col_text);
2575 else
2576 snprintf(cp, column_len+1, "%-*s", args->col_widths[i], col_text);
2577 cp += column_len;
2578 if (i != args->num_visible_cols - 1)
2579 *cp++ = ' ';
2581 *cp = '\0';
2584 * Generate a bookmark, using the summary line as the title.
2586 if (!print_bookmark(args->print_args->stream, bookmark_name,
2587 args->line_buf))
2588 goto fail;
2590 if (!print_line(args->print_args->stream, 0, args->line_buf))
2591 goto fail;
2592 } else {
2594 * Generate a bookmark, using "Frame N" as the title, as we're not
2595 * printing the summary line.
2597 snprintf(bookmark_title, sizeof bookmark_title, "Frame %u", fdata->num);
2598 if (!print_bookmark(args->print_args->stream, bookmark_name,
2599 bookmark_title))
2600 goto fail;
2601 } /* if (print_summary) */
2603 if (args->print_args->print_dissections != print_dissections_none) {
2604 if (args->print_args->print_summary) {
2605 /* Separate the summary line from the tree with a blank line. */
2606 if (!print_line(args->print_args->stream, 0, ""))
2607 goto fail;
2610 /* Print the information in that tree. */
2611 if (!proto_tree_print(args->print_args->print_dissections,
2612 args->print_args->print_hex, &args->edt, NULL,
2613 args->print_args->stream))
2614 goto fail;
2616 /* Print a blank line if we print anything after this (aka more than one packet). */
2617 args->print_separator = true;
2619 /* Print a header line if we print any more packet summaries */
2620 if (args->print_args->print_col_headings)
2621 args->print_header_line = true;
2624 if (args->print_args->print_hex) {
2625 if (args->print_args->print_summary || (args->print_args->print_dissections != print_dissections_none)) {
2626 if (!print_line(args->print_args->stream, 0, ""))
2627 goto fail;
2629 /* Print the full packet data as hex. */
2630 if (!print_hex_data(args->print_args->stream, &args->edt, args->print_args->hexdump_options))
2631 goto fail;
2633 /* Print a blank line if we print anything after this (aka more than one packet). */
2634 args->print_separator = true;
2636 /* Print a header line if we print any more packet summaries */
2637 if (args->print_args->print_col_headings)
2638 args->print_header_line = true;
2639 } /* if (args->print_args->print_dissections != print_dissections_none) */
2641 epan_dissect_reset(&args->edt);
2643 /* do we want to have a formfeed between each packet from now on? */
2644 if (args->print_args->print_formfeed) {
2645 args->print_formfeed = true;
2648 return true;
2650 fail:
2651 epan_dissect_reset(&args->edt);
2652 return false;
2655 cf_print_status_t
2656 cf_print_packets(capture_file *cf, print_args_t *print_args,
2657 bool show_progress_bar)
2659 print_callback_args_t callback_args;
2660 int data_width;
2661 char *cp;
2662 int i, cp_off, column_len, line_len;
2663 int num_visible_col = 0, last_visible_col = 0, visible_col_count;
2664 psp_return_t ret;
2665 GList *clp;
2666 fmt_data *cfmt;
2667 bool proto_tree_needed;
2669 callback_args.print_args = print_args;
2670 callback_args.print_header_line = print_args->print_col_headings;
2671 callback_args.header_line_buf = NULL;
2672 callback_args.header_line_buf_len = 256;
2673 callback_args.print_formfeed = false;
2674 callback_args.print_separator = false;
2675 callback_args.line_buf = NULL;
2676 callback_args.line_buf_len = 256;
2677 callback_args.col_widths = NULL;
2678 callback_args.num_visible_cols = 0;
2679 callback_args.visible_cols = NULL;
2681 if (!print_preamble(print_args->stream, cf->filename, get_ws_vcs_version_info())) {
2682 destroy_print_stream(print_args->stream);
2683 return CF_PRINT_WRITE_ERROR;
2686 if (print_args->print_summary) {
2687 /* We're printing packet summaries. Allocate the header line buffer
2688 and get the column widths. */
2689 callback_args.header_line_buf = (char *)g_malloc(callback_args.header_line_buf_len + 1);
2691 /* Find the number of visible columns and the last visible column */
2692 for (i = 0; i < prefs.num_cols; i++) {
2694 clp = g_list_nth(prefs.col_list, i);
2695 if (clp == NULL) /* Sanity check, Invalid column requested */
2696 continue;
2698 cfmt = (fmt_data *) clp->data;
2699 if (cfmt->visible) {
2700 num_visible_col++;
2701 last_visible_col = i;
2705 /* if num_visible_col is 0, we are done */
2706 if (num_visible_col == 0) {
2707 g_free(callback_args.header_line_buf);
2708 return CF_PRINT_OK;
2711 /* Find the widths for each of the columns - maximum of the
2712 width of the title and the width of the data - and construct
2713 a buffer with a line containing the column titles. */
2714 callback_args.num_visible_cols = num_visible_col;
2715 callback_args.col_widths = g_new(int, num_visible_col);
2716 callback_args.visible_cols = g_new(int, num_visible_col);
2717 cp = &callback_args.header_line_buf[0];
2718 line_len = 0;
2719 visible_col_count = 0;
2720 for (i = 0; i < cf->cinfo.num_cols; i++) {
2722 clp = g_list_nth(prefs.col_list, i);
2723 if (clp == NULL) /* Sanity check, Invalid column requested */
2724 continue;
2726 cfmt = (fmt_data *) clp->data;
2727 if (cfmt->visible == false)
2728 continue;
2730 /* Save the order of visible columns */
2731 callback_args.visible_cols[visible_col_count] = i;
2733 /* Don't pad the last column. */
2734 if (i == last_visible_col)
2735 callback_args.col_widths[visible_col_count] = 0;
2736 else {
2737 callback_args.col_widths[visible_col_count] = (int) strlen(cf->cinfo.columns[i].col_title);
2738 data_width = get_column_char_width(get_column_format(i));
2739 if (data_width > callback_args.col_widths[visible_col_count])
2740 callback_args.col_widths[visible_col_count] = data_width;
2743 /* Find the length of the string for this column. */
2744 column_len = (int) strlen(cf->cinfo.columns[i].col_title);
2745 if (callback_args.col_widths[visible_col_count] > column_len)
2746 column_len = callback_args.col_widths[visible_col_count];
2748 /* Make sure there's room in the line buffer for the column; if not,
2749 double its length. */
2750 line_len += column_len + 1; /* "+1" for space */
2751 if (line_len > callback_args.header_line_buf_len) {
2752 cp_off = (int) (cp - callback_args.header_line_buf);
2753 callback_args.header_line_buf_len = 2 * line_len;
2754 callback_args.header_line_buf = (char *)g_realloc(callback_args.header_line_buf,
2755 callback_args.header_line_buf_len + 1);
2756 cp = callback_args.header_line_buf + cp_off;
2759 /* Right-justify the packet number column. */
2760 /* if (cf->cinfo.col_fmt[i] == COL_NUMBER || cf->cinfo.col_fmt[i] == COL_NUMBER_DIS)
2761 snprintf(cp, column_len+1, "%*s", callback_args.col_widths[visible_col_count], cf->cinfo.columns[i].col_title);
2762 else*/
2763 snprintf(cp, column_len+1, "%-*s", callback_args.col_widths[visible_col_count], cf->cinfo.columns[i].col_title);
2764 cp += column_len;
2765 if (i != cf->cinfo.num_cols - 1)
2766 *cp++ = ' ';
2768 visible_col_count++;
2770 *cp = '\0';
2772 /* Now start out the main line buffer with the same length as the
2773 header line buffer. */
2774 callback_args.line_buf_len = callback_args.header_line_buf_len;
2775 callback_args.line_buf = (char *)g_malloc(callback_args.line_buf_len + 1);
2776 } /* if (print_summary) */
2778 /* Create the protocol tree, and make it visible, if we're printing
2779 the dissection or the hex data.
2780 XXX - do we need it if we're just printing the hex data? */
2781 proto_tree_needed =
2782 callback_args.print_args->print_dissections != print_dissections_none ||
2783 callback_args.print_args->print_hex ||
2784 have_custom_cols(&cf->cinfo) || have_field_extractors();
2785 epan_dissect_init(&callback_args.edt, cf->epan, proto_tree_needed, proto_tree_needed);
2787 /* Iterate through the list of packets, printing the packets we were
2788 told to print. */
2789 ret = process_specified_records(cf, &print_args->range, "Printing",
2790 "selected packets", true, print_packet,
2791 &callback_args, show_progress_bar);
2792 epan_dissect_cleanup(&callback_args.edt);
2793 g_free(callback_args.header_line_buf);
2794 g_free(callback_args.line_buf);
2795 g_free(callback_args.col_widths);
2796 g_free(callback_args.visible_cols);
2798 switch (ret) {
2800 case PSP_FINISHED:
2801 /* Completed successfully. */
2802 break;
2804 case PSP_STOPPED:
2805 /* Well, the user decided to abort the printing.
2807 XXX - note that what got generated before they did that
2808 will get printed if we're piping to a print program; we'd
2809 have to write to a file and then hand that to the print
2810 program to make it actually not print anything. */
2811 break;
2813 case PSP_FAILED:
2814 /* Error while printing.
2816 XXX - note that what got generated before they did that
2817 will get printed if we're piping to a print program; we'd
2818 have to write to a file and then hand that to the print
2819 program to make it actually not print anything. */
2820 destroy_print_stream(print_args->stream);
2821 return CF_PRINT_WRITE_ERROR;
2824 if (!print_finale(print_args->stream)) {
2825 destroy_print_stream(print_args->stream);
2826 return CF_PRINT_WRITE_ERROR;
2829 if (!destroy_print_stream(print_args->stream))
2830 return CF_PRINT_WRITE_ERROR;
2832 return CF_PRINT_OK;
2835 typedef struct {
2836 FILE *fh;
2837 epan_dissect_t edt;
2838 print_args_t *print_args;
2839 json_dumper jdumper;
2840 } write_packet_callback_args_t;
2842 static bool
2843 write_pdml_packet(capture_file *cf, frame_data *fdata, wtap_rec *rec,
2844 Buffer *buf, void *argsp)
2846 write_packet_callback_args_t *args = (write_packet_callback_args_t *)argsp;
2848 /* Create the protocol tree, but don't fill in the column information. */
2849 epan_dissect_run(&args->edt, cf->cd_t, rec,
2850 ws_buffer_start_ptr(buf),
2851 fdata, NULL);
2853 /* Write out the information in that tree. */
2854 write_pdml_proto_tree(NULL, &args->edt, &cf->cinfo, args->fh, false);
2856 epan_dissect_reset(&args->edt);
2858 return !ferror(args->fh);
2861 cf_print_status_t
2862 cf_write_pdml_packets(capture_file *cf, print_args_t *print_args)
2864 write_packet_callback_args_t callback_args;
2865 FILE *fh;
2866 psp_return_t ret;
2868 fh = ws_fopen(print_args->file, "w");
2869 if (fh == NULL)
2870 return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
2872 write_pdml_preamble(fh, cf->filename);
2873 if (ferror(fh)) {
2874 fclose(fh);
2875 return CF_PRINT_WRITE_ERROR;
2878 callback_args.fh = fh;
2879 callback_args.print_args = print_args;
2880 epan_dissect_init(&callback_args.edt, cf->epan, true, true);
2882 /* Iterate through the list of packets, printing the packets we were
2883 told to print. */
2884 ret = process_specified_records(cf, &print_args->range, "Writing PDML",
2885 "selected packets", true,
2886 write_pdml_packet, &callback_args, true);
2888 epan_dissect_cleanup(&callback_args.edt);
2890 switch (ret) {
2892 case PSP_FINISHED:
2893 /* Completed successfully. */
2894 break;
2896 case PSP_STOPPED:
2897 /* Well, the user decided to abort the printing. */
2898 break;
2900 case PSP_FAILED:
2901 /* Error while printing. */
2902 fclose(fh);
2903 return CF_PRINT_WRITE_ERROR;
2906 write_pdml_finale(fh);
2907 if (ferror(fh)) {
2908 fclose(fh);
2909 return CF_PRINT_WRITE_ERROR;
2912 /* XXX - check for an error */
2913 fclose(fh);
2915 return CF_PRINT_OK;
2918 static bool
2919 write_psml_packet(capture_file *cf, frame_data *fdata, wtap_rec *rec,
2920 Buffer *buf, void *argsp)
2922 write_packet_callback_args_t *args = (write_packet_callback_args_t *)argsp;
2924 /* Fill in the column information */
2925 col_custom_prime_edt(&args->edt, &cf->cinfo);
2926 epan_dissect_run(&args->edt, cf->cd_t, rec,
2927 ws_buffer_start_ptr(buf),
2928 fdata, &cf->cinfo);
2929 epan_dissect_fill_in_columns(&args->edt, false, true);
2931 /* Write out the column information. */
2932 write_psml_columns(&args->edt, args->fh, false);
2934 epan_dissect_reset(&args->edt);
2936 return !ferror(args->fh);
2939 cf_print_status_t
2940 cf_write_psml_packets(capture_file *cf, print_args_t *print_args)
2942 write_packet_callback_args_t callback_args;
2943 FILE *fh;
2944 psp_return_t ret;
2946 bool proto_tree_needed;
2948 fh = ws_fopen(print_args->file, "w");
2949 if (fh == NULL)
2950 return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
2952 write_psml_preamble(&cf->cinfo, fh);
2953 if (ferror(fh)) {
2954 fclose(fh);
2955 return CF_PRINT_WRITE_ERROR;
2958 callback_args.fh = fh;
2959 callback_args.print_args = print_args;
2961 /* Fill in the column information, only create the protocol tree
2962 if having custom columns or field extractors. */
2963 proto_tree_needed = have_custom_cols(&cf->cinfo) || have_field_extractors();
2964 epan_dissect_init(&callback_args.edt, cf->epan, proto_tree_needed, proto_tree_needed);
2966 /* Iterate through the list of packets, printing the packets we were
2967 told to print. */
2968 ret = process_specified_records(cf, &print_args->range, "Writing PSML",
2969 "selected packets", true,
2970 write_psml_packet, &callback_args, true);
2972 epan_dissect_cleanup(&callback_args.edt);
2974 switch (ret) {
2976 case PSP_FINISHED:
2977 /* Completed successfully. */
2978 break;
2980 case PSP_STOPPED:
2981 /* Well, the user decided to abort the printing. */
2982 break;
2984 case PSP_FAILED:
2985 /* Error while printing. */
2986 fclose(fh);
2987 return CF_PRINT_WRITE_ERROR;
2990 write_psml_finale(fh);
2991 if (ferror(fh)) {
2992 fclose(fh);
2993 return CF_PRINT_WRITE_ERROR;
2996 /* XXX - check for an error */
2997 fclose(fh);
2999 return CF_PRINT_OK;
3002 static bool
3003 write_csv_packet(capture_file *cf, frame_data *fdata, wtap_rec *rec,
3004 Buffer *buf, void *argsp)
3006 write_packet_callback_args_t *args = (write_packet_callback_args_t *)argsp;
3008 /* Fill in the column information */
3009 col_custom_prime_edt(&args->edt, &cf->cinfo);
3010 epan_dissect_run(&args->edt, cf->cd_t, rec,
3011 ws_buffer_start_ptr(buf),
3012 fdata, &cf->cinfo);
3013 epan_dissect_fill_in_columns(&args->edt, false, true);
3015 /* Write out the column information. */
3016 write_csv_columns(&args->edt, args->fh);
3018 epan_dissect_reset(&args->edt);
3020 return !ferror(args->fh);
3023 cf_print_status_t
3024 cf_write_csv_packets(capture_file *cf, print_args_t *print_args)
3026 write_packet_callback_args_t callback_args;
3027 bool proto_tree_needed;
3028 FILE *fh;
3029 psp_return_t ret;
3031 fh = ws_fopen(print_args->file, "w");
3032 if (fh == NULL)
3033 return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
3035 write_csv_column_titles(&cf->cinfo, fh);
3036 if (ferror(fh)) {
3037 fclose(fh);
3038 return CF_PRINT_WRITE_ERROR;
3041 callback_args.fh = fh;
3042 callback_args.print_args = print_args;
3044 /* only create the protocol tree if having custom columns or field extractors. */
3045 proto_tree_needed = have_custom_cols(&cf->cinfo) || have_field_extractors();
3046 epan_dissect_init(&callback_args.edt, cf->epan, proto_tree_needed, proto_tree_needed);
3048 /* Iterate through the list of packets, printing the packets we were
3049 told to print. */
3050 ret = process_specified_records(cf, &print_args->range, "Writing CSV",
3051 "selected packets", true,
3052 write_csv_packet, &callback_args, true);
3054 epan_dissect_cleanup(&callback_args.edt);
3056 switch (ret) {
3058 case PSP_FINISHED:
3059 /* Completed successfully. */
3060 break;
3062 case PSP_STOPPED:
3063 /* Well, the user decided to abort the printing. */
3064 break;
3066 case PSP_FAILED:
3067 /* Error while printing. */
3068 fclose(fh);
3069 return CF_PRINT_WRITE_ERROR;
3072 /* XXX - check for an error */
3073 fclose(fh);
3075 return CF_PRINT_OK;
3078 static bool
3079 carrays_write_packet(capture_file *cf, frame_data *fdata, wtap_rec *rec,
3080 Buffer *buf, void *argsp)
3082 write_packet_callback_args_t *args = (write_packet_callback_args_t *)argsp;
3084 epan_dissect_run(&args->edt, cf->cd_t, rec,
3085 ws_buffer_start_ptr(buf),
3086 fdata, NULL);
3087 write_carrays_hex_data(fdata->num, args->fh, &args->edt);
3088 epan_dissect_reset(&args->edt);
3090 return !ferror(args->fh);
3093 cf_print_status_t
3094 cf_write_carrays_packets(capture_file *cf, print_args_t *print_args)
3096 write_packet_callback_args_t callback_args;
3097 FILE *fh;
3098 psp_return_t ret;
3100 fh = ws_fopen(print_args->file, "w");
3102 if (fh == NULL)
3103 return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
3105 if (ferror(fh)) {
3106 fclose(fh);
3107 return CF_PRINT_WRITE_ERROR;
3110 callback_args.fh = fh;
3111 callback_args.print_args = print_args;
3112 epan_dissect_init(&callback_args.edt, cf->epan, true, true);
3114 /* Iterate through the list of packets, printing the packets we were
3115 told to print. */
3116 ret = process_specified_records(cf, &print_args->range,
3117 "Writing C Arrays",
3118 "selected packets", true,
3119 carrays_write_packet, &callback_args, true);
3121 epan_dissect_cleanup(&callback_args.edt);
3123 switch (ret) {
3124 case PSP_FINISHED:
3125 /* Completed successfully. */
3126 break;
3127 case PSP_STOPPED:
3128 /* Well, the user decided to abort the printing. */
3129 break;
3130 case PSP_FAILED:
3131 /* Error while printing. */
3132 fclose(fh);
3133 return CF_PRINT_WRITE_ERROR;
3136 fclose(fh);
3137 return CF_PRINT_OK;
3140 static bool
3141 write_json_packet(capture_file *cf, frame_data *fdata, wtap_rec *rec,
3142 Buffer *buf, void *argsp)
3144 write_packet_callback_args_t *args = (write_packet_callback_args_t *)argsp;
3146 /* Create the protocol tree, but don't fill in the column information. */
3147 epan_dissect_run(&args->edt, cf->cd_t, rec,
3148 ws_buffer_start_ptr(buf),
3149 fdata, NULL);
3151 /* Write out the information in that tree. */
3152 write_json_proto_tree(NULL, args->print_args->print_dissections,
3153 args->print_args->print_hex,
3154 &args->edt, &cf->cinfo, proto_node_group_children_by_unique,
3155 &args->jdumper);
3157 epan_dissect_reset(&args->edt);
3159 return !ferror(args->fh);
3162 cf_print_status_t
3163 cf_write_json_packets(capture_file *cf, print_args_t *print_args)
3165 write_packet_callback_args_t callback_args;
3166 FILE *fh;
3167 psp_return_t ret;
3169 fh = ws_fopen(print_args->file, "w");
3170 if (fh == NULL)
3171 return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
3173 callback_args.jdumper = write_json_preamble(fh);
3174 if (ferror(fh)) {
3175 fclose(fh);
3176 return CF_PRINT_WRITE_ERROR;
3179 callback_args.fh = fh;
3180 callback_args.print_args = print_args;
3181 epan_dissect_init(&callback_args.edt, cf->epan, true, true);
3183 /* Iterate through the list of packets, printing the packets we were
3184 told to print. */
3185 ret = process_specified_records(cf, &print_args->range, "Writing JSON",
3186 "selected packets", true,
3187 write_json_packet, &callback_args, true);
3189 epan_dissect_cleanup(&callback_args.edt);
3191 switch (ret) {
3193 case PSP_FINISHED:
3194 /* Completed successfully. */
3195 break;
3197 case PSP_STOPPED:
3198 /* Well, the user decided to abort the printing. */
3199 break;
3201 case PSP_FAILED:
3202 /* Error while printing. */
3203 fclose(fh);
3204 return CF_PRINT_WRITE_ERROR;
3207 write_json_finale(&callback_args.jdumper);
3208 if (ferror(fh)) {
3209 fclose(fh);
3210 return CF_PRINT_WRITE_ERROR;
3213 /* XXX - check for an error */
3214 fclose(fh);
3216 return CF_PRINT_OK;
3219 bool
3220 cf_find_packet_protocol_tree(capture_file *cf, const char *string,
3221 search_direction dir, bool multiple)
3223 match_data mdata;
3225 mdata.frame_matched = false;
3226 mdata.halt = false;
3227 mdata.string = string;
3228 mdata.string_len = strlen(string);
3229 mdata.cf = cf;
3230 mdata.prev_finfo = cf->finfo_selected;
3231 if (multiple && cf->finfo_selected && cf->edt) {
3232 if (dir == SD_FORWARD) {
3233 proto_tree_children_foreach(cf->edt->tree, match_subtree_text, &mdata);
3234 } else {
3235 proto_tree_children_foreach(cf->edt->tree, match_subtree_text_reverse, &mdata);
3237 if (mdata.frame_matched) {
3238 packet_list_select_finfo(mdata.finfo);
3239 return true;
3242 return find_packet(cf, match_protocol_tree, &mdata, dir, true);
3245 field_info*
3246 cf_find_string_protocol_tree(capture_file *cf, proto_tree *tree)
3248 match_data mdata;
3249 mdata.frame_matched = false;
3250 mdata.halt = false;
3251 mdata.string = convert_string_case(cf->sfilter, cf->case_type);
3252 mdata.string_len = strlen(mdata.string);
3253 mdata.cf = cf;
3254 mdata.prev_finfo = NULL;
3255 /* Iterate through all the nodes looking for matching text */
3256 if (cf->dir == SD_FORWARD) {
3257 proto_tree_children_foreach(tree, match_subtree_text, &mdata);
3258 } else {
3259 proto_tree_children_foreach(tree, match_subtree_text_reverse, &mdata);
3261 g_free((char *)mdata.string);
3262 return mdata.frame_matched ? mdata.finfo : NULL;
3265 static match_result
3266 match_protocol_tree(capture_file *cf, frame_data *fdata,
3267 wtap_rec *rec, Buffer *buf, void *criterion)
3269 match_data *mdata = (match_data *)criterion;
3270 epan_dissect_t edt;
3272 /* Load the frame's data. */
3273 if (!cf_read_record(cf, fdata, rec, buf)) {
3274 /* Attempt to get the packet failed. */
3275 return MR_ERROR;
3278 /* Construct the protocol tree, including the displayed text */
3279 epan_dissect_init(&edt, cf->epan, true, true);
3280 /* We don't need the column information */
3281 epan_dissect_run(&edt, cf->cd_t, rec,
3282 ws_buffer_start_ptr(buf),
3283 fdata, NULL);
3285 /* Iterate through all the nodes, seeing if they have text that matches. */
3286 mdata->cf = cf;
3287 mdata->frame_matched = false;
3288 mdata->halt = false;
3289 mdata->prev_finfo = NULL;
3290 /* We don't care about the direction here, because we're just looking
3291 * for one match and we'll destroy this tree anyway. (We find the actual
3292 * field later in PacketList::selectionChanged().) Forwards is faster.
3294 proto_tree_children_foreach(edt.tree, match_subtree_text, mdata);
3295 epan_dissect_cleanup(&edt);
3296 return mdata->frame_matched ? MR_MATCHED : MR_NOTMATCHED;
3299 static void
3300 match_subtree_text(proto_node *node, void *data)
3302 match_data *mdata = (match_data *) data;
3303 const char *string = mdata->string;
3304 size_t string_len = mdata->string_len;
3305 capture_file *cf = mdata->cf;
3306 field_info *fi = PNODE_FINFO(node);
3307 char label_str[ITEM_LABEL_LENGTH];
3308 char *label_ptr;
3309 size_t label_len;
3310 uint32_t i, i_restart;
3311 uint8_t c_char;
3312 size_t c_match = 0;
3314 /* dissection with an invisible proto tree? */
3315 ws_assert(fi);
3317 if (mdata->frame_matched) {
3318 /* We already had a match; don't bother doing any more work. */
3319 return;
3322 /* Don't match invisible entries. */
3323 if (proto_item_is_hidden(node))
3324 return;
3326 if (mdata->prev_finfo) {
3327 /* Haven't found the old match, so don't match this node. */
3328 if (fi == mdata->prev_finfo) {
3329 /* Found the old match, look for the next one after this. */
3330 mdata->prev_finfo = NULL;
3332 } else {
3333 /* was a free format label produced? */
3334 if (fi->rep) {
3335 label_ptr = fi->rep->representation;
3336 } else {
3337 /* no, make a generic label */
3338 label_ptr = label_str;
3339 proto_item_fill_label(fi, label_str, NULL);
3342 if (cf->regex) {
3343 if (ws_regex_matches(cf->regex, label_ptr)) {
3344 mdata->frame_matched = true;
3345 mdata->finfo = fi;
3346 return;
3348 } else if (cf->case_type) {
3349 /* Case insensitive match */
3350 label_len = strlen(label_ptr);
3351 i_restart = 0;
3352 for (i = 0; i < label_len; i++) {
3353 if (i_restart == 0 && c_match == 0 && (label_len - i < string_len))
3354 break;
3355 c_char = label_ptr[i];
3356 c_char = g_ascii_toupper(c_char);
3357 /* If c_match is non-zero, save candidate for retrying full match. */
3358 if (c_match > 0 && i_restart == 0 && c_char == string[0])
3359 i_restart = i;
3360 if (c_char == string[c_match]) {
3361 c_match++;
3362 if (c_match == string_len) {
3363 mdata->frame_matched = true;
3364 mdata->finfo = fi;
3365 /* No need to look further; we have a match */
3366 return;
3368 } else if (i_restart) {
3369 i = i_restart;
3370 c_match = 1;
3371 i_restart = 0;
3372 } else
3373 c_match = 0;
3375 } else if (strstr(label_ptr, string) != NULL) {
3376 /* Case sensitive match */
3377 mdata->frame_matched = true;
3378 mdata->finfo = fi;
3379 return;
3383 /* Recurse into the subtree, if it exists */
3384 if (node->first_child != NULL)
3385 proto_tree_children_foreach(node, match_subtree_text, mdata);
3388 static void
3389 match_subtree_text_reverse(proto_node *node, void *data)
3391 match_data *mdata = (match_data *) data;
3392 const char *string = mdata->string;
3393 size_t string_len = mdata->string_len;
3394 capture_file *cf = mdata->cf;
3395 field_info *fi = PNODE_FINFO(node);
3396 char label_str[ITEM_LABEL_LENGTH];
3397 char *label_ptr;
3398 size_t label_len;
3399 uint32_t i, i_restart;
3400 uint8_t c_char;
3401 size_t c_match = 0;
3403 /* dissection with an invisible proto tree? */
3404 ws_assert(fi);
3406 /* We don't have an easy way to search backwards in the tree
3407 * (see also, proto_find_field_from_offset()) because we don't
3408 * have a previous node pointer, so we search backwards by
3409 * searching forwards, only stopping if we see the old match
3410 * (if we have one).
3413 if (mdata->halt) {
3414 return;
3417 /* Don't match invisible entries. */
3418 if (proto_item_is_hidden(node))
3419 return;
3421 if (mdata->prev_finfo && fi == mdata->prev_finfo) {
3422 /* Found the old match, use the previous match. */
3423 mdata->halt = true;
3424 return;
3427 /* was a free format label produced? */
3428 if (fi->rep) {
3429 label_ptr = fi->rep->representation;
3430 } else {
3431 /* no, make a generic label */
3432 label_ptr = label_str;
3433 proto_item_fill_label(fi, label_str, NULL);
3436 if (cf->regex) {
3437 if (ws_regex_matches(cf->regex, label_ptr)) {
3438 mdata->frame_matched = true;
3439 mdata->finfo = fi;
3441 } else if (cf->case_type) {
3442 /* Case insensitive match */
3443 label_len = strlen(label_ptr);
3444 i_restart = 0;
3445 for (i = 0; i < label_len; i++) {
3446 if (i_restart == 0 && c_match == 0 && (label_len - i < string_len))
3447 break;
3448 c_char = label_ptr[i];
3449 c_char = g_ascii_toupper(c_char);
3450 /* If c_match is non-zero, save candidate for retrying full match. */
3451 if (c_match > 0 && i_restart == 0 && c_char == string[0])
3452 i_restart = i;
3453 if (c_char == string[c_match]) {
3454 c_match++;
3455 if (c_match == string_len) {
3456 mdata->frame_matched = true;
3457 mdata->finfo = fi;
3458 break;
3460 } else if (i_restart) {
3461 i = i_restart;
3462 c_match = 1;
3463 i_restart = 0;
3464 } else
3465 c_match = 0;
3467 } else if (strstr(label_ptr, string) != NULL) {
3468 /* Case sensitive match */
3469 mdata->frame_matched = true;
3470 mdata->finfo = fi;
3473 /* Recurse into the subtree, if it exists */
3474 if (node->first_child != NULL)
3475 proto_tree_children_foreach(node, match_subtree_text_reverse, mdata);
3478 bool
3479 cf_find_packet_summary_line(capture_file *cf, const char *string,
3480 search_direction dir)
3482 match_data mdata;
3484 mdata.string = string;
3485 mdata.string_len = strlen(string);
3486 return find_packet(cf, match_summary_line, &mdata, dir, true);
3489 static match_result
3490 match_summary_line(capture_file *cf, frame_data *fdata,
3491 wtap_rec *rec, Buffer *buf, void *criterion)
3493 match_data *mdata = (match_data *)criterion;
3494 const char *string = mdata->string;
3495 size_t string_len = mdata->string_len;
3496 epan_dissect_t edt;
3497 const char *info_column;
3498 size_t info_column_len;
3499 match_result result = MR_NOTMATCHED;
3500 int colx;
3501 uint32_t i, i_restart;
3502 uint8_t c_char;
3503 size_t c_match = 0;
3505 /* Load the frame's data. */
3506 if (!cf_read_record(cf, fdata, rec, buf)) {
3507 /* Attempt to get the packet failed. */
3508 return MR_ERROR;
3511 /* Don't bother constructing the protocol tree */
3512 epan_dissect_init(&edt, cf->epan, false, false);
3513 /* Get the column information */
3514 epan_dissect_run(&edt, cf->cd_t, rec,
3515 ws_buffer_start_ptr(buf),
3516 fdata, &cf->cinfo);
3518 /* Find the Info column */
3519 for (colx = 0; colx < cf->cinfo.num_cols; colx++) {
3520 if (cf->cinfo.columns[colx].fmt_matx[COL_INFO]) {
3521 /* Found it. See if we match. */
3522 info_column = get_column_text(edt.pi.cinfo, colx);
3523 info_column_len = strlen(info_column);
3524 if (cf->regex) {
3525 if (ws_regex_matches(cf->regex, info_column)) {
3526 result = MR_MATCHED;
3527 break;
3529 } else if (cf->case_type) {
3530 /* Case insensitive match */
3531 i_restart = 0;
3532 for (i = 0; i < info_column_len; i++) {
3533 if (i_restart == 0 && c_match == 0 && (info_column_len - i < string_len))
3534 break;
3535 c_char = info_column[i];
3536 c_char = g_ascii_toupper(c_char);
3537 /* If c_match is non-zero, save candidate for retrying full match. */
3538 if (c_match > 0 && i_restart == 0 && c_char == string[0])
3539 i_restart = i;
3540 if (c_char == string[c_match]) {
3541 c_match++;
3542 if (c_match == string_len) {
3543 result = MR_MATCHED;
3544 break;
3546 } else if (i_restart) {
3547 i = i_restart;
3548 c_match = 1;
3549 i_restart = 0;
3550 } else
3551 c_match = 0;
3553 } else if (strstr(info_column, string) != NULL) {
3554 /* Case sensitive match */
3555 result = MR_MATCHED;
3557 break;
3560 epan_dissect_cleanup(&edt);
3561 return result;
3564 typedef struct {
3565 const uint8_t *data;
3566 size_t data_len;
3567 ws_mempbrk_pattern *pattern;
3568 } cbs_t; /* "Counted byte string" */
3572 * The current match_* routines only support ASCII case insensitivity and don't
3573 * convert UTF-8 inputs to UTF-16 for matching. The UTF-16 support just
3574 * interleaves with \0 bytes, which works for 7 bit ASCII.
3576 * We could modify them to use the GLib Unicode routines or the International
3577 * Components for Unicode library but it's not apparent that we could do so
3578 * without consuming a lot more CPU and memory or that searching would be
3579 * significantly better.
3581 * XXX: We could test the search string to see if it's all ASCII, and if not
3582 * use Unicode aware routines for case insensitive searches or any UTF-16
3583 * search.
3586 bool
3587 cf_find_packet_data(capture_file *cf, const uint8_t *string, size_t string_size,
3588 search_direction dir, bool multiple)
3590 cbs_t info;
3591 uint8_t needles[3];
3592 ws_mempbrk_pattern pattern = {0};
3593 ws_match_function match_function;
3595 info.data = string;
3596 info.data_len = string_size;
3598 /* Regex, String or hex search? */
3599 if (cf->regex) {
3600 /* Regular Expression search */
3601 match_function = (dir == SD_FORWARD) ? match_regex : match_regex_reverse;
3602 } else if (cf->string) {
3603 /* String search - what type of string? */
3604 if (cf->case_type) {
3605 needles[0] = string[0];
3606 needles[1] = g_ascii_tolower(needles[0]);
3607 needles[2] = '\0';
3608 ws_mempbrk_compile(&pattern, needles);
3609 info.pattern = &pattern;
3610 switch (cf->scs_type) {
3612 case SCS_NARROW_AND_WIDE:
3613 match_function = (dir == SD_FORWARD) ? match_narrow_and_wide_case : match_narrow_and_wide_case_reverse;
3614 break;
3616 case SCS_NARROW:
3617 match_function = (dir == SD_FORWARD) ? match_narrow_case : match_narrow_case_reverse;
3618 break;
3620 case SCS_WIDE:
3621 match_function = (dir == SD_FORWARD) ? match_wide_case : match_wide_case_reverse;
3622 break;
3624 default:
3625 ws_assert_not_reached();
3626 return false;
3629 } else {
3630 switch (cf->scs_type) {
3632 case SCS_NARROW_AND_WIDE:
3633 match_function = (dir == SD_FORWARD) ? match_narrow_and_wide : match_narrow_and_wide_reverse;
3634 break;
3636 case SCS_NARROW:
3637 /* Narrow, case-sensitive match is the same as looking
3638 * for a converted hexstring. */
3639 match_function = (dir == SD_FORWARD) ? match_binary : match_binary_reverse;
3640 break;
3642 case SCS_WIDE:
3643 match_function = (dir == SD_FORWARD) ? match_wide : match_wide_reverse;
3644 break;
3646 default:
3647 ws_assert_not_reached();
3648 return false;
3651 } else {
3652 match_function = (dir == SD_FORWARD) ? match_binary : match_binary_reverse;
3655 if (multiple && cf->current_frame && (cf->search_pos || cf->search_len)) {
3656 /* Use the current frame (this will perform the equivalent of
3657 * cf_read_current_record() in match_function).
3659 if (match_function(cf, cf->current_frame, &cf->rec, &cf->buf, &info)) {
3660 cf->search_in_progress = true;
3661 if (cf->edt) {
3662 field_info *fi = NULL;
3663 /* The regex match can match an empty string. */
3664 if (cf->search_len) {
3665 fi = proto_find_field_from_offset(cf->edt->tree, cf->search_pos + cf->search_len - 1, cf->edt->tvb);
3667 packet_list_select_finfo(fi);
3668 } else {
3669 packet_list_select_row_from_data(cf->current_frame);
3671 cf->search_in_progress = false;
3672 return true;
3675 cf->search_pos = 0; /* Reset the position */
3676 cf->search_len = 0; /* Reset length */
3677 return find_packet(cf, match_function, &info, dir, true);
3680 static match_result
3681 match_narrow_and_wide(capture_file *cf, frame_data *fdata,
3682 wtap_rec *rec, Buffer *buf, void *criterion)
3684 cbs_t *info = (cbs_t *)criterion;
3685 const uint8_t *ascii_text = info->data;
3686 size_t textlen = info->data_len;
3687 match_result result;
3688 uint32_t buf_len;
3689 uint8_t *pd, *buf_start, *buf_end;
3690 uint32_t i;
3691 uint8_t c_char;
3692 size_t c_match = 0;
3694 /* Load the frame's data. */
3695 if (!cf_read_record(cf, fdata, rec, buf)) {
3696 /* Attempt to get the packet failed. */
3697 return MR_ERROR;
3700 result = MR_NOTMATCHED;
3701 buf_len = fdata->cap_len;
3702 buf_start = ws_buffer_start_ptr(buf);
3703 buf_end = buf_start + buf_len;
3704 pd = buf_start;
3705 if (cf->search_len || cf->search_pos) {
3706 /* we want to start searching one byte past the previous match start */
3707 pd += cf->search_pos + 1;
3709 for (; pd < buf_end; pd++) {
3710 pd = (uint8_t *)memchr(pd, ascii_text[0], buf_end - pd);
3711 if (pd == NULL) break;
3712 /* Try narrow match at this start location */
3713 c_match = 0;
3714 for (i = 0; pd + i < buf_end; i++) {
3715 c_char = pd[i];
3716 if (c_char == ascii_text[c_match]) {
3717 c_match++;
3718 if (c_match == textlen) {
3719 result = MR_MATCHED;
3720 /* Save position and length for highlighting the field. */
3721 cf->search_pos = (uint32_t)(pd - buf_start);
3722 cf->search_len = (uint32_t)(i + 1);
3723 goto done;
3725 } else {
3726 break;
3730 /* Now try wide match at the same start location. */
3731 c_match = 0;
3732 for (i = 0; pd + i < buf_end; i++) {
3733 c_char = pd[i];
3734 if (c_char == ascii_text[c_match]) {
3735 c_match++;
3736 if (c_match == textlen) {
3737 result = MR_MATCHED;
3738 /* Save position and length for highlighting the field. */
3739 cf->search_pos = (uint32_t)(pd - buf_start);
3740 cf->search_len = (uint32_t)(i + 1);
3741 goto done;
3743 i++;
3744 if (pd + i >= buf_end || pd[i] != '\0') break;
3745 } else {
3746 break;
3751 done:
3752 return result;
3755 static match_result
3756 match_narrow_and_wide_reverse(capture_file *cf, frame_data *fdata,
3757 wtap_rec *rec, Buffer *buf, void *criterion)
3759 cbs_t *info = (cbs_t *)criterion;
3760 const uint8_t *ascii_text = info->data;
3761 size_t textlen = info->data_len;
3762 match_result result;
3763 uint32_t buf_len;
3764 uint8_t *pd, *buf_start, *buf_end;
3765 uint32_t i;
3766 uint8_t c_char;
3767 size_t c_match = 0;
3769 /* Load the frame's data. */
3770 if (!cf_read_record(cf, fdata, rec, buf)) {
3771 /* Attempt to get the packet failed. */
3772 return MR_ERROR;
3775 result = MR_NOTMATCHED;
3776 /* Has to be room to hold the sought data. */
3777 if (textlen > fdata->cap_len) {
3778 return result;
3780 buf_len = fdata->cap_len;
3781 buf_start = ws_buffer_start_ptr(buf);
3782 buf_end = buf_start + buf_len;
3783 pd = buf_end - textlen;
3784 if (cf->search_len || cf->search_pos) {
3785 /* we want to start searching one byte before the previous match start */
3786 pd = buf_start + cf->search_pos - 1;
3788 for (; pd < buf_end; pd++) {
3789 pd = (uint8_t *)ws_memrchr(buf_start, ascii_text[0], pd - buf_start + 1);
3790 if (pd == NULL) break;
3791 /* Try narrow match at this start location */
3792 c_match = 0;
3793 for (i = 0; pd + i < buf_end; i++) {
3794 c_char = pd[i];
3795 if (c_char == ascii_text[c_match]) {
3796 c_match++;
3797 if (c_match == textlen) {
3798 result = MR_MATCHED;
3799 /* Save position and length for highlighting the field. */
3800 cf->search_pos = (uint32_t)(pd - buf_start);
3801 cf->search_len = (uint32_t)(i + 1);
3802 goto done;
3804 } else {
3805 break;
3809 /* Now try wide match at the same start location. */
3810 c_match = 0;
3811 for (i = 0; pd + i < buf_end; i++) {
3812 c_char = pd[i];
3813 if (c_char == ascii_text[c_match]) {
3814 c_match++;
3815 if (c_match == textlen) {
3816 result = MR_MATCHED;
3817 /* Save position and length for highlighting the field. */
3818 cf->search_pos = (uint32_t)(pd - buf_start);
3819 cf->search_len = (uint32_t)(i + 1);
3820 goto done;
3822 i++;
3823 if (pd + i >= buf_end || pd[i] != '\0') break;
3824 } else {
3825 break;
3830 done:
3831 return result;
3834 /* Case insensitive match */
3835 static match_result
3836 match_narrow_and_wide_case(capture_file *cf, frame_data *fdata,
3837 wtap_rec *rec, Buffer *buf, void *criterion)
3839 cbs_t *info = (cbs_t *)criterion;
3840 const uint8_t *ascii_text = info->data;
3841 size_t textlen = info->data_len;
3842 ws_mempbrk_pattern *pattern = info->pattern;
3843 match_result result;
3844 uint32_t buf_len;
3845 uint8_t *pd, *buf_start, *buf_end;
3846 uint32_t i;
3847 uint8_t c_char;
3848 size_t c_match = 0;
3850 /* Load the frame's data. */
3851 if (!cf_read_record(cf, fdata, rec, buf)) {
3852 /* Attempt to get the packet failed. */
3853 return MR_ERROR;
3856 ws_assert(pattern != NULL);
3858 result = MR_NOTMATCHED;
3859 buf_len = fdata->cap_len;
3860 buf_start = ws_buffer_start_ptr(buf);
3861 buf_end = buf_start + buf_len;
3862 pd = buf_start;
3863 if (cf->search_len || cf->search_pos) {
3864 /* we want to start searching one byte past the previous match start */
3865 pd += cf->search_pos + 1;
3867 for (; pd < buf_end; pd++) {
3868 pd = (uint8_t *)ws_mempbrk_exec(pd, buf_end - pd, pattern, &c_char);
3869 if (pd == NULL) break;
3870 /* Try narrow match at this start location */
3871 c_match = 0;
3872 for (i = 0; pd + i < buf_end; i++) {
3873 c_char = g_ascii_toupper(pd[i]);
3874 if (c_char == ascii_text[c_match]) {
3875 c_match++;
3876 if (c_match == textlen) {
3877 result = MR_MATCHED;
3878 /* Save position and length for highlighting the field. */
3879 cf->search_pos = (uint32_t)(pd - buf_start);
3880 cf->search_len = (uint32_t)(i + 1);
3881 goto done;
3883 } else {
3884 break;
3888 /* Now try wide match at the same start location. */
3889 c_match = 0;
3890 for (i = 0; pd + i < buf_end; i++) {
3891 c_char = g_ascii_toupper(pd[i]);
3892 if (c_char == ascii_text[c_match]) {
3893 c_match++;
3894 if (c_match == textlen) {
3895 result = MR_MATCHED;
3896 /* Save position and length for highlighting the field. */
3897 cf->search_pos = (uint32_t)(pd - buf_start);
3898 cf->search_len = (uint32_t)(i + 1);
3899 goto done;
3901 i++;
3902 if (pd + i >= buf_end || pd[i] != '\0') break;
3903 } else {
3904 break;
3909 done:
3910 return result;
3913 static match_result
3914 match_narrow_and_wide_case_reverse(capture_file *cf, frame_data *fdata,
3915 wtap_rec *rec, Buffer *buf, void *criterion)
3917 cbs_t *info = (cbs_t *)criterion;
3918 const uint8_t *ascii_text = info->data;
3919 size_t textlen = info->data_len;
3920 ws_mempbrk_pattern *pattern = info->pattern;
3921 match_result result;
3922 uint32_t buf_len;
3923 uint8_t *pd, *buf_start, *buf_end;
3924 uint32_t i;
3925 uint8_t c_char;
3926 size_t c_match = 0;
3928 /* Load the frame's data. */
3929 if (!cf_read_record(cf, fdata, rec, buf)) {
3930 /* Attempt to get the packet failed. */
3931 return MR_ERROR;
3934 ws_assert(pattern != NULL);
3936 result = MR_NOTMATCHED;
3937 /* Has to be room to hold the sought data. */
3938 if (textlen > fdata->cap_len) {
3939 return result;
3941 buf_len = fdata->cap_len;
3942 buf_start = ws_buffer_start_ptr(buf);
3943 buf_end = buf_start + buf_len;
3944 pd = buf_end - textlen;
3945 if (cf->search_len || cf->search_pos) {
3946 /* we want to start searching one byte before the previous match start */
3947 pd = buf_start + cf->search_pos - 1;
3949 for (; pd >= buf_start; pd--) {
3950 pd = (uint8_t *)ws_memrpbrk_exec(buf_start, pd - buf_start + 1, pattern, &c_char);
3951 if (pd == NULL) break;
3952 /* Try narrow match at this start location */
3953 c_match = 0;
3954 for (i = 0; pd + i < buf_end; i++) {
3955 c_char = g_ascii_toupper(pd[i]);
3956 if (c_char == ascii_text[c_match]) {
3957 c_match++;
3958 if (c_match == textlen) {
3959 result = MR_MATCHED;
3960 /* Save position and length for highlighting the field. */
3961 cf->search_pos = (uint32_t)(pd - buf_start);
3962 cf->search_len = (uint32_t)(i + 1);
3963 goto done;
3965 } else {
3966 break;
3970 /* Now try wide match at the same start location. */
3971 c_match = 0;
3972 for (i = 0; pd + i < buf_end; i++) {
3973 c_char = g_ascii_toupper(pd[i]);
3974 if (c_char == ascii_text[c_match]) {
3975 c_match++;
3976 if (c_match == textlen) {
3977 result = MR_MATCHED;
3978 /* Save position and length for highlighting the field. */
3979 cf->search_pos = (uint32_t)(pd - buf_start);
3980 cf->search_len = (uint32_t)(i + 1);
3981 goto done;
3983 i++;
3984 if (pd + i >= buf_end || pd[i] != '\0') break;
3985 } else {
3986 break;
3991 done:
3992 return result;
3995 /* Case insensitive match */
3996 static match_result
3997 match_narrow_case(capture_file *cf, frame_data *fdata,
3998 wtap_rec *rec, Buffer *buf, void *criterion)
4000 cbs_t *info = (cbs_t *)criterion;
4001 const uint8_t *ascii_text = info->data;
4002 size_t textlen = info->data_len;
4003 ws_mempbrk_pattern *pattern = info->pattern;
4004 match_result result;
4005 uint32_t buf_len;
4006 uint8_t *pd, *buf_start, *buf_end;
4007 uint32_t i;
4008 uint8_t c_char;
4009 size_t c_match = 0;
4011 /* Load the frame's data. */
4012 if (!cf_read_record(cf, fdata, rec, buf)) {
4013 /* Attempt to get the packet failed. */
4014 return MR_ERROR;
4017 ws_assert(pattern != NULL);
4019 result = MR_NOTMATCHED;
4020 buf_len = fdata->cap_len;
4021 buf_start = ws_buffer_start_ptr(buf);
4022 buf_end = buf_start + buf_len;
4023 pd = buf_start;
4024 if (cf->search_len || cf->search_pos) {
4025 /* we want to start searching one byte past the previous match start */
4026 pd += cf->search_pos + 1;
4028 for (; pd < buf_end; pd++) {
4029 pd = (uint8_t *)ws_mempbrk_exec(pd, buf_end - pd, pattern, &c_char);
4030 if (pd == NULL) break;
4031 c_match = 0;
4032 for (i = 0; pd + i < buf_end; i++) {
4033 c_char = g_ascii_toupper(pd[i]);
4034 if (c_char == ascii_text[c_match]) {
4035 c_match++;
4036 if (c_match == textlen) {
4037 /* Save position and length for highlighting the field. */
4038 result = MR_MATCHED;
4039 cf->search_pos = (uint32_t)(pd - buf_start);
4040 cf->search_len = (uint32_t)(i + 1);
4041 goto done;
4043 } else {
4044 break;
4049 done:
4050 return result;
4053 static match_result
4054 match_narrow_case_reverse(capture_file *cf, frame_data *fdata,
4055 wtap_rec *rec, Buffer *buf, void *criterion)
4057 cbs_t *info = (cbs_t *)criterion;
4058 const uint8_t *ascii_text = info->data;
4059 size_t textlen = info->data_len;
4060 ws_mempbrk_pattern *pattern = info->pattern;
4061 match_result result;
4062 uint32_t buf_len;
4063 uint8_t *pd, *buf_start, *buf_end;
4064 uint32_t i;
4065 uint8_t c_char;
4066 size_t c_match = 0;
4068 /* Load the frame's data. */
4069 if (!cf_read_record(cf, fdata, rec, buf)) {
4070 /* Attempt to get the packet failed. */
4071 return MR_ERROR;
4074 ws_assert(pattern != NULL);
4076 result = MR_NOTMATCHED;
4077 /* Has to be room to hold the sought data. */
4078 if (textlen > fdata->cap_len) {
4079 return result;
4081 buf_len = fdata->cap_len;
4082 buf_start = ws_buffer_start_ptr(buf);
4083 buf_end = buf_start + buf_len;
4084 pd = buf_end - textlen;
4085 if (cf->search_len || cf->search_pos) {
4086 /* we want to start searching one byte before the previous match start */
4087 pd = buf_start + cf->search_pos - 1;
4089 for (; pd >= buf_start; pd--) {
4090 pd = (uint8_t *)ws_memrpbrk_exec(buf_start, pd - buf_start + 1, pattern, &c_char);
4091 if (pd == NULL) break;
4092 c_match = 0;
4093 for (i = 0; pd + i < buf_end; i++) {
4094 c_char = g_ascii_toupper(pd[i]);
4095 if (c_char == ascii_text[c_match]) {
4096 c_match++;
4097 if (c_match == textlen) {
4098 /* Save position and length for highlighting the field. */
4099 result = MR_MATCHED;
4100 cf->search_pos = (uint32_t)(pd - buf_start);
4101 cf->search_len = (uint32_t)(i + 1);
4102 goto done;
4104 } else {
4105 break;
4110 done:
4111 return result;
4114 static match_result
4115 match_wide(capture_file *cf, frame_data *fdata,
4116 wtap_rec *rec, Buffer *buf, void *criterion)
4118 cbs_t *info = (cbs_t *)criterion;
4119 const uint8_t *ascii_text = info->data;
4120 size_t textlen = info->data_len;
4121 match_result result;
4122 uint32_t buf_len;
4123 uint8_t *pd, *buf_start, *buf_end;
4124 uint32_t i;
4125 uint8_t c_char;
4126 size_t c_match = 0;
4128 /* Load the frame's data. */
4129 if (!cf_read_record(cf, fdata, rec, buf)) {
4130 /* Attempt to get the packet failed. */
4131 return MR_ERROR;
4134 result = MR_NOTMATCHED;
4135 buf_len = fdata->cap_len;
4136 buf_start = ws_buffer_start_ptr(buf);
4137 buf_end = buf_start + buf_len;
4138 pd = buf_start;
4139 if (cf->search_len || cf->search_pos) {
4140 /* we want to start searching one byte past the previous match start */
4141 pd += cf->search_pos + 1;
4143 for (; pd < buf_end; pd++) {
4144 pd = (uint8_t *)memchr(pd, ascii_text[0], buf_end - pd);
4145 if (pd == NULL) break;
4146 c_match = 0;
4147 for (i = 0; pd + i < buf_end; i++) {
4148 c_char = pd[i];
4149 if (c_char == ascii_text[c_match]) {
4150 c_match++;
4151 if (c_match == textlen) {
4152 result = MR_MATCHED;
4153 /* Save position and length for highlighting the field. */
4154 cf->search_pos = (uint32_t)(pd - buf_start);
4155 cf->search_len = (uint32_t)(i + 1);
4156 goto done;
4158 i++;
4159 if (pd + i >= buf_end || pd[i] != '\0') break;
4160 } else {
4161 break;
4166 done:
4167 return result;
4170 static match_result
4171 match_wide_reverse(capture_file *cf, frame_data *fdata,
4172 wtap_rec *rec, Buffer *buf, void *criterion)
4174 cbs_t *info = (cbs_t *)criterion;
4175 const uint8_t *ascii_text = info->data;
4176 size_t textlen = info->data_len;
4177 match_result result;
4178 uint32_t buf_len;
4179 uint8_t *pd, *buf_start, *buf_end;
4180 uint32_t i;
4181 uint8_t c_char;
4182 size_t c_match = 0;
4184 /* Load the frame's data. */
4185 if (!cf_read_record(cf, fdata, rec, buf)) {
4186 /* Attempt to get the packet failed. */
4187 return MR_ERROR;
4190 result = MR_NOTMATCHED;
4191 /* Has to be room to hold the sought data. */
4192 if (textlen > fdata->cap_len) {
4193 return result;
4195 buf_len = fdata->cap_len;
4196 buf_start = ws_buffer_start_ptr(buf);
4197 buf_end = buf_start + buf_len;
4198 pd = buf_end - textlen;
4199 if (cf->search_len || cf->search_pos) {
4200 /* we want to start searching one byte before the previous match start */
4201 pd = buf_start + cf->search_pos - 1;
4203 for (; pd < buf_end; pd++) {
4204 pd = (uint8_t *)ws_memrchr(buf_start, ascii_text[0], pd - buf_start + 1);
4205 if (pd == NULL) break;
4206 c_match = 0;
4207 for (i = 0; pd + i < buf_end; i++) {
4208 c_char = pd[i];
4209 if (c_char == ascii_text[c_match]) {
4210 c_match++;
4211 if (c_match == textlen) {
4212 result = MR_MATCHED;
4213 /* Save position and length for highlighting the field. */
4214 cf->search_pos = (uint32_t)(pd - buf_start);
4215 cf->search_len = (uint32_t)(i + 1);
4216 goto done;
4218 i++;
4219 if (pd + i >= buf_end || pd[i] != '\0') break;
4220 } else {
4221 break;
4226 done:
4227 return result;
4230 /* Case insensitive match */
4231 static match_result
4232 match_wide_case(capture_file *cf, frame_data *fdata,
4233 wtap_rec *rec, Buffer *buf, void *criterion)
4235 cbs_t *info = (cbs_t *)criterion;
4236 const uint8_t *ascii_text = info->data;
4237 size_t textlen = info->data_len;
4238 ws_mempbrk_pattern *pattern = info->pattern;
4239 match_result result;
4240 uint32_t buf_len;
4241 uint8_t *pd, *buf_start, *buf_end;
4242 uint32_t i;
4243 uint8_t c_char;
4244 size_t c_match = 0;
4246 /* Load the frame's data. */
4247 if (!cf_read_record(cf, fdata, rec, buf)) {
4248 /* Attempt to get the packet failed. */
4249 return MR_ERROR;
4252 ws_assert(pattern != NULL);
4254 result = MR_NOTMATCHED;
4255 buf_len = fdata->cap_len;
4256 buf_start = ws_buffer_start_ptr(buf);
4257 buf_end = buf_start + buf_len;
4258 pd = buf_start;
4259 if (cf->search_len || cf->search_pos) {
4260 /* we want to start searching one byte past the previous match start */
4261 pd += cf->search_pos + 1;
4263 for (; pd < buf_end; pd++) {
4264 pd = (uint8_t *)ws_mempbrk_exec(pd, buf_end - pd, pattern, &c_char);
4265 if (pd == NULL) break;
4266 c_match = 0;
4267 for (i = 0; pd + i < buf_end; i++) {
4268 c_char = g_ascii_toupper(pd[i]);
4269 if (c_char == ascii_text[c_match]) {
4270 c_match++;
4271 if (c_match == textlen) {
4272 result = MR_MATCHED;
4273 /* Save position and length for highlighting the field. */
4274 cf->search_pos = (uint32_t)(pd - buf_start);
4275 cf->search_len = (uint32_t)(i + 1);
4276 goto done;
4278 i++;
4279 if (pd + i >= buf_end || pd[i] != '\0') break;
4280 } else {
4281 break;
4286 done:
4287 return result;
4290 /* Case insensitive match */
4291 static match_result
4292 match_wide_case_reverse(capture_file *cf, frame_data *fdata,
4293 wtap_rec *rec, Buffer *buf, void *criterion)
4295 cbs_t *info = (cbs_t *)criterion;
4296 const uint8_t *ascii_text = info->data;
4297 size_t textlen = info->data_len;
4298 ws_mempbrk_pattern *pattern = info->pattern;
4299 match_result result;
4300 uint32_t buf_len;
4301 uint8_t *pd, *buf_start, *buf_end;
4302 uint32_t i;
4303 uint8_t c_char;
4304 size_t c_match = 0;
4306 /* Load the frame's data. */
4307 if (!cf_read_record(cf, fdata, rec, buf)) {
4308 /* Attempt to get the packet failed. */
4309 return MR_ERROR;
4312 ws_assert(pattern != NULL);
4314 result = MR_NOTMATCHED;
4315 /* Has to be room to hold the sought data. */
4316 if (textlen > fdata->cap_len) {
4317 return result;
4319 buf_len = fdata->cap_len;
4320 buf_start = ws_buffer_start_ptr(buf);
4321 buf_end = buf_start + buf_len;
4322 pd = buf_end - textlen;
4323 if (cf->search_len || cf->search_pos) {
4324 /* we want to start searching one byte before the previous match start */
4325 pd = buf_start + cf->search_pos - 1;
4327 for (; pd >= buf_start; pd--) {
4328 pd = (uint8_t *)ws_memrpbrk_exec(buf_start, pd - buf_start + 1, pattern, &c_char);
4329 if (pd == NULL) break;
4330 c_match = 0;
4331 for (i = 0; pd + i < buf_end; i++) {
4332 c_char = g_ascii_toupper(pd[i]);
4333 if (c_char == ascii_text[c_match]) {
4334 c_match++;
4335 if (c_match == textlen) {
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)(i + 1);
4340 goto done;
4342 i++;
4343 if (pd + i >= buf_end || pd[i] != '\0') break;
4344 } else {
4345 break;
4350 done:
4351 return result;
4354 static match_result
4355 match_binary(capture_file *cf, frame_data *fdata,
4356 wtap_rec *rec, Buffer *buf, void *criterion)
4358 cbs_t *info = (cbs_t *)criterion;
4359 size_t datalen = info->data_len;
4360 match_result result;
4361 const uint8_t *pd = NULL, *buf_start;
4363 /* Load the frame's data. */
4364 if (!cf_read_record(cf, fdata, rec, buf)) {
4365 /* Attempt to get the packet failed. */
4366 return MR_ERROR;
4369 result = MR_NOTMATCHED;
4370 buf_start = ws_buffer_start_ptr(buf);
4371 size_t offset = 0;
4372 if (cf->search_len || cf->search_pos) {
4373 /* we want to start searching one byte past the previous match start */
4374 offset = cf->search_pos + 1;
4376 if (offset < fdata->cap_len) {
4377 pd = ws_memmem(buf_start + offset, fdata->cap_len - offset, info->data, datalen);
4379 if (pd != NULL) {
4380 result = MR_MATCHED;
4381 /* Save position and length for highlighting the field. */
4382 cf->search_pos = (uint32_t)(pd - buf_start);
4383 cf->search_len = (uint32_t)datalen;
4386 return result;
4389 static match_result
4390 match_binary_reverse(capture_file *cf, frame_data *fdata,
4391 wtap_rec *rec, Buffer *buf, void *criterion)
4393 cbs_t *info = (cbs_t *)criterion;
4394 size_t datalen = info->data_len;
4395 match_result result;
4396 const uint8_t *pd = NULL, *buf_start;
4398 /* Load the frame's data. */
4399 if (!cf_read_record(cf, fdata, rec, buf)) {
4400 /* Attempt to get the packet failed. */
4401 return MR_ERROR;
4404 result = MR_NOTMATCHED;
4405 buf_start = ws_buffer_start_ptr(buf);
4406 /* Has to be room to hold the sought data. */
4407 if (datalen > fdata->cap_len) {
4408 return result;
4410 pd = buf_start + fdata->cap_len - datalen;
4411 if (cf->search_len || cf->search_pos) {
4412 /* we want to start searching one byte before the previous match start */
4413 pd = buf_start + cf->search_pos - 1;
4415 for (; pd >= buf_start; pd--) {
4416 pd = (uint8_t *)ws_memrchr(buf_start, info->data[0], pd - buf_start + 1);
4417 if (pd == NULL) break;
4418 if (memcmp(pd, info->data, datalen) == 0) {
4419 result = MR_MATCHED;
4420 /* Save position and length for highlighting the field. */
4421 cf->search_pos = (uint32_t)(pd - buf_start);
4422 cf->search_len = (uint32_t)datalen;
4423 break;
4427 return result;
4430 static match_result
4431 match_regex(capture_file *cf, frame_data *fdata,
4432 wtap_rec *rec, Buffer *buf, void *criterion _U_)
4434 match_result result = MR_NOTMATCHED;
4435 size_t result_pos[2] = {0, 0};
4437 /* Load the frame's data. */
4438 if (!cf_read_record(cf, fdata, rec, buf)) {
4439 /* Attempt to get the packet failed. */
4440 return MR_ERROR;
4443 size_t offset = 0;
4444 if (cf->search_len || cf->search_pos) {
4445 /* we want to start searching one byte past the previous match start */
4446 offset = cf->search_pos + 1;
4448 if (offset < fdata->cap_len) {
4449 if (ws_regex_matches_pos(cf->regex,
4450 (const char *)ws_buffer_start_ptr(buf),
4451 fdata->cap_len, offset,
4452 result_pos)) {
4453 //TODO: A chosen regex can match the empty string (zero length)
4454 // which doesn't make a lot of sense for searching the packet bytes.
4455 // Should we search with the PCRE2_NOTEMPTY option?
4456 //TODO: Fix cast.
4457 /* Save position and length for highlighting the field. */
4458 cf->search_pos = (uint32_t)(result_pos[0]);
4459 cf->search_len = (uint32_t)(result_pos[1] - result_pos[0]);
4460 result = MR_MATCHED;
4463 return result;
4466 static match_result
4467 match_regex_reverse(capture_file *cf, frame_data *fdata,
4468 wtap_rec *rec, Buffer *buf, void *criterion _U_)
4470 match_result result = MR_NOTMATCHED;
4471 size_t result_pos[2] = {0, 0};
4473 /* Load the frame's data. */
4474 if (!cf_read_record(cf, fdata, rec, buf)) {
4475 /* Attempt to get the packet failed. */
4476 return MR_ERROR;
4479 size_t offset = fdata->cap_len - 1;
4480 if (cf->search_pos) {
4481 /* we want to start searching one byte before the previous match */
4482 offset = cf->search_pos - 1;
4484 for (; offset > 0; offset--) {
4485 if (ws_regex_matches_pos(cf->regex,
4486 (const char *)ws_buffer_start_ptr(buf),
4487 fdata->cap_len, offset,
4488 result_pos)) {
4489 //TODO: A chosen regex can match the empty string (zero length)
4490 // which doesn't make a lot of sense for searching the packet bytes.
4491 // Should we search with the PCRE2_NOTEMPTY option?
4492 //TODO: Fix cast.
4493 /* Save position and length for highlighting the field. */
4494 cf->search_pos = (uint32_t)(result_pos[0]);
4495 cf->search_len = (uint32_t)(result_pos[1] - result_pos[0]);
4496 result = MR_MATCHED;
4497 break;
4500 return result;
4503 bool
4504 cf_find_packet_dfilter(capture_file *cf, dfilter_t *sfcode,
4505 search_direction dir, bool start_current)
4507 return find_packet(cf, match_dfilter, sfcode, dir, start_current);
4510 bool
4511 cf_find_packet_dfilter_string(capture_file *cf, const char *filter,
4512 search_direction dir)
4514 dfilter_t *sfcode;
4515 bool result;
4517 if (!dfilter_compile(filter, &sfcode, NULL)) {
4519 * XXX - this shouldn't happen, as the filter string is machine
4520 * generated
4522 return false;
4524 if (sfcode == NULL) {
4526 * XXX - this shouldn't happen, as the filter string is machine
4527 * generated.
4529 return false;
4531 result = find_packet(cf, match_dfilter, sfcode, dir, true);
4532 dfilter_free(sfcode);
4533 return result;
4536 static match_result
4537 match_dfilter(capture_file *cf, frame_data *fdata,
4538 wtap_rec *rec, Buffer *buf, void *criterion)
4540 dfilter_t *sfcode = (dfilter_t *)criterion;
4541 epan_dissect_t edt;
4542 match_result result;
4544 /* Load the frame's data. */
4545 if (!cf_read_record(cf, fdata, rec, buf)) {
4546 /* Attempt to get the packet failed. */
4547 return MR_ERROR;
4550 epan_dissect_init(&edt, cf->epan, true, false);
4551 epan_dissect_prime_with_dfilter(&edt, sfcode);
4552 epan_dissect_run(&edt, cf->cd_t, rec,
4553 ws_buffer_start_ptr(buf),
4554 fdata, NULL);
4555 result = dfilter_apply_edt(sfcode, &edt) ? MR_MATCHED : MR_NOTMATCHED;
4556 epan_dissect_cleanup(&edt);
4557 return result;
4560 bool
4561 cf_find_packet_marked(capture_file *cf, search_direction dir)
4563 return find_packet(cf, match_marked, NULL, dir, true);
4566 static match_result
4567 match_marked(capture_file *cf _U_, frame_data *fdata, wtap_rec *rec _U_,
4568 Buffer *buf _U_, void *criterion _U_)
4570 return fdata->marked ? MR_MATCHED : MR_NOTMATCHED;
4573 bool
4574 cf_find_packet_time_reference(capture_file *cf, search_direction dir)
4576 return find_packet(cf, match_time_reference, NULL, dir, true);
4579 static match_result
4580 match_time_reference(capture_file *cf _U_, frame_data *fdata, wtap_rec *rec _U_,
4581 Buffer *buf _U_, void *criterion _U_)
4583 return fdata->ref_time ? MR_MATCHED : MR_NOTMATCHED;
4586 static bool
4587 find_packet(capture_file *cf, ws_match_function match_function,
4588 void *criterion, search_direction dir, bool start_current)
4590 frame_data *start_fd;
4591 uint32_t framenum;
4592 uint32_t prev_framenum;
4593 frame_data *fdata;
4594 wtap_rec rec;
4595 Buffer buf;
4596 frame_data *new_fd = NULL;
4597 progdlg_t *progbar = NULL;
4598 GTimer *prog_timer = g_timer_new();
4599 int count;
4600 bool wrap = prefs.gui_find_wrap;
4601 bool succeeded;
4602 float progbar_val;
4603 char status_str[100];
4604 match_result result;
4606 wtap_rec_init(&rec);
4607 ws_buffer_init(&buf, 1514);
4609 start_fd = start_current ? cf->current_frame : NULL;
4610 if (start_fd != NULL) {
4611 prev_framenum = start_fd->num;
4612 } else {
4613 prev_framenum = 0; /* No start packet selected. */
4614 wrap = false;
4617 /* Iterate through the list of packets, starting at the packet we've
4618 picked, calling a routine to run the filter on the packet, see if
4619 it matches, and stop if so. */
4620 count = 0;
4621 framenum = prev_framenum;
4622 if (framenum == 0 && dir == SD_BACKWARD) {
4623 /* If we have no start packet selected, and we're going backwards,
4624 * start at the end (even if wrap is off.)
4626 framenum = cf->count + 1;
4629 g_timer_start(prog_timer);
4630 /* Progress so far. */
4631 progbar_val = 0.0f;
4633 cf->stop_flag = false;
4635 for (;;) {
4636 /* Create the progress bar if necessary.
4637 We check on every iteration of the loop, so that it takes no
4638 longer than the standard time to create it (otherwise, for a
4639 large file, we might take considerably longer than that standard
4640 time in order to get to the next progress bar step). */
4641 if (progbar == NULL)
4642 progbar = delayed_create_progress_dlg(cf->window, NULL, NULL,
4643 false, &cf->stop_flag, progbar_val);
4646 * Update the progress bar, but do it only after PROGBAR_UPDATE_INTERVAL
4647 * has elapsed. Calling update_progress_dlg and packets_bar_update will
4648 * likely trigger UI paint events, which might take a while depending on
4649 * the platform and display. Reset our timer *after* painting.
4651 if (g_timer_elapsed(prog_timer, NULL) > PROGBAR_UPDATE_INTERVAL) {
4652 /* let's not divide by zero. I should never be started
4653 * with count == 0, so let's assert that
4655 ws_assert(cf->count > 0);
4657 progbar_val = (float) count / cf->count;
4659 snprintf(status_str, sizeof(status_str),
4660 "%4u of %u packets", count, cf->count);
4661 update_progress_dlg(progbar, progbar_val, status_str);
4663 g_timer_start(prog_timer);
4666 if (cf->stop_flag) {
4667 /* Well, the user decided to abort the search. Go back to the
4668 frame where we started.
4669 XXX - This ends up selecting the start packet and reporting
4670 "success". Perhaps new_fd should stay NULL? */
4671 new_fd = start_fd;
4672 break;
4675 /* Go past the current frame. */
4676 if (dir == SD_BACKWARD) {
4677 /* Go on to the previous frame. */
4678 if (framenum <= 1) {
4680 * XXX - other apps have a bit more of a detailed message
4681 * for this, and instead of offering "OK" and "Cancel",
4682 * they offer things such as "Continue" and "Cancel";
4683 * we need an API for popping up alert boxes with
4684 * {Verb} and "Cancel".
4687 if (wrap) {
4688 statusbar_push_temporary_msg("Search reached the beginning. Continuing at end.");
4689 framenum = cf->count; /* wrap around */
4690 wrap = false;
4691 } else {
4692 statusbar_push_temporary_msg("Search reached the beginning.");
4693 framenum = prev_framenum; /* stay on previous packet */
4695 } else
4696 framenum--;
4697 } else {
4698 /* Go on to the next frame. */
4699 if (framenum == cf->count) {
4700 if (wrap) {
4701 statusbar_push_temporary_msg("Search reached the end. Continuing at beginning.");
4702 framenum = 1; /* wrap around */
4703 wrap = false;
4704 } else {
4705 statusbar_push_temporary_msg("Search reached the end.");
4706 framenum = prev_framenum; /* stay on previous packet */
4708 } else
4709 framenum++;
4712 fdata = frame_data_sequence_find(cf->provider.frames, framenum);
4713 count++;
4715 /* Is this packet in the display? */
4716 if (fdata && fdata->passed_dfilter) {
4717 /* Yes. Does it match the search criterion? */
4718 result = (*match_function)(cf, fdata, &rec, &buf, criterion);
4719 if (result == MR_ERROR) {
4720 /* Error; our caller has reported the error. Go back to the frame
4721 where we started.
4722 XXX - This ends up selecting the start packet and reporting
4723 "success." Perhaps new_fd should stay NULL? */
4724 new_fd = start_fd;
4725 break;
4726 } else if (result == MR_MATCHED) {
4727 /* Yes. Go to the new frame. */
4728 new_fd = fdata;
4729 break;
4731 wtap_rec_reset(&rec);
4734 if (fdata == start_fd) {
4735 /* We're back to the frame we were on originally, and that frame
4736 doesn't match the search filter. The search failed. */
4737 break;
4741 /* We're done scanning the packets; destroy the progress bar if it
4742 was created. */
4743 if (progbar != NULL)
4744 destroy_progress_dlg(progbar);
4745 g_timer_destroy(prog_timer);
4747 if (new_fd != NULL) {
4748 /* We found a frame that's displayed and that matches.
4749 Try to find and select the packet summary list row for that frame. */
4750 bool found_row;
4752 cf->search_in_progress = true;
4753 found_row = packet_list_select_row_from_data(new_fd);
4754 cf->search_in_progress = false;
4755 if (!found_row) {
4756 /* We didn't find a row corresponding to this frame.
4757 This means that the frame isn't being displayed currently,
4758 so we can't select it. */
4759 cf->search_pos = 0; /* Reset the position */
4760 cf->search_len = 0; /* Reset length */
4761 simple_message_box(ESD_TYPE_INFO, NULL,
4762 "The capture file is probably not fully dissected.",
4763 "End of capture exceeded.");
4764 succeeded = false; /* The search succeeded but we didn't find the row */
4765 } else
4766 succeeded = true; /* The search succeeded and we found the row */
4767 } else
4768 succeeded = false; /* The search failed */
4769 wtap_rec_cleanup(&rec);
4770 ws_buffer_free(&buf);
4771 return succeeded;
4774 bool
4775 cf_goto_frame(capture_file *cf, unsigned fnumber, bool exact)
4777 frame_data *fdata;
4779 if (cf == NULL || cf->provider.frames == NULL) {
4780 /* we don't have a loaded capture file - fix for bugs 11810 & 11989 */
4781 statusbar_push_temporary_msg("There is no file loaded");
4782 return false; /* we failed to go to that packet */
4785 fdata = frame_data_sequence_find(cf->provider.frames, fnumber);
4787 if (fdata == NULL) {
4788 /* we didn't find a packet with that packet number */
4789 statusbar_push_temporary_msg("There is no packet number %u.", fnumber);
4790 return false; /* we failed to go to that packet */
4792 if (!fdata->passed_dfilter) {
4793 /* that packet currently isn't displayed */
4794 /* XXX - add it to the set of displayed packets? */
4795 if (cf->first_displayed == 0 || exact) {
4796 /* We only want that exact frame, or no frames are displayed. */
4797 statusbar_push_temporary_msg("Packet number %u isn't displayed.", fnumber);
4798 return false; /* we failed to go to that packet */
4800 if (fdata->prev_dis_num == 0) {
4801 /* There is no previous displayed frame, so this frame is
4802 * before the first displayed frame. Go to the first line,
4803 * which is the closest frame.
4805 fdata = NULL; /* This will select the first row. */
4806 statusbar_push_temporary_msg("Packet number %u isn't displayed, going to the first displayed packet, %u.", fnumber, cf->first_displayed);
4807 } else {
4808 uint32_t delta = fnumber - fdata->prev_dis_num;
4809 /* The next displayed frame might be closer, we can do an
4810 * O(log n) binary search for the earliest displayed frame
4811 * in the open interval (fnumber, fnumber + delta).
4813 * This is possibly overkill, we could just go to the previous
4814 * displayed frame.
4816 frame_data *fdata2;
4817 uint32_t lower_bound = fnumber + 1;
4818 uint32_t upper_bound = fnumber + delta - 1;
4819 bool found = false;
4820 while (lower_bound <= upper_bound) {
4821 uint32_t middle = (lower_bound + upper_bound) / 2;
4822 fdata2 = frame_data_sequence_find(cf->provider.frames, middle);
4823 if (fdata2 == NULL) {
4824 /* We don't have a frame of that number, so search before it. */
4825 upper_bound = middle - 1;
4826 continue;
4828 /* We have a frame of that number. What's the displayed
4829 * frame before it? */
4830 if (fdata2->prev_dis_num > fnumber) {
4831 /* The previous frame that passed the filter is also after
4832 * our target, so our answer is no later than that.
4834 upper_bound = fdata2->prev_dis_num;
4835 } else {
4836 /* The previous displayed frame is before fnumber.
4837 * (We already know fnumber itself is not displayed.)
4838 * Is this frame itself displayed?
4840 if (fdata2->passed_dfilter) {
4841 /* Yes. So this is our answer. */
4842 found = true;
4843 break;
4845 /* No. So our answer, if any, is after this frame. */
4846 lower_bound = middle + 1;
4849 if (found) {
4850 fdata = fdata2;
4851 statusbar_push_temporary_msg("Packet number %u isn't displayed, going to the next displayed packet, %u.", fnumber, fdata->num);
4852 } else {
4853 statusbar_push_temporary_msg("Packet number %u isn't displayed, going to the previous displayed packet, %u.", fnumber, fdata->prev_dis_num);
4854 fdata = frame_data_sequence_find(cf->provider.frames, fdata->prev_dis_num);
4859 if (!packet_list_select_row_from_data(fdata)) {
4860 /* We didn't find a row corresponding to this frame.
4861 This means that the frame isn't being displayed currently,
4862 so we can't select it. */
4863 simple_message_box(ESD_TYPE_INFO, NULL,
4864 "The capture file is probably not fully dissected.",
4865 "End of capture exceeded.");
4866 return false;
4868 return true; /* we got to that packet */
4872 * Go to frame specified by currently selected protocol tree item.
4874 bool
4875 cf_goto_framenum(capture_file *cf)
4877 const header_field_info *hfinfo;
4878 uint32_t framenum;
4880 if (cf->finfo_selected) {
4881 hfinfo = cf->finfo_selected->hfinfo;
4882 ws_assert(hfinfo);
4883 if (hfinfo->type == FT_FRAMENUM) {
4884 framenum = fvalue_get_uinteger(cf->finfo_selected->value);
4885 if (framenum != 0) {
4886 /* We probably only want to go to the exact match,
4887 * even though "Go to Previous Packet in History" exists.
4889 return cf_goto_frame(cf, framenum, true);
4894 return false;
4897 /* Select the packet on a given row. */
4898 void
4899 cf_select_packet(capture_file *cf, frame_data *fdata)
4901 epan_dissect_t *old_edt;
4903 /* check the frame data struct pointer for this frame */
4904 if (fdata == NULL) {
4905 return;
4908 /* Get the data in that frame. */
4909 if (!cf_read_record(cf, fdata, &cf->rec, &cf->buf)) {
4910 return;
4913 /* Record that this frame is the current frame. */
4914 cf->current_frame = fdata;
4917 * The change to defer freeing the current epan_dissect_t was in
4918 * commit a2bb94c3b33d53f42534aceb7cc67aab1d1fb1f9; to quote
4919 * that commit's comment:
4921 * Clear GtkTreeStore before freeing edt
4923 * When building current data for packet details treeview we store two
4924 * things.
4925 * - Generated string with item label
4926 * - Pointer to node field_info structure
4928 * After epan_dissect_{free, cleanup} pointer to field_info node is no
4929 * longer valid so we should clear GtkTreeStore before freeing.
4931 * XXX - we're no longer using GTK+; is there a way to ensure that
4932 * *nothing* refers to any of the current frame information before
4933 * we replace it?
4935 old_edt = cf->edt;
4936 /* Create the logical protocol tree. */
4937 /* We don't need the columns here. */
4938 cf->edt = epan_dissect_new(cf->epan, true, true);
4940 tap_build_interesting(cf->edt);
4941 epan_dissect_run(cf->edt, cf->cd_t, &cf->rec,
4942 ws_buffer_start_ptr(&cf->buf),
4943 cf->current_frame, NULL);
4945 if (old_edt != NULL)
4946 epan_dissect_free(old_edt);
4949 /* Unselect the selected packet, if any. */
4950 void
4951 cf_unselect_packet(capture_file *cf)
4953 epan_dissect_t *old_edt = cf->edt;
4956 * See the comment in cf_select_packet() about deferring the freeing
4957 * of the old cf->edt.
4959 cf->edt = NULL;
4961 /* No packet is selected. */
4962 cf->current_frame = NULL;
4964 /* Destroy the epan_dissect_t for the unselected packet. */
4965 if (old_edt != NULL)
4966 epan_dissect_free(old_edt);
4970 * Mark a particular frame.
4972 void
4973 cf_mark_frame(capture_file *cf, frame_data *frame)
4975 if (! frame->marked) {
4976 frame->marked = true;
4977 if (cf->count > cf->marked_count)
4978 cf->marked_count++;
4983 * Unmark a particular frame.
4985 void
4986 cf_unmark_frame(capture_file *cf, frame_data *frame)
4988 if (frame->marked) {
4989 frame->marked = false;
4990 if (cf->marked_count > 0)
4991 cf->marked_count--;
4996 * Ignore a particular frame.
4998 void
4999 cf_ignore_frame(capture_file *cf, frame_data *frame)
5001 if (! frame->ignored) {
5002 frame->ignored = true;
5003 if (cf->count > cf->ignored_count)
5004 cf->ignored_count++;
5009 * Un-ignore a particular frame.
5011 void
5012 cf_unignore_frame(capture_file *cf, frame_data *frame)
5014 if (frame->ignored) {
5015 frame->ignored = false;
5016 if (cf->ignored_count > 0)
5017 cf->ignored_count--;
5022 * Modify the section comment.
5024 void
5025 cf_update_section_comment(capture_file *cf, char *comment)
5027 wtap_block_t shb_inf;
5028 char *shb_comment;
5030 /* Get the first SHB. */
5031 /* XXX - support multiple SHBs */
5032 shb_inf = wtap_file_get_shb(cf->provider.wth, 0);
5034 /* Get the first comment from the SHB. */
5035 /* XXX - support multiple comments */
5036 if (wtap_block_get_nth_string_option_value(shb_inf, OPT_COMMENT, 0, &shb_comment) != WTAP_OPTTYPE_SUCCESS) {
5037 /* There's no comment - add one. */
5038 wtap_block_add_string_option(shb_inf, OPT_COMMENT, comment, strlen(comment));
5039 } else {
5040 /* See if the comment has changed or not */
5041 if (strcmp(shb_comment, comment) == 0) {
5042 g_free(comment);
5043 return;
5046 /* The comment has changed, let's update it */
5047 wtap_block_set_nth_string_option_value(shb_inf, OPT_COMMENT, 0, comment, strlen(comment));
5049 /* Mark the file as having unsaved changes */
5050 cf->unsaved_changes = true;
5054 * Modify the section comments for a given section.
5056 void
5057 cf_update_section_comments(capture_file *cf, unsigned shb_idx, char **comments)
5059 wtap_block_t shb_inf;
5060 char *shb_comment;
5062 shb_inf = wtap_file_get_shb(cf->provider.wth, shb_idx);
5063 if (shb_inf == NULL) {
5064 /* Shouldn't happen. XXX: Report it if it does? */
5065 return;
5068 unsigned n_comments = g_strv_length(comments);
5069 unsigned i;
5070 char* comment;
5072 for (i = 0; i < n_comments; i++) {
5073 comment = comments[i];
5074 if (wtap_block_get_nth_string_option_value(shb_inf, OPT_COMMENT, i, &shb_comment) != WTAP_OPTTYPE_SUCCESS) {
5075 /* There's no comment - add one. */
5076 wtap_block_add_string_option_owned(shb_inf, OPT_COMMENT, comment);
5077 cf->unsaved_changes = true;
5078 } else {
5079 /* See if the comment has changed or not */
5080 if (strcmp(shb_comment, comment) != 0) {
5081 /* The comment has changed, let's update it */
5082 wtap_block_set_nth_string_option_value(shb_inf, OPT_COMMENT, 0, comment, strlen(comment));
5083 cf->unsaved_changes = true;
5085 g_free(comment);
5088 /* We either transferred ownership of the comments or freed them
5089 * above, so free the array of strings but not the strings themselves. */
5090 g_free(comments);
5092 /* If there are extra old comments, remove them. Start at the end. */
5093 for (i = wtap_block_count_option(shb_inf, OPT_COMMENT); i > n_comments; i--) {
5094 wtap_block_remove_nth_option_instance(shb_inf, OPT_COMMENT, i - 1);
5095 cf->unsaved_changes = true;
5100 * Get the packet block for a packet (record).
5101 * If the block has been edited, it returns the result of the edit,
5102 * otherwise it returns the block from the file.
5103 * NB. Caller must wtap_block_unref() the result when done.
5105 wtap_block_t
5106 cf_get_packet_block(capture_file *cf, const frame_data *fd)
5108 /* If this block has been modified, fetch the modified version */
5109 if (fd->has_modified_block)
5110 return wtap_block_ref(cap_file_provider_get_modified_block(&cf->provider, fd));
5111 else {
5112 wtap_rec rec; /* Record metadata */
5113 Buffer buf; /* Record data */
5114 wtap_block_t block;
5116 /* fetch record block */
5117 wtap_rec_init(&rec);
5118 ws_buffer_init(&buf, 1514);
5120 if (!cf_read_record(cf, fd, &rec, &buf))
5121 { /* XXX, what we can do here? */ }
5123 /* rec.block is owned by the record, steal it before it is gone. */
5124 block = wtap_block_ref(rec.block);
5126 wtap_rec_cleanup(&rec);
5127 ws_buffer_free(&buf);
5128 return block;
5133 * Update(replace) the block on a capture from a frame
5135 bool
5136 cf_set_modified_block(capture_file *cf, frame_data *fd, const wtap_block_t new_block)
5138 wtap_block_t pkt_block = cf_get_packet_block(cf, fd);
5140 /* It's possible to further modify the modified block "in place" by doing
5141 * a call to cf_get_packet_block() that returns an already created modified
5142 * block, modifying that, and calling this function.
5143 * If the caller did that, then the block pointers will be equal.
5145 if (pkt_block == new_block) {
5146 /* No need to save anything here, the caller changes went right
5147 * onto the block.
5148 * Unfortunately we don't have a way to know how many comments were
5149 * in the block before the caller modified it, so tell the caller
5150 * it is its responsibility to update the comment count.
5152 return false;
5154 else {
5155 if (pkt_block)
5156 cf->packet_comment_count -= wtap_block_count_option(pkt_block, OPT_COMMENT);
5158 if (new_block)
5159 cf->packet_comment_count += wtap_block_count_option(new_block, OPT_COMMENT);
5161 cap_file_provider_set_modified_block(&cf->provider, fd, new_block);
5163 expert_update_comment_count(cf->packet_comment_count);
5166 /* Either way, we have unsaved changes. */
5167 wtap_block_unref(pkt_block);
5168 cf->unsaved_changes = true;
5169 return true;
5173 * What types of comments does this capture file have?
5175 uint32_t
5176 cf_comment_types(capture_file *cf)
5178 uint32_t comment_types = 0;
5181 * Does this file have any sections with at least one comment?
5183 for (unsigned section_number = 0;
5184 section_number < wtap_file_get_num_shbs(cf->provider.wth);
5185 section_number++) {
5186 wtap_block_t shb_inf;
5187 char *shb_comment;
5189 shb_inf = wtap_file_get_shb(cf->provider.wth, section_number);
5191 /* Try to get the first comment from that SHB. */
5192 if (wtap_block_get_nth_string_option_value(shb_inf, OPT_COMMENT, 0,
5193 &shb_comment) == WTAP_OPTTYPE_SUCCESS) {
5194 /* We succeeded, so this file has at least one section comment. */
5195 comment_types |= WTAP_COMMENT_PER_SECTION;
5197 /* We don't need to search any more. */
5198 break;
5201 if (cf->packet_comment_count != 0)
5202 comment_types |= WTAP_COMMENT_PER_PACKET;
5203 return comment_types;
5207 * Add a resolved address to this file's list of resolved addresses.
5209 bool
5210 cf_add_ip_name_from_string(capture_file *cf, const char *addr, const char *name)
5213 * XXX - support multiple resolved address lists, and add to the one
5214 * attached to this file?
5216 if (!add_ip_name_from_string(addr, name))
5217 return false;
5219 /* OK, we have unsaved changes. */
5220 cf->unsaved_changes = true;
5221 return true;
5224 typedef struct {
5225 wtap_dumper *pdh;
5226 const char *fname;
5227 int file_type;
5228 bool export;
5229 } save_callback_args_t;
5232 * Save a capture to a file, in a particular format, saving either
5233 * all packets, all currently-displayed packets, or all marked packets.
5235 * Returns true if it succeeds, false otherwise; if it fails, it pops
5236 * up a message box for the failure.
5238 static bool
5239 save_record(capture_file *cf, frame_data *fdata, wtap_rec *rec,
5240 Buffer *buf, void *argsp)
5242 save_callback_args_t *args = (save_callback_args_t *)argsp;
5243 wtap_rec new_rec;
5244 int err;
5245 char *err_info;
5246 wtap_block_t pkt_block;
5248 /* Copy the record information from what was read in from the file. */
5249 new_rec = *rec;
5251 /* Make changes based on anything that the user has done but that
5252 hasn't been saved yet. */
5253 if (fdata->has_modified_block)
5254 pkt_block = cap_file_provider_get_modified_block(&cf->provider, fdata);
5255 else
5256 pkt_block = rec->block;
5257 new_rec.block = pkt_block;
5258 new_rec.block_was_modified = fdata->has_modified_block ? true : false;
5260 if (!nstime_is_zero(&fdata->shift_offset)) {
5261 if (new_rec.presence_flags & WTAP_HAS_TS) {
5262 nstime_add(&new_rec.ts, &fdata->shift_offset);
5266 /* and save the packet */
5267 if (!wtap_dump(args->pdh, &new_rec, ws_buffer_start_ptr(buf), &err, &err_info)) {
5268 report_cfile_write_failure(NULL, args->fname, err, err_info, fdata->num,
5269 args->file_type);
5270 return false;
5273 /* If we are saving (i.e., replacing the current file with the one we're
5274 * writing), then update the frame data to clear the shift offset.
5275 * This keeps us from having to re-read the entire file.
5276 * We could do this in rescan_file(), but
5277 * 1) Ideally we shouldn't have to call rescan_file if all we're doing
5278 * is changing the timestamps, since that shouldn't change the offsets.
5279 * 2) The long term goal is to try to do the offset adjustment here
5280 * instead of using rescan_file, which should be faster (#1257).
5282 * If we're exporting to a different file, then don't do that.
5284 if (!args->export && new_rec.presence_flags & WTAP_HAS_TS) {
5285 nstime_set_zero(&fdata->shift_offset);
5288 return true;
5292 * Can this capture file be written out in any format using Wiretap
5293 * rather than by copying the raw data?
5295 bool
5296 cf_can_write_with_wiretap(capture_file *cf)
5298 /* We don't care whether we support the comments in this file or not;
5299 if we can't, we'll offer the user the option of discarding the
5300 comments. */
5301 return wtap_dump_can_write(cf->linktypes, 0);
5305 * Should we let the user do a save?
5307 * We should if:
5309 * the file has unsaved changes, and we can save it in some
5310 * format through Wiretap
5312 * or
5314 * the file is a temporary file and has no unsaved changes (so
5315 * that "saving" it just means copying it).
5317 * XXX - we shouldn't allow files to be edited if they can't be saved,
5318 * so cf->unsaved_changes should be true only if the file can be saved.
5320 * We don't care whether we support the comments in this file or not;
5321 * if we can't, we'll offer the user the option of discarding the
5322 * comments.
5324 bool
5325 cf_can_save(capture_file *cf)
5327 if (cf->unsaved_changes && wtap_dump_can_write(cf->linktypes, 0)) {
5328 /* Saved changes, and we can write it out with Wiretap. */
5329 return true;
5332 if (cf->is_tempfile && !cf->unsaved_changes) {
5334 * Temporary file with no unsaved changes, so we can just do a
5335 * raw binary copy.
5337 return true;
5340 /* Nothing to save. */
5341 return false;
5345 * Should we let the user do a "save as"?
5347 * That's true if:
5349 * we can save it in some format through Wiretap
5351 * or
5353 * the file is a temporary file and has no unsaved changes (so
5354 * that "saving" it just means copying it).
5356 * XXX - we shouldn't allow files to be edited if they can't be saved,
5357 * so cf->unsaved_changes should be true only if the file can be saved.
5359 * We don't care whether we support the comments in this file or not;
5360 * if we can't, we'll offer the user the option of discarding the
5361 * comments.
5363 bool
5364 cf_can_save_as(capture_file *cf)
5366 if (wtap_dump_can_write(cf->linktypes, 0)) {
5367 /* We can write it out with Wiretap. */
5368 return true;
5371 if (cf->is_tempfile && !cf->unsaved_changes) {
5373 * Temporary file with no unsaved changes, so we can just do a
5374 * raw binary copy.
5376 return true;
5379 /* Nothing to save. */
5380 return false;
5384 * Does this file have unsaved data?
5386 bool
5387 cf_has_unsaved_data(capture_file *cf)
5390 * If this is a temporary file, or a file with unsaved changes, it
5391 * has unsaved data.
5393 return (cf->is_tempfile && cf->count>0) || cf->unsaved_changes;
5397 * Quick scan to find packet offsets.
5399 static cf_read_status_t
5400 rescan_file(capture_file *cf, const char *fname, bool is_tempfile)
5402 wtap_rec rec;
5403 Buffer buf;
5404 int err;
5405 char *err_info;
5406 char *name_ptr;
5407 int64_t data_offset;
5408 progdlg_t *progbar = NULL;
5409 GTimer *prog_timer = g_timer_new();
5410 int64_t size;
5411 float progbar_val;
5412 int64_t start_time;
5413 char status_str[100];
5414 uint32_t framenum;
5415 frame_data *fdata;
5417 /* Close the old handle. */
5418 wtap_close(cf->provider.wth);
5420 /* Open the new file. */
5421 /* XXX: this will go through all open_routines for a matching one. But right
5422 now rescan_file() is only used when a file is being saved to a different
5423 format than the original, and the user is not given a choice of which
5424 reader to use (only which format to save it in), so doing this makes
5425 sense for now. (XXX: Now it is also used when saving a changed file,
5426 e.g. comments or time-shifted frames.) */
5427 cf->provider.wth = wtap_open_offline(fname, WTAP_TYPE_AUTO, &err, &err_info, true);
5428 if (cf->provider.wth == NULL) {
5429 report_cfile_open_failure(fname, err, err_info);
5430 return CF_READ_ERROR;
5433 /* We're scanning a file whose contents should be the same as what
5434 we had before, so we don't discard dissection state etc.. */
5435 cf->f_datalen = 0;
5437 /* Set the file name because we need it to set the follow stream filter.
5438 XXX - is that still true? We need it for other reasons, though,
5439 in any case. */
5440 if (cf->filename != NULL) {
5441 g_free(cf->filename);
5443 cf->filename = g_strdup(fname);
5445 /* Indicate whether it's a permanent or temporary file. */
5446 cf->is_tempfile = is_tempfile;
5448 /* No user changes yet. */
5449 cf->unsaved_changes = false;
5451 cf->cd_t = wtap_file_type_subtype(cf->provider.wth);
5452 if (cf->linktypes != NULL) {
5453 g_array_free(cf->linktypes, TRUE);
5455 cf->linktypes = g_array_sized_new(FALSE, FALSE, (unsigned) sizeof(int), 1);
5457 cf->snap = wtap_snapshot_length(cf->provider.wth);
5459 name_ptr = g_filename_display_basename(cf->filename);
5461 cf_callback_invoke(cf_cb_file_rescan_started, cf);
5463 /* Record the file's compression type.
5464 XXX - do we know this at open time? */
5465 cf->compression_type = wtap_get_compression_type(cf->provider.wth);
5467 /* Find the size of the file. */
5468 size = wtap_file_size(cf->provider.wth, NULL);
5470 g_timer_start(prog_timer);
5472 cf->stop_flag = false;
5473 start_time = g_get_monotonic_time();
5475 framenum = 0;
5476 wtap_rec_init(&rec);
5477 ws_buffer_init(&buf, 1514);
5478 while ((wtap_read(cf->provider.wth, &rec, &buf, &err, &err_info,
5479 &data_offset))) {
5480 framenum++;
5481 fdata = frame_data_sequence_find(cf->provider.frames, framenum);
5482 if (G_LIKELY(fdata != NULL)) {
5483 fdata->file_off = data_offset;
5485 if (size >= 0) {
5486 cf->f_datalen = wtap_read_so_far(cf->provider.wth);
5488 /* Create the progress bar if necessary. */
5489 if (progress_is_slow(progbar, prog_timer, size, cf->f_datalen)) {
5490 progbar_val = calc_progbar_val(cf, size, cf->f_datalen, status_str, sizeof(status_str));
5491 progbar = delayed_create_progress_dlg(cf->window, NULL, NULL,
5492 true, &cf->stop_flag, progbar_val);
5496 * Update the progress bar, but do it only after PROGBAR_UPDATE_INTERVAL
5497 * has elapsed. Calling update_progress_dlg and packets_bar_update will
5498 * likely trigger UI paint events, which might take a while depending on
5499 * the platform and display. Reset our timer *after* painting.
5501 if (progbar && g_timer_elapsed(prog_timer, NULL) > PROGBAR_UPDATE_INTERVAL) {
5502 progbar_val = calc_progbar_val(cf, size, cf->f_datalen, status_str, sizeof(status_str));
5503 /* update the packet bar content on the first run or frequently on very large files */
5504 update_progress_dlg(progbar, progbar_val, status_str);
5505 compute_elapsed(cf, start_time);
5506 packets_bar_update();
5507 g_timer_start(prog_timer);
5511 if (cf->stop_flag) {
5512 /* Well, the user decided to abort the rescan. Sadly, as this
5513 isn't a reread, recovering is difficult, so we'll just
5514 close the current capture. */
5515 break;
5518 /* Add this packet's link-layer encapsulation type to cf->linktypes, if
5519 it's not already there.
5520 XXX - yes, this is O(N), so if every packet had a different
5521 link-layer encapsulation type, it'd be O(N^2) to read the file, but
5522 there are probably going to be a small number of encapsulation types
5523 in a file. */
5524 if (rec.rec_type == REC_TYPE_PACKET) {
5525 cf_add_encapsulation_type(cf, rec.rec_header.packet_header.pkt_encap);
5527 wtap_rec_reset(&rec);
5529 wtap_rec_cleanup(&rec);
5530 ws_buffer_free(&buf);
5532 /* Free the display name */
5533 g_free(name_ptr);
5535 /* We're done reading the file; destroy the progress bar if it was created. */
5536 if (progbar != NULL)
5537 destroy_progress_dlg(progbar);
5538 g_timer_destroy(prog_timer);
5540 /* We're done reading sequentially through the file. */
5541 cf->state = FILE_READ_DONE;
5543 /* Close the sequential I/O side, to free up memory it requires. */
5544 wtap_sequential_close(cf->provider.wth);
5546 /* compute the time it took to load the file */
5547 compute_elapsed(cf, start_time);
5549 /* Set the file encapsulation type now; we don't know what it is until
5550 we've looked at all the packets, as we don't know until then whether
5551 there's more than one type (and thus whether it's
5552 WTAP_ENCAP_PER_PACKET). */
5553 cf->lnk_t = wtap_file_encap(cf->provider.wth);
5555 cf_callback_invoke(cf_cb_file_rescan_finished, cf);
5557 if (cf->stop_flag) {
5558 /* Our caller will give up at this point. */
5559 return CF_READ_ABORTED;
5562 if (err != 0) {
5563 /* Put up a message box noting that the read failed somewhere along
5564 the line. Don't throw out the stuff we managed to read, though,
5565 if any. */
5566 report_cfile_read_failure(NULL, err, err_info);
5567 return CF_READ_ERROR;
5568 } else
5569 return CF_READ_OK;
5572 cf_write_status_t
5573 cf_save_records(capture_file *cf, const char *fname, unsigned save_format,
5574 wtap_compression_type compression_type,
5575 bool discard_comments, bool dont_reopen)
5577 char *err_info = "Unknown error";
5578 char *fname_new = NULL;
5579 wtap_dumper *pdh;
5580 frame_data *fdata;
5581 addrinfo_lists_t *addr_lists;
5582 unsigned framenum;
5583 int err;
5584 enum {
5585 SAVE_WITH_MOVE,
5586 SAVE_WITH_COPY,
5587 SAVE_WITH_WTAP
5588 } how_to_save;
5589 save_callback_args_t callback_args;
5590 callback_args.export = false;
5591 bool needs_reload = false;
5593 /* XXX caller should avoid saving the file while a read is pending
5594 * (e.g. by delaying the save action) */
5595 if (cf->read_lock) {
5596 ws_warning("cf_save_records(\"%s\") while the file is being read, potential crash ahead", fname);
5599 cf_callback_invoke(cf_cb_file_save_started, (void *)fname);
5601 addr_lists = get_addrinfo_list();
5603 if (save_format == cf->cd_t && compression_type == cf->compression_type
5604 && !discard_comments && !cf->unsaved_changes
5605 && (wtap_addrinfo_list_empty(addr_lists) || wtap_file_type_subtype_supports_block(save_format, WTAP_BLOCK_NAME_RESOLUTION) == BLOCK_NOT_SUPPORTED)) {
5606 /* We're saving in the format it's already in, and we're not discarding
5607 comments, and there are no changes we have in memory that aren't saved
5608 to the file, and we have no name resolution information to write or
5609 the file format we're saving in doesn't support writing name
5610 resolution information, so we can just move or copy the raw data. */
5612 if (cf->is_tempfile) {
5613 /* The file being saved is a temporary file from a live
5614 capture, so it doesn't need to stay around under that name;
5615 first, try renaming the capture buffer file to the new name.
5616 This acts as a "safe save", in that, if the file already
5617 exists, the existing file will be removed only if the rename
5618 succeeds.
5620 Sadly, on Windows, as we have the current capture file
5621 open, even MoveFileEx() with MOVEFILE_REPLACE_EXISTING
5622 (to cause the rename to remove an existing target), as
5623 done by ws_stdio_rename() (ws_rename() is #defined to
5624 be ws_stdio_rename() on Windows) will fail.
5626 According to the MSDN documentation for CreateFile(), if,
5627 when we open a capture file, we were to directly do a CreateFile(),
5628 opening with FILE_SHARE_DELETE|FILE_SHARE_READ, and then
5629 convert it to a file descriptor with _open_osfhandle(),
5630 that would allow the file to be renamed out from under us.
5632 However, that doesn't work in practice. Perhaps the problem
5633 is that the process doing the rename is the process that
5634 has the file open. */
5635 #ifndef _WIN32
5636 if (ws_rename(cf->filename, fname) == 0) {
5637 /* That succeeded - there's no need to copy the source file. */
5638 how_to_save = SAVE_WITH_MOVE;
5639 } else {
5640 if (errno == EXDEV) {
5641 /* They're on different file systems, so we have to copy the
5642 file. */
5643 how_to_save = SAVE_WITH_COPY;
5644 } else {
5645 /* The rename failed, but not because they're on different
5646 file systems - put up an error message. (Or should we
5647 just punt and try to copy? The only reason why I'd
5648 expect the rename to fail and the copy to succeed would
5649 be if we didn't have permission to remove the file from
5650 the temporary directory, and that might be fixable - but
5651 is it worth requiring the user to go off and fix it?) */
5652 report_rename_failure(cf->filename, fname, errno);
5653 goto fail;
5656 #else
5657 /* Windows - copy the file to its new location. */
5658 how_to_save = SAVE_WITH_COPY;
5659 #endif
5660 } else {
5661 /* It's a permanent file, so we should copy it, and not remove the
5662 original. */
5663 how_to_save = SAVE_WITH_COPY;
5666 if (how_to_save == SAVE_WITH_COPY) {
5667 /* Copy the file, if we haven't moved it. If we're overwriting
5668 an existing file, we do it with a "safe save", by writing
5669 to a new file and, if the write succeeds, renaming the
5670 new file on top of the old file. */
5671 if (file_exists(fname)) {
5672 fname_new = ws_strdup_printf("%s~", fname);
5673 if (!copy_file_binary_mode(cf->filename, fname_new))
5674 goto fail;
5675 } else {
5676 if (!copy_file_binary_mode(cf->filename, fname))
5677 goto fail;
5680 } else {
5681 /* Either we're saving in a different format or we're saving changes,
5682 such as added, modified, or removed comments, that haven't yet
5683 been written to the underlying file; we can't do that by copying
5684 or moving the capture file, we have to do it by writing the packets
5685 out in Wiretap. */
5687 wtap_dump_params params;
5688 int encap;
5690 how_to_save = SAVE_WITH_WTAP;
5691 wtap_dump_params_init(&params, cf->provider.wth);
5693 /* Determine what file encapsulation type we should use. */
5694 encap = wtap_dump_required_file_encap_type(cf->linktypes);
5695 params.encap = encap;
5697 /* Use the snaplen from cf (XXX - does wtap_dump_params_init handle that?) */
5698 params.snaplen = cf->snap;
5700 if (file_exists(fname)) {
5701 /* We're overwriting an existing file; write out to a new file,
5702 and, if that succeeds, rename the new file on top of the
5703 old file. That makes this a "safe save", so that we don't
5704 lose the old file if we have a problem writing out the new
5705 file. (If the existing file is the current capture file,
5706 we *HAVE* to do that, otherwise we're overwriting the file
5707 from which we're reading the packets that we're writing!) */
5708 fname_new = ws_strdup_printf("%s~", fname);
5709 pdh = wtap_dump_open(fname_new, save_format, compression_type, &params,
5710 &err, &err_info);
5711 } else {
5712 pdh = wtap_dump_open(fname, save_format, compression_type, &params,
5713 &err, &err_info);
5715 /* XXX idb_inf is documented to be used until wtap_dump_close. */
5716 g_free(params.idb_inf);
5717 params.idb_inf = NULL;
5719 if (pdh == NULL) {
5720 report_cfile_dump_open_failure(fname, err, err_info, save_format);
5721 goto fail;
5724 /* Add address resolution */
5725 wtap_dump_set_addrinfo_list(pdh, addr_lists);
5727 /* Iterate through the list of packets, processing all the packets. */
5728 callback_args.pdh = pdh;
5729 callback_args.fname = fname;
5730 callback_args.file_type = save_format;
5731 switch (process_specified_records(cf, NULL, "Saving", "packets",
5732 true, save_record, &callback_args, true)) {
5734 case PSP_FINISHED:
5735 /* Completed successfully. */
5736 break;
5738 case PSP_STOPPED:
5739 /* The user decided to abort the saving.
5740 If we're writing to a temporary file, remove it.
5741 XXX - should we do so even if we're not writing to a
5742 temporary file? */
5743 wtap_dump_close(pdh, NULL, &err, &err_info);
5744 if (fname_new != NULL)
5745 ws_unlink(fname_new);
5746 cf_callback_invoke(cf_cb_file_save_stopped, NULL);
5747 wtap_dump_params_cleanup(&params);
5748 return CF_WRITE_ABORTED;
5750 case PSP_FAILED:
5751 /* Error while saving.
5752 If we're writing to a temporary file, remove it. */
5753 if (fname_new != NULL)
5754 ws_unlink(fname_new);
5755 wtap_dump_close(pdh, NULL, &err, &err_info);
5756 wtap_dump_params_cleanup(&params);
5757 goto fail;
5760 if (!wtap_dump_close(pdh, &needs_reload, &err, &err_info)) {
5761 report_cfile_close_failure(fname, err, err_info);
5762 wtap_dump_params_cleanup(&params);
5763 goto fail;
5766 wtap_dump_params_cleanup(&params);
5769 if (fname_new != NULL) {
5770 /* We wrote out to fname_new, and should rename it on top of
5771 fname. fname_new is now closed, so that should be possible even
5772 on Windows. However, on Windows, we first need to close whatever
5773 file descriptors we have open for fname. */
5774 #ifdef _WIN32
5775 wtap_fdclose(cf->provider.wth);
5776 #endif
5777 /* Now do the rename. */
5778 if (ws_rename(fname_new, fname) == -1) {
5779 /* Well, the rename failed. */
5780 report_rename_failure(fname_new, fname, errno);
5781 #ifdef _WIN32
5782 /* Attempt to reopen the random file descriptor using the
5783 current file's filename. (At this point, the sequential
5784 file descriptor is closed.) */
5785 if (!wtap_fdreopen(cf->provider.wth, cf->filename, &err)) {
5786 /* Oh, well, we're screwed. */
5787 report_cfile_open_failure(cf->filename, err, NULL);
5789 #endif
5790 goto fail;
5792 g_free(fname_new);
5795 /* If this was a temporary file, and we didn't do the save by doing
5796 a move, so the tempoary file is still around under its old name,
5797 remove it. */
5798 if (cf->is_tempfile && how_to_save != SAVE_WITH_MOVE) {
5799 /* If this fails, there's not much we can do, so just ignore errors. */
5800 ws_unlink(cf->filename);
5803 cf_callback_invoke(cf_cb_file_save_finished, NULL);
5804 cf->unsaved_changes = false;
5806 if (!dont_reopen) {
5807 switch (how_to_save) {
5809 case SAVE_WITH_MOVE:
5810 /* We just moved the file, so the wtap structure refers to the
5811 new file, and all the information other than the filename
5812 and the "is temporary" status applies to the new file; just
5813 update that. */
5814 g_free(cf->filename);
5815 cf->filename = g_strdup(fname);
5816 cf->is_tempfile = false;
5817 cf_callback_invoke(cf_cb_file_fast_save_finished, cf);
5818 break;
5820 case SAVE_WITH_COPY:
5821 /* We just copied the file, so all the information other than
5822 the file descriptors, the filename, and the "is temporary"
5823 status applies to the new file; just update that. */
5824 wtap_fdclose(cf->provider.wth);
5825 /* Attempt to reopen the random file descriptor using the
5826 new file's filename. (At this point, the sequential
5827 file descriptor is closed.) */
5828 if (!wtap_fdreopen(cf->provider.wth, fname, &err)) {
5829 report_cfile_open_failure(fname, err, err_info);
5830 cf_close(cf);
5831 } else {
5832 g_free(cf->filename);
5833 cf->filename = g_strdup(fname);
5834 cf->is_tempfile = false;
5836 cf_callback_invoke(cf_cb_file_fast_save_finished, cf);
5837 break;
5839 case SAVE_WITH_WTAP:
5840 /* Open and read the file we saved to.
5842 XXX - this is somewhat of a waste; we already have the
5843 packets, all this gets us is updated file type information
5844 (which we could just stuff into "cf"), and having the new
5845 file be the one we have opened and from which we're reading
5846 the data, and it means we have to spend time opening and
5847 reading the file, which could be a significant amount of
5848 time if the file is large.
5850 If the capture-file-writing code were to return the
5851 seek offset of each packet it writes, we could save that
5852 in the frame_data structure for the frame, and just open
5853 the file without reading it again...
5855 ...as long as, for gzipped files, the process of writing
5856 out the file *also* generates the information needed to
5857 support fast random access to the compressed file. */
5858 /* rescan_file will cause us to try all open_routines, so
5859 reset cfile's open_type */
5860 cf->open_type = WTAP_TYPE_AUTO;
5861 /* There are cases when SAVE_WITH_WTAP can result in new packets
5862 being written to the file, e.g ERF records
5863 In that case, we need to reload the whole file */
5864 if(needs_reload) {
5865 if (cf_open(cf, fname, WTAP_TYPE_AUTO, false, &err) == CF_OK) {
5866 if (cf_read(cf, /*reloading=*/true) != CF_READ_OK) {
5867 /* The rescan failed; just close the file. Either
5868 a dialog was popped up for the failure, so the
5869 user knows what happened, or they stopped the
5870 rescan, in which case they know what happened. */
5871 /* XXX: This is inconsistent with normal open/reload behaviour. */
5872 cf_close(cf);
5876 else {
5877 if (rescan_file(cf, fname, false) != CF_READ_OK) {
5878 /* The rescan failed; just close the file. Either
5879 a dialog was popped up for the failure, so the
5880 user knows what happened, or they stopped the
5881 rescan, in which case they know what happened. */
5882 cf_close(cf);
5885 break;
5888 /* If we were told to discard the comments, do so. */
5889 if (discard_comments) {
5890 /* Remove SHB comment, if any. */
5891 wtap_write_shb_comment(cf->provider.wth, NULL);
5893 /* remove all user comments */
5894 for (framenum = 1; framenum <= cf->count; framenum++) {
5895 fdata = frame_data_sequence_find(cf->provider.frames, framenum);
5897 // XXX: This also ignores non-comment options like verdict
5898 fdata->has_modified_block = false;
5901 if (cf->provider.frames_modified_blocks) {
5902 g_tree_destroy(cf->provider.frames_modified_blocks);
5903 cf->provider.frames_modified_blocks = NULL;
5906 cf->packet_comment_count = 0;
5909 return CF_WRITE_OK;
5911 fail:
5912 if (fname_new != NULL) {
5913 /* We were trying to write to a temporary file; get rid of it if it
5914 exists. (We don't care whether this fails, as, if it fails,
5915 there's not much we can do about it. I guess if it failed for
5916 a reason other than "it doesn't exist", we could report an
5917 error, so the user knows there's a junk file that they might
5918 want to clean up.) */
5919 ws_unlink(fname_new);
5920 g_free(fname_new);
5922 cf_callback_invoke(cf_cb_file_save_failed, NULL);
5923 return CF_WRITE_ERROR;
5926 cf_write_status_t
5927 cf_export_specified_packets(capture_file *cf, const char *fname,
5928 packet_range_t *range, unsigned save_format,
5929 wtap_compression_type compression_type)
5931 char *fname_new = NULL;
5932 int err;
5933 char *err_info;
5934 wtap_dumper *pdh;
5935 save_callback_args_t callback_args;
5936 wtap_dump_params params;
5937 int encap;
5939 callback_args.export = true;
5940 packet_range_process_init(range);
5942 /* We're writing out specified packets from the specified capture
5943 file to another file. Even if all captured packets are to be
5944 written, don't special-case the operation - read each packet
5945 and then write it out if it's one of the specified ones. */
5947 wtap_dump_params_init(&params, cf->provider.wth);
5949 /* Determine what file encapsulation type we should use. */
5950 encap = wtap_dump_required_file_encap_type(cf->linktypes);
5951 params.encap = encap;
5953 /* Use the snaplen from cf (XXX - does wtap_dump_params_init handle that?) */
5954 params.snaplen = cf->snap;
5956 if (file_exists(fname)) {
5957 /* We're overwriting an existing file; write out to a new file,
5958 and, if that succeeds, rename the new file on top of the
5959 old file. That makes this a "safe save", so that we don't
5960 lose the old file if we have a problem writing out the new
5961 file. (If the existing file is the current capture file,
5962 we *HAVE* to do that, otherwise we're overwriting the file
5963 from which we're reading the packets that we're writing!) */
5964 fname_new = ws_strdup_printf("%s~", fname);
5965 pdh = wtap_dump_open(fname_new, save_format, compression_type, &params,
5966 &err, &err_info);
5967 } else {
5968 pdh = wtap_dump_open(fname, save_format, compression_type, &params,
5969 &err, &err_info);
5971 /* XXX idb_inf is documented to be used until wtap_dump_close. */
5972 g_free(params.idb_inf);
5973 params.idb_inf = NULL;
5975 if (pdh == NULL) {
5976 report_cfile_dump_open_failure(fname, err, err_info, save_format);
5977 goto fail;
5980 /* Add address resolution */
5981 wtap_dump_set_addrinfo_list(pdh, get_addrinfo_list());
5983 /* Iterate through the list of packets, processing the packets we were
5984 told to process.
5986 XXX - we've already called "packet_range_process_init(range)", but
5987 "process_specified_records()" will do it again. Fortunately,
5988 that's harmless in this case, as we haven't done anything to
5989 "range" since we initialized it. */
5990 callback_args.pdh = pdh;
5991 callback_args.fname = fname;
5992 callback_args.file_type = save_format;
5993 switch (process_specified_records(cf, range, "Writing", "specified records",
5994 true, save_record, &callback_args, true)) {
5996 case PSP_FINISHED:
5997 /* Completed successfully. */
5998 break;
6000 case PSP_STOPPED:
6001 /* The user decided to abort the saving.
6002 If we're writing to a temporary file, remove it.
6003 XXX - should we do so even if we're not writing to a
6004 temporary file? */
6005 wtap_dump_close(pdh, NULL, &err, &err_info);
6006 if (fname_new != NULL) {
6007 ws_unlink(fname_new);
6008 g_free(fname_new);
6010 wtap_dump_params_cleanup(&params);
6012 return CF_WRITE_ABORTED;
6014 case PSP_FAILED:
6015 /* Error while saving. */
6016 wtap_dump_close(pdh, NULL, &err, &err_info);
6018 * We don't report any error from closing; the error that caused
6019 * process_specified_records() to fail has already been reported.
6021 goto fail;
6024 if (!wtap_dump_close(pdh, NULL, &err, &err_info)) {
6025 report_cfile_close_failure(fname, err, err_info);
6026 goto fail;
6029 if (fname_new != NULL) {
6030 /* We wrote out to fname_new, and should rename it on top of
6031 fname; fname is now closed, so that should be possible even
6032 on Windows. Do the rename. */
6033 if (ws_rename(fname_new, fname) == -1) {
6034 /* Well, the rename failed. */
6035 report_rename_failure(fname_new, fname, errno);
6036 goto fail;
6038 g_free(fname_new);
6040 wtap_dump_params_cleanup(&params);
6042 return CF_WRITE_OK;
6044 fail:
6045 if (fname_new != NULL) {
6046 /* We were trying to write to a temporary file; get rid of it if it
6047 exists. (We don't care whether this fails, as, if it fails,
6048 there's not much we can do about it. I guess if it failed for
6049 a reason other than "it doesn't exist", we could report an
6050 error, so the user knows there's a junk file that they might
6051 want to clean up.) */
6052 ws_unlink(fname_new);
6053 g_free(fname_new);
6055 wtap_dump_params_cleanup(&params);
6057 return CF_WRITE_ERROR;
6060 /* Reload the current capture file. */
6061 cf_status_t
6062 cf_reload(capture_file *cf)
6064 char *filename;
6065 bool is_tempfile;
6066 cf_status_t cf_status = CF_OK;
6067 int err;
6069 if (cf->read_lock) {
6070 ws_warning("Failing cf_reload(\"%s\") since a read is in progress", cf->filename);
6071 return CF_ERROR;
6074 /* If the file could be opened, "cf_open()" calls "cf_close()"
6075 to get rid of state for the old capture file before filling in state
6076 for the new capture file. "cf_close()" will remove the file if
6077 it's a temporary file; we don't want that to happen (for one thing,
6078 it'd prevent subsequent reopens from working). Remember whether it's
6079 a temporary file, mark it as not being a temporary file, and then
6080 reopen it as the type of file it was.
6082 Also, "cf_close()" will free "cf->filename", so we must make
6083 a copy of it first. */
6084 filename = g_strdup(cf->filename);
6085 is_tempfile = cf->is_tempfile;
6086 cf->is_tempfile = false;
6087 if (cf_open(cf, filename, cf->open_type, is_tempfile, &err) == CF_OK) {
6088 switch (cf_read(cf, /*reloading=*/true)) {
6090 case CF_READ_OK:
6091 case CF_READ_ERROR:
6092 /* Just because we got an error, that doesn't mean we were unable
6093 to read any of the file; we handle what we could get from the
6094 file. */
6095 break;
6097 case CF_READ_ABORTED:
6098 /* The user bailed out of re-reading the capture file; the
6099 capture file has been closed. */
6100 break;
6102 } else {
6103 /* The open failed, so "cf->is_tempfile" wasn't set to "is_tempfile".
6104 Instead, the file was left open, so we should restore "cf->is_tempfile"
6105 ourselves.
6107 XXX - change the menu? Presumably "cf_open()" will do that;
6108 make sure it does! */
6109 cf->is_tempfile = is_tempfile;
6110 cf_status = CF_ERROR;
6112 /* "cf_open()" made a copy of the file name we handed it, so
6113 we should free up our copy. */
6114 g_free(filename);
6115 return cf_status;