drsuapi_SupportedExtensionsExt
[wireshark-sm.git] / file.c
blob2ebcefd779ed514809ada111b4e448a4a277f9a0
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"
51 #include "frame_tvbuff.h"
53 #include "ui/simple_dialog.h"
54 #include "ui/main_statusbar.h"
55 #include "ui/progress_dlg.h"
56 #include "ui/urls.h"
57 #include "ui/ws_ui_util.h"
58 #include "ui/packet_list_utils.h"
60 /* Needed for addrinfo */
61 #include <sys/types.h>
63 #ifdef HAVE_SYS_SOCKET_H
64 #include <sys/socket.h>
65 #endif
67 #ifdef HAVE_NETINET_IN_H
68 # include <netinet/in.h>
69 #endif
71 #ifdef _WIN32
72 # include <winsock2.h>
73 # include <ws2tcpip.h>
74 #endif
76 static bool read_record(capture_file *cf, wtap_rec *rec, Buffer *buf,
77 dfilter_t *dfcode, epan_dissect_t *edt, column_info *cinfo, int64_t offset,
78 fifo_string_cache_t *frame_dup_cache, GChecksum *frame_cksum);
80 static void rescan_packets(capture_file *cf, const char *action, const char *action_item, bool redissect);
82 typedef enum {
83 MR_NOTMATCHED,
84 MR_MATCHED,
85 MR_ERROR
86 } match_result;
87 typedef match_result (*ws_match_function)(capture_file *, frame_data *,
88 wtap_rec *, Buffer *, void *);
89 static match_result match_protocol_tree(capture_file *cf, frame_data *fdata,
90 wtap_rec *, Buffer *, void *criterion);
91 static void match_subtree_text(proto_node *node, void *data);
92 static void match_subtree_text_reverse(proto_node *node, void *data);
93 static match_result match_summary_line(capture_file *cf, frame_data *fdata,
94 wtap_rec *, Buffer *, void *criterion);
95 static match_result match_narrow_and_wide(capture_file *cf, frame_data *fdata,
96 wtap_rec *, Buffer *, void *criterion);
97 static match_result match_narrow_and_wide_reverse(capture_file *cf, frame_data *fdata,
98 wtap_rec *, Buffer *, void *criterion);
99 static match_result match_narrow_and_wide_case(capture_file *cf, frame_data *fdata,
100 wtap_rec *, Buffer *, void *criterion);
101 static match_result match_narrow_and_wide_case_reverse(capture_file *cf, frame_data *fdata,
102 wtap_rec *, Buffer *, void *criterion);
103 static match_result match_narrow_case(capture_file *cf, frame_data *fdata,
104 wtap_rec *, Buffer *, void *criterion);
105 static match_result match_narrow_case_reverse(capture_file *cf, frame_data *fdata,
106 wtap_rec *, Buffer *, void *criterion);
107 static match_result match_wide(capture_file *cf, frame_data *fdata,
108 wtap_rec *, Buffer *, void *criterion);
109 static match_result match_wide_reverse(capture_file *cf, frame_data *fdata,
110 wtap_rec *, Buffer *, void *criterion);
111 static match_result match_wide_case(capture_file *cf, frame_data *fdata,
112 wtap_rec *, Buffer *, void *criterion);
113 static match_result match_wide_case_reverse(capture_file *cf, frame_data *fdata,
114 wtap_rec *, Buffer *, void *criterion);
115 static match_result match_binary(capture_file *cf, frame_data *fdata,
116 wtap_rec *, Buffer *, void *criterion);
117 static match_result match_binary_reverse(capture_file *cf, frame_data *fdata,
118 wtap_rec *, Buffer *, void *criterion);
119 static match_result match_regex(capture_file *cf, frame_data *fdata,
120 wtap_rec *, Buffer *, void *criterion);
121 static match_result match_regex_reverse(capture_file *cf, frame_data *fdata,
122 wtap_rec *, Buffer *, void *criterion);
123 static match_result match_dfilter(capture_file *cf, frame_data *fdata,
124 wtap_rec *, Buffer *, void *criterion);
125 static match_result match_marked(capture_file *cf, frame_data *fdata,
126 wtap_rec *, Buffer *, void *criterion);
127 static match_result match_time_reference(capture_file *cf, frame_data *fdata,
128 wtap_rec *, Buffer *, void *criterion);
129 static bool find_packet(capture_file *cf, ws_match_function match_function,
130 void *criterion, search_direction dir);
132 /* Seconds spent processing packets between pushing UI updates. */
133 #define PROGBAR_UPDATE_INTERVAL 0.150
135 /* Show the progress bar after this many seconds. */
136 #define PROGBAR_SHOW_DELAY 0.5
139 * Maximum number of records we support in a file.
141 * It is, at most, the maximum value of a uint32_t, as we use a uint32_t
142 * for the frame number.
144 * We allow it to be set to a lower value; see issue #16908 for why
145 * we're doing this. Thanks, Qt!
147 static uint32_t max_records = UINT32_MAX;
149 void
150 cf_set_max_records(unsigned max_records_arg)
152 max_records = max_records_arg;
156 * We could probably use g_signal_...() instead of the callbacks below but that
157 * would require linking our CLI programs to libgobject and creating an object
158 * instance for the signals.
160 typedef struct {
161 cf_callback_t cb_fct;
162 void * user_data;
163 } cf_callback_data_t;
165 static GList *cf_callbacks;
167 static void
168 cf_callback_invoke(int event, void *data)
170 cf_callback_data_t *cb;
171 GList *cb_item = cf_callbacks;
173 /* there should be at least one interested */
174 ws_assert(cb_item != NULL);
176 while (cb_item != NULL) {
177 cb = (cf_callback_data_t *)cb_item->data;
178 cb->cb_fct(event, data, cb->user_data);
179 cb_item = g_list_next(cb_item);
183 void
184 cf_callback_add(cf_callback_t func, void *user_data)
186 cf_callback_data_t *cb;
188 cb = g_new(cf_callback_data_t,1);
189 cb->cb_fct = func;
190 cb->user_data = user_data;
192 cf_callbacks = g_list_prepend(cf_callbacks, cb);
195 void
196 cf_callback_remove(cf_callback_t func, void *user_data)
198 cf_callback_data_t *cb;
199 GList *cb_item = cf_callbacks;
201 while (cb_item != NULL) {
202 cb = (cf_callback_data_t *)cb_item->data;
203 if (cb->cb_fct == func && cb->user_data == user_data) {
204 cf_callbacks = g_list_remove(cf_callbacks, cb);
205 g_free(cb);
206 return;
208 cb_item = g_list_next(cb_item);
211 ws_assert_not_reached();
214 unsigned long
215 cf_get_computed_elapsed(capture_file *cf)
217 return cf->computed_elapsed;
220 static void
221 compute_elapsed(capture_file *cf, int64_t start_time)
223 int64_t delta_time = g_get_monotonic_time() - start_time;
225 cf->computed_elapsed = (unsigned long) (delta_time / 1000); /* ms */
228 static epan_t *
229 ws_epan_new(capture_file *cf)
231 static const struct packet_provider_funcs funcs = {
232 cap_file_provider_get_frame_ts,
233 cap_file_provider_get_interface_name,
234 cap_file_provider_get_interface_description,
235 cap_file_provider_get_modified_block
238 return epan_new(&cf->provider, &funcs);
241 cf_status_t
242 cf_open(capture_file *cf, const char *fname, unsigned int type, bool is_tempfile, int *err)
244 wtap *wth;
245 char *err_info;
247 wth = wtap_open_offline(fname, type, err, &err_info, true);
248 if (wth == NULL)
249 goto fail;
251 /* The open succeeded. Close whatever capture file we had open,
252 and fill in the information for this file. */
253 cf_close(cf);
255 /* Initialize the record metadata. */
256 wtap_rec_init(&cf->rec);
258 /* XXX - we really want to initialize this after we've read all
259 the packets, so we know how much we'll ultimately need. */
260 ws_buffer_init(&cf->buf, 1514);
262 /* We're about to start reading the file. */
263 cf->state = FILE_READ_IN_PROGRESS;
265 /* If there was a pending redissection for the old file (there
266 * shouldn't be), clear it. cf_close() should have failed if the
267 * old file's read lock was held, but it doesn't hurt to clear it. */
268 cf->read_lock = false;
269 cf->redissection_queued = RESCAN_NONE;
271 cf->provider.wth = wth;
272 cf->f_datalen = 0;
274 /* Set the file name because we need it to set the follow stream filter.
275 XXX - is that still true? We need it for other reasons, though,
276 in any case. */
277 cf->filename = g_strdup(fname);
279 /* Indicate whether it's a permanent or temporary file. */
280 cf->is_tempfile = is_tempfile;
282 /* No user changes yet. */
283 cf->unsaved_changes = false;
285 cf->computed_elapsed = 0;
287 cf->cd_t = wtap_file_type_subtype(cf->provider.wth);
288 cf->open_type = type;
289 cf->linktypes = g_array_sized_new(FALSE, FALSE, (unsigned) sizeof(int), 1);
290 cf->count = 0;
291 cf->packet_comment_count = 0;
292 cf->displayed_count = 0;
293 cf->marked_count = 0;
294 cf->ignored_count = 0;
295 cf->ref_time_count = 0;
296 cf->drops_known = false;
297 cf->drops = 0;
298 cf->snap = wtap_snapshot_length(cf->provider.wth);
300 /* Allocate a frame_data_sequence for the frames in this file */
301 cf->provider.frames = new_frame_data_sequence();
303 nstime_set_zero(&cf->elapsed_time);
304 cf->provider.ref = NULL;
305 cf->provider.prev_dis = NULL;
306 cf->provider.prev_cap = NULL;
307 cf->cum_bytes = 0;
309 /* Create new epan session for dissection.
310 * (The old one was freed in cf_close().)
312 cf->epan = ws_epan_new(cf);
314 packet_list_queue_draw();
315 cf_callback_invoke(cf_cb_file_opened, cf);
317 wtap_set_cb_new_ipv4(cf->provider.wth, add_ipv4_name);
318 wtap_set_cb_new_ipv6(cf->provider.wth, (wtap_new_ipv6_callback_t) add_ipv6_name);
319 wtap_set_cb_new_secrets(cf->provider.wth, secrets_wtap_callback);
321 return CF_OK;
323 fail:
324 report_cfile_open_failure(fname, *err, err_info);
325 return CF_ERROR;
329 * Add an encapsulation type to cf->linktypes.
331 static void
332 cf_add_encapsulation_type(capture_file *cf, int encap)
334 unsigned i;
336 for (i = 0; i < cf->linktypes->len; i++) {
337 if (g_array_index(cf->linktypes, int, i) == encap)
338 return; /* it's already there */
340 /* It's not already there - add it. */
341 g_array_append_val(cf->linktypes, encap);
344 /* Reset everything to a pristine state */
345 void
346 cf_close(capture_file *cf)
348 cf->stop_flag = false;
349 if (cf->state == FILE_CLOSED || cf->state == FILE_READ_PENDING)
350 return; /* Nothing to do */
352 /* Die if we're in the middle of reading a file. */
353 ws_assert(cf->state != FILE_READ_IN_PROGRESS);
354 ws_assert(!cf->read_lock);
356 cf_callback_invoke(cf_cb_file_closing, cf);
358 /* close things, if not already closed before */
359 color_filters_cleanup();
361 if (cf->provider.wth) {
362 wtap_close(cf->provider.wth);
363 cf->provider.wth = NULL;
365 /* We have no file open... */
366 if (cf->filename != NULL) {
367 /* If it's a temporary file, remove it. */
368 if (cf->is_tempfile)
369 ws_unlink(cf->filename);
370 g_free(cf->filename);
371 cf->filename = NULL;
373 /* ...which means we have no changes to that file to save. */
374 cf->unsaved_changes = false;
376 /* no open_routine type */
377 cf->open_type = WTAP_TYPE_AUTO;
379 /* Clean up the record metadata. */
380 wtap_rec_cleanup(&cf->rec);
382 /* Clear the packet list. */
383 packet_list_freeze();
384 packet_list_clear();
385 packet_list_thaw();
387 /* Free up the packet buffer. */
388 ws_buffer_free(&cf->buf);
390 dfilter_free(cf->rfcode);
391 cf->rfcode = NULL;
392 if (cf->provider.frames != NULL) {
393 free_frame_data_sequence(cf->provider.frames);
394 cf->provider.frames = NULL;
396 if (cf->provider.frames_modified_blocks) {
397 g_tree_destroy(cf->provider.frames_modified_blocks);
398 cf->provider.frames_modified_blocks = NULL;
400 cf_unselect_packet(cf); /* nothing to select */
401 cf->first_displayed = 0;
402 cf->last_displayed = 0;
404 /* No frames, no frame selected, no field in that frame selected. */
405 cf->count = 0;
406 cf->current_frame = NULL;
407 cf->finfo_selected = NULL;
409 /* No frame link-layer types, either. */
410 if (cf->linktypes != NULL) {
411 g_array_free(cf->linktypes, TRUE);
412 cf->linktypes = NULL;
415 cf->f_datalen = 0;
416 nstime_set_zero(&cf->elapsed_time);
418 reset_tap_listeners();
420 epan_free(cf->epan);
421 cf->epan = NULL;
423 /* We have no file open. */
424 cf->state = FILE_CLOSED;
426 cf_callback_invoke(cf_cb_file_closed, cf);
430 * true if the progress dialog doesn't exist and it looks like we'll
431 * take > PROGBAR_SHOW_DELAY (500ms) to load, false otherwise.
433 static inline bool
434 progress_is_slow(progdlg_t *progdlg, GTimer *prog_timer, int64_t size, int64_t pos)
436 double elapsed;
438 if (progdlg) return false;
439 elapsed = g_timer_elapsed(prog_timer, NULL);
440 /* This only gets checked between reading records, which doesn't help if
441 * a single record takes a very long time, e.g., the first TLS packet if
442 * the SSLKEYLOGFILE is very large. (#17051) */
443 if ((elapsed * 2 > PROGBAR_SHOW_DELAY && (size / pos) >= 2) /* It looks like we're going to be slow. */
444 || elapsed > PROGBAR_SHOW_DELAY) { /* We are indeed slow. */
445 return true;
447 return false;
450 static float
451 calc_progbar_val(capture_file *cf, int64_t size, int64_t file_pos, char *status_str, unsigned long status_size)
453 float progbar_val;
455 progbar_val = (float) file_pos / (float) size;
456 if (progbar_val > 1.0) {
458 /* The file probably grew while we were reading it.
459 * Update file size, and try again.
461 size = wtap_file_size(cf->provider.wth, NULL);
463 if (size >= 0)
464 progbar_val = (float) file_pos / (float) size;
466 /* If it's still > 1, either "wtap_file_size()" failed (in which
467 * case there's not much we can do about it), or the file
468 * *shrank* (in which case there's not much we can do about
469 * it); just clip the progress value at 1.0.
471 if (progbar_val > 1.0f)
472 progbar_val = 1.0f;
475 snprintf(status_str, status_size,
476 "%" PRId64 "KB of %" PRId64 "KB",
477 file_pos / 1024, size / 1024);
479 return progbar_val;
482 cf_read_status_t
483 cf_read(capture_file *cf, bool reloading)
485 int err = 0;
486 char *err_info = NULL;
487 volatile bool too_many_records = false;
488 char *name_ptr;
489 progdlg_t *volatile progbar = NULL;
490 GTimer *prog_timer = g_timer_new();
491 int64_t size;
492 int64_t start_time;
493 epan_dissect_t edt;
494 wtap_rec rec;
495 Buffer buf;
496 dfilter_t *dfcode = NULL;
497 column_info *cinfo;
498 volatile bool create_proto_tree;
499 unsigned tap_flags;
500 bool compiled _U_;
501 volatile bool is_read_aborted = false;
503 /* The update_progress_dlg call below might end up accepting a user request to
504 * trigger redissection/rescans which can modify/destroy the dissection
505 * context ("cf->epan"). That condition should be prevented by callers, but in
506 * case it occurs let's fail gracefully.
508 if (cf->read_lock) {
509 ws_warning("Failing due to recursive cf_read(\"%s\", %d) call!",
510 cf->filename, reloading);
511 return CF_READ_ERROR;
513 /* This is a full dissection, so clear any pending request for one. */
514 cf->redissection_queued = RESCAN_NONE;
515 cf->read_lock = true;
517 /* Compile the current display filter.
518 * The code it compiles to might have changed, e.g. if a display
519 * filter macro used has changed.
521 * We assume this will not fail since cf->dfilter is only set in
522 * cf_filter IFF the filter was valid.
523 * XXX - This is not necessarily true, if the filter has a FT_IPv4
524 * or FT_IPv6 field compared to a resolved hostname in it, because
525 * we do a new host lookup, and that *could* timeout this time
526 * (though with the read lock above we shouldn't have many lookups at
527 * once, reducing the chances of that)... (#19612)
529 if (cf->dfilter) {
530 compiled = dfilter_compile(cf->dfilter, &dfcode, NULL);
531 ws_assert(compiled && dfcode);
534 dfilter_free(cf->dfcode);
535 cf->dfcode = dfcode;
537 /* The compiled dfilter might have a field reference; recompiling it
538 * means that the field references won't match anything. That's what
539 * we want since this is a new sequential read and we don't have
540 * a selected frame with a tree. (Will taps with filters with display
541 * references also have cleared display references?)
544 /* Get the union of the flags for all tap listeners. */
545 tap_flags = union_of_tap_listener_flags();
548 * Determine whether we need to create a protocol tree.
549 * We do if:
551 * we're going to apply a display filter;
553 * one of the tap listeners is going to apply a filter;
555 * one of the tap listeners requires a protocol tree;
557 * a postdissector wants field values or protocols on
558 * the first pass.
560 create_proto_tree =
561 (cf->dfcode != NULL || have_filtering_tap_listeners() ||
562 (tap_flags & TL_REQUIRES_PROTO_TREE) || postdissectors_want_hfids());
564 reset_tap_listeners();
566 name_ptr = g_filename_display_basename(cf->filename);
568 if (reloading)
569 cf_callback_invoke(cf_cb_file_reload_started, cf);
570 else
571 cf_callback_invoke(cf_cb_file_read_started, cf);
573 /* Record the file's compression type.
574 XXX - do we know this at open time? */
575 cf->compression_type = wtap_get_compression_type(cf->provider.wth);
577 /* The packet list window will be empty until the file is completely loaded */
578 packet_list_freeze();
580 cf->stop_flag = false;
581 start_time = g_get_monotonic_time();
583 epan_dissect_init(&edt, cf->epan, create_proto_tree, false);
585 /* If the display filter or any tap listeners require the columns,
586 * construct them. */
587 cinfo = (tap_listeners_require_columns() ||
588 dfilter_requires_columns(cf->dfcode)) ? &cf->cinfo : NULL;
590 /* Find the size of the file. */
591 size = wtap_file_size(cf->provider.wth, NULL);
593 /* If we are to ignore duplicate frames, we need a container to store
594 * hashes frame contents */
595 fifo_string_cache_t frame_dup_cache;
596 GChecksum *volatile cksum = NULL;
598 if (prefs.ignore_dup_frames) {
599 fifo_string_cache_init(&frame_dup_cache, prefs.ignore_dup_frames_cache_entries, g_free);
600 cksum = g_checksum_new(G_CHECKSUM_SHA256);
603 g_timer_start(prog_timer);
605 wtap_rec_init(&rec);
606 ws_buffer_init(&buf, 1514);
608 TRY {
609 int64_t file_pos;
610 int64_t data_offset;
612 float progbar_val;
613 char status_str[100];
615 while ((wtap_read(cf->provider.wth, &rec, &buf, &err, &err_info,
616 &data_offset))) {
617 if (size >= 0) {
618 if (cf->count == max_records) {
620 * Quit if we've already read the maximum number of
621 * records allowed.
623 too_many_records = true;
624 break;
626 file_pos = wtap_read_so_far(cf->provider.wth);
628 /* Create the progress bar if necessary. */
629 if (progress_is_slow(progbar, prog_timer, size, file_pos)) {
630 progbar_val = calc_progbar_val(cf, size, file_pos, status_str, sizeof(status_str));
631 progbar = delayed_create_progress_dlg(cf->window, NULL, NULL, true,
632 &cf->stop_flag, progbar_val);
636 * Update the progress bar, but do it only after
637 * PROGBAR_UPDATE_INTERVAL has elapsed. Calling update_progress_dlg
638 * and packets_bar_update will likely trigger UI paint events, which
639 * might take a while depending on the platform and display. Reset
640 * our timer *after* painting.
642 if (progbar && g_timer_elapsed(prog_timer, NULL) > PROGBAR_UPDATE_INTERVAL) {
643 progbar_val = calc_progbar_val(cf, size, file_pos, status_str, sizeof(status_str));
644 /* update the packet bar content on the first run or frequently on very large files */
645 update_progress_dlg(progbar, progbar_val, status_str);
646 compute_elapsed(cf, start_time);
647 packets_bar_update();
648 g_timer_start(prog_timer);
651 * The previous GUI triggers should not have destroyed the running
652 * session. If that did happen, it could blow up when read_record tries
653 * to use the destroyed edt.session, so detect it right here.
655 ws_assert(edt.session == cf->epan);
658 if (cf->state == FILE_READ_ABORTED) {
659 /* Well, the user decided to exit Wireshark. Break out of the
660 loop, and let the code below (which is called even if there
661 aren't any packets left to read) exit. */
662 is_read_aborted = true;
663 break;
665 if (cf->stop_flag) {
666 /* Well, the user decided to abort the read. He/She will be warned and
667 it might be enough for him/her to work with the already loaded
668 packets.
669 This is especially true for very large capture files, where you don't
670 want to wait loading the whole file (which may last minutes or even
671 hours even on fast machines) just to see that it was the wrong file. */
672 break;
674 read_record(cf, &rec, &buf, cf->dfcode, &edt, cinfo, data_offset, &frame_dup_cache, cksum);
675 wtap_rec_reset(&rec);
678 CATCH(OutOfMemoryError) {
679 simple_message_box(ESD_TYPE_ERROR, NULL,
680 "More information and workarounds can be found at\n"
681 WS_WIKI_URL("KnownBugs/OutOfMemory"),
682 "Sorry, but Wireshark has run out of memory and has to terminate now.");
683 #if 0
684 /* Could we close the current capture and free up memory from that? */
685 #else
686 /* we have to terminate, as we cannot recover from the memory error */
687 exit(1);
688 #endif
690 ENDTRY;
692 // If we're ignoring duplicate frames, clear the data structures.
693 // We really could look at prefs.ignore_dup_frames here, but it's even
694 // safer to check if we had allocated 'cksum'.
695 if (cksum != NULL) {
696 fifo_string_cache_free(&frame_dup_cache);
697 g_checksum_free(cksum);
700 /* We're done reading sequentially through the file. */
701 cf->state = FILE_READ_DONE;
703 /* Destroy the progress bar if it was created. */
704 if (progbar != NULL)
705 destroy_progress_dlg(progbar);
706 g_timer_destroy(prog_timer);
708 /* Free the display name */
709 g_free(name_ptr);
711 epan_dissect_cleanup(&edt);
712 wtap_rec_cleanup(&rec);
713 ws_buffer_free(&buf);
715 /* Close the sequential I/O side, to free up memory it requires. */
716 wtap_sequential_close(cf->provider.wth);
718 /* Allow the protocol dissectors to free up memory that they
719 * don't need after the sequential run-through of the packets. */
720 postseq_cleanup_all_protocols();
722 /* compute the time it took to load the file */
723 compute_elapsed(cf, start_time);
725 /* Set the file encapsulation type now; we don't know what it is until
726 we've looked at all the packets, as we don't know until then whether
727 there's more than one type (and thus whether it's
728 WTAP_ENCAP_PER_PACKET). */
729 cf->lnk_t = wtap_file_encap(cf->provider.wth);
731 cf->current_frame = frame_data_sequence_find(cf->provider.frames, cf->first_displayed);
733 packet_list_thaw();
735 /* It is safe again to execute redissections or sort. */
736 ws_assert(cf->read_lock);
737 cf->read_lock = false;
739 if (reloading)
740 cf_callback_invoke(cf_cb_file_reload_finished, cf);
741 else
742 cf_callback_invoke(cf_cb_file_read_finished, cf);
744 /* If we have any displayed packets to select, select the first of those
745 packets by making the first row the selected row. */
746 if (cf->first_displayed != 0) {
747 packet_list_select_row_from_data(NULL);
750 if (is_read_aborted) {
752 * Well, the user decided to exit Wireshark while reading this *offline*
753 * capture file (Live captures are handled by something like
754 * cf_continue_tail). Clean up accordingly.
756 cf_close(cf);
757 cf->redissection_queued = RESCAN_NONE;
758 return CF_READ_ABORTED;
761 if (cf->redissection_queued != RESCAN_NONE) {
762 /* Redissection was queued up. Clear the request and perform it now. */
763 bool redissect = cf->redissection_queued == RESCAN_REDISSECT;
764 rescan_packets(cf, NULL, NULL, redissect);
767 if (cf->stop_flag) {
768 simple_message_box(ESD_TYPE_WARN, NULL,
769 "The remaining packets in the file were discarded.\n"
770 "\n"
771 "As a lot of packets from the original file will be missing,\n"
772 "remember to be careful when saving the current content to a file.\n",
773 "File loading was cancelled.");
774 return CF_READ_ERROR;
777 if (err != 0) {
778 /* Put up a message box noting that the read failed somewhere along
779 the line. Don't throw out the stuff we managed to read, though,
780 if any. */
781 report_cfile_read_failure(NULL, err, err_info);
782 return CF_READ_ERROR;
783 } else if (too_many_records) {
784 simple_message_box(ESD_TYPE_WARN, NULL,
785 "The remaining packets in the file were discarded.\n"
786 "\n"
787 "As a lot of packets from the original file will be missing,\n"
788 "remember to be careful when saving the current content to a file.\n"
789 "\n"
790 "The command-line utility editcap can be used to split "
791 "the file into multiple smaller files",
792 "The file contains more records than the maximum "
793 "supported number of records, %u.", max_records);
794 return CF_READ_ERROR;
795 } else
796 return CF_READ_OK;
799 #ifdef HAVE_LIBPCAP
800 cf_read_status_t
801 cf_continue_tail(capture_file *cf, volatile int to_read, wtap_rec *rec,
802 Buffer *buf, int *err, fifo_string_cache_t *frame_dup_cache, GChecksum *frame_cksum)
804 char *err_info;
805 volatile int newly_displayed_packets = 0;
806 epan_dissect_t edt;
807 bool create_proto_tree;
808 unsigned tap_flags;
810 /* Don't compile the current display filter. The current display filter
811 * text might compile to different code than when the capture started:
813 * If it has a IP address resolved name, calling get_host_ipaddr every
814 * time new packets arrive can mean a *lot* of gethostbyname calls
815 * in flight at once, eventually leading to a timeout (#19612).
816 * addr_resolv.c says that ares_gethostbyname is "usually interactive",
817 * unlike ares_gethostbyaddr (used in dissection), and violating that
818 * expectation is bad.
820 * If it has a display filter macro, the definition might have changed.
822 * If it has a field reference, the selected frame / current proto tree
823 * might have changed, and we don't have the old one. If we recompile,
824 * we can't set the field references to the old values.
826 * For a rescan, redissection, reload, retap, or opening a new file, we
827 * want to compile. What about here, when new frames have arrived in a live
828 * capture? We might be able to cache the host lookup, and a user might want
829 * the new display filter macro definition, but the user almost surely wants
830 * the field references to refer to values from the proto tree when the
831 * filter was applied, not whatever it happens to be now if the user has
832 * clicked on a different packet.
834 * To get the new compiled filter, the user should refilter.
837 /* Get the union of the flags for all tap listeners. */
838 tap_flags = union_of_tap_listener_flags();
841 * Determine whether we need to create a protocol tree.
842 * We do if:
844 * we're going to apply a display filter;
846 * one of the tap listeners is going to apply a filter;
848 * one of the tap listeners requires a protocol tree;
850 * a postdissector wants field values or protocols on
851 * the first pass.
853 create_proto_tree =
854 (cf->dfcode != NULL || have_filtering_tap_listeners() ||
855 (tap_flags & TL_REQUIRES_PROTO_TREE) || postdissectors_want_hfids());
857 *err = 0;
859 /* Don't freeze/thaw the list when doing live capture */
860 /*packet_list_freeze();*/
862 epan_dissect_init(&edt, cf->epan, create_proto_tree, false);
864 TRY {
865 int64_t data_offset = 0;
866 column_info *cinfo;
868 /* If the display filter or any tap listeners require the columns,
869 * construct them. */
870 cinfo = (tap_listeners_require_columns() ||
871 dfilter_requires_columns(cf->dfcode)) ? &cf->cinfo : NULL;
873 while (to_read != 0) {
874 wtap_cleareof(cf->provider.wth);
875 if (!wtap_read(cf->provider.wth, rec, buf, err, &err_info,
876 &data_offset)) {
877 break;
879 if (cf->state == FILE_READ_ABORTED) {
880 /* Well, the user decided to exit Wireshark. Break out of the
881 loop, and let the code below (which is called even if there
882 aren't any packets left to read) exit. */
883 break;
885 if (read_record(cf, rec, buf, cf->dfcode, &edt, cinfo, data_offset, frame_dup_cache, frame_cksum)) {
886 newly_displayed_packets++;
888 to_read--;
890 wtap_rec_reset(rec);
892 CATCH(OutOfMemoryError) {
893 simple_message_box(ESD_TYPE_ERROR, NULL,
894 "More information and workarounds can be found at\n"
895 WS_WIKI_URL("KnownBugs/OutOfMemory"),
896 "Sorry, but Wireshark has run out of memory and has to terminate now.");
897 #if 0
898 /* Could we close the current capture and free up memory from that? */
899 return CF_READ_ABORTED;
900 #else
901 /* we have to terminate, as we cannot recover from the memory error */
902 exit(1);
903 #endif
905 ENDTRY;
907 /* Update the file encapsulation; it might have changed based on the
908 packets we've read. */
909 cf->lnk_t = wtap_file_encap(cf->provider.wth);
911 epan_dissect_cleanup(&edt);
913 /* Don't freeze/thaw the list when doing live capture */
914 /*packet_list_thaw();*/
915 /* With the new packet list the first packet
916 * isn't automatically selected.
918 if (!cf->current_frame && !packet_list_multi_select_active())
919 packet_list_select_row_from_data(NULL);
921 if (cf->state == FILE_READ_ABORTED) {
922 /* Well, the user decided to exit Wireshark. Return CF_READ_ABORTED
923 so that our caller can kill off the capture child process;
924 this will cause an EOF on the pipe from the child, so
925 "cf_finish_tail()" will be called, and it will clean up
926 and exit. */
927 return CF_READ_ABORTED;
928 } else if (*err != 0) {
929 /* We got an error reading the capture file.
930 XXX - pop up a dialog box instead? */
931 if (err_info != NULL) {
932 ws_warning("Error \"%s\" while reading \"%s\" (\"%s\")",
933 wtap_strerror(*err), cf->filename, err_info);
934 g_free(err_info);
935 } else {
936 ws_warning("Error \"%s\" while reading \"%s\"",
937 wtap_strerror(*err), cf->filename);
939 return CF_READ_ERROR;
940 } else
941 return CF_READ_OK;
944 void
945 cf_fake_continue_tail(capture_file *cf)
947 if (cf->state == FILE_CLOSED) {
948 cf->state = FILE_READ_PENDING;
952 cf_read_status_t
953 cf_finish_tail(capture_file *cf, wtap_rec *rec, Buffer *buf, int *err,
954 fifo_string_cache_t *frame_dup_cache, GChecksum *frame_cksum)
956 char *err_info;
957 int64_t data_offset;
958 column_info *cinfo;
959 epan_dissect_t edt;
960 bool create_proto_tree;
961 unsigned tap_flags;
963 /* All the comments above in cf_continue_tail apply regarding the
964 * current display filter.
967 /* Get the union of the flags for all tap listeners. */
968 tap_flags = union_of_tap_listener_flags();
970 /* If the display filter or any tap listeners require the columns,
971 * construct them. */
972 cinfo = (tap_listeners_require_columns() ||
973 dfilter_requires_columns(cf->dfcode)) ? &cf->cinfo : NULL;
976 * Determine whether we need to create a protocol tree.
977 * We do if:
979 * we're going to apply a display filter;
981 * one of the tap listeners is going to apply a filter;
983 * one of the tap listeners requires a protocol tree;
985 * a postdissector wants field values or protocols on
986 * the first pass.
988 create_proto_tree =
989 (cf->dfcode != NULL || have_filtering_tap_listeners() ||
990 (tap_flags & TL_REQUIRES_PROTO_TREE) || postdissectors_want_hfids());
992 if (cf->provider.wth == NULL) {
993 cf_close(cf);
994 return CF_READ_ERROR;
997 /* Don't freeze/thaw the list when doing live capture */
998 /*packet_list_freeze();*/
1000 epan_dissect_init(&edt, cf->epan, create_proto_tree, false);
1002 while ((wtap_read(cf->provider.wth, rec, buf, err, &err_info, &data_offset))) {
1003 if (cf->state == FILE_READ_ABORTED) {
1004 /* Well, the user decided to abort the read. Break out of the
1005 loop, and let the code below (which is called even if there
1006 aren't any packets left to read) exit. */
1007 break;
1009 read_record(cf, rec, buf, cf->dfcode, &edt, cinfo, data_offset, frame_dup_cache, frame_cksum);
1010 wtap_rec_reset(rec);
1013 epan_dissect_cleanup(&edt);
1015 /* Don't freeze/thaw the list when doing live capture */
1016 /*packet_list_thaw();*/
1018 if (cf->state == FILE_READ_ABORTED) {
1019 /* Well, the user decided to abort the read. We're only called
1020 when the child capture process closes the pipe to us (meaning
1021 it's probably exited), so we can just close the capture
1022 file; we return CF_READ_ABORTED so our caller can do whatever
1023 is appropriate when that happens. */
1024 cf_close(cf);
1025 return CF_READ_ABORTED;
1028 /* We're done reading sequentially through the file. */
1029 cf->state = FILE_READ_DONE;
1031 /* We're done reading sequentially through the file; close the
1032 sequential I/O side, to free up memory it requires. */
1033 wtap_sequential_close(cf->provider.wth);
1035 /* Allow the protocol dissectors to free up memory that they
1036 * don't need after the sequential run-through of the packets. */
1037 postseq_cleanup_all_protocols();
1039 /* Update the file encapsulation; it might have changed based on the
1040 packets we've read. */
1041 cf->lnk_t = wtap_file_encap(cf->provider.wth);
1043 /* Update the details in the file-set dialog, as the capture file
1044 * has likely grown since we first stat-ed it */
1045 fileset_update_file(cf->filename);
1047 if (*err != 0) {
1048 /* We got an error reading the capture file.
1049 XXX - pop up a dialog box? */
1050 if (err_info != NULL) {
1051 ws_warning("Error \"%s\" while reading \"%s\" (\"%s\")",
1052 wtap_strerror(*err), cf->filename, err_info);
1053 g_free(err_info);
1054 } else {
1055 ws_warning("Error \"%s\" while reading \"%s\"",
1056 wtap_strerror(*err), cf->filename);
1058 return CF_READ_ERROR;
1059 } else {
1060 return CF_READ_OK;
1063 #endif /* HAVE_LIBPCAP */
1065 char *
1066 cf_get_display_name(capture_file *cf)
1068 char *displayname;
1070 /* Return a name to use in displays */
1071 if (!cf->is_tempfile) {
1072 /* Get the last component of the file name, and use that. */
1073 if (cf->filename) {
1074 displayname = g_filename_display_basename(cf->filename);
1075 } else {
1076 displayname=g_strdup("(No file)");
1078 } else {
1079 /* The file we read is a temporary file from a live capture or
1080 a merge operation; we don't mention its name, but, if it's
1081 from a capture, give the source of the capture. */
1082 if (cf->source) {
1083 displayname = g_strdup(cf->source);
1084 } else {
1085 displayname = g_strdup("(Untitled)");
1088 return displayname;
1091 char *
1092 cf_get_basename(capture_file *cf)
1094 char *displayname;
1096 /* Return a name to use in the GUI for the basename for files to
1097 which we save statistics */
1098 if (!cf->is_tempfile) {
1099 /* Get the last component of the file name, and use that. */
1100 if (cf->filename) {
1101 displayname = g_filename_display_basename(cf->filename);
1103 /* If the file name ends with any extension that corresponds
1104 to a file type we support - including compressed versions
1105 of those files - strip it off. */
1106 size_t displayname_len = strlen(displayname);
1107 GSList *extensions = wtap_get_all_file_extensions_list();
1108 GSList *suffix;
1109 for (suffix = extensions; suffix != NULL; suffix = g_slist_next(suffix)) {
1110 /* Does the file name end with that extension? */
1111 const char *extension = (char *)suffix->data;
1112 size_t extension_len = strlen(extension);
1113 if (displayname_len > extension_len &&
1114 displayname[displayname_len - extension_len - 1] == '.' &&
1115 strcmp(&displayname[displayname_len - extension_len], extension) == 0) {
1116 /* Yes. Strip the extension off, and return the result. */
1117 displayname[displayname_len - extension_len - 1] = '\0';
1118 break;
1121 wtap_free_extensions_list(extensions);
1122 } else {
1123 displayname=g_strdup("");
1125 } else {
1126 /* The file we read is a temporary file from a live capture or
1127 a merge operation; we don't mention its name, but, if it's
1128 from a capture, give the source of the capture. */
1129 if (cf->source) {
1130 displayname = g_strdup(cf->source);
1131 } else {
1132 displayname = g_strdup("");
1135 return displayname;
1138 void
1139 cf_set_tempfile_source(capture_file *cf, char *source)
1141 if (cf->source) {
1142 g_free(cf->source);
1145 if (source) {
1146 cf->source = g_strdup(source);
1147 } else {
1148 cf->source = g_strdup("");
1152 const char *
1153 cf_get_tempfile_source(capture_file *cf)
1155 if (!cf->source) {
1156 return "";
1159 return cf->source;
1162 /* XXX - use a macro instead? */
1164 cf_get_packet_count(capture_file *cf)
1166 return cf->count;
1169 /* XXX - use a macro instead? */
1170 bool
1171 cf_is_tempfile(capture_file *cf)
1173 return cf->is_tempfile;
1176 void
1177 cf_set_tempfile(capture_file *cf, bool is_tempfile)
1179 cf->is_tempfile = is_tempfile;
1183 /* XXX - use a macro instead? */
1184 void
1185 cf_set_drops_known(capture_file *cf, bool drops_known)
1187 cf->drops_known = drops_known;
1190 /* XXX - use a macro instead? */
1191 void
1192 cf_set_drops(capture_file *cf, uint32_t drops)
1194 cf->drops = drops;
1197 /* XXX - use a macro instead? */
1198 bool
1199 cf_get_drops_known(capture_file *cf)
1201 return cf->drops_known;
1204 /* XXX - use a macro instead? */
1205 uint32_t
1206 cf_get_drops(capture_file *cf)
1208 return cf->drops;
1211 void
1212 cf_set_rfcode(capture_file *cf, dfilter_t *rfcode)
1214 cf->rfcode = rfcode;
1217 static void
1218 add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
1219 epan_dissect_t *edt, dfilter_t *dfcode, column_info *cinfo,
1220 wtap_rec *rec, Buffer *buf, bool add_to_packet_list)
1222 frame_data_set_before_dissect(fdata, &cf->elapsed_time,
1223 &cf->provider.ref, cf->provider.prev_dis);
1224 cf->provider.prev_cap = fdata;
1226 if (dfcode != NULL) {
1227 epan_dissect_prime_with_dfilter(edt, dfcode);
1229 #if 0
1230 /* Prepare coloring rules, this ensures that display filter rules containing
1231 * frame.color_rule references are still processed.
1232 * TODO: actually detect that situation or maybe apply other optimizations? */
1233 if (edt->tree && color_filters_used()) {
1234 color_filters_prime_edt(edt);
1235 fdata->need_colorize = 1;
1237 #endif
1239 if (!fdata->visited) {
1240 /* This is the first pass, so prime the epan_dissect_t with the
1241 hfids postdissectors want on the first pass. */
1242 prime_epan_dissect_with_postdissector_wanted_hfids(edt);
1245 /* Initialize passed_dfilter here so that dissectors can hide packets. */
1246 /* XXX We might want to add a separate "visible" bit to frame_data instead. */
1247 fdata->passed_dfilter = 1;
1249 /* Dissect the frame. */
1250 epan_dissect_run_with_taps(edt, cf->cd_t, rec,
1251 frame_tvbuff_new_buffer(&cf->provider, fdata, buf),
1252 fdata, cinfo);
1254 if (fdata->passed_dfilter && dfcode != NULL) {
1255 fdata->passed_dfilter = dfilter_apply_edt(dfcode, edt) ? 1 : 0;
1257 if (fdata->passed_dfilter && edt->pi.fd->dependent_frames) {
1258 /* This frame passed the display filter but it may depend on other
1259 * (potentially not displayed) frames. Find those frames and mark them
1260 * as depended upon.
1262 g_hash_table_foreach(edt->pi.fd->dependent_frames, find_and_mark_frame_depended_upon, cf->provider.frames);
1266 if (fdata->passed_dfilter || fdata->ref_time) {
1267 cf->displayed_count++;
1268 fdata->dis_num = cf->displayed_count;
1271 if (add_to_packet_list) {
1272 /* We fill the needed columns from new_packet_list */
1273 packet_list_append(cinfo, fdata);
1276 if (fdata->passed_dfilter || fdata->ref_time)
1278 frame_data_set_after_dissect(fdata, &cf->cum_bytes);
1279 /* The only way we use prev_dis is to get the time stamp of
1280 * the previous displayed frame, so ignore it if it doesn't
1281 * have a time stamp, because we're presumably interested in
1282 * the timestamp of the previously displayed frame with a
1283 * time. XXX: What if in the future we want to use the previously
1284 * displayed frame for something else, too?
1286 if (fdata->has_ts) {
1287 cf->provider.prev_dis = fdata;
1290 /* If we haven't yet seen the first frame, this is it. */
1291 if (cf->first_displayed == 0)
1292 cf->first_displayed = fdata->num;
1294 /* This is the last frame we've seen so far. */
1295 cf->last_displayed = fdata->num;
1298 epan_dissect_reset(edt);
1302 * Read in a new record.
1303 * Returns true if the packet was added to the packet (record) list,
1304 * false otherwise.
1306 static bool
1307 read_record(capture_file *cf, wtap_rec *rec, Buffer *buf, dfilter_t *dfcode,
1308 epan_dissect_t *edt, column_info *cinfo, int64_t offset,
1309 fifo_string_cache_t *frame_dup_cache, GChecksum *frame_cksum)
1311 frame_data fdlocal;
1312 frame_data *fdata;
1313 bool passed = true;
1314 bool added = false;
1315 const char *cksum_string;
1316 bool was_in_cache;
1318 /* Add this packet's link-layer encapsulation type to cf->linktypes, if
1319 it's not already there.
1320 XXX - yes, this is O(N), so if every packet had a different
1321 link-layer encapsulation type, it'd be O(N^2) to read the file, but
1322 there are probably going to be a small number of encapsulation types
1323 in a file. */
1324 if (rec->rec_type == REC_TYPE_PACKET) {
1325 cf_add_encapsulation_type(cf, rec->rec_header.packet_header.pkt_encap);
1328 /* The frame number of this packet, if we add it to the set of frames,
1329 would be one more than the count of frames in the file so far. */
1330 frame_data_init(&fdlocal, cf->count + 1, rec, offset, cf->cum_bytes);
1332 if (cf->rfcode) {
1333 epan_dissect_t rf_edt;
1334 column_info *rf_cinfo = NULL;
1336 epan_dissect_init(&rf_edt, cf->epan, true, false);
1337 epan_dissect_prime_with_dfilter(&rf_edt, cf->rfcode);
1338 if (dfilter_requires_columns(cf->rfcode)) {
1339 rf_cinfo = &cf->cinfo;
1341 epan_dissect_run(&rf_edt, cf->cd_t, rec,
1342 frame_tvbuff_new_buffer(&cf->provider, &fdlocal, buf),
1343 &fdlocal, rf_cinfo);
1344 passed = dfilter_apply_edt(cf->rfcode, &rf_edt);
1345 epan_dissect_cleanup(&rf_edt);
1348 if (passed) {
1349 added = true;
1351 /* This does a shallow copy of fdlocal, which is good enough. */
1352 fdata = frame_data_sequence_add(cf->provider.frames, &fdlocal);
1354 cf->count++;
1355 if (rec->block != NULL)
1356 cf->packet_comment_count += wtap_block_count_option(rec->block, OPT_COMMENT);
1357 cf->f_datalen = offset + fdlocal.cap_len;
1359 // Should we check if the frame data is a duplicate, and thus, ignore
1360 // this frame?
1361 if (frame_cksum != NULL && rec->rec_type == REC_TYPE_PACKET) {
1362 g_checksum_reset(frame_cksum);
1363 g_checksum_update(frame_cksum, ws_buffer_start_ptr(buf), ws_buffer_length(buf));
1364 cksum_string = g_strdup(g_checksum_get_string(frame_cksum));
1365 was_in_cache = fifo_string_cache_insert(frame_dup_cache, cksum_string);
1366 if (was_in_cache) {
1367 g_free((void *)cksum_string);
1368 fdata->ignored = true;
1369 cf->ignored_count++;
1373 /* When a redissection is in progress (or queued), do not process packets.
1374 * This will be done once all (new) packets have been scanned. */
1375 if (!cf->redissecting && cf->redissection_queued == RESCAN_NONE) {
1376 add_packet_to_packet_list(fdata, cf, edt, dfcode, cinfo, rec, buf, true);
1380 return added;
1384 typedef struct _callback_data_t {
1385 void * pd_window;
1386 int64_t f_len;
1387 progdlg_t *progbar;
1388 GTimer *prog_timer;
1389 bool stop_flag;
1390 } callback_data_t;
1393 static bool
1394 merge_callback(merge_event event, int num _U_,
1395 const merge_in_file_t in_files[], const unsigned in_file_count,
1396 void *data)
1398 unsigned i;
1399 callback_data_t *cb_data = (callback_data_t*) data;
1401 ws_assert(cb_data != NULL);
1403 switch (event) {
1405 case MERGE_EVENT_INPUT_FILES_OPENED:
1406 /* do nothing */
1407 break;
1409 case MERGE_EVENT_FRAME_TYPE_SELECTED:
1410 /* do nothing */
1411 break;
1413 case MERGE_EVENT_READY_TO_MERGE:
1414 /* Get the sum of the sizes of all the files. */
1415 for (i = 0; i < in_file_count; i++)
1416 cb_data->f_len += in_files[i].size;
1418 cb_data->prog_timer = g_timer_new();
1419 g_timer_start(cb_data->prog_timer);
1420 break;
1422 case MERGE_EVENT_RECORD_WAS_READ:
1424 /* Create the progress bar if necessary.
1425 We check on every iteration of the loop, so that it takes no
1426 longer than the standard time to create it (otherwise, for a
1427 large file, we might take considerably longer than that standard
1428 time in order to get to the next progress bar step). */
1429 if (cb_data->progbar == NULL) {
1430 cb_data->progbar = delayed_create_progress_dlg(cb_data->pd_window, NULL, NULL,
1431 false, &cb_data->stop_flag, 0.0f);
1435 * Update the progress bar, but do it only after
1436 * PROGBAR_UPDATE_INTERVAL has elapsed. Calling update_progress_dlg
1437 * and packets_bar_update will likely trigger UI paint events, which
1438 * might take a while depending on the platform and display. Reset
1439 * our timer *after* painting.
1441 if (g_timer_elapsed(cb_data->prog_timer, NULL) > PROGBAR_UPDATE_INTERVAL) {
1442 float progbar_val;
1443 int64_t file_pos = 0;
1444 /* Get the sum of the seek positions in all of the files. */
1445 for (i = 0; i < in_file_count; i++)
1446 file_pos += wtap_read_so_far(in_files[i].wth);
1448 progbar_val = (float) file_pos / (float) cb_data->f_len;
1449 if (progbar_val > 1.0f) {
1450 /* Some file probably grew while we were reading it.
1451 That "shouldn't happen", so we'll just clip the progress
1452 value at 1.0. */
1453 progbar_val = 1.0f;
1456 if (cb_data->progbar != NULL) {
1457 char status_str[100];
1458 snprintf(status_str, sizeof(status_str),
1459 "%" PRId64 "KB of %" PRId64 "KB",
1460 file_pos / 1024, cb_data->f_len / 1024);
1461 update_progress_dlg(cb_data->progbar, progbar_val, status_str);
1463 g_timer_start(cb_data->prog_timer);
1466 break;
1468 case MERGE_EVENT_DONE:
1469 /* We're done merging the files; destroy the progress bar if it was created. */
1470 if (cb_data->progbar != NULL)
1471 destroy_progress_dlg(cb_data->progbar);
1472 g_timer_destroy(cb_data->prog_timer);
1473 break;
1476 return cb_data->stop_flag;
1481 cf_status_t
1482 cf_merge_files_to_tempfile(void *pd_window, const char *temp_dir, char **out_filenamep,
1483 int in_file_count, const char *const *in_filenames,
1484 int file_type, bool do_append)
1486 bool status;
1487 merge_progress_callback_t cb;
1488 callback_data_t *cb_data = g_new0(callback_data_t, 1);
1490 /* prepare our callback routine */
1491 cb_data->pd_window = pd_window;
1492 cb.callback_func = merge_callback;
1493 cb.data = cb_data;
1495 cf_callback_invoke(cf_cb_file_merge_started, NULL);
1497 /* merge the files */
1498 status = merge_files_to_tempfile(temp_dir, out_filenamep, "wireshark", file_type,
1499 in_filenames,
1500 in_file_count, do_append,
1501 IDB_MERGE_MODE_ALL_SAME, 0 /* snaplen */,
1502 "Wireshark", &cb);
1504 g_free(cb.data);
1506 cf_callback_invoke(cf_cb_file_merge_finished, NULL);
1508 if (!status) {
1509 /* Callers aren't expected to treat an error or an explicit abort
1510 differently - the merge code puts up error dialogs itself, so
1511 they don't have to. */
1512 return CF_ERROR;
1513 } else
1514 return CF_OK;
1517 cf_status_t
1518 cf_filter_packets(capture_file *cf, char *dftext, bool force)
1520 const char *filter_new = dftext ? dftext : "";
1521 const char *filter_old = cf->dfilter ? cf->dfilter : "";
1522 dfilter_t *dfcode;
1523 df_error_t *df_err;
1525 /* if new filter equals old one, do nothing unless told to do so */
1526 /* XXX - The text can be the same without compiling to the same code.
1527 * (Macros, field references, etc.)
1529 if (!force && strcmp(filter_new, filter_old) == 0) {
1530 return CF_OK;
1533 dfcode=NULL;
1535 if (dftext == NULL) {
1536 /* The new filter is an empty filter (i.e., display all packets).
1537 * so leave dfcode==NULL
1539 } else {
1541 * We have a filter; make a copy of it (as we'll be saving it),
1542 * and try to compile it.
1544 dftext = g_strdup(dftext);
1545 if (!dfilter_compile(dftext, &dfcode, &df_err)) {
1546 /* The attempt failed; report an error. */
1547 simple_message_box(ESD_TYPE_ERROR, NULL,
1548 "See the help for a description of the display filter syntax.",
1549 "\"%s\" isn't a valid display filter: %s",
1550 dftext, df_err->msg);
1551 df_error_free(&df_err);
1552 g_free(dftext);
1553 return CF_ERROR;
1556 /* Was it empty? */
1557 if (dfcode == NULL) {
1558 /* Yes - free the filter text, and set it to null. */
1559 g_free(dftext);
1560 dftext = NULL;
1564 /* We have a valid filter. Replace the current filter. */
1565 g_free(cf->dfilter);
1566 cf->dfilter = dftext;
1568 /* We'll recompile this when the rescan starts, or in cf_read()
1569 * if no file is open currently. However, if no file is open and
1570 * we start a new capture, we want to use this rather than
1571 * recompiling in cf_continue_tail() */
1572 dfilter_free(cf->dfcode);
1573 cf->dfcode = dfcode;
1575 /* Now rescan the packet list, applying the new filter, but not
1576 * throwing away information constructed on a previous pass.
1577 * If a dissection is already in progress, queue it.
1579 if (cf->redissection_queued == RESCAN_NONE) {
1580 if (cf->read_lock) {
1581 cf->redissection_queued = RESCAN_SCAN;
1582 } else if (cf->state != FILE_CLOSED) {
1583 if (dftext == NULL) {
1584 rescan_packets(cf, "Resetting", "filter", false);
1585 } else {
1586 rescan_packets(cf, "Filtering", dftext, false);
1591 return CF_OK;
1594 void
1595 cf_redissect_packets(capture_file *cf)
1597 if (cf->read_lock || cf->redissection_queued == RESCAN_SCAN) {
1598 /* Dissection in progress, signal redissection rather than rescanning. That
1599 * would destroy the current (in-progress) dissection in "cf_read" which
1600 * will cause issues when "cf_read" tries to add packets to the list.
1601 * If a previous rescan was requested, "upgrade" it to a full redissection.
1603 cf->redissection_queued = RESCAN_REDISSECT;
1605 if (cf->redissection_queued != RESCAN_NONE) {
1606 /* Redissection is (already) queued, wait for "cf_read" to finish. */
1607 /* XXX - what if whatever set and later clears read_lock is *not*
1608 * cf_read, e.g. process_specified_records ? We need to handle a
1609 * queued redissection there too like we do in cf_read.
1611 return;
1614 if (cf->state != FILE_CLOSED) {
1615 /* Restart dissection in case no cf_read is pending. */
1616 rescan_packets(cf, "Reprocessing", "all packets", true);
1620 bool
1621 cf_read_record(capture_file *cf, const frame_data *fdata,
1622 wtap_rec *rec, Buffer *buf)
1624 int err;
1625 char *err_info;
1627 if (!wtap_seek_read(cf->provider.wth, fdata->file_off, rec, buf, &err, &err_info)) {
1628 report_cfile_read_failure(cf->filename, err, err_info);
1629 return false;
1631 return true;
1634 bool
1635 cf_read_record_no_alert(capture_file *cf, const frame_data *fdata,
1636 wtap_rec *rec, Buffer *buf)
1638 int err;
1639 char *err_info;
1641 if (!wtap_seek_read(cf->provider.wth, fdata->file_off, rec, buf, &err, &err_info)) {
1642 g_free(err_info);
1643 return false;
1645 return true;
1648 bool
1649 cf_read_current_record(capture_file *cf)
1651 return cf_read_record(cf, cf->current_frame, &cf->rec, &cf->buf);
1654 /* Rescan the list of packets, reconstructing the CList.
1656 "action" describes why we're doing this; it's used in the progress
1657 dialog box.
1659 "action_item" describes what we're doing; it's used in the progress
1660 dialog box.
1662 "redissect" is true if we need to make the dissectors reconstruct
1663 any state information they have (because a preference that affects
1664 some dissector has changed, meaning some dissector might construct
1665 its state differently from the way it was constructed the last time). */
1666 static void
1667 rescan_packets(capture_file *cf, const char *action, const char *action_item, bool redissect)
1669 /* Rescan packets new packet list */
1670 uint32_t framenum;
1671 frame_data *fdata;
1672 wtap_rec rec;
1673 Buffer buf;
1674 progdlg_t *progbar = NULL;
1675 GTimer *prog_timer = g_timer_new();
1676 int count;
1677 frame_data *selected_frame, *preceding_frame, *following_frame, *prev_frame;
1678 int selected_frame_num, preceding_frame_num, following_frame_num, prev_frame_num;
1679 bool selected_frame_seen;
1680 float progbar_val;
1681 int64_t start_time;
1682 char status_str[100];
1683 epan_dissect_t edt;
1684 dfilter_t *dfcode = NULL;
1685 column_info *cinfo;
1686 bool create_proto_tree;
1687 bool filtering_tap_listeners = false;
1688 unsigned tap_flags;
1689 bool add_to_packet_list = false;
1690 bool compiled _U_;
1691 uint32_t frames_count;
1692 rescan_type queued_rescan_type = RESCAN_NONE;
1694 if (cf->state == FILE_CLOSED || cf->state == FILE_READ_PENDING) {
1695 return;
1698 /* Rescan in progress, clear pending actions. */
1699 cf->redissection_queued = RESCAN_NONE;
1700 ws_assert(!cf->read_lock);
1701 cf->read_lock = true;
1703 wtap_rec_init(&rec);
1704 ws_buffer_init(&buf, 1514);
1706 /* Compile the current display filter.
1707 * The code it compiles to might have changed, e.g. if a display
1708 * filter macro used has changed.
1710 * We assume this will not fail since cf->dfilter is only set in
1711 * cf_filter IFF the filter was valid.
1712 * XXX - This is not necessarily true, if the filter has a FT_IPv4
1713 * or FT_IPv6 field compared to a resolved hostname in it, because
1714 * we do a new host lookup, and that *could* timeout this time
1715 * (though with the read lock above we shouldn't have many lookups at
1716 * once, reducing the chances of that)... (#19612)
1718 if (cf->dfilter) {
1719 compiled = dfilter_compile(cf->dfilter, &dfcode, NULL);
1720 ws_assert(compiled && dfcode);
1723 dfilter_free(cf->dfcode);
1724 cf->dfcode = dfcode;
1726 /* Do we have any tap listeners with filters? */
1727 filtering_tap_listeners = have_filtering_tap_listeners();
1729 /* Update references in filters (if any) for the protocol
1730 * tree corresponding to the currently selected frame in the GUI. */
1731 if (cf->edt != NULL && cf->edt->tree != NULL) {
1732 if (cf->dfcode)
1733 dfilter_load_field_references(cf->dfcode, cf->edt->tree);
1734 if (filtering_tap_listeners)
1735 tap_listeners_load_field_references(cf->edt);
1738 if (cf->dfcode != NULL) {
1739 dfilter_log_full(LOG_DOMAIN_DFILTER, LOG_LEVEL_NOISY, NULL, -1, NULL,
1740 cf->dfcode, "Rescanning packets with display filter");
1743 /* Get the union of the flags for all tap listeners. */
1744 tap_flags = union_of_tap_listener_flags();
1746 /* If the display filter or any tap listeners require the columns,
1747 * construct them. */
1748 cinfo = (tap_listeners_require_columns() ||
1749 dfilter_requires_columns(cf->dfcode)) ? &cf->cinfo : NULL;
1752 * Determine whether we need to create a protocol tree.
1753 * We do if:
1755 * we're going to apply a display filter;
1757 * one of the tap listeners is going to apply a filter;
1759 * one of the tap listeners requires a protocol tree;
1761 * we're redissecting and a postdissector wants field
1762 * values or protocols on the first pass.
1764 create_proto_tree =
1765 (cf->dfcode != NULL || filtering_tap_listeners ||
1766 (tap_flags & TL_REQUIRES_PROTO_TREE) ||
1767 (redissect && postdissectors_want_hfids()));
1769 reset_tap_listeners();
1770 /* Which frame, if any, is the currently selected frame?
1771 XXX - should the selected frame or the focus frame be the "current"
1772 frame, that frame being the one from which "Find Frame" searches
1773 start? */
1774 selected_frame = cf->current_frame;
1776 /* Mark frame num as not found */
1777 selected_frame_num = -1;
1779 /* Freeze the packet list while we redo it, so we don't get any
1780 screen updates while it happens. */
1781 packet_list_freeze();
1783 if (redissect) {
1784 /* We need to re-initialize all the state information that protocols
1785 keep, because some preference that controls a dissector has changed,
1786 which might cause the state information to be constructed differently
1787 by that dissector. */
1789 /* We might receive new packets while redissecting, and we don't
1790 want to dissect those before their time. */
1791 cf->redissecting = true;
1793 /* 'reset' dissection session */
1794 epan_free(cf->epan);
1795 if (cf->edt && cf->edt->pi.fd) {
1796 /* All pointers in "per frame proto data" for the currently selected
1797 packet are allocated in wmem_file_scope() and deallocated in epan_free().
1798 Free them here to avoid unintended usage in packet_list_clear(). */
1799 frame_data_destroy(cf->edt->pi.fd);
1801 cf->epan = ws_epan_new(cf);
1802 cf->cinfo.epan = cf->epan;
1804 /* A new Lua tap listener may be registered in lua_prime_all_fields()
1805 called via epan_new() / init_dissection() when reloading Lua plugins. */
1806 if (!create_proto_tree && have_filtering_tap_listeners()) {
1807 create_proto_tree = true;
1809 if (!cinfo && tap_listeners_require_columns()) {
1810 cinfo = &cf->cinfo;
1813 /* We need to redissect the packets so we have to discard our old
1814 * packet list store. */
1815 packet_list_clear();
1816 add_to_packet_list = true;
1819 /* We don't yet know which will be the first and last frames displayed. */
1820 cf->first_displayed = 0;
1821 cf->last_displayed = 0;
1823 /* We currently don't display any packets */
1824 cf->displayed_count = 0;
1826 /* Iterate through the list of frames. Call a routine for each frame
1827 to check whether it should be displayed and, if so, add it to
1828 the display list. */
1829 cf->provider.ref = NULL;
1830 cf->provider.prev_dis = NULL;
1831 cf->provider.prev_cap = NULL;
1832 cf->cum_bytes = 0;
1834 cf_callback_invoke(cf_cb_file_rescan_started, cf);
1836 g_timer_start(prog_timer);
1837 /* Count of packets at which we've looked. */
1838 count = 0;
1839 /* Progress so far. */
1840 progbar_val = 0.0f;
1842 cf->stop_flag = false;
1843 start_time = g_get_monotonic_time();
1845 /* no previous row yet */
1846 prev_frame_num = -1;
1847 prev_frame = NULL;
1849 preceding_frame_num = -1;
1850 preceding_frame = NULL;
1851 following_frame_num = -1;
1852 following_frame = NULL;
1854 selected_frame_seen = false;
1856 frames_count = cf->count;
1858 epan_dissect_init(&edt, cf->epan, create_proto_tree, false);
1860 if (redissect) {
1862 * Decryption secrets and name resolution blocks are read while
1863 * sequentially processing records and then passed to the dissector.
1864 * During redissection, the previous information is lost (see epan_free
1865 * above), but they are not read again from the file as only packet
1866 * records are re-read. Therefore reset the wtap secrets and name
1867 * resolution callbacks such that wtap resupplies the callbacks with
1868 * previously read information.
1870 wtap_set_cb_new_ipv4(cf->provider.wth, add_ipv4_name);
1871 wtap_set_cb_new_ipv6(cf->provider.wth, (wtap_new_ipv6_callback_t) add_ipv6_name);
1872 wtap_set_cb_new_secrets(cf->provider.wth, secrets_wtap_callback);
1875 for (framenum = 1; framenum <= frames_count; framenum++) {
1876 fdata = frame_data_sequence_find(cf->provider.frames, framenum);
1878 /* Create the progress bar if necessary.
1879 We check on every iteration of the loop, so that it takes no
1880 longer than the standard time to create it (otherwise, for a
1881 large file, we might take considerably longer than that standard
1882 time in order to get to the next progress bar step). */
1883 if (progbar == NULL)
1884 progbar = delayed_create_progress_dlg(cf->window, action, action_item, true,
1885 &cf->stop_flag,
1886 progbar_val);
1889 * Update the progress bar, but do it only after PROGBAR_UPDATE_INTERVAL
1890 * has elapsed. Calling update_progress_dlg and packets_bar_update will
1891 * likely trigger UI paint events, which might take a while depending on
1892 * the platform and display. Reset our timer *after* painting.
1894 if (g_timer_elapsed(prog_timer, NULL) > PROGBAR_UPDATE_INTERVAL) {
1895 /* let's not divide by zero. I should never be started
1896 * with count == 0, so let's assert that
1898 ws_assert(cf->count > 0);
1899 progbar_val = (float) count / frames_count;
1901 if (progbar != NULL) {
1902 snprintf(status_str, sizeof(status_str),
1903 "%4u of %u frames", count, frames_count);
1904 update_progress_dlg(progbar, progbar_val, status_str);
1907 g_timer_start(prog_timer);
1910 queued_rescan_type = cf->redissection_queued;
1911 if (queued_rescan_type != RESCAN_NONE) {
1912 /* A redissection was requested while an existing redissection was
1913 * pending. */
1914 break;
1917 if (cf->stop_flag) {
1918 /* Well, the user decided to abort the filtering. Just stop.
1920 XXX - go back to the previous filter? Users probably just
1921 want not to wait for a filtering operation to finish;
1922 unless we cancel by having no filter, reverting to the
1923 previous filter will probably be even more expensive than
1924 continuing the filtering, as it involves going back to the
1925 beginning and filtering, and even with no filter we currently
1926 have to re-generate the entire clist, which is also expensive.
1928 I'm not sure what Network Monitor does, but it doesn't appear
1929 to give you an unfiltered display if you cancel. */
1930 break;
1933 count++;
1935 if (redissect) {
1936 /* Since all state for the frame was destroyed, mark the frame
1937 * as not visited, free the GSList referring to the state
1938 * data (the per-frame data itself was freed by
1939 * "init_dissection()"), and null out the GSList pointer. */
1940 frame_data_reset(fdata);
1941 frames_count = cf->count;
1944 /* Frame dependencies from the previous dissection/filtering are no longer valid. */
1945 fdata->dependent_of_displayed = 0;
1947 if (!cf_read_record(cf, fdata, &rec, &buf))
1948 break; /* error reading the frame */
1950 /* If the previous frame is displayed, and we haven't yet seen the
1951 selected frame, remember that frame - it's the closest one we've
1952 yet seen before the selected frame. */
1953 if (prev_frame_num != -1 && !selected_frame_seen && prev_frame->passed_dfilter) {
1954 preceding_frame_num = prev_frame_num;
1955 preceding_frame = prev_frame;
1958 add_packet_to_packet_list(fdata, cf, &edt, cf->dfcode,
1959 cinfo, &rec, &buf,
1960 add_to_packet_list);
1962 /* If this frame is displayed, and this is the first frame we've
1963 seen displayed after the selected frame, remember this frame -
1964 it's the closest one we've yet seen at or after the selected
1965 frame. */
1966 if (fdata->passed_dfilter && selected_frame_seen && following_frame_num == -1) {
1967 following_frame_num = fdata->num;
1968 following_frame = fdata;
1970 if (fdata == selected_frame) {
1971 selected_frame_seen = true;
1972 if (fdata->passed_dfilter)
1973 selected_frame_num = fdata->num;
1976 /* Remember this frame - it'll be the previous frame
1977 on the next pass through the loop. */
1978 prev_frame_num = fdata->num;
1979 prev_frame = fdata;
1980 wtap_rec_reset(&rec);
1983 epan_dissect_cleanup(&edt);
1984 wtap_rec_cleanup(&rec);
1985 ws_buffer_free(&buf);
1987 /* We are done redissecting the packet list. */
1988 cf->redissecting = false;
1990 if (redissect) {
1991 frames_count = cf->count;
1992 /* Clear out what remains of the visited flags and per-frame data
1993 pointers.
1995 XXX - that may cause various forms of bogosity when dissecting
1996 these frames, as they won't have been seen by this sequential
1997 pass, but the only alternative I see is to keep scanning them
1998 even though the user requested that the scan stop, and that
1999 would leave the user stuck with an Wireshark grinding on
2000 until it finishes. Should we just stick them with that? */
2001 for (; framenum <= frames_count; framenum++) {
2002 fdata = frame_data_sequence_find(cf->provider.frames, framenum);
2003 frame_data_reset(fdata);
2007 /* We're done filtering the packets; destroy the progress bar if it
2008 was created. */
2009 if (progbar != NULL)
2010 destroy_progress_dlg(progbar);
2011 g_timer_destroy(prog_timer);
2013 /* Unfreeze the packet list. */
2014 if (!add_to_packet_list)
2015 packet_list_recreate_visible_rows();
2017 /* Compute the time it took to filter the file */
2018 compute_elapsed(cf, start_time);
2020 packet_list_thaw();
2022 /* It is safe again to execute redissections or sort. */
2023 ws_assert(cf->read_lock);
2024 cf->read_lock = false;
2026 cf_callback_invoke(cf_cb_file_rescan_finished, cf);
2028 if (selected_frame_num == -1) {
2029 /* The selected frame didn't pass the filter. */
2030 if (selected_frame == NULL) {
2031 /* That's because there *was* no selected frame. Make the first
2032 displayed frame the current frame. */
2033 selected_frame_num = 0;
2034 } else {
2035 /* Find the nearest displayed frame to the selected frame (whether
2036 it's before or after that frame) and make that the current frame.
2037 If the next and previous displayed frames are equidistant from the
2038 selected frame, choose the next one. */
2039 ws_assert(following_frame == NULL ||
2040 following_frame->num >= selected_frame->num);
2041 ws_assert(preceding_frame == NULL ||
2042 preceding_frame->num <= selected_frame->num);
2043 if (following_frame == NULL) {
2044 /* No frame after the selected frame passed the filter, so we
2045 have to select the last displayed frame before the selected
2046 frame. */
2047 selected_frame_num = preceding_frame_num;
2048 selected_frame = preceding_frame;
2049 } else if (preceding_frame == NULL) {
2050 /* No frame before the selected frame passed the filter, so we
2051 have to select the first displayed frame after the selected
2052 frame. */
2053 selected_frame_num = following_frame_num;
2054 selected_frame = following_frame;
2055 } else {
2056 /* Frames before and after the selected frame passed the filter, so
2057 we'll select the previous frame */
2058 selected_frame_num = preceding_frame_num;
2059 selected_frame = preceding_frame;
2064 if (selected_frame_num == -1) {
2065 /* There are no frames displayed at all. */
2066 cf_unselect_packet(cf);
2067 } else {
2068 /* Either the frame that was selected passed the filter, or we've
2069 found the nearest displayed frame to that frame. Select it, make
2070 it the focus row, and make it visible. */
2071 /* Set to invalid to force update of packet list and packet details */
2072 if (selected_frame_num == 0) {
2073 packet_list_select_row_from_data(NULL);
2074 }else{
2075 if (!packet_list_select_row_from_data(selected_frame)) {
2076 /* We didn't find a row corresponding to this frame.
2077 This means that the frame isn't being displayed currently,
2078 so we can't select it. */
2079 simple_message_box(ESD_TYPE_INFO, NULL,
2080 "The capture file is probably not fully dissected.",
2081 "End of capture exceeded.");
2086 /* If another rescan (due to dfilter change) or redissection (due to profile
2087 * change) was requested, the rescan above is aborted and restarted here. */
2088 if (queued_rescan_type != RESCAN_NONE) {
2089 redissect = redissect || queued_rescan_type == RESCAN_REDISSECT;
2090 rescan_packets(cf, "Reprocessing", "all packets", redissect);
2096 * Scan through all frame data and recalculate the ref time
2097 * without rereading the file.
2098 * XXX - do we need a progress bar or is this fast enough?
2100 void
2101 cf_reftime_packets(capture_file* cf)
2103 uint32_t framenum;
2104 frame_data *fdata;
2105 nstime_t rel_ts;
2107 cf->provider.ref = NULL;
2108 cf->provider.prev_dis = NULL;
2109 cf->cum_bytes = 0;
2111 for (framenum = 1; framenum <= cf->count; framenum++) {
2112 fdata = frame_data_sequence_find(cf->provider.frames, framenum);
2114 /* just add some value here until we know if it is being displayed or not */
2115 fdata->cum_bytes = cf->cum_bytes + fdata->pkt_len;
2118 * Timestamps
2121 if (fdata->has_ts) {
2122 /* If we don't have the time stamp of the first packet in the
2123 capture, it's because this is the first packet. Save the time
2124 stamp of this packet as the time stamp of the first packet. */
2125 if (cf->provider.ref == NULL)
2126 cf->provider.ref = fdata;
2127 /* if this frames is marked as a reference time frame, reset
2128 firstsec and firstusec to this frame */
2129 if (fdata->ref_time)
2130 cf->provider.ref = fdata;
2132 /* Get the time elapsed between the first packet and this one. */
2133 fdata->frame_ref_num = (fdata != cf->provider.ref) ? cf->provider.ref->num : 0;
2134 nstime_delta(&rel_ts, &fdata->abs_ts, &cf->provider.ref->abs_ts);
2136 /* If it's greater than the current elapsed time, set the elapsed
2137 time to it (we check for "greater than" so as not to be
2138 confused by time moving backwards). */
2139 if ((int32_t)cf->elapsed_time.secs < rel_ts.secs
2140 || ((int32_t)cf->elapsed_time.secs == rel_ts.secs && (int32_t)cf->elapsed_time.nsecs < rel_ts.nsecs)) {
2141 cf->elapsed_time = rel_ts;
2144 /* If this frame is displayed, get the time elapsed between the
2145 previous displayed packet and this packet. */
2146 /* XXX: What if in the future we want to use the previously
2147 * displayed frame for something else, too? Then we'd want
2148 * to store this frame as prev_dis even if it doesn't have a
2149 * timestamp. */
2150 if ( fdata->passed_dfilter ) {
2151 /* If we don't have the time stamp of the previous displayed
2152 packet, it's because this is the first displayed packet.
2153 Save the time stamp of this packet as the time stamp of
2154 the previous displayed packet. */
2155 if (cf->provider.prev_dis == NULL) {
2156 cf->provider.prev_dis = fdata;
2159 fdata->prev_dis_num = cf->provider.prev_dis->num;
2160 cf->provider.prev_dis = fdata;
2162 } else {
2163 /* If this frame doesn't have a timestamp, don't calculate
2164 anything with relative times. */
2165 /* However, if this frame is marked as a reference time frame,
2166 clear the reference frame so that the next frame with a
2167 timestamp becomes the reference frame. */
2168 if (fdata->ref_time) {
2169 cf->provider.ref = NULL;
2174 * Byte counts
2176 if ( (fdata->passed_dfilter) || (fdata->ref_time) ) {
2177 /* This frame either passed the display filter list or is marked as
2178 a time reference frame. All time reference frames are displayed
2179 even if they don't pass the display filter */
2180 if (fdata->ref_time) {
2181 /* if this was a TIME REF frame we should reset the cum_bytes field */
2182 cf->cum_bytes = fdata->pkt_len;
2183 fdata->cum_bytes = cf->cum_bytes;
2184 } else {
2185 /* increase cum_bytes with this packets length */
2186 cf->cum_bytes += fdata->pkt_len;
2192 typedef enum {
2193 PSP_FINISHED,
2194 PSP_STOPPED,
2195 PSP_FAILED
2196 } psp_return_t;
2198 static psp_return_t
2199 process_specified_records(capture_file *cf, packet_range_t *range,
2200 const char *string1, const char *string2, bool terminate_is_stop,
2201 bool (*callback)(capture_file *, frame_data *,
2202 wtap_rec *, Buffer *, void *),
2203 void *callback_args,
2204 bool show_progress_bar)
2206 uint32_t framenum;
2207 frame_data *fdata;
2208 wtap_rec rec;
2209 Buffer buf;
2210 psp_return_t ret = PSP_FINISHED;
2212 progdlg_t *progbar = NULL;
2213 GTimer *prog_timer = g_timer_new();
2214 int progbar_count;
2215 float progbar_val;
2216 char progbar_status_str[100];
2217 range_process_e process_this;
2219 wtap_rec_init(&rec);
2220 ws_buffer_init(&buf, 1514);
2222 g_timer_start(prog_timer);
2223 /* Count of packets at which we've looked. */
2224 progbar_count = 0;
2225 /* Progress so far. */
2226 progbar_val = 0.0f;
2228 /* XXX - It should be ok to have multiple readers, so long as nothing
2229 * frees the epan context, e.g. rescan_packets with redissect true,
2230 * or anything that closes the file (including reload and certain forms
2231 * of saving.) This is mostly to stop cf_save_records but should probably
2232 * be handled by callers in order to allow multiple readers (e.g.,
2233 * restarting taps after adding or changing one.) We should probably
2234 * make this a real reader-writer lock.
2236 if (cf->read_lock) {
2237 ws_warning("Failing due to nested process_specified_records(\"%s\") call!", cf->filename);
2238 return PSP_FAILED;
2240 cf->read_lock = true;
2242 cf->stop_flag = false;
2244 if (range != NULL)
2245 packet_range_process_init(range);
2247 /* Iterate through all the packets, printing the packets that
2248 were selected by the current display filter. */
2249 for (framenum = 1; framenum <= cf->count; framenum++) {
2250 fdata = frame_data_sequence_find(cf->provider.frames, framenum);
2252 /* Create the progress bar if necessary.
2253 We check on every iteration of the loop, so that it takes no
2254 longer than the standard time to create it (otherwise, for a
2255 large file, we might take considerably longer than that standard
2256 time in order to get to the next progress bar step). */
2257 if (show_progress_bar && progbar == NULL)
2258 progbar = delayed_create_progress_dlg(cf->window, string1, string2,
2259 terminate_is_stop,
2260 &cf->stop_flag,
2261 progbar_val);
2264 * Update the progress bar, but do it only after PROGBAR_UPDATE_INTERVAL
2265 * has elapsed. Calling update_progress_dlg and packets_bar_update will
2266 * likely trigger UI paint events, which might take a while depending on
2267 * the platform and display. Reset our timer *after* painting.
2269 if (progbar && g_timer_elapsed(prog_timer, NULL) > PROGBAR_UPDATE_INTERVAL) {
2270 /* let's not divide by zero. I should never be started
2271 * with count == 0, so let's assert that
2273 ws_assert(cf->count > 0);
2274 progbar_val = (float) progbar_count / cf->count;
2276 snprintf(progbar_status_str, sizeof(progbar_status_str),
2277 "%4u of %u packets", progbar_count, cf->count);
2278 update_progress_dlg(progbar, progbar_val, progbar_status_str);
2280 g_timer_start(prog_timer);
2283 if (cf->stop_flag) {
2284 /* Well, the user decided to abort the operation. Just stop,
2285 and arrange to return PSP_STOPPED to our caller, so they know
2286 it was stopped explicitly. */
2287 ret = PSP_STOPPED;
2288 break;
2291 progbar_count++;
2293 if (range != NULL) {
2294 /* do we have to process this packet? */
2295 process_this = packet_range_process_packet(range, fdata);
2296 if (process_this == range_process_next) {
2297 /* this packet uninteresting, continue with next one */
2298 continue;
2299 } else if (process_this == range_processing_finished) {
2300 /* all interesting packets processed, stop the loop */
2301 break;
2305 /* Get the packet */
2306 if (!cf_read_record(cf, fdata, &rec, &buf)) {
2307 /* Attempt to get the packet failed. */
2308 ret = PSP_FAILED;
2309 break;
2311 /* Process the packet */
2312 if (!callback(cf, fdata, &rec, &buf, callback_args)) {
2313 /* Callback failed. We assume it reported the error appropriately. */
2314 ret = PSP_FAILED;
2315 break;
2317 wtap_rec_reset(&rec);
2320 /* We're done printing the packets; destroy the progress bar if
2321 it was created. */
2322 if (progbar != NULL)
2323 destroy_progress_dlg(progbar);
2324 g_timer_destroy(prog_timer);
2326 ws_assert(cf->read_lock);
2327 cf->read_lock = false;
2329 wtap_rec_cleanup(&rec);
2330 ws_buffer_free(&buf);
2332 return ret;
2335 typedef struct {
2336 epan_dissect_t edt;
2337 column_info *cinfo;
2338 } retap_callback_args_t;
2340 static bool
2341 retap_packet(capture_file *cf, frame_data *fdata, wtap_rec *rec, Buffer *buf,
2342 void *argsp)
2344 retap_callback_args_t *args = (retap_callback_args_t *)argsp;
2346 epan_dissect_run_with_taps(&args->edt, cf->cd_t, rec,
2347 frame_tvbuff_new_buffer(&cf->provider, fdata, buf),
2348 fdata, args->cinfo);
2349 epan_dissect_reset(&args->edt);
2351 return true;
2354 cf_read_status_t
2355 cf_retap_packets(capture_file *cf)
2357 packet_range_t range;
2358 retap_callback_args_t callback_args;
2359 bool create_proto_tree;
2360 bool filtering_tap_listeners;
2361 unsigned tap_flags;
2362 psp_return_t ret;
2364 /* Presumably the user closed the capture file. */
2365 if (cf == NULL) {
2366 return CF_READ_ABORTED;
2369 /* XXX - If cf->read_lock is true, process_specified_records will fail
2370 * due to a nested call. We fail here so that we don't reset the tap
2371 * listeners if this tap isn't going to succeed.
2373 if (cf->read_lock) {
2374 ws_warning("Failing due to nested process_specified_records(\"%s\") call!", cf->filename);
2375 return CF_READ_ERROR;
2378 cf_callback_invoke(cf_cb_file_retap_started, cf);
2380 /* Do we have any tap listeners with filters? */
2381 filtering_tap_listeners = have_filtering_tap_listeners();
2383 /* Update references in filters (if any) for the protocol
2384 * tree corresponding to the currently selected frame in the GUI. */
2385 /* XXX - What if we *don't* have a currently selected frame in the GUI,
2386 * but we did the last time we loaded field references? Then they'll
2387 * match something instead of nothing (unless they've been recompiled).
2388 * Should we have a way to clear the field references even with a NULL tree?
2390 if (cf->edt != NULL && cf->edt->tree != NULL) {
2391 if (filtering_tap_listeners)
2392 tap_listeners_load_field_references(cf->edt);
2395 /* Get the union of the flags for all tap listeners. */
2396 tap_flags = union_of_tap_listener_flags();
2398 /* If any tap listeners require the columns, construct them. */
2399 callback_args.cinfo = (tap_listeners_require_columns()) ? &cf->cinfo : NULL;
2402 * Determine whether we need to create a protocol tree.
2403 * We do if:
2405 * one of the tap listeners is going to apply a filter;
2407 * one of the tap listeners requires a protocol tree.
2409 create_proto_tree =
2410 (filtering_tap_listeners || (tap_flags & TL_REQUIRES_PROTO_TREE));
2412 /* Reset the tap listeners. */
2413 reset_tap_listeners();
2414 uint32_t count = cf->count;
2416 epan_dissect_init(&callback_args.edt, cf->epan, create_proto_tree, false);
2418 /* Iterate through the list of packets, dissecting all packets and
2419 re-running the taps. */
2420 packet_range_init(&range, cf);
2421 packet_range_process_init(&range);
2423 if (cf->state == FILE_READ_IN_PROGRESS) {
2424 /* We're not done with the sequential read of the file and might
2425 * add more frames while process_specified_records is going. We
2426 * don't want to tap new frames twice, so limit the range to the
2427 * frames already here.
2429 * cf_read sets read_lock so we don't tap in case of an offline
2430 * file, but cf_continue_tail and cf_finish_tail don't, and we
2431 * don't want them to, because tapping new packets in a live
2432 * capture is a common use case.
2434 * Note that most other users of process_specified_records (saving,
2435 * printing) do want to process new packets, unlike taps.
2437 if (count) {
2438 char* range_str = g_strdup_printf("-%u", count);
2439 packet_range_convert_str(&range, range_str);
2440 g_free(range_str);
2441 } else {
2442 /* range_t treats a missing number as meaning 1, not 0, and
2443 * reverses the order if backwards; thus the syntax -0 means
2444 * 0-1, so to only take zero packets we do this.
2446 packet_range_convert_str(&range, "0");
2448 range.process = range_process_user_range;
2451 ret = process_specified_records(cf, &range, "Recalculating statistics on",
2452 "all packets", true, retap_packet,
2453 &callback_args, true);
2455 packet_range_cleanup(&range);
2456 epan_dissect_cleanup(&callback_args.edt);
2458 cf_callback_invoke(cf_cb_file_retap_finished, cf);
2460 switch (ret) {
2461 case PSP_FINISHED:
2462 /* Completed successfully. */
2463 return CF_READ_OK;
2465 case PSP_STOPPED:
2466 /* Well, the user decided to abort the refiltering.
2467 Return CF_READ_ABORTED so our caller knows they did that. */
2468 return CF_READ_ABORTED;
2470 case PSP_FAILED:
2471 /* Error while retapping. */
2472 return CF_READ_ERROR;
2475 ws_assert_not_reached();
2476 return CF_READ_OK;
2479 typedef struct {
2480 print_args_t *print_args;
2481 bool print_header_line;
2482 char *header_line_buf;
2483 int header_line_buf_len;
2484 bool print_formfeed;
2485 bool print_separator;
2486 char *line_buf;
2487 int line_buf_len;
2488 int *col_widths;
2489 int num_visible_cols;
2490 int *visible_cols;
2491 epan_dissect_t edt;
2492 } print_callback_args_t;
2494 static bool
2495 print_packet(capture_file *cf, frame_data *fdata, wtap_rec *rec, Buffer *buf,
2496 void *argsp)
2498 print_callback_args_t *args = (print_callback_args_t *)argsp;
2499 int i;
2500 char *cp;
2501 int line_len;
2502 int column_len;
2503 int cp_off;
2504 char bookmark_name[9+10+1]; /* "__frameNNNNNNNNNN__\0" */
2505 char bookmark_title[6+10+1]; /* "Frame NNNNNNNNNN__\0" */
2506 col_item_t* col_item;
2507 const char* col_text;
2509 /* Fill in the column information if we're printing the summary
2510 information. */
2511 if (args->print_args->print_summary) {
2512 col_custom_prime_edt(&args->edt, &cf->cinfo);
2513 epan_dissect_run(&args->edt, cf->cd_t, rec,
2514 frame_tvbuff_new_buffer(&cf->provider, fdata, buf),
2515 fdata, &cf->cinfo);
2516 epan_dissect_fill_in_columns(&args->edt, false, true);
2517 } else
2518 epan_dissect_run(&args->edt, cf->cd_t, rec,
2519 frame_tvbuff_new_buffer(&cf->provider, fdata, buf),
2520 fdata, NULL);
2522 if (args->print_formfeed) {
2523 if (!new_page(args->print_args->stream))
2524 goto fail;
2527 * Print another header line if we print a packet summary on the
2528 * new page.
2530 if (args->print_args->print_col_headings)
2531 args->print_header_line = true;
2532 } else {
2533 if (args->print_separator) {
2534 if (!print_line(args->print_args->stream, 0, ""))
2535 goto fail;
2540 * We generate bookmarks, if the output format supports them.
2541 * The name is "__frameN__".
2543 snprintf(bookmark_name, sizeof bookmark_name, "__frame%u__", fdata->num);
2545 if (args->print_args->print_summary) {
2546 if (!args->print_args->print_col_headings)
2547 args->print_header_line = false;
2548 if (args->print_header_line) {
2549 if (!print_line(args->print_args->stream, 0, args->header_line_buf))
2550 goto fail;
2551 args->print_header_line = false; /* we might not need to print any more */
2553 cp = &args->line_buf[0];
2554 line_len = 0;
2555 for (i = 0; i < args->num_visible_cols; i++) {
2556 col_item = &cf->cinfo.columns[args->visible_cols[i]];
2557 col_text = get_column_text(&cf->cinfo, args->visible_cols[i]);
2558 /* Find the length of the string for this column. */
2559 column_len = (int) strlen(col_text);
2560 if (args->col_widths[i] > column_len)
2561 column_len = args->col_widths[i];
2563 /* Make sure there's room in the line buffer for the column; if not,
2564 double its length. */
2565 line_len += column_len + 1; /* "+1" for space */
2566 if (line_len > args->line_buf_len) {
2567 cp_off = (int) (cp - args->line_buf);
2568 args->line_buf_len = 2 * line_len;
2569 args->line_buf = (char *)g_realloc(args->line_buf, args->line_buf_len + 1);
2570 cp = args->line_buf + cp_off;
2573 /* Right-justify the packet number column. */
2574 if (col_item->col_fmt == COL_NUMBER || col_item->col_fmt == COL_NUMBER_DIS)
2575 snprintf(cp, column_len+1, "%*s", args->col_widths[i], col_text);
2576 else
2577 snprintf(cp, column_len+1, "%-*s", args->col_widths[i], col_text);
2578 cp += column_len;
2579 if (i != args->num_visible_cols - 1)
2580 *cp++ = ' ';
2582 *cp = '\0';
2585 * Generate a bookmark, using the summary line as the title.
2587 if (!print_bookmark(args->print_args->stream, bookmark_name,
2588 args->line_buf))
2589 goto fail;
2591 if (!print_line(args->print_args->stream, 0, args->line_buf))
2592 goto fail;
2593 } else {
2595 * Generate a bookmark, using "Frame N" as the title, as we're not
2596 * printing the summary line.
2598 snprintf(bookmark_title, sizeof bookmark_title, "Frame %u", fdata->num);
2599 if (!print_bookmark(args->print_args->stream, bookmark_name,
2600 bookmark_title))
2601 goto fail;
2602 } /* if (print_summary) */
2604 if (args->print_args->print_dissections != print_dissections_none) {
2605 if (args->print_args->print_summary) {
2606 /* Separate the summary line from the tree with a blank line. */
2607 if (!print_line(args->print_args->stream, 0, ""))
2608 goto fail;
2611 /* Print the information in that tree. */
2612 if (!proto_tree_print(args->print_args->print_dissections,
2613 args->print_args->print_hex, &args->edt, NULL,
2614 args->print_args->stream))
2615 goto fail;
2617 /* Print a blank line if we print anything after this (aka more than one packet). */
2618 args->print_separator = true;
2620 /* Print a header line if we print any more packet summaries */
2621 if (args->print_args->print_col_headings)
2622 args->print_header_line = true;
2625 if (args->print_args->print_hex) {
2626 if (args->print_args->print_summary || (args->print_args->print_dissections != print_dissections_none)) {
2627 if (!print_line(args->print_args->stream, 0, ""))
2628 goto fail;
2630 /* Print the full packet data as hex. */
2631 if (!print_hex_data(args->print_args->stream, &args->edt, args->print_args->hexdump_options))
2632 goto fail;
2634 /* Print a blank line if we print anything after this (aka more than one packet). */
2635 args->print_separator = true;
2637 /* Print a header line if we print any more packet summaries */
2638 if (args->print_args->print_col_headings)
2639 args->print_header_line = true;
2640 } /* if (args->print_args->print_dissections != print_dissections_none) */
2642 epan_dissect_reset(&args->edt);
2644 /* do we want to have a formfeed between each packet from now on? */
2645 if (args->print_args->print_formfeed) {
2646 args->print_formfeed = true;
2649 return true;
2651 fail:
2652 epan_dissect_reset(&args->edt);
2653 return false;
2656 cf_print_status_t
2657 cf_print_packets(capture_file *cf, print_args_t *print_args,
2658 bool show_progress_bar)
2660 print_callback_args_t callback_args;
2661 int data_width;
2662 char *cp;
2663 int i, cp_off, column_len, line_len;
2664 int num_visible_col = 0, last_visible_col = 0, visible_col_count;
2665 psp_return_t ret;
2666 GList *clp;
2667 fmt_data *cfmt;
2668 bool proto_tree_needed;
2670 callback_args.print_args = print_args;
2671 callback_args.print_header_line = print_args->print_col_headings;
2672 callback_args.header_line_buf = NULL;
2673 callback_args.header_line_buf_len = 256;
2674 callback_args.print_formfeed = false;
2675 callback_args.print_separator = false;
2676 callback_args.line_buf = NULL;
2677 callback_args.line_buf_len = 256;
2678 callback_args.col_widths = NULL;
2679 callback_args.num_visible_cols = 0;
2680 callback_args.visible_cols = NULL;
2682 if (!print_preamble(print_args->stream, cf->filename, get_ws_vcs_version_info())) {
2683 destroy_print_stream(print_args->stream);
2684 return CF_PRINT_WRITE_ERROR;
2687 if (print_args->print_summary) {
2688 /* We're printing packet summaries. Allocate the header line buffer
2689 and get the column widths. */
2690 callback_args.header_line_buf = (char *)g_malloc(callback_args.header_line_buf_len + 1);
2692 /* Find the number of visible columns and the last visible column */
2693 for (i = 0; i < prefs.num_cols; i++) {
2695 clp = g_list_nth(prefs.col_list, i);
2696 if (clp == NULL) /* Sanity check, Invalid column requested */
2697 continue;
2699 cfmt = (fmt_data *) clp->data;
2700 if (cfmt->visible) {
2701 num_visible_col++;
2702 last_visible_col = i;
2706 /* if num_visible_col is 0, we are done */
2707 if (num_visible_col == 0) {
2708 g_free(callback_args.header_line_buf);
2709 return CF_PRINT_OK;
2712 /* Find the widths for each of the columns - maximum of the
2713 width of the title and the width of the data - and construct
2714 a buffer with a line containing the column titles. */
2715 callback_args.num_visible_cols = num_visible_col;
2716 callback_args.col_widths = g_new(int, num_visible_col);
2717 callback_args.visible_cols = g_new(int, num_visible_col);
2718 cp = &callback_args.header_line_buf[0];
2719 line_len = 0;
2720 visible_col_count = 0;
2721 for (i = 0; i < cf->cinfo.num_cols; i++) {
2723 clp = g_list_nth(prefs.col_list, i);
2724 if (clp == NULL) /* Sanity check, Invalid column requested */
2725 continue;
2727 cfmt = (fmt_data *) clp->data;
2728 if (cfmt->visible == false)
2729 continue;
2731 /* Save the order of visible columns */
2732 callback_args.visible_cols[visible_col_count] = i;
2734 /* Don't pad the last column. */
2735 if (i == last_visible_col)
2736 callback_args.col_widths[visible_col_count] = 0;
2737 else {
2738 callback_args.col_widths[visible_col_count] = (int) strlen(cf->cinfo.columns[i].col_title);
2739 data_width = get_column_char_width(get_column_format(i));
2740 if (data_width > callback_args.col_widths[visible_col_count])
2741 callback_args.col_widths[visible_col_count] = data_width;
2744 /* Find the length of the string for this column. */
2745 column_len = (int) strlen(cf->cinfo.columns[i].col_title);
2746 if (callback_args.col_widths[visible_col_count] > column_len)
2747 column_len = callback_args.col_widths[visible_col_count];
2749 /* Make sure there's room in the line buffer for the column; if not,
2750 double its length. */
2751 line_len += column_len + 1; /* "+1" for space */
2752 if (line_len > callback_args.header_line_buf_len) {
2753 cp_off = (int) (cp - callback_args.header_line_buf);
2754 callback_args.header_line_buf_len = 2 * line_len;
2755 callback_args.header_line_buf = (char *)g_realloc(callback_args.header_line_buf,
2756 callback_args.header_line_buf_len + 1);
2757 cp = callback_args.header_line_buf + cp_off;
2760 /* Right-justify the packet number column. */
2761 /* if (cf->cinfo.col_fmt[i] == COL_NUMBER || cf->cinfo.col_fmt[i] == COL_NUMBER_DIS)
2762 snprintf(cp, column_len+1, "%*s", callback_args.col_widths[visible_col_count], cf->cinfo.columns[i].col_title);
2763 else*/
2764 snprintf(cp, column_len+1, "%-*s", callback_args.col_widths[visible_col_count], cf->cinfo.columns[i].col_title);
2765 cp += column_len;
2766 if (i != cf->cinfo.num_cols - 1)
2767 *cp++ = ' ';
2769 visible_col_count++;
2771 *cp = '\0';
2773 /* Now start out the main line buffer with the same length as the
2774 header line buffer. */
2775 callback_args.line_buf_len = callback_args.header_line_buf_len;
2776 callback_args.line_buf = (char *)g_malloc(callback_args.line_buf_len + 1);
2777 } /* if (print_summary) */
2779 /* Create the protocol tree, and make it visible, if we're printing
2780 the dissection or the hex data.
2781 XXX - do we need it if we're just printing the hex data? */
2782 proto_tree_needed =
2783 callback_args.print_args->print_dissections != print_dissections_none ||
2784 callback_args.print_args->print_hex ||
2785 have_custom_cols(&cf->cinfo) || have_field_extractors();
2786 epan_dissect_init(&callback_args.edt, cf->epan, proto_tree_needed, proto_tree_needed);
2788 /* Iterate through the list of packets, printing the packets we were
2789 told to print. */
2790 ret = process_specified_records(cf, &print_args->range, "Printing",
2791 "selected packets", true, print_packet,
2792 &callback_args, show_progress_bar);
2793 epan_dissect_cleanup(&callback_args.edt);
2794 g_free(callback_args.header_line_buf);
2795 g_free(callback_args.line_buf);
2796 g_free(callback_args.col_widths);
2797 g_free(callback_args.visible_cols);
2799 switch (ret) {
2801 case PSP_FINISHED:
2802 /* Completed successfully. */
2803 break;
2805 case PSP_STOPPED:
2806 /* Well, the user decided to abort the printing.
2808 XXX - note that what got generated before they did that
2809 will get printed if we're piping to a print program; we'd
2810 have to write to a file and then hand that to the print
2811 program to make it actually not print anything. */
2812 break;
2814 case PSP_FAILED:
2815 /* Error while printing.
2817 XXX - note that what got generated before they did that
2818 will get printed if we're piping to a print program; we'd
2819 have to write to a file and then hand that to the print
2820 program to make it actually not print anything. */
2821 destroy_print_stream(print_args->stream);
2822 return CF_PRINT_WRITE_ERROR;
2825 if (!print_finale(print_args->stream)) {
2826 destroy_print_stream(print_args->stream);
2827 return CF_PRINT_WRITE_ERROR;
2830 if (!destroy_print_stream(print_args->stream))
2831 return CF_PRINT_WRITE_ERROR;
2833 return CF_PRINT_OK;
2836 typedef struct {
2837 FILE *fh;
2838 epan_dissect_t edt;
2839 print_args_t *print_args;
2840 json_dumper jdumper;
2841 } write_packet_callback_args_t;
2843 static bool
2844 write_pdml_packet(capture_file *cf, frame_data *fdata, wtap_rec *rec,
2845 Buffer *buf, void *argsp)
2847 write_packet_callback_args_t *args = (write_packet_callback_args_t *)argsp;
2849 /* Create the protocol tree, but don't fill in the column information. */
2850 epan_dissect_run(&args->edt, cf->cd_t, rec,
2851 frame_tvbuff_new_buffer(&cf->provider, fdata, buf),
2852 fdata, NULL);
2854 /* Write out the information in that tree. */
2855 write_pdml_proto_tree(NULL, &args->edt, &cf->cinfo, args->fh, false);
2857 epan_dissect_reset(&args->edt);
2859 return !ferror(args->fh);
2862 cf_print_status_t
2863 cf_write_pdml_packets(capture_file *cf, print_args_t *print_args)
2865 write_packet_callback_args_t callback_args;
2866 FILE *fh;
2867 psp_return_t ret;
2869 fh = ws_fopen(print_args->file, "w");
2870 if (fh == NULL)
2871 return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
2873 write_pdml_preamble(fh, cf->filename);
2874 if (ferror(fh)) {
2875 fclose(fh);
2876 return CF_PRINT_WRITE_ERROR;
2879 callback_args.fh = fh;
2880 callback_args.print_args = print_args;
2881 epan_dissect_init(&callback_args.edt, cf->epan, true, true);
2883 /* Iterate through the list of packets, printing the packets we were
2884 told to print. */
2885 ret = process_specified_records(cf, &print_args->range, "Writing PDML",
2886 "selected packets", true,
2887 write_pdml_packet, &callback_args, true);
2889 epan_dissect_cleanup(&callback_args.edt);
2891 switch (ret) {
2893 case PSP_FINISHED:
2894 /* Completed successfully. */
2895 break;
2897 case PSP_STOPPED:
2898 /* Well, the user decided to abort the printing. */
2899 break;
2901 case PSP_FAILED:
2902 /* Error while printing. */
2903 fclose(fh);
2904 return CF_PRINT_WRITE_ERROR;
2907 write_pdml_finale(fh);
2908 if (ferror(fh)) {
2909 fclose(fh);
2910 return CF_PRINT_WRITE_ERROR;
2913 /* XXX - check for an error */
2914 fclose(fh);
2916 return CF_PRINT_OK;
2919 static bool
2920 write_psml_packet(capture_file *cf, frame_data *fdata, wtap_rec *rec,
2921 Buffer *buf, void *argsp)
2923 write_packet_callback_args_t *args = (write_packet_callback_args_t *)argsp;
2925 /* Fill in the column information */
2926 col_custom_prime_edt(&args->edt, &cf->cinfo);
2927 epan_dissect_run(&args->edt, cf->cd_t, rec,
2928 frame_tvbuff_new_buffer(&cf->provider, fdata, buf),
2929 fdata, &cf->cinfo);
2930 epan_dissect_fill_in_columns(&args->edt, false, true);
2932 /* Write out the column information. */
2933 write_psml_columns(&args->edt, args->fh, false);
2935 epan_dissect_reset(&args->edt);
2937 return !ferror(args->fh);
2940 cf_print_status_t
2941 cf_write_psml_packets(capture_file *cf, print_args_t *print_args)
2943 write_packet_callback_args_t callback_args;
2944 FILE *fh;
2945 psp_return_t ret;
2947 bool proto_tree_needed;
2949 fh = ws_fopen(print_args->file, "w");
2950 if (fh == NULL)
2951 return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
2953 write_psml_preamble(&cf->cinfo, fh);
2954 if (ferror(fh)) {
2955 fclose(fh);
2956 return CF_PRINT_WRITE_ERROR;
2959 callback_args.fh = fh;
2960 callback_args.print_args = print_args;
2962 /* Fill in the column information, only create the protocol tree
2963 if having custom columns or field extractors. */
2964 proto_tree_needed = have_custom_cols(&cf->cinfo) || have_field_extractors();
2965 epan_dissect_init(&callback_args.edt, cf->epan, proto_tree_needed, proto_tree_needed);
2967 /* Iterate through the list of packets, printing the packets we were
2968 told to print. */
2969 ret = process_specified_records(cf, &print_args->range, "Writing PSML",
2970 "selected packets", true,
2971 write_psml_packet, &callback_args, true);
2973 epan_dissect_cleanup(&callback_args.edt);
2975 switch (ret) {
2977 case PSP_FINISHED:
2978 /* Completed successfully. */
2979 break;
2981 case PSP_STOPPED:
2982 /* Well, the user decided to abort the printing. */
2983 break;
2985 case PSP_FAILED:
2986 /* Error while printing. */
2987 fclose(fh);
2988 return CF_PRINT_WRITE_ERROR;
2991 write_psml_finale(fh);
2992 if (ferror(fh)) {
2993 fclose(fh);
2994 return CF_PRINT_WRITE_ERROR;
2997 /* XXX - check for an error */
2998 fclose(fh);
3000 return CF_PRINT_OK;
3003 static bool
3004 write_csv_packet(capture_file *cf, frame_data *fdata, wtap_rec *rec,
3005 Buffer *buf, void *argsp)
3007 write_packet_callback_args_t *args = (write_packet_callback_args_t *)argsp;
3009 /* Fill in the column information */
3010 col_custom_prime_edt(&args->edt, &cf->cinfo);
3011 epan_dissect_run(&args->edt, cf->cd_t, rec,
3012 frame_tvbuff_new_buffer(&cf->provider, fdata, buf),
3013 fdata, &cf->cinfo);
3014 epan_dissect_fill_in_columns(&args->edt, false, true);
3016 /* Write out the column information. */
3017 write_csv_columns(&args->edt, args->fh);
3019 epan_dissect_reset(&args->edt);
3021 return !ferror(args->fh);
3024 cf_print_status_t
3025 cf_write_csv_packets(capture_file *cf, print_args_t *print_args)
3027 write_packet_callback_args_t callback_args;
3028 bool proto_tree_needed;
3029 FILE *fh;
3030 psp_return_t ret;
3032 fh = ws_fopen(print_args->file, "w");
3033 if (fh == NULL)
3034 return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
3036 write_csv_column_titles(&cf->cinfo, fh);
3037 if (ferror(fh)) {
3038 fclose(fh);
3039 return CF_PRINT_WRITE_ERROR;
3042 callback_args.fh = fh;
3043 callback_args.print_args = print_args;
3045 /* only create the protocol tree if having custom columns or field extractors. */
3046 proto_tree_needed = have_custom_cols(&cf->cinfo) || have_field_extractors();
3047 epan_dissect_init(&callback_args.edt, cf->epan, proto_tree_needed, proto_tree_needed);
3049 /* Iterate through the list of packets, printing the packets we were
3050 told to print. */
3051 ret = process_specified_records(cf, &print_args->range, "Writing CSV",
3052 "selected packets", true,
3053 write_csv_packet, &callback_args, true);
3055 epan_dissect_cleanup(&callback_args.edt);
3057 switch (ret) {
3059 case PSP_FINISHED:
3060 /* Completed successfully. */
3061 break;
3063 case PSP_STOPPED:
3064 /* Well, the user decided to abort the printing. */
3065 break;
3067 case PSP_FAILED:
3068 /* Error while printing. */
3069 fclose(fh);
3070 return CF_PRINT_WRITE_ERROR;
3073 /* XXX - check for an error */
3074 fclose(fh);
3076 return CF_PRINT_OK;
3079 static bool
3080 carrays_write_packet(capture_file *cf, frame_data *fdata, wtap_rec *rec,
3081 Buffer *buf, void *argsp)
3083 write_packet_callback_args_t *args = (write_packet_callback_args_t *)argsp;
3085 epan_dissect_run(&args->edt, cf->cd_t, rec,
3086 frame_tvbuff_new_buffer(&cf->provider, fdata, buf),
3087 fdata, NULL);
3088 write_carrays_hex_data(fdata->num, args->fh, &args->edt);
3089 epan_dissect_reset(&args->edt);
3091 return !ferror(args->fh);
3094 cf_print_status_t
3095 cf_write_carrays_packets(capture_file *cf, print_args_t *print_args)
3097 write_packet_callback_args_t callback_args;
3098 FILE *fh;
3099 psp_return_t ret;
3101 fh = ws_fopen(print_args->file, "w");
3103 if (fh == NULL)
3104 return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
3106 if (ferror(fh)) {
3107 fclose(fh);
3108 return CF_PRINT_WRITE_ERROR;
3111 callback_args.fh = fh;
3112 callback_args.print_args = print_args;
3113 epan_dissect_init(&callback_args.edt, cf->epan, true, true);
3115 /* Iterate through the list of packets, printing the packets we were
3116 told to print. */
3117 ret = process_specified_records(cf, &print_args->range,
3118 "Writing C Arrays",
3119 "selected packets", true,
3120 carrays_write_packet, &callback_args, true);
3122 epan_dissect_cleanup(&callback_args.edt);
3124 switch (ret) {
3125 case PSP_FINISHED:
3126 /* Completed successfully. */
3127 break;
3128 case PSP_STOPPED:
3129 /* Well, the user decided to abort the printing. */
3130 break;
3131 case PSP_FAILED:
3132 /* Error while printing. */
3133 fclose(fh);
3134 return CF_PRINT_WRITE_ERROR;
3137 fclose(fh);
3138 return CF_PRINT_OK;
3141 static bool
3142 write_json_packet(capture_file *cf, frame_data *fdata, wtap_rec *rec,
3143 Buffer *buf, void *argsp)
3145 write_packet_callback_args_t *args = (write_packet_callback_args_t *)argsp;
3147 /* Create the protocol tree, but don't fill in the column information. */
3148 epan_dissect_run(&args->edt, cf->cd_t, rec,
3149 frame_tvbuff_new_buffer(&cf->provider, fdata, buf),
3150 fdata, NULL);
3152 /* Write out the information in that tree. */
3153 write_json_proto_tree(NULL, args->print_args->print_dissections,
3154 args->print_args->print_hex,
3155 &args->edt, &cf->cinfo, proto_node_group_children_by_unique,
3156 &args->jdumper);
3158 epan_dissect_reset(&args->edt);
3160 return !ferror(args->fh);
3163 cf_print_status_t
3164 cf_write_json_packets(capture_file *cf, print_args_t *print_args)
3166 write_packet_callback_args_t callback_args;
3167 FILE *fh;
3168 psp_return_t ret;
3170 fh = ws_fopen(print_args->file, "w");
3171 if (fh == NULL)
3172 return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
3174 callback_args.jdumper = write_json_preamble(fh);
3175 if (ferror(fh)) {
3176 fclose(fh);
3177 return CF_PRINT_WRITE_ERROR;
3180 callback_args.fh = fh;
3181 callback_args.print_args = print_args;
3182 epan_dissect_init(&callback_args.edt, cf->epan, true, true);
3184 /* Iterate through the list of packets, printing the packets we were
3185 told to print. */
3186 ret = process_specified_records(cf, &print_args->range, "Writing JSON",
3187 "selected packets", true,
3188 write_json_packet, &callback_args, true);
3190 epan_dissect_cleanup(&callback_args.edt);
3192 switch (ret) {
3194 case PSP_FINISHED:
3195 /* Completed successfully. */
3196 break;
3198 case PSP_STOPPED:
3199 /* Well, the user decided to abort the printing. */
3200 break;
3202 case PSP_FAILED:
3203 /* Error while printing. */
3204 fclose(fh);
3205 return CF_PRINT_WRITE_ERROR;
3208 write_json_finale(&callback_args.jdumper);
3209 if (ferror(fh)) {
3210 fclose(fh);
3211 return CF_PRINT_WRITE_ERROR;
3214 /* XXX - check for an error */
3215 fclose(fh);
3217 return CF_PRINT_OK;
3220 bool
3221 cf_find_packet_protocol_tree(capture_file *cf, const char *string,
3222 search_direction dir, bool multiple)
3224 match_data mdata;
3226 mdata.frame_matched = false;
3227 mdata.halt = false;
3228 mdata.string = string;
3229 mdata.string_len = strlen(string);
3230 mdata.cf = cf;
3231 mdata.prev_finfo = cf->finfo_selected;
3232 if (multiple && cf->finfo_selected && cf->edt) {
3233 if (dir == SD_FORWARD) {
3234 proto_tree_children_foreach(cf->edt->tree, match_subtree_text, &mdata);
3235 } else {
3236 proto_tree_children_foreach(cf->edt->tree, match_subtree_text_reverse, &mdata);
3238 if (mdata.frame_matched) {
3239 packet_list_select_finfo(mdata.finfo);
3240 return true;
3243 return find_packet(cf, match_protocol_tree, &mdata, dir);
3246 field_info*
3247 cf_find_string_protocol_tree(capture_file *cf, proto_tree *tree)
3249 match_data mdata;
3250 mdata.frame_matched = false;
3251 mdata.halt = false;
3252 mdata.string = convert_string_case(cf->sfilter, cf->case_type);
3253 mdata.string_len = strlen(mdata.string);
3254 mdata.cf = cf;
3255 mdata.prev_finfo = NULL;
3256 /* Iterate through all the nodes looking for matching text */
3257 if (cf->dir == SD_FORWARD) {
3258 proto_tree_children_foreach(tree, match_subtree_text, &mdata);
3259 } else {
3260 proto_tree_children_foreach(tree, match_subtree_text_reverse, &mdata);
3262 g_free((char *)mdata.string);
3263 return mdata.frame_matched ? mdata.finfo : NULL;
3266 static match_result
3267 match_protocol_tree(capture_file *cf, frame_data *fdata,
3268 wtap_rec *rec, Buffer *buf, void *criterion)
3270 match_data *mdata = (match_data *)criterion;
3271 epan_dissect_t edt;
3273 /* Load the frame's data. */
3274 if (!cf_read_record(cf, fdata, rec, buf)) {
3275 /* Attempt to get the packet failed. */
3276 return MR_ERROR;
3279 /* Construct the protocol tree, including the displayed text */
3280 epan_dissect_init(&edt, cf->epan, true, true);
3281 /* We don't need the column information */
3282 epan_dissect_run(&edt, cf->cd_t, rec,
3283 frame_tvbuff_new_buffer(&cf->provider, fdata, buf),
3284 fdata, NULL);
3286 /* Iterate through all the nodes, seeing if they have text that matches. */
3287 mdata->cf = cf;
3288 mdata->frame_matched = false;
3289 mdata->halt = false;
3290 mdata->prev_finfo = NULL;
3291 /* We don't care about the direction here, because we're just looking
3292 * for one match and we'll destroy this tree anyway. (We find the actual
3293 * field later in PacketList::selectionChanged().) Forwards is faster.
3295 proto_tree_children_foreach(edt.tree, match_subtree_text, mdata);
3296 epan_dissect_cleanup(&edt);
3297 return mdata->frame_matched ? MR_MATCHED : MR_NOTMATCHED;
3300 static void
3301 match_subtree_text(proto_node *node, void *data)
3303 match_data *mdata = (match_data *) data;
3304 const char *string = mdata->string;
3305 size_t string_len = mdata->string_len;
3306 capture_file *cf = mdata->cf;
3307 field_info *fi = PNODE_FINFO(node);
3308 char label_str[ITEM_LABEL_LENGTH];
3309 char *label_ptr;
3310 size_t label_len;
3311 uint32_t i, i_restart;
3312 uint8_t c_char;
3313 size_t c_match = 0;
3315 /* dissection with an invisible proto tree? */
3316 ws_assert(fi);
3318 if (mdata->frame_matched) {
3319 /* We already had a match; don't bother doing any more work. */
3320 return;
3323 /* Don't match invisible entries. */
3324 if (proto_item_is_hidden(node))
3325 return;
3327 if (mdata->prev_finfo) {
3328 /* Haven't found the old match, so don't match this node. */
3329 if (fi == mdata->prev_finfo) {
3330 /* Found the old match, look for the next one after this. */
3331 mdata->prev_finfo = NULL;
3333 } else {
3334 /* was a free format label produced? */
3335 if (fi->rep) {
3336 label_ptr = fi->rep->representation;
3337 } else {
3338 /* no, make a generic label */
3339 label_ptr = label_str;
3340 proto_item_fill_label(fi, label_str, NULL);
3343 if (cf->regex) {
3344 if (ws_regex_matches(cf->regex, label_ptr)) {
3345 mdata->frame_matched = true;
3346 mdata->finfo = fi;
3347 return;
3349 } else if (cf->case_type) {
3350 /* Case insensitive match */
3351 label_len = strlen(label_ptr);
3352 i_restart = 0;
3353 for (i = 0; i < label_len; i++) {
3354 if (i_restart == 0 && c_match == 0 && (label_len - i < string_len))
3355 break;
3356 c_char = label_ptr[i];
3357 c_char = g_ascii_toupper(c_char);
3358 /* If c_match is non-zero, save candidate for retrying full match. */
3359 if (c_match > 0 && i_restart == 0 && c_char == string[0])
3360 i_restart = i;
3361 if (c_char == string[c_match]) {
3362 c_match++;
3363 if (c_match == string_len) {
3364 mdata->frame_matched = true;
3365 mdata->finfo = fi;
3366 /* No need to look further; we have a match */
3367 return;
3369 } else if (i_restart) {
3370 i = i_restart;
3371 c_match = 1;
3372 i_restart = 0;
3373 } else
3374 c_match = 0;
3376 } else if (strstr(label_ptr, string) != NULL) {
3377 /* Case sensitive match */
3378 mdata->frame_matched = true;
3379 mdata->finfo = fi;
3380 return;
3384 /* Recurse into the subtree, if it exists */
3385 if (node->first_child != NULL)
3386 proto_tree_children_foreach(node, match_subtree_text, mdata);
3389 static void
3390 match_subtree_text_reverse(proto_node *node, void *data)
3392 match_data *mdata = (match_data *) data;
3393 const char *string = mdata->string;
3394 size_t string_len = mdata->string_len;
3395 capture_file *cf = mdata->cf;
3396 field_info *fi = PNODE_FINFO(node);
3397 char label_str[ITEM_LABEL_LENGTH];
3398 char *label_ptr;
3399 size_t label_len;
3400 uint32_t i, i_restart;
3401 uint8_t c_char;
3402 size_t c_match = 0;
3404 /* dissection with an invisible proto tree? */
3405 ws_assert(fi);
3407 /* We don't have an easy way to search backwards in the tree
3408 * (see also, proto_find_field_from_offset()) because we don't
3409 * have a previous node pointer, so we search backwards by
3410 * searching forwards, only stopping if we see the old match
3411 * (if we have one).
3414 if (mdata->halt) {
3415 return;
3418 /* Don't match invisible entries. */
3419 if (proto_item_is_hidden(node))
3420 return;
3422 if (mdata->prev_finfo && fi == mdata->prev_finfo) {
3423 /* Found the old match, use the previous match. */
3424 mdata->halt = true;
3425 return;
3428 /* was a free format label produced? */
3429 if (fi->rep) {
3430 label_ptr = fi->rep->representation;
3431 } else {
3432 /* no, make a generic label */
3433 label_ptr = label_str;
3434 proto_item_fill_label(fi, label_str, NULL);
3437 if (cf->regex) {
3438 if (ws_regex_matches(cf->regex, label_ptr)) {
3439 mdata->frame_matched = true;
3440 mdata->finfo = fi;
3442 } else if (cf->case_type) {
3443 /* Case insensitive match */
3444 label_len = strlen(label_ptr);
3445 i_restart = 0;
3446 for (i = 0; i < label_len; i++) {
3447 if (i_restart == 0 && c_match == 0 && (label_len - i < string_len))
3448 break;
3449 c_char = label_ptr[i];
3450 c_char = g_ascii_toupper(c_char);
3451 /* If c_match is non-zero, save candidate for retrying full match. */
3452 if (c_match > 0 && i_restart == 0 && c_char == string[0])
3453 i_restart = i;
3454 if (c_char == string[c_match]) {
3455 c_match++;
3456 if (c_match == string_len) {
3457 mdata->frame_matched = true;
3458 mdata->finfo = fi;
3459 break;
3461 } else if (i_restart) {
3462 i = i_restart;
3463 c_match = 1;
3464 i_restart = 0;
3465 } else
3466 c_match = 0;
3468 } else if (strstr(label_ptr, string) != NULL) {
3469 /* Case sensitive match */
3470 mdata->frame_matched = true;
3471 mdata->finfo = fi;
3474 /* Recurse into the subtree, if it exists */
3475 if (node->first_child != NULL)
3476 proto_tree_children_foreach(node, match_subtree_text_reverse, mdata);
3479 bool
3480 cf_find_packet_summary_line(capture_file *cf, const char *string,
3481 search_direction dir)
3483 match_data mdata;
3485 mdata.string = string;
3486 mdata.string_len = strlen(string);
3487 return find_packet(cf, match_summary_line, &mdata, dir);
3490 static match_result
3491 match_summary_line(capture_file *cf, frame_data *fdata,
3492 wtap_rec *rec, Buffer *buf, void *criterion)
3494 match_data *mdata = (match_data *)criterion;
3495 const char *string = mdata->string;
3496 size_t string_len = mdata->string_len;
3497 epan_dissect_t edt;
3498 const char *info_column;
3499 size_t info_column_len;
3500 match_result result = MR_NOTMATCHED;
3501 int colx;
3502 uint32_t i, i_restart;
3503 uint8_t c_char;
3504 size_t c_match = 0;
3506 /* Load the frame's data. */
3507 if (!cf_read_record(cf, fdata, rec, buf)) {
3508 /* Attempt to get the packet failed. */
3509 return MR_ERROR;
3512 /* Don't bother constructing the protocol tree */
3513 epan_dissect_init(&edt, cf->epan, false, false);
3514 /* Get the column information */
3515 epan_dissect_run(&edt, cf->cd_t, rec,
3516 frame_tvbuff_new_buffer(&cf->provider, fdata, buf),
3517 fdata, &cf->cinfo);
3519 /* Find the Info column */
3520 for (colx = 0; colx < cf->cinfo.num_cols; colx++) {
3521 if (cf->cinfo.columns[colx].fmt_matx[COL_INFO]) {
3522 /* Found it. See if we match. */
3523 info_column = get_column_text(edt.pi.cinfo, colx);
3524 info_column_len = strlen(info_column);
3525 if (cf->regex) {
3526 if (ws_regex_matches(cf->regex, info_column)) {
3527 result = MR_MATCHED;
3528 break;
3530 } else if (cf->case_type) {
3531 /* Case insensitive match */
3532 i_restart = 0;
3533 for (i = 0; i < info_column_len; i++) {
3534 if (i_restart == 0 && c_match == 0 && (info_column_len - i < string_len))
3535 break;
3536 c_char = info_column[i];
3537 c_char = g_ascii_toupper(c_char);
3538 /* If c_match is non-zero, save candidate for retrying full match. */
3539 if (c_match > 0 && i_restart == 0 && c_char == string[0])
3540 i_restart = i;
3541 if (c_char == string[c_match]) {
3542 c_match++;
3543 if (c_match == string_len) {
3544 result = MR_MATCHED;
3545 break;
3547 } else if (i_restart) {
3548 i = i_restart;
3549 c_match = 1;
3550 i_restart = 0;
3551 } else
3552 c_match = 0;
3554 } else if (strstr(info_column, string) != NULL) {
3555 /* Case sensitive match */
3556 result = MR_MATCHED;
3558 break;
3561 epan_dissect_cleanup(&edt);
3562 return result;
3565 typedef struct {
3566 const uint8_t *data;
3567 size_t data_len;
3568 ws_mempbrk_pattern *pattern;
3569 } cbs_t; /* "Counted byte string" */
3573 * The current match_* routines only support ASCII case insensitivity and don't
3574 * convert UTF-8 inputs to UTF-16 for matching. The UTF-16 support just
3575 * interleaves with \0 bytes, which works for 7 bit ASCII.
3577 * We could modify them to use the GLib Unicode routines or the International
3578 * Components for Unicode library but it's not apparent that we could do so
3579 * without consuming a lot more CPU and memory or that searching would be
3580 * significantly better.
3582 * XXX: We could test the search string to see if it's all ASCII, and if not
3583 * use Unicode aware routines for case insensitive searches or any UTF-16
3584 * search.
3587 bool
3588 cf_find_packet_data(capture_file *cf, const uint8_t *string, size_t string_size,
3589 search_direction dir, bool multiple)
3591 cbs_t info;
3592 uint8_t needles[3];
3593 ws_mempbrk_pattern pattern = {0};
3594 ws_match_function match_function;
3596 info.data = string;
3597 info.data_len = string_size;
3599 /* Regex, String or hex search? */
3600 if (cf->regex) {
3601 /* Regular Expression search */
3602 match_function = (cf->dir == SD_FORWARD) ? match_regex : match_regex_reverse;
3603 } else if (cf->string) {
3604 /* String search - what type of string? */
3605 if (cf->case_type) {
3606 needles[0] = string[0];
3607 needles[1] = g_ascii_tolower(needles[0]);
3608 needles[2] = '\0';
3609 ws_mempbrk_compile(&pattern, needles);
3610 info.pattern = &pattern;
3611 switch (cf->scs_type) {
3613 case SCS_NARROW_AND_WIDE:
3614 match_function = (cf->dir == SD_FORWARD) ? match_narrow_and_wide_case : match_narrow_and_wide_case_reverse;
3615 break;
3617 case SCS_NARROW:
3618 match_function = (cf->dir == SD_FORWARD) ? match_narrow_case : match_narrow_case_reverse;
3619 break;
3621 case SCS_WIDE:
3622 match_function = (cf->dir == SD_FORWARD) ? match_wide_case : match_wide_case_reverse;
3623 break;
3625 default:
3626 ws_assert_not_reached();
3627 return false;
3630 } else {
3631 switch (cf->scs_type) {
3633 case SCS_NARROW_AND_WIDE:
3634 match_function = (cf->dir == SD_FORWARD) ? match_narrow_and_wide : match_narrow_and_wide_reverse;
3635 break;
3637 case SCS_NARROW:
3638 /* Narrow, case-sensitive match is the same as looking
3639 * for a converted hexstring. */
3640 match_function = (cf->dir == SD_FORWARD) ? match_binary : match_binary_reverse;
3641 break;
3643 case SCS_WIDE:
3644 match_function = (cf->dir == SD_FORWARD) ? match_wide : match_wide_reverse;
3645 break;
3647 default:
3648 ws_assert_not_reached();
3649 return false;
3652 } else {
3653 match_function = (cf->dir == SD_FORWARD) ? match_binary : match_binary_reverse;
3656 if (multiple && cf->current_frame && (cf->search_pos || cf->search_len)) {
3657 /* Use the current frame (this will perform the equivalent of
3658 * cf_read_current_record() in match_function).
3660 if (match_function(cf, cf->current_frame, &cf->rec, &cf->buf, &info)) {
3661 cf->search_in_progress = true;
3662 if (cf->edt) {
3663 field_info *fi = NULL;
3664 /* The regex match can match an empty string. */
3665 if (cf->search_len) {
3666 fi = proto_find_field_from_offset(cf->edt->tree, cf->search_pos + cf->search_len - 1, cf->edt->tvb);
3668 packet_list_select_finfo(fi);
3669 } else {
3670 packet_list_select_row_from_data(cf->current_frame);
3672 cf->search_in_progress = false;
3673 return true;
3676 cf->search_pos = 0; /* Reset the position */
3677 cf->search_len = 0; /* Reset length */
3678 return find_packet(cf, match_function, &info, dir);
3681 static match_result
3682 match_narrow_and_wide(capture_file *cf, frame_data *fdata,
3683 wtap_rec *rec, Buffer *buf, void *criterion)
3685 cbs_t *info = (cbs_t *)criterion;
3686 const uint8_t *ascii_text = info->data;
3687 size_t textlen = info->data_len;
3688 match_result result;
3689 uint32_t buf_len;
3690 uint8_t *pd, *buf_start, *buf_end;
3691 uint32_t i;
3692 uint8_t c_char;
3693 size_t c_match = 0;
3695 /* Load the frame's data. */
3696 if (!cf_read_record(cf, fdata, rec, buf)) {
3697 /* Attempt to get the packet failed. */
3698 return MR_ERROR;
3701 result = MR_NOTMATCHED;
3702 buf_len = fdata->cap_len;
3703 buf_start = ws_buffer_start_ptr(buf);
3704 buf_end = buf_start + buf_len;
3705 pd = buf_start;
3706 if (cf->search_len || cf->search_pos) {
3707 /* we want to start searching one byte past the previous match start */
3708 pd += cf->search_pos + 1;
3710 for (; pd < buf_end; pd++) {
3711 pd = (uint8_t *)memchr(pd, ascii_text[0], buf_end - pd);
3712 if (pd == NULL) break;
3713 /* Try narrow match at this start location */
3714 c_match = 0;
3715 for (i = 0; pd + i < buf_end; i++) {
3716 c_char = pd[i];
3717 if (c_char == ascii_text[c_match]) {
3718 c_match++;
3719 if (c_match == textlen) {
3720 result = MR_MATCHED;
3721 /* Save position and length for highlighting the field. */
3722 cf->search_pos = (uint32_t)(pd - buf_start);
3723 cf->search_len = (uint32_t)(i + 1);
3724 goto done;
3726 } else {
3727 break;
3731 /* Now try wide match at the same start location. */
3732 c_match = 0;
3733 for (i = 0; pd + i < buf_end; i++) {
3734 c_char = pd[i];
3735 if (c_char == ascii_text[c_match]) {
3736 c_match++;
3737 if (c_match == textlen) {
3738 result = MR_MATCHED;
3739 /* Save position and length for highlighting the field. */
3740 cf->search_pos = (uint32_t)(pd - buf_start);
3741 cf->search_len = (uint32_t)(i + 1);
3742 goto done;
3744 i++;
3745 if (pd + i >= buf_end || pd[i] != '\0') break;
3746 } else {
3747 break;
3752 done:
3753 return result;
3756 static match_result
3757 match_narrow_and_wide_reverse(capture_file *cf, frame_data *fdata,
3758 wtap_rec *rec, Buffer *buf, void *criterion)
3760 cbs_t *info = (cbs_t *)criterion;
3761 const uint8_t *ascii_text = info->data;
3762 size_t textlen = info->data_len;
3763 match_result result;
3764 uint32_t buf_len;
3765 uint8_t *pd, *buf_start, *buf_end;
3766 uint32_t i;
3767 uint8_t c_char;
3768 size_t c_match = 0;
3770 /* Load the frame's data. */
3771 if (!cf_read_record(cf, fdata, rec, buf)) {
3772 /* Attempt to get the packet failed. */
3773 return MR_ERROR;
3776 result = MR_NOTMATCHED;
3777 /* Has to be room to hold the sought data. */
3778 if (textlen > fdata->cap_len) {
3779 return result;
3781 buf_len = fdata->cap_len;
3782 buf_start = ws_buffer_start_ptr(buf);
3783 buf_end = buf_start + buf_len;
3784 pd = buf_end - textlen;
3785 if (cf->search_len || cf->search_pos) {
3786 /* we want to start searching one byte before the previous match start */
3787 pd = buf_start + cf->search_pos - 1;
3789 for (; pd < buf_end; pd++) {
3790 pd = (uint8_t *)ws_memrchr(buf_start, ascii_text[0], pd - buf_start + 1);
3791 if (pd == NULL) break;
3792 /* Try narrow match at this start location */
3793 c_match = 0;
3794 for (i = 0; pd + i < buf_end; i++) {
3795 c_char = pd[i];
3796 if (c_char == ascii_text[c_match]) {
3797 c_match++;
3798 if (c_match == textlen) {
3799 result = MR_MATCHED;
3800 /* Save position and length for highlighting the field. */
3801 cf->search_pos = (uint32_t)(pd - buf_start);
3802 cf->search_len = (uint32_t)(i + 1);
3803 goto done;
3805 } else {
3806 break;
3810 /* Now try wide match at the same start location. */
3811 c_match = 0;
3812 for (i = 0; pd + i < buf_end; i++) {
3813 c_char = pd[i];
3814 if (c_char == ascii_text[c_match]) {
3815 c_match++;
3816 if (c_match == textlen) {
3817 result = MR_MATCHED;
3818 /* Save position and length for highlighting the field. */
3819 cf->search_pos = (uint32_t)(pd - buf_start);
3820 cf->search_len = (uint32_t)(i + 1);
3821 goto done;
3823 i++;
3824 if (pd + i >= buf_end || pd[i] != '\0') break;
3825 } else {
3826 break;
3831 done:
3832 return result;
3835 /* Case insensitive match */
3836 static match_result
3837 match_narrow_and_wide_case(capture_file *cf, frame_data *fdata,
3838 wtap_rec *rec, Buffer *buf, void *criterion)
3840 cbs_t *info = (cbs_t *)criterion;
3841 const uint8_t *ascii_text = info->data;
3842 size_t textlen = info->data_len;
3843 ws_mempbrk_pattern *pattern = info->pattern;
3844 match_result result;
3845 uint32_t buf_len;
3846 uint8_t *pd, *buf_start, *buf_end;
3847 uint32_t i;
3848 uint8_t c_char;
3849 size_t c_match = 0;
3851 /* Load the frame's data. */
3852 if (!cf_read_record(cf, fdata, rec, buf)) {
3853 /* Attempt to get the packet failed. */
3854 return MR_ERROR;
3857 ws_assert(pattern != NULL);
3859 result = MR_NOTMATCHED;
3860 buf_len = fdata->cap_len;
3861 buf_start = ws_buffer_start_ptr(buf);
3862 buf_end = buf_start + buf_len;
3863 pd = buf_start;
3864 if (cf->search_len || cf->search_pos) {
3865 /* we want to start searching one byte past the previous match start */
3866 pd += cf->search_pos + 1;
3868 for (; pd < buf_end; pd++) {
3869 pd = (uint8_t *)ws_mempbrk_exec(pd, buf_end - pd, pattern, &c_char);
3870 if (pd == NULL) break;
3871 /* Try narrow match at this start location */
3872 c_match = 0;
3873 for (i = 0; pd + i < buf_end; i++) {
3874 c_char = g_ascii_toupper(pd[i]);
3875 if (c_char == ascii_text[c_match]) {
3876 c_match++;
3877 if (c_match == textlen) {
3878 result = MR_MATCHED;
3879 /* Save position and length for highlighting the field. */
3880 cf->search_pos = (uint32_t)(pd - buf_start);
3881 cf->search_len = (uint32_t)(i + 1);
3882 goto done;
3884 } else {
3885 break;
3889 /* Now try wide match at the same start location. */
3890 c_match = 0;
3891 for (i = 0; pd + i < buf_end; i++) {
3892 c_char = g_ascii_toupper(pd[i]);
3893 if (c_char == ascii_text[c_match]) {
3894 c_match++;
3895 if (c_match == textlen) {
3896 result = MR_MATCHED;
3897 /* Save position and length for highlighting the field. */
3898 cf->search_pos = (uint32_t)(pd - buf_start);
3899 cf->search_len = (uint32_t)(i + 1);
3900 goto done;
3902 i++;
3903 if (pd + i >= buf_end || pd[i] != '\0') break;
3904 } else {
3905 break;
3910 done:
3911 return result;
3914 static match_result
3915 match_narrow_and_wide_case_reverse(capture_file *cf, frame_data *fdata,
3916 wtap_rec *rec, Buffer *buf, void *criterion)
3918 cbs_t *info = (cbs_t *)criterion;
3919 const uint8_t *ascii_text = info->data;
3920 size_t textlen = info->data_len;
3921 ws_mempbrk_pattern *pattern = info->pattern;
3922 match_result result;
3923 uint32_t buf_len;
3924 uint8_t *pd, *buf_start, *buf_end;
3925 uint32_t i;
3926 uint8_t c_char;
3927 size_t c_match = 0;
3929 /* Load the frame's data. */
3930 if (!cf_read_record(cf, fdata, rec, buf)) {
3931 /* Attempt to get the packet failed. */
3932 return MR_ERROR;
3935 ws_assert(pattern != NULL);
3937 result = MR_NOTMATCHED;
3938 /* Has to be room to hold the sought data. */
3939 if (textlen > fdata->cap_len) {
3940 return result;
3942 buf_len = fdata->cap_len;
3943 buf_start = ws_buffer_start_ptr(buf);
3944 buf_end = buf_start + buf_len;
3945 pd = buf_end - textlen;
3946 if (cf->search_len || cf->search_pos) {
3947 /* we want to start searching one byte before the previous match start */
3948 pd = buf_start + cf->search_pos - 1;
3950 for (; pd >= buf_start; pd--) {
3951 pd = (uint8_t *)ws_memrpbrk_exec(buf_start, pd - buf_start + 1, pattern, &c_char);
3952 if (pd == NULL) break;
3953 /* Try narrow match at this start location */
3954 c_match = 0;
3955 for (i = 0; pd + i < buf_end; i++) {
3956 c_char = g_ascii_toupper(pd[i]);
3957 if (c_char == ascii_text[c_match]) {
3958 c_match++;
3959 if (c_match == textlen) {
3960 result = MR_MATCHED;
3961 /* Save position and length for highlighting the field. */
3962 cf->search_pos = (uint32_t)(pd - buf_start);
3963 cf->search_len = (uint32_t)(i + 1);
3964 goto done;
3966 } else {
3967 break;
3971 /* Now try wide match at the same start location. */
3972 c_match = 0;
3973 for (i = 0; pd + i < buf_end; i++) {
3974 c_char = g_ascii_toupper(pd[i]);
3975 if (c_char == ascii_text[c_match]) {
3976 c_match++;
3977 if (c_match == textlen) {
3978 result = MR_MATCHED;
3979 /* Save position and length for highlighting the field. */
3980 cf->search_pos = (uint32_t)(pd - buf_start);
3981 cf->search_len = (uint32_t)(i + 1);
3982 goto done;
3984 i++;
3985 if (pd + i >= buf_end || pd[i] != '\0') break;
3986 } else {
3987 break;
3992 done:
3993 return result;
3996 /* Case insensitive match */
3997 static match_result
3998 match_narrow_case(capture_file *cf, frame_data *fdata,
3999 wtap_rec *rec, Buffer *buf, void *criterion)
4001 cbs_t *info = (cbs_t *)criterion;
4002 const uint8_t *ascii_text = info->data;
4003 size_t textlen = info->data_len;
4004 ws_mempbrk_pattern *pattern = info->pattern;
4005 match_result result;
4006 uint32_t buf_len;
4007 uint8_t *pd, *buf_start, *buf_end;
4008 uint32_t i;
4009 uint8_t c_char;
4010 size_t c_match = 0;
4012 /* Load the frame's data. */
4013 if (!cf_read_record(cf, fdata, rec, buf)) {
4014 /* Attempt to get the packet failed. */
4015 return MR_ERROR;
4018 ws_assert(pattern != NULL);
4020 result = MR_NOTMATCHED;
4021 buf_len = fdata->cap_len;
4022 buf_start = ws_buffer_start_ptr(buf);
4023 buf_end = buf_start + buf_len;
4024 pd = buf_start;
4025 if (cf->search_len || cf->search_pos) {
4026 /* we want to start searching one byte past the previous match start */
4027 pd += cf->search_pos + 1;
4029 for (; pd < buf_end; pd++) {
4030 pd = (uint8_t *)ws_mempbrk_exec(pd, buf_end - pd, pattern, &c_char);
4031 if (pd == NULL) break;
4032 c_match = 0;
4033 for (i = 0; pd + i < buf_end; i++) {
4034 c_char = g_ascii_toupper(pd[i]);
4035 if (c_char == ascii_text[c_match]) {
4036 c_match++;
4037 if (c_match == textlen) {
4038 /* Save position and length for highlighting the field. */
4039 result = MR_MATCHED;
4040 cf->search_pos = (uint32_t)(pd - buf_start);
4041 cf->search_len = (uint32_t)(i + 1);
4042 goto done;
4044 } else {
4045 break;
4050 done:
4051 return result;
4054 static match_result
4055 match_narrow_case_reverse(capture_file *cf, frame_data *fdata,
4056 wtap_rec *rec, Buffer *buf, void *criterion)
4058 cbs_t *info = (cbs_t *)criterion;
4059 const uint8_t *ascii_text = info->data;
4060 size_t textlen = info->data_len;
4061 ws_mempbrk_pattern *pattern = info->pattern;
4062 match_result result;
4063 uint32_t buf_len;
4064 uint8_t *pd, *buf_start, *buf_end;
4065 uint32_t i;
4066 uint8_t c_char;
4067 size_t c_match = 0;
4069 /* Load the frame's data. */
4070 if (!cf_read_record(cf, fdata, rec, buf)) {
4071 /* Attempt to get the packet failed. */
4072 return MR_ERROR;
4075 ws_assert(pattern != NULL);
4077 result = MR_NOTMATCHED;
4078 /* Has to be room to hold the sought data. */
4079 if (textlen > fdata->cap_len) {
4080 return result;
4082 buf_len = fdata->cap_len;
4083 buf_start = ws_buffer_start_ptr(buf);
4084 buf_end = buf_start + buf_len;
4085 pd = buf_end - textlen;
4086 if (cf->search_len || cf->search_pos) {
4087 /* we want to start searching one byte before the previous match start */
4088 pd = buf_start + cf->search_pos - 1;
4090 for (; pd >= buf_start; pd--) {
4091 pd = (uint8_t *)ws_memrpbrk_exec(buf_start, pd - buf_start + 1, pattern, &c_char);
4092 if (pd == NULL) break;
4093 c_match = 0;
4094 for (i = 0; pd + i < buf_end; i++) {
4095 c_char = g_ascii_toupper(pd[i]);
4096 if (c_char == ascii_text[c_match]) {
4097 c_match++;
4098 if (c_match == textlen) {
4099 /* Save position and length for highlighting the field. */
4100 result = MR_MATCHED;
4101 cf->search_pos = (uint32_t)(pd - buf_start);
4102 cf->search_len = (uint32_t)(i + 1);
4103 goto done;
4105 } else {
4106 break;
4111 done:
4112 return result;
4115 static match_result
4116 match_wide(capture_file *cf, frame_data *fdata,
4117 wtap_rec *rec, Buffer *buf, void *criterion)
4119 cbs_t *info = (cbs_t *)criterion;
4120 const uint8_t *ascii_text = info->data;
4121 size_t textlen = info->data_len;
4122 match_result result;
4123 uint32_t buf_len;
4124 uint8_t *pd, *buf_start, *buf_end;
4125 uint32_t i;
4126 uint8_t c_char;
4127 size_t c_match = 0;
4129 /* Load the frame's data. */
4130 if (!cf_read_record(cf, fdata, rec, buf)) {
4131 /* Attempt to get the packet failed. */
4132 return MR_ERROR;
4135 result = MR_NOTMATCHED;
4136 buf_len = fdata->cap_len;
4137 buf_start = ws_buffer_start_ptr(buf);
4138 buf_end = buf_start + buf_len;
4139 pd = buf_start;
4140 if (cf->search_len || cf->search_pos) {
4141 /* we want to start searching one byte past the previous match start */
4142 pd += cf->search_pos + 1;
4144 for (; pd < buf_end; pd++) {
4145 pd = (uint8_t *)memchr(pd, ascii_text[0], buf_end - pd);
4146 if (pd == NULL) break;
4147 c_match = 0;
4148 for (i = 0; pd + i < buf_end; i++) {
4149 c_char = pd[i];
4150 if (c_char == ascii_text[c_match]) {
4151 c_match++;
4152 if (c_match == textlen) {
4153 result = MR_MATCHED;
4154 /* Save position and length for highlighting the field. */
4155 cf->search_pos = (uint32_t)(pd - buf_start);
4156 cf->search_len = (uint32_t)(i + 1);
4157 goto done;
4159 i++;
4160 if (pd + i >= buf_end || pd[i] != '\0') break;
4161 } else {
4162 break;
4167 done:
4168 return result;
4171 static match_result
4172 match_wide_reverse(capture_file *cf, frame_data *fdata,
4173 wtap_rec *rec, Buffer *buf, void *criterion)
4175 cbs_t *info = (cbs_t *)criterion;
4176 const uint8_t *ascii_text = info->data;
4177 size_t textlen = info->data_len;
4178 match_result result;
4179 uint32_t buf_len;
4180 uint8_t *pd, *buf_start, *buf_end;
4181 uint32_t i;
4182 uint8_t c_char;
4183 size_t c_match = 0;
4185 /* Load the frame's data. */
4186 if (!cf_read_record(cf, fdata, rec, buf)) {
4187 /* Attempt to get the packet failed. */
4188 return MR_ERROR;
4191 result = MR_NOTMATCHED;
4192 /* Has to be room to hold the sought data. */
4193 if (textlen > fdata->cap_len) {
4194 return result;
4196 buf_len = fdata->cap_len;
4197 buf_start = ws_buffer_start_ptr(buf);
4198 buf_end = buf_start + buf_len;
4199 pd = buf_end - textlen;
4200 if (cf->search_len || cf->search_pos) {
4201 /* we want to start searching one byte before the previous match start */
4202 pd = buf_start + cf->search_pos - 1;
4204 for (; pd < buf_end; pd++) {
4205 pd = (uint8_t *)ws_memrchr(buf_start, ascii_text[0], pd - buf_start + 1);
4206 if (pd == NULL) break;
4207 c_match = 0;
4208 for (i = 0; pd + i < buf_end; i++) {
4209 c_char = pd[i];
4210 if (c_char == ascii_text[c_match]) {
4211 c_match++;
4212 if (c_match == textlen) {
4213 result = MR_MATCHED;
4214 /* Save position and length for highlighting the field. */
4215 cf->search_pos = (uint32_t)(pd - buf_start);
4216 cf->search_len = (uint32_t)(i + 1);
4217 goto done;
4219 i++;
4220 if (pd + i >= buf_end || pd[i] != '\0') break;
4221 } else {
4222 break;
4227 done:
4228 return result;
4231 /* Case insensitive match */
4232 static match_result
4233 match_wide_case(capture_file *cf, frame_data *fdata,
4234 wtap_rec *rec, Buffer *buf, void *criterion)
4236 cbs_t *info = (cbs_t *)criterion;
4237 const uint8_t *ascii_text = info->data;
4238 size_t textlen = info->data_len;
4239 ws_mempbrk_pattern *pattern = info->pattern;
4240 match_result result;
4241 uint32_t buf_len;
4242 uint8_t *pd, *buf_start, *buf_end;
4243 uint32_t i;
4244 uint8_t c_char;
4245 size_t c_match = 0;
4247 /* Load the frame's data. */
4248 if (!cf_read_record(cf, fdata, rec, buf)) {
4249 /* Attempt to get the packet failed. */
4250 return MR_ERROR;
4253 ws_assert(pattern != NULL);
4255 result = MR_NOTMATCHED;
4256 buf_len = fdata->cap_len;
4257 buf_start = ws_buffer_start_ptr(buf);
4258 buf_end = buf_start + buf_len;
4259 pd = buf_start;
4260 if (cf->search_len || cf->search_pos) {
4261 /* we want to start searching one byte past the previous match start */
4262 pd += cf->search_pos + 1;
4264 for (; pd < buf_end; pd++) {
4265 pd = (uint8_t *)ws_mempbrk_exec(pd, buf_end - pd, pattern, &c_char);
4266 if (pd == NULL) break;
4267 c_match = 0;
4268 for (i = 0; pd + i < buf_end; i++) {
4269 c_char = g_ascii_toupper(pd[i]);
4270 if (c_char == ascii_text[c_match]) {
4271 c_match++;
4272 if (c_match == textlen) {
4273 result = MR_MATCHED;
4274 /* Save position and length for highlighting the field. */
4275 cf->search_pos = (uint32_t)(pd - buf_start);
4276 cf->search_len = (uint32_t)(i + 1);
4277 goto done;
4279 i++;
4280 if (pd + i >= buf_end || pd[i] != '\0') break;
4281 } else {
4282 break;
4287 done:
4288 return result;
4291 /* Case insensitive match */
4292 static match_result
4293 match_wide_case_reverse(capture_file *cf, frame_data *fdata,
4294 wtap_rec *rec, Buffer *buf, void *criterion)
4296 cbs_t *info = (cbs_t *)criterion;
4297 const uint8_t *ascii_text = info->data;
4298 size_t textlen = info->data_len;
4299 ws_mempbrk_pattern *pattern = info->pattern;
4300 match_result result;
4301 uint32_t buf_len;
4302 uint8_t *pd, *buf_start, *buf_end;
4303 uint32_t i;
4304 uint8_t c_char;
4305 size_t c_match = 0;
4307 /* Load the frame's data. */
4308 if (!cf_read_record(cf, fdata, rec, buf)) {
4309 /* Attempt to get the packet failed. */
4310 return MR_ERROR;
4313 ws_assert(pattern != NULL);
4315 result = MR_NOTMATCHED;
4316 /* Has to be room to hold the sought data. */
4317 if (textlen > fdata->cap_len) {
4318 return result;
4320 buf_len = fdata->cap_len;
4321 buf_start = ws_buffer_start_ptr(buf);
4322 buf_end = buf_start + buf_len;
4323 pd = buf_end - textlen;
4324 if (cf->search_len || cf->search_pos) {
4325 /* we want to start searching one byte before the previous match start */
4326 pd = buf_start + cf->search_pos - 1;
4328 for (; pd >= buf_start; pd--) {
4329 pd = (uint8_t *)ws_memrpbrk_exec(buf_start, pd - buf_start + 1, pattern, &c_char);
4330 if (pd == NULL) break;
4331 c_match = 0;
4332 for (i = 0; pd + i < buf_end; i++) {
4333 c_char = g_ascii_toupper(pd[i]);
4334 if (c_char == ascii_text[c_match]) {
4335 c_match++;
4336 if (c_match == textlen) {
4337 result = MR_MATCHED;
4338 /* Save position and length for highlighting the field. */
4339 cf->search_pos = (uint32_t)(pd - buf_start);
4340 cf->search_len = (uint32_t)(i + 1);
4341 goto done;
4343 i++;
4344 if (pd + i >= buf_end || pd[i] != '\0') break;
4345 } else {
4346 break;
4351 done:
4352 return result;
4355 static match_result
4356 match_binary(capture_file *cf, frame_data *fdata,
4357 wtap_rec *rec, Buffer *buf, void *criterion)
4359 cbs_t *info = (cbs_t *)criterion;
4360 size_t datalen = info->data_len;
4361 match_result result;
4362 const uint8_t *pd = NULL, *buf_start;
4364 /* Load the frame's data. */
4365 if (!cf_read_record(cf, fdata, rec, buf)) {
4366 /* Attempt to get the packet failed. */
4367 return MR_ERROR;
4370 result = MR_NOTMATCHED;
4371 buf_start = ws_buffer_start_ptr(buf);
4372 size_t offset = 0;
4373 if (cf->search_len || cf->search_pos) {
4374 /* we want to start searching one byte past the previous match start */
4375 offset = cf->search_pos + 1;
4377 if (offset < fdata->cap_len) {
4378 pd = ws_memmem(buf_start + offset, fdata->cap_len - offset, info->data, datalen);
4380 if (pd != NULL) {
4381 result = MR_MATCHED;
4382 /* Save position and length for highlighting the field. */
4383 cf->search_pos = (uint32_t)(pd - buf_start);
4384 cf->search_len = (uint32_t)datalen;
4387 return result;
4390 static match_result
4391 match_binary_reverse(capture_file *cf, frame_data *fdata,
4392 wtap_rec *rec, Buffer *buf, void *criterion)
4394 cbs_t *info = (cbs_t *)criterion;
4395 size_t datalen = info->data_len;
4396 match_result result;
4397 const uint8_t *pd = NULL, *buf_start;
4399 /* Load the frame's data. */
4400 if (!cf_read_record(cf, fdata, rec, buf)) {
4401 /* Attempt to get the packet failed. */
4402 return MR_ERROR;
4405 result = MR_NOTMATCHED;
4406 buf_start = ws_buffer_start_ptr(buf);
4407 /* Has to be room to hold the sought data. */
4408 if (datalen > fdata->cap_len) {
4409 return result;
4411 pd = buf_start + fdata->cap_len - datalen;
4412 if (cf->search_len || cf->search_pos) {
4413 /* we want to start searching one byte before the previous match start */
4414 pd = buf_start + cf->search_pos - 1;
4416 for (; pd >= buf_start; pd--) {
4417 pd = (uint8_t *)ws_memrchr(buf_start, info->data[0], pd - buf_start + 1);
4418 if (pd == NULL) break;
4419 if (memcmp(pd, info->data, datalen) == 0) {
4420 result = MR_MATCHED;
4421 /* Save position and length for highlighting the field. */
4422 cf->search_pos = (uint32_t)(pd - buf_start);
4423 cf->search_len = (uint32_t)datalen;
4424 break;
4428 return result;
4431 static match_result
4432 match_regex(capture_file *cf, frame_data *fdata,
4433 wtap_rec *rec, Buffer *buf, void *criterion _U_)
4435 match_result result = MR_NOTMATCHED;
4436 size_t result_pos[2] = {0, 0};
4438 /* Load the frame's data. */
4439 if (!cf_read_record(cf, fdata, rec, buf)) {
4440 /* Attempt to get the packet failed. */
4441 return MR_ERROR;
4444 size_t offset = 0;
4445 if (cf->search_len || cf->search_pos) {
4446 /* we want to start searching one byte past the previous match start */
4447 offset = cf->search_pos + 1;
4449 if (offset < fdata->cap_len) {
4450 if (ws_regex_matches_pos(cf->regex,
4451 (const char *)ws_buffer_start_ptr(buf),
4452 fdata->cap_len, offset,
4453 result_pos)) {
4454 //TODO: A chosen regex can match the empty string (zero length)
4455 // which doesn't make a lot of sense for searching the packet bytes.
4456 // Should we search with the PCRE2_NOTEMPTY option?
4457 //TODO: Fix cast.
4458 /* Save position and length for highlighting the field. */
4459 cf->search_pos = (uint32_t)(result_pos[0]);
4460 cf->search_len = (uint32_t)(result_pos[1] - result_pos[0]);
4461 result = MR_MATCHED;
4464 return result;
4467 static match_result
4468 match_regex_reverse(capture_file *cf, frame_data *fdata,
4469 wtap_rec *rec, Buffer *buf, void *criterion _U_)
4471 match_result result = MR_NOTMATCHED;
4472 size_t result_pos[2] = {0, 0};
4474 /* Load the frame's data. */
4475 if (!cf_read_record(cf, fdata, rec, buf)) {
4476 /* Attempt to get the packet failed. */
4477 return MR_ERROR;
4480 size_t offset = fdata->cap_len - 1;
4481 if (cf->search_pos) {
4482 /* we want to start searching one byte before the previous match */
4483 offset = cf->search_pos - 1;
4485 for (; offset > 0; offset--) {
4486 if (ws_regex_matches_pos(cf->regex,
4487 (const char *)ws_buffer_start_ptr(buf),
4488 fdata->cap_len, offset,
4489 result_pos)) {
4490 //TODO: A chosen regex can match the empty string (zero length)
4491 // which doesn't make a lot of sense for searching the packet bytes.
4492 // Should we search with the PCRE2_NOTEMPTY option?
4493 //TODO: Fix cast.
4494 /* Save position and length for highlighting the field. */
4495 cf->search_pos = (uint32_t)(result_pos[0]);
4496 cf->search_len = (uint32_t)(result_pos[1] - result_pos[0]);
4497 result = MR_MATCHED;
4498 break;
4501 return result;
4504 bool
4505 cf_find_packet_dfilter(capture_file *cf, dfilter_t *sfcode,
4506 search_direction dir)
4508 return find_packet(cf, match_dfilter, sfcode, dir);
4511 bool
4512 cf_find_packet_dfilter_string(capture_file *cf, const char *filter,
4513 search_direction dir)
4515 dfilter_t *sfcode;
4516 bool result;
4518 if (!dfilter_compile(filter, &sfcode, NULL)) {
4520 * XXX - this shouldn't happen, as the filter string is machine
4521 * generated
4523 return false;
4525 if (sfcode == NULL) {
4527 * XXX - this shouldn't happen, as the filter string is machine
4528 * generated.
4530 return false;
4532 result = find_packet(cf, match_dfilter, sfcode, dir);
4533 dfilter_free(sfcode);
4534 return result;
4537 static match_result
4538 match_dfilter(capture_file *cf, frame_data *fdata,
4539 wtap_rec *rec, Buffer *buf, void *criterion)
4541 dfilter_t *sfcode = (dfilter_t *)criterion;
4542 epan_dissect_t edt;
4543 match_result result;
4545 /* Load the frame's data. */
4546 if (!cf_read_record(cf, fdata, rec, buf)) {
4547 /* Attempt to get the packet failed. */
4548 return MR_ERROR;
4551 epan_dissect_init(&edt, cf->epan, true, false);
4552 epan_dissect_prime_with_dfilter(&edt, sfcode);
4553 epan_dissect_run(&edt, cf->cd_t, rec,
4554 frame_tvbuff_new_buffer(&cf->provider, fdata, buf),
4555 fdata, NULL);
4556 result = dfilter_apply_edt(sfcode, &edt) ? MR_MATCHED : MR_NOTMATCHED;
4557 epan_dissect_cleanup(&edt);
4558 return result;
4561 bool
4562 cf_find_packet_marked(capture_file *cf, search_direction dir)
4564 return find_packet(cf, match_marked, NULL, dir);
4567 static match_result
4568 match_marked(capture_file *cf _U_, frame_data *fdata, wtap_rec *rec _U_,
4569 Buffer *buf _U_, void *criterion _U_)
4571 return fdata->marked ? MR_MATCHED : MR_NOTMATCHED;
4574 bool
4575 cf_find_packet_time_reference(capture_file *cf, search_direction dir)
4577 return find_packet(cf, match_time_reference, NULL, dir);
4580 static match_result
4581 match_time_reference(capture_file *cf _U_, frame_data *fdata, wtap_rec *rec _U_,
4582 Buffer *buf _U_, void *criterion _U_)
4584 return fdata->ref_time ? MR_MATCHED : MR_NOTMATCHED;
4587 static bool
4588 find_packet(capture_file *cf, ws_match_function match_function,
4589 void *criterion, search_direction dir)
4591 frame_data *start_fd;
4592 uint32_t framenum;
4593 uint32_t prev_framenum;
4594 frame_data *fdata;
4595 wtap_rec rec;
4596 Buffer buf;
4597 frame_data *new_fd = NULL;
4598 progdlg_t *progbar = NULL;
4599 GTimer *prog_timer = g_timer_new();
4600 int count;
4601 bool wrap = prefs.gui_find_wrap;
4602 bool succeeded;
4603 float progbar_val;
4604 char status_str[100];
4605 match_result result;
4607 wtap_rec_init(&rec);
4608 ws_buffer_init(&buf, 1514);
4610 start_fd = cf->current_frame;
4611 if (start_fd != NULL) {
4612 prev_framenum = start_fd->num;
4613 } else {
4614 prev_framenum = 0; /* No start packet selected. */
4615 wrap = false;
4618 /* Iterate through the list of packets, starting at the packet we've
4619 picked, calling a routine to run the filter on the packet, see if
4620 it matches, and stop if so. */
4621 count = 0;
4622 framenum = prev_framenum;
4623 if (framenum == 0 && dir == SD_BACKWARD) {
4624 /* If we have no start packet selected, and we're going backwards,
4625 * start at the end (even if wrap is off.)
4627 framenum = cf->count + 1;
4630 g_timer_start(prog_timer);
4631 /* Progress so far. */
4632 progbar_val = 0.0f;
4634 cf->stop_flag = false;
4636 for (;;) {
4637 /* Create the progress bar if necessary.
4638 We check on every iteration of the loop, so that it takes no
4639 longer than the standard time to create it (otherwise, for a
4640 large file, we might take considerably longer than that standard
4641 time in order to get to the next progress bar step). */
4642 if (progbar == NULL)
4643 progbar = delayed_create_progress_dlg(cf->window, NULL, NULL,
4644 false, &cf->stop_flag, progbar_val);
4647 * Update the progress bar, but do it only after PROGBAR_UPDATE_INTERVAL
4648 * has elapsed. Calling update_progress_dlg and packets_bar_update will
4649 * likely trigger UI paint events, which might take a while depending on
4650 * the platform and display. Reset our timer *after* painting.
4652 if (g_timer_elapsed(prog_timer, NULL) > PROGBAR_UPDATE_INTERVAL) {
4653 /* let's not divide by zero. I should never be started
4654 * with count == 0, so let's assert that
4656 ws_assert(cf->count > 0);
4658 progbar_val = (float) count / cf->count;
4660 snprintf(status_str, sizeof(status_str),
4661 "%4u of %u packets", count, cf->count);
4662 update_progress_dlg(progbar, progbar_val, status_str);
4664 g_timer_start(prog_timer);
4667 if (cf->stop_flag) {
4668 /* Well, the user decided to abort the search. Go back to the
4669 frame where we started. */
4670 new_fd = start_fd;
4671 break;
4674 /* Go past the current frame. */
4675 if (dir == SD_BACKWARD) {
4676 /* Go on to the previous frame. */
4677 if (framenum <= 1) {
4679 * XXX - other apps have a bit more of a detailed message
4680 * for this, and instead of offering "OK" and "Cancel",
4681 * they offer things such as "Continue" and "Cancel";
4682 * we need an API for popping up alert boxes with
4683 * {Verb} and "Cancel".
4686 if (wrap) {
4687 statusbar_push_temporary_msg("Search reached the beginning. Continuing at end.");
4688 framenum = cf->count; /* wrap around */
4689 wrap = false;
4690 } else {
4691 statusbar_push_temporary_msg("Search reached the beginning.");
4692 framenum = prev_framenum; /* stay on previous packet */
4694 } else
4695 framenum--;
4696 } else {
4697 /* Go on to the next frame. */
4698 if (framenum == cf->count) {
4699 if (wrap) {
4700 statusbar_push_temporary_msg("Search reached the end. Continuing at beginning.");
4701 framenum = 1; /* wrap around */
4702 wrap = false;
4703 } else {
4704 statusbar_push_temporary_msg("Search reached the end.");
4705 framenum = prev_framenum; /* stay on previous packet */
4707 } else
4708 framenum++;
4711 fdata = frame_data_sequence_find(cf->provider.frames, framenum);
4712 count++;
4714 /* Is this packet in the display? */
4715 if (fdata && fdata->passed_dfilter) {
4716 /* Yes. Does it match the search criterion? */
4717 result = (*match_function)(cf, fdata, &rec, &buf, criterion);
4718 if (result == MR_ERROR) {
4719 /* Error; our caller has reported the error. Go back to the frame
4720 where we started. */
4721 new_fd = start_fd;
4722 break;
4723 } else if (result == MR_MATCHED) {
4724 /* Yes. Go to the new frame. */
4725 new_fd = fdata;
4726 break;
4728 wtap_rec_reset(&rec);
4731 if (fdata == start_fd) {
4732 /* We're back to the frame we were on originally, and that frame
4733 doesn't match the search filter. The search failed. */
4734 break;
4738 /* We're done scanning the packets; destroy the progress bar if it
4739 was created. */
4740 if (progbar != NULL)
4741 destroy_progress_dlg(progbar);
4742 g_timer_destroy(prog_timer);
4744 if (new_fd != NULL) {
4745 /* We found a frame that's displayed and that matches.
4746 Try to find and select the packet summary list row for that frame. */
4747 bool found_row;
4749 cf->search_in_progress = true;
4750 found_row = packet_list_select_row_from_data(new_fd);
4751 cf->search_in_progress = false;
4752 if (!found_row) {
4753 /* We didn't find a row corresponding to this frame.
4754 This means that the frame isn't being displayed currently,
4755 so we can't select it. */
4756 cf->search_pos = 0; /* Reset the position */
4757 cf->search_len = 0; /* Reset length */
4758 simple_message_box(ESD_TYPE_INFO, NULL,
4759 "The capture file is probably not fully dissected.",
4760 "End of capture exceeded.");
4761 succeeded = false; /* The search succeeded but we didn't find the row */
4762 } else
4763 succeeded = true; /* The search succeeded and we found the row */
4764 } else
4765 succeeded = false; /* The search failed */
4766 wtap_rec_cleanup(&rec);
4767 ws_buffer_free(&buf);
4768 return succeeded;
4771 bool
4772 cf_goto_frame(capture_file *cf, unsigned fnumber, bool exact)
4774 frame_data *fdata;
4776 if (cf == NULL || cf->provider.frames == NULL) {
4777 /* we don't have a loaded capture file - fix for bugs 11810 & 11989 */
4778 statusbar_push_temporary_msg("There is no file loaded");
4779 return false; /* we failed to go to that packet */
4782 fdata = frame_data_sequence_find(cf->provider.frames, fnumber);
4784 if (fdata == NULL) {
4785 /* we didn't find a packet with that packet number */
4786 statusbar_push_temporary_msg("There is no packet number %u.", fnumber);
4787 return false; /* we failed to go to that packet */
4789 if (!fdata->passed_dfilter) {
4790 /* that packet currently isn't displayed */
4791 /* XXX - add it to the set of displayed packets? */
4792 if (cf->first_displayed == 0 || exact) {
4793 /* We only want that exact frame, or no frames are displayed. */
4794 statusbar_push_temporary_msg("Packet number %u isn't displayed.", fnumber);
4795 return false; /* we failed to go to that packet */
4797 if (fdata->prev_dis_num == 0) {
4798 /* There is no previous displayed frame, so this frame is
4799 * before the first displayed frame. Go to the first line,
4800 * which is the closest frame.
4802 fdata = NULL; /* This will select the first row. */
4803 statusbar_push_temporary_msg("Packet number %u isn't displayed, going to the first displayed packet, %u.", fnumber, cf->first_displayed);
4804 } else {
4805 uint32_t delta = fnumber - fdata->prev_dis_num;
4806 /* The next displayed frame might be closer, we can do an
4807 * O(log n) binary search for the earliest displayed frame
4808 * in the open interval (fnumber, fnumber + delta).
4810 * This is possibly overkill, we could just go to the previous
4811 * displayed frame.
4813 frame_data *fdata2;
4814 uint32_t lower_bound = fnumber + 1;
4815 uint32_t upper_bound = fnumber + delta - 1;
4816 bool found = false;
4817 while (lower_bound <= upper_bound) {
4818 uint32_t middle = (lower_bound + upper_bound) / 2;
4819 fdata2 = frame_data_sequence_find(cf->provider.frames, middle);
4820 if (fdata2 == NULL) {
4821 /* We don't have a frame of that number, so search before it. */
4822 upper_bound = middle - 1;
4823 continue;
4825 /* We have a frame of that number. What's the displayed
4826 * frame before it? */
4827 if (fdata2->prev_dis_num > fnumber) {
4828 /* The previous frame that passed the filter is also after
4829 * our target, so our answer is no later than that.
4831 upper_bound = fdata2->prev_dis_num;
4832 } else {
4833 /* The previous displayed frame is before fnumber.
4834 * (We already know fnumber itself is not displayed.)
4835 * Is this frame itself displayed?
4837 if (fdata2->passed_dfilter) {
4838 /* Yes. So this is our answer. */
4839 found = true;
4840 break;
4842 /* No. So our answer, if any, is after this frame. */
4843 lower_bound = middle + 1;
4846 if (found) {
4847 fdata = fdata2;
4848 statusbar_push_temporary_msg("Packet number %u isn't displayed, going to the next displayed packet, %u.", fnumber, fdata->num);
4849 } else {
4850 statusbar_push_temporary_msg("Packet number %u isn't displayed, going to the previous displayed packet, %u.", fnumber, fdata->prev_dis_num);
4851 fdata = frame_data_sequence_find(cf->provider.frames, fdata->prev_dis_num);
4856 if (!packet_list_select_row_from_data(fdata)) {
4857 /* We didn't find a row corresponding to this frame.
4858 This means that the frame isn't being displayed currently,
4859 so we can't select it. */
4860 simple_message_box(ESD_TYPE_INFO, NULL,
4861 "The capture file is probably not fully dissected.",
4862 "End of capture exceeded.");
4863 return false;
4865 return true; /* we got to that packet */
4869 * Go to frame specified by currently selected protocol tree item.
4871 bool
4872 cf_goto_framenum(capture_file *cf)
4874 const header_field_info *hfinfo;
4875 uint32_t framenum;
4877 if (cf->finfo_selected) {
4878 hfinfo = cf->finfo_selected->hfinfo;
4879 ws_assert(hfinfo);
4880 if (hfinfo->type == FT_FRAMENUM) {
4881 framenum = fvalue_get_uinteger(cf->finfo_selected->value);
4882 if (framenum != 0) {
4883 /* We probably only want to go to the exact match,
4884 * even though "Go to Previous Packet in History" exists.
4886 return cf_goto_frame(cf, framenum, true);
4891 return false;
4894 /* Select the packet on a given row. */
4895 void
4896 cf_select_packet(capture_file *cf, frame_data *fdata)
4898 epan_dissect_t *old_edt;
4900 /* check the frame data struct pointer for this frame */
4901 if (fdata == NULL) {
4902 return;
4905 /* Get the data in that frame. */
4906 if (!cf_read_record(cf, fdata, &cf->rec, &cf->buf)) {
4907 return;
4910 /* Record that this frame is the current frame. */
4911 cf->current_frame = fdata;
4914 * The change to defer freeing the current epan_dissect_t was in
4915 * commit a2bb94c3b33d53f42534aceb7cc67aab1d1fb1f9; to quote
4916 * that commit's comment:
4918 * Clear GtkTreeStore before freeing edt
4920 * When building current data for packet details treeview we store two
4921 * things.
4922 * - Generated string with item label
4923 * - Pointer to node field_info structure
4925 * After epan_dissect_{free, cleanup} pointer to field_info node is no
4926 * longer valid so we should clear GtkTreeStore before freeing.
4928 * XXX - we're no longer using GTK+; is there a way to ensure that
4929 * *nothing* refers to any of the current frame information before
4930 * we replace it?
4932 old_edt = cf->edt;
4933 /* Create the logical protocol tree. */
4934 /* We don't need the columns here. */
4935 cf->edt = epan_dissect_new(cf->epan, true, true);
4937 tap_build_interesting(cf->edt);
4938 epan_dissect_run(cf->edt, cf->cd_t, &cf->rec,
4939 frame_tvbuff_new_buffer(&cf->provider, cf->current_frame, &cf->buf),
4940 cf->current_frame, NULL);
4942 if (old_edt != NULL)
4943 epan_dissect_free(old_edt);
4946 /* Unselect the selected packet, if any. */
4947 void
4948 cf_unselect_packet(capture_file *cf)
4950 epan_dissect_t *old_edt = cf->edt;
4953 * See the comment in cf_select_packet() about deferring the freeing
4954 * of the old cf->edt.
4956 cf->edt = NULL;
4958 /* No packet is selected. */
4959 cf->current_frame = NULL;
4961 /* Destroy the epan_dissect_t for the unselected packet. */
4962 if (old_edt != NULL)
4963 epan_dissect_free(old_edt);
4967 * Mark a particular frame.
4969 void
4970 cf_mark_frame(capture_file *cf, frame_data *frame)
4972 if (! frame->marked) {
4973 frame->marked = true;
4974 if (cf->count > cf->marked_count)
4975 cf->marked_count++;
4980 * Unmark a particular frame.
4982 void
4983 cf_unmark_frame(capture_file *cf, frame_data *frame)
4985 if (frame->marked) {
4986 frame->marked = false;
4987 if (cf->marked_count > 0)
4988 cf->marked_count--;
4993 * Ignore a particular frame.
4995 void
4996 cf_ignore_frame(capture_file *cf, frame_data *frame)
4998 if (! frame->ignored) {
4999 frame->ignored = true;
5000 if (cf->count > cf->ignored_count)
5001 cf->ignored_count++;
5006 * Un-ignore a particular frame.
5008 void
5009 cf_unignore_frame(capture_file *cf, frame_data *frame)
5011 if (frame->ignored) {
5012 frame->ignored = false;
5013 if (cf->ignored_count > 0)
5014 cf->ignored_count--;
5019 * Modify the section comment.
5021 void
5022 cf_update_section_comment(capture_file *cf, char *comment)
5024 wtap_block_t shb_inf;
5025 char *shb_comment;
5027 /* Get the first SHB. */
5028 /* XXX - support multiple SHBs */
5029 shb_inf = wtap_file_get_shb(cf->provider.wth, 0);
5031 /* Get the first comment from the SHB. */
5032 /* XXX - support multiple comments */
5033 if (wtap_block_get_nth_string_option_value(shb_inf, OPT_COMMENT, 0, &shb_comment) != WTAP_OPTTYPE_SUCCESS) {
5034 /* There's no comment - add one. */
5035 wtap_block_add_string_option(shb_inf, OPT_COMMENT, comment, strlen(comment));
5036 } else {
5037 /* See if the comment has changed or not */
5038 if (strcmp(shb_comment, comment) == 0) {
5039 g_free(comment);
5040 return;
5043 /* The comment has changed, let's update it */
5044 wtap_block_set_nth_string_option_value(shb_inf, OPT_COMMENT, 0, comment, strlen(comment));
5046 /* Mark the file as having unsaved changes */
5047 cf->unsaved_changes = true;
5051 * Modify the section comments for a given section.
5053 void
5054 cf_update_section_comments(capture_file *cf, unsigned shb_idx, char **comments)
5056 wtap_block_t shb_inf;
5057 char *shb_comment;
5059 shb_inf = wtap_file_get_shb(cf->provider.wth, shb_idx);
5060 if (shb_inf == NULL) {
5061 /* Shouldn't happen. XXX: Report it if it does? */
5062 return;
5065 unsigned n_comments = g_strv_length(comments);
5066 unsigned i;
5067 char* comment;
5069 for (i = 0; i < n_comments; i++) {
5070 comment = comments[i];
5071 if (wtap_block_get_nth_string_option_value(shb_inf, OPT_COMMENT, i, &shb_comment) != WTAP_OPTTYPE_SUCCESS) {
5072 /* There's no comment - add one. */
5073 wtap_block_add_string_option_owned(shb_inf, OPT_COMMENT, comment);
5074 cf->unsaved_changes = true;
5075 } else {
5076 /* See if the comment has changed or not */
5077 if (strcmp(shb_comment, comment) != 0) {
5078 /* The comment has changed, let's update it */
5079 wtap_block_set_nth_string_option_value(shb_inf, OPT_COMMENT, 0, comment, strlen(comment));
5080 cf->unsaved_changes = true;
5082 g_free(comment);
5085 /* We either transferred ownership of the comments or freed them
5086 * above, so free the array of strings but not the strings themselves. */
5087 g_free(comments);
5089 /* If there are extra old comments, remove them. Start at the end. */
5090 for (i = wtap_block_count_option(shb_inf, OPT_COMMENT); i > n_comments; i--) {
5091 wtap_block_remove_nth_option_instance(shb_inf, OPT_COMMENT, i - 1);
5092 cf->unsaved_changes = true;
5097 * Get the packet block for a packet (record).
5098 * If the block has been edited, it returns the result of the edit,
5099 * otherwise it returns the block from the file.
5100 * NB. Caller must wtap_block_unref() the result when done.
5102 wtap_block_t
5103 cf_get_packet_block(capture_file *cf, const frame_data *fd)
5105 /* If this block has been modified, fetch the modified version */
5106 if (fd->has_modified_block)
5107 return wtap_block_ref(cap_file_provider_get_modified_block(&cf->provider, fd));
5108 else {
5109 wtap_rec rec; /* Record metadata */
5110 Buffer buf; /* Record data */
5111 wtap_block_t block;
5113 /* fetch record block */
5114 wtap_rec_init(&rec);
5115 ws_buffer_init(&buf, 1514);
5117 if (!cf_read_record(cf, fd, &rec, &buf))
5118 { /* XXX, what we can do here? */ }
5120 /* rec.block is owned by the record, steal it before it is gone. */
5121 block = wtap_block_ref(rec.block);
5123 wtap_rec_cleanup(&rec);
5124 ws_buffer_free(&buf);
5125 return block;
5130 * Update(replace) the block on a capture from a frame
5132 bool
5133 cf_set_modified_block(capture_file *cf, frame_data *fd, const wtap_block_t new_block)
5135 wtap_block_t pkt_block = cf_get_packet_block(cf, fd);
5137 /* It's possible to further modify the modified block "in place" by doing
5138 * a call to cf_get_packet_block() that returns an already created modified
5139 * block, modifying that, and calling this function.
5140 * If the caller did that, then the block pointers will be equal.
5142 if (pkt_block == new_block) {
5143 /* No need to save anything here, the caller changes went right
5144 * onto the block.
5145 * Unfortunately we don't have a way to know how many comments were
5146 * in the block before the caller modified it, so tell the caller
5147 * it is its responsibility to update the comment count.
5149 return false;
5151 else {
5152 if (pkt_block)
5153 cf->packet_comment_count -= wtap_block_count_option(pkt_block, OPT_COMMENT);
5155 if (new_block)
5156 cf->packet_comment_count += wtap_block_count_option(new_block, OPT_COMMENT);
5158 cap_file_provider_set_modified_block(&cf->provider, fd, new_block);
5160 expert_update_comment_count(cf->packet_comment_count);
5163 /* Either way, we have unsaved changes. */
5164 wtap_block_unref(pkt_block);
5165 cf->unsaved_changes = true;
5166 return true;
5170 * What types of comments does this capture file have?
5172 uint32_t
5173 cf_comment_types(capture_file *cf)
5175 uint32_t comment_types = 0;
5178 * Does this file have any sections with at least one comment?
5180 for (unsigned section_number = 0;
5181 section_number < wtap_file_get_num_shbs(cf->provider.wth);
5182 section_number++) {
5183 wtap_block_t shb_inf;
5184 char *shb_comment;
5186 shb_inf = wtap_file_get_shb(cf->provider.wth, section_number);
5188 /* Try to get the first comment from that SHB. */
5189 if (wtap_block_get_nth_string_option_value(shb_inf, OPT_COMMENT, 0,
5190 &shb_comment) == WTAP_OPTTYPE_SUCCESS) {
5191 /* We succeeded, so this file has at least one section comment. */
5192 comment_types |= WTAP_COMMENT_PER_SECTION;
5194 /* We don't need to search any more. */
5195 break;
5198 if (cf->packet_comment_count != 0)
5199 comment_types |= WTAP_COMMENT_PER_PACKET;
5200 return comment_types;
5204 * Add a resolved address to this file's list of resolved addresses.
5206 bool
5207 cf_add_ip_name_from_string(capture_file *cf, const char *addr, const char *name)
5210 * XXX - support multiple resolved address lists, and add to the one
5211 * attached to this file?
5213 if (!add_ip_name_from_string(addr, name))
5214 return false;
5216 /* OK, we have unsaved changes. */
5217 cf->unsaved_changes = true;
5218 return true;
5221 typedef struct {
5222 wtap_dumper *pdh;
5223 const char *fname;
5224 int file_type;
5225 bool export;
5226 } save_callback_args_t;
5229 * Save a capture to a file, in a particular format, saving either
5230 * all packets, all currently-displayed packets, or all marked packets.
5232 * Returns true if it succeeds, false otherwise; if it fails, it pops
5233 * up a message box for the failure.
5235 static bool
5236 save_record(capture_file *cf, frame_data *fdata, wtap_rec *rec,
5237 Buffer *buf, void *argsp)
5239 save_callback_args_t *args = (save_callback_args_t *)argsp;
5240 wtap_rec new_rec;
5241 int err;
5242 char *err_info;
5243 wtap_block_t pkt_block;
5245 /* Copy the record information from what was read in from the file. */
5246 new_rec = *rec;
5248 /* Make changes based on anything that the user has done but that
5249 hasn't been saved yet. */
5250 if (fdata->has_modified_block)
5251 pkt_block = cap_file_provider_get_modified_block(&cf->provider, fdata);
5252 else
5253 pkt_block = rec->block;
5254 new_rec.block = pkt_block;
5255 new_rec.block_was_modified = fdata->has_modified_block ? true : false;
5257 if (!nstime_is_zero(&fdata->shift_offset)) {
5258 if (new_rec.presence_flags & WTAP_HAS_TS) {
5259 nstime_add(&new_rec.ts, &fdata->shift_offset);
5263 /* and save the packet */
5264 if (!wtap_dump(args->pdh, &new_rec, ws_buffer_start_ptr(buf), &err, &err_info)) {
5265 report_cfile_write_failure(NULL, args->fname, err, err_info, fdata->num,
5266 args->file_type);
5267 return false;
5270 /* If we are saving (i.e., replacing the current file with the one we're
5271 * writing), then update the frame data to clear the shift offset.
5272 * This keeps us from having to re-read the entire file.
5273 * We could do this in rescan_file(), but
5274 * 1) Ideally we shouldn't have to call rescan_file if all we're doing
5275 * is changing the timestamps, since that shouldn't change the offsets.
5276 * 2) The long term goal is to try to do the offset adjustment here
5277 * instead of using rescan_file, which should be faster (#1257).
5279 * If we're exporting to a different file, then don't do that.
5281 if (!args->export && new_rec.presence_flags & WTAP_HAS_TS) {
5282 nstime_set_zero(&fdata->shift_offset);
5285 return true;
5289 * Can this capture file be written out in any format using Wiretap
5290 * rather than by copying the raw data?
5292 bool
5293 cf_can_write_with_wiretap(capture_file *cf)
5295 /* We don't care whether we support the comments in this file or not;
5296 if we can't, we'll offer the user the option of discarding the
5297 comments. */
5298 return wtap_dump_can_write(cf->linktypes, 0);
5302 * Should we let the user do a save?
5304 * We should if:
5306 * the file has unsaved changes, and we can save it in some
5307 * format through Wiretap
5309 * or
5311 * the file is a temporary file and has no unsaved changes (so
5312 * that "saving" it just means copying it).
5314 * XXX - we shouldn't allow files to be edited if they can't be saved,
5315 * so cf->unsaved_changes should be true only if the file can be saved.
5317 * We don't care whether we support the comments in this file or not;
5318 * if we can't, we'll offer the user the option of discarding the
5319 * comments.
5321 bool
5322 cf_can_save(capture_file *cf)
5324 if (cf->unsaved_changes && wtap_dump_can_write(cf->linktypes, 0)) {
5325 /* Saved changes, and we can write it out with Wiretap. */
5326 return true;
5329 if (cf->is_tempfile && !cf->unsaved_changes) {
5331 * Temporary file with no unsaved changes, so we can just do a
5332 * raw binary copy.
5334 return true;
5337 /* Nothing to save. */
5338 return false;
5342 * Should we let the user do a "save as"?
5344 * That's true if:
5346 * we can save it in some format through Wiretap
5348 * or
5350 * the file is a temporary file and has no unsaved changes (so
5351 * that "saving" it just means copying it).
5353 * XXX - we shouldn't allow files to be edited if they can't be saved,
5354 * so cf->unsaved_changes should be true only if the file can be saved.
5356 * We don't care whether we support the comments in this file or not;
5357 * if we can't, we'll offer the user the option of discarding the
5358 * comments.
5360 bool
5361 cf_can_save_as(capture_file *cf)
5363 if (wtap_dump_can_write(cf->linktypes, 0)) {
5364 /* We can write it out with Wiretap. */
5365 return true;
5368 if (cf->is_tempfile && !cf->unsaved_changes) {
5370 * Temporary file with no unsaved changes, so we can just do a
5371 * raw binary copy.
5373 return true;
5376 /* Nothing to save. */
5377 return false;
5381 * Does this file have unsaved data?
5383 bool
5384 cf_has_unsaved_data(capture_file *cf)
5387 * If this is a temporary file, or a file with unsaved changes, it
5388 * has unsaved data.
5390 return (cf->is_tempfile && cf->count>0) || cf->unsaved_changes;
5394 * Quick scan to find packet offsets.
5396 static cf_read_status_t
5397 rescan_file(capture_file *cf, const char *fname, bool is_tempfile)
5399 wtap_rec rec;
5400 Buffer buf;
5401 int err;
5402 char *err_info;
5403 char *name_ptr;
5404 int64_t data_offset;
5405 progdlg_t *progbar = NULL;
5406 GTimer *prog_timer = g_timer_new();
5407 int64_t size;
5408 float progbar_val;
5409 int64_t start_time;
5410 char status_str[100];
5411 uint32_t framenum;
5412 frame_data *fdata;
5414 /* Close the old handle. */
5415 wtap_close(cf->provider.wth);
5417 /* Open the new file. */
5418 /* XXX: this will go through all open_routines for a matching one. But right
5419 now rescan_file() is only used when a file is being saved to a different
5420 format than the original, and the user is not given a choice of which
5421 reader to use (only which format to save it in), so doing this makes
5422 sense for now. (XXX: Now it is also used when saving a changed file,
5423 e.g. comments or time-shifted frames.) */
5424 cf->provider.wth = wtap_open_offline(fname, WTAP_TYPE_AUTO, &err, &err_info, true);
5425 if (cf->provider.wth == NULL) {
5426 report_cfile_open_failure(fname, err, err_info);
5427 return CF_READ_ERROR;
5430 /* We're scanning a file whose contents should be the same as what
5431 we had before, so we don't discard dissection state etc.. */
5432 cf->f_datalen = 0;
5434 /* Set the file name because we need it to set the follow stream filter.
5435 XXX - is that still true? We need it for other reasons, though,
5436 in any case. */
5437 if (cf->filename != NULL) {
5438 g_free(cf->filename);
5440 cf->filename = g_strdup(fname);
5442 /* Indicate whether it's a permanent or temporary file. */
5443 cf->is_tempfile = is_tempfile;
5445 /* No user changes yet. */
5446 cf->unsaved_changes = false;
5448 cf->cd_t = wtap_file_type_subtype(cf->provider.wth);
5449 if (cf->linktypes != NULL) {
5450 g_array_free(cf->linktypes, TRUE);
5452 cf->linktypes = g_array_sized_new(FALSE, FALSE, (unsigned) sizeof(int), 1);
5454 cf->snap = wtap_snapshot_length(cf->provider.wth);
5456 name_ptr = g_filename_display_basename(cf->filename);
5458 cf_callback_invoke(cf_cb_file_rescan_started, cf);
5460 /* Record the file's compression type.
5461 XXX - do we know this at open time? */
5462 cf->compression_type = wtap_get_compression_type(cf->provider.wth);
5464 /* Find the size of the file. */
5465 size = wtap_file_size(cf->provider.wth, NULL);
5467 g_timer_start(prog_timer);
5469 cf->stop_flag = false;
5470 start_time = g_get_monotonic_time();
5472 framenum = 0;
5473 wtap_rec_init(&rec);
5474 ws_buffer_init(&buf, 1514);
5475 while ((wtap_read(cf->provider.wth, &rec, &buf, &err, &err_info,
5476 &data_offset))) {
5477 framenum++;
5478 fdata = frame_data_sequence_find(cf->provider.frames, framenum);
5479 if (G_LIKELY(fdata != NULL)) {
5480 fdata->file_off = data_offset;
5482 if (size >= 0) {
5483 cf->f_datalen = wtap_read_so_far(cf->provider.wth);
5485 /* Create the progress bar if necessary. */
5486 if (progress_is_slow(progbar, prog_timer, size, cf->f_datalen)) {
5487 progbar_val = calc_progbar_val(cf, size, cf->f_datalen, status_str, sizeof(status_str));
5488 progbar = delayed_create_progress_dlg(cf->window, NULL, NULL,
5489 true, &cf->stop_flag, progbar_val);
5493 * Update the progress bar, but do it only after PROGBAR_UPDATE_INTERVAL
5494 * has elapsed. Calling update_progress_dlg and packets_bar_update will
5495 * likely trigger UI paint events, which might take a while depending on
5496 * the platform and display. Reset our timer *after* painting.
5498 if (progbar && g_timer_elapsed(prog_timer, NULL) > PROGBAR_UPDATE_INTERVAL) {
5499 progbar_val = calc_progbar_val(cf, size, cf->f_datalen, status_str, sizeof(status_str));
5500 /* update the packet bar content on the first run or frequently on very large files */
5501 update_progress_dlg(progbar, progbar_val, status_str);
5502 compute_elapsed(cf, start_time);
5503 packets_bar_update();
5504 g_timer_start(prog_timer);
5508 if (cf->stop_flag) {
5509 /* Well, the user decided to abort the rescan. Sadly, as this
5510 isn't a reread, recovering is difficult, so we'll just
5511 close the current capture. */
5512 break;
5515 /* Add this packet's link-layer encapsulation type to cf->linktypes, if
5516 it's not already there.
5517 XXX - yes, this is O(N), so if every packet had a different
5518 link-layer encapsulation type, it'd be O(N^2) to read the file, but
5519 there are probably going to be a small number of encapsulation types
5520 in a file. */
5521 if (rec.rec_type == REC_TYPE_PACKET) {
5522 cf_add_encapsulation_type(cf, rec.rec_header.packet_header.pkt_encap);
5524 wtap_rec_reset(&rec);
5526 wtap_rec_cleanup(&rec);
5527 ws_buffer_free(&buf);
5529 /* Free the display name */
5530 g_free(name_ptr);
5532 /* We're done reading the file; destroy the progress bar if it was created. */
5533 if (progbar != NULL)
5534 destroy_progress_dlg(progbar);
5535 g_timer_destroy(prog_timer);
5537 /* We're done reading sequentially through the file. */
5538 cf->state = FILE_READ_DONE;
5540 /* Close the sequential I/O side, to free up memory it requires. */
5541 wtap_sequential_close(cf->provider.wth);
5543 /* compute the time it took to load the file */
5544 compute_elapsed(cf, start_time);
5546 /* Set the file encapsulation type now; we don't know what it is until
5547 we've looked at all the packets, as we don't know until then whether
5548 there's more than one type (and thus whether it's
5549 WTAP_ENCAP_PER_PACKET). */
5550 cf->lnk_t = wtap_file_encap(cf->provider.wth);
5552 cf_callback_invoke(cf_cb_file_rescan_finished, cf);
5554 if (cf->stop_flag) {
5555 /* Our caller will give up at this point. */
5556 return CF_READ_ABORTED;
5559 if (err != 0) {
5560 /* Put up a message box noting that the read failed somewhere along
5561 the line. Don't throw out the stuff we managed to read, though,
5562 if any. */
5563 report_cfile_read_failure(NULL, err, err_info);
5564 return CF_READ_ERROR;
5565 } else
5566 return CF_READ_OK;
5569 cf_write_status_t
5570 cf_save_records(capture_file *cf, const char *fname, unsigned save_format,
5571 wtap_compression_type compression_type,
5572 bool discard_comments, bool dont_reopen)
5574 char *err_info = "Unknown error";
5575 char *fname_new = NULL;
5576 wtap_dumper *pdh;
5577 frame_data *fdata;
5578 addrinfo_lists_t *addr_lists;
5579 unsigned framenum;
5580 int err;
5581 enum {
5582 SAVE_WITH_MOVE,
5583 SAVE_WITH_COPY,
5584 SAVE_WITH_WTAP
5585 } how_to_save;
5586 save_callback_args_t callback_args;
5587 callback_args.export = false;
5588 bool needs_reload = false;
5590 /* XXX caller should avoid saving the file while a read is pending
5591 * (e.g. by delaying the save action) */
5592 if (cf->read_lock) {
5593 ws_warning("cf_save_records(\"%s\") while the file is being read, potential crash ahead", fname);
5596 cf_callback_invoke(cf_cb_file_save_started, (void *)fname);
5598 addr_lists = get_addrinfo_list();
5600 if (save_format == cf->cd_t && compression_type == cf->compression_type
5601 && !discard_comments && !cf->unsaved_changes
5602 && (wtap_addrinfo_list_empty(addr_lists) || wtap_file_type_subtype_supports_block(save_format, WTAP_BLOCK_NAME_RESOLUTION) == BLOCK_NOT_SUPPORTED)) {
5603 /* We're saving in the format it's already in, and we're not discarding
5604 comments, and there are no changes we have in memory that aren't saved
5605 to the file, and we have no name resolution information to write or
5606 the file format we're saving in doesn't support writing name
5607 resolution information, so we can just move or copy the raw data. */
5609 if (cf->is_tempfile) {
5610 /* The file being saved is a temporary file from a live
5611 capture, so it doesn't need to stay around under that name;
5612 first, try renaming the capture buffer file to the new name.
5613 This acts as a "safe save", in that, if the file already
5614 exists, the existing file will be removed only if the rename
5615 succeeds.
5617 Sadly, on Windows, as we have the current capture file
5618 open, even MoveFileEx() with MOVEFILE_REPLACE_EXISTING
5619 (to cause the rename to remove an existing target), as
5620 done by ws_stdio_rename() (ws_rename() is #defined to
5621 be ws_stdio_rename() on Windows) will fail.
5623 According to the MSDN documentation for CreateFile(), if,
5624 when we open a capture file, we were to directly do a CreateFile(),
5625 opening with FILE_SHARE_DELETE|FILE_SHARE_READ, and then
5626 convert it to a file descriptor with _open_osfhandle(),
5627 that would allow the file to be renamed out from under us.
5629 However, that doesn't work in practice. Perhaps the problem
5630 is that the process doing the rename is the process that
5631 has the file open. */
5632 #ifndef _WIN32
5633 if (ws_rename(cf->filename, fname) == 0) {
5634 /* That succeeded - there's no need to copy the source file. */
5635 how_to_save = SAVE_WITH_MOVE;
5636 } else {
5637 if (errno == EXDEV) {
5638 /* They're on different file systems, so we have to copy the
5639 file. */
5640 how_to_save = SAVE_WITH_COPY;
5641 } else {
5642 /* The rename failed, but not because they're on different
5643 file systems - put up an error message. (Or should we
5644 just punt and try to copy? The only reason why I'd
5645 expect the rename to fail and the copy to succeed would
5646 be if we didn't have permission to remove the file from
5647 the temporary directory, and that might be fixable - but
5648 is it worth requiring the user to go off and fix it?) */
5649 report_rename_failure(cf->filename, fname, errno);
5650 goto fail;
5653 #else
5654 /* Windows - copy the file to its new location. */
5655 how_to_save = SAVE_WITH_COPY;
5656 #endif
5657 } else {
5658 /* It's a permanent file, so we should copy it, and not remove the
5659 original. */
5660 how_to_save = SAVE_WITH_COPY;
5663 if (how_to_save == SAVE_WITH_COPY) {
5664 /* Copy the file, if we haven't moved it. If we're overwriting
5665 an existing file, we do it with a "safe save", by writing
5666 to a new file and, if the write succeeds, renaming the
5667 new file on top of the old file. */
5668 if (file_exists(fname)) {
5669 fname_new = ws_strdup_printf("%s~", fname);
5670 if (!copy_file_binary_mode(cf->filename, fname_new))
5671 goto fail;
5672 } else {
5673 if (!copy_file_binary_mode(cf->filename, fname))
5674 goto fail;
5677 } else {
5678 /* Either we're saving in a different format or we're saving changes,
5679 such as added, modified, or removed comments, that haven't yet
5680 been written to the underlying file; we can't do that by copying
5681 or moving the capture file, we have to do it by writing the packets
5682 out in Wiretap. */
5684 wtap_dump_params params;
5685 int encap;
5687 how_to_save = SAVE_WITH_WTAP;
5688 wtap_dump_params_init(&params, cf->provider.wth);
5690 /* Determine what file encapsulation type we should use. */
5691 encap = wtap_dump_required_file_encap_type(cf->linktypes);
5692 params.encap = encap;
5694 /* Use the snaplen from cf (XXX - does wtap_dump_params_init handle that?) */
5695 params.snaplen = cf->snap;
5697 if (file_exists(fname)) {
5698 /* We're overwriting an existing file; write out to a new file,
5699 and, if that succeeds, rename the new file on top of the
5700 old file. That makes this a "safe save", so that we don't
5701 lose the old file if we have a problem writing out the new
5702 file. (If the existing file is the current capture file,
5703 we *HAVE* to do that, otherwise we're overwriting the file
5704 from which we're reading the packets that we're writing!) */
5705 fname_new = ws_strdup_printf("%s~", fname);
5706 pdh = wtap_dump_open(fname_new, save_format, compression_type, &params,
5707 &err, &err_info);
5708 } else {
5709 pdh = wtap_dump_open(fname, save_format, compression_type, &params,
5710 &err, &err_info);
5712 /* XXX idb_inf is documented to be used until wtap_dump_close. */
5713 g_free(params.idb_inf);
5714 params.idb_inf = NULL;
5716 if (pdh == NULL) {
5717 report_cfile_dump_open_failure(fname, err, err_info, save_format);
5718 goto fail;
5721 /* Add address resolution */
5722 wtap_dump_set_addrinfo_list(pdh, addr_lists);
5724 /* Iterate through the list of packets, processing all the packets. */
5725 callback_args.pdh = pdh;
5726 callback_args.fname = fname;
5727 callback_args.file_type = save_format;
5728 switch (process_specified_records(cf, NULL, "Saving", "packets",
5729 true, save_record, &callback_args, true)) {
5731 case PSP_FINISHED:
5732 /* Completed successfully. */
5733 break;
5735 case PSP_STOPPED:
5736 /* The user decided to abort the saving.
5737 If we're writing to a temporary file, remove it.
5738 XXX - should we do so even if we're not writing to a
5739 temporary file? */
5740 wtap_dump_close(pdh, NULL, &err, &err_info);
5741 if (fname_new != NULL)
5742 ws_unlink(fname_new);
5743 cf_callback_invoke(cf_cb_file_save_stopped, NULL);
5744 wtap_dump_params_cleanup(&params);
5745 return CF_WRITE_ABORTED;
5747 case PSP_FAILED:
5748 /* Error while saving.
5749 If we're writing to a temporary file, remove it. */
5750 if (fname_new != NULL)
5751 ws_unlink(fname_new);
5752 wtap_dump_close(pdh, NULL, &err, &err_info);
5753 wtap_dump_params_cleanup(&params);
5754 goto fail;
5757 if (!wtap_dump_close(pdh, &needs_reload, &err, &err_info)) {
5758 report_cfile_close_failure(fname, err, err_info);
5759 wtap_dump_params_cleanup(&params);
5760 goto fail;
5763 wtap_dump_params_cleanup(&params);
5766 if (fname_new != NULL) {
5767 /* We wrote out to fname_new, and should rename it on top of
5768 fname. fname_new is now closed, so that should be possible even
5769 on Windows. However, on Windows, we first need to close whatever
5770 file descriptors we have open for fname. */
5771 #ifdef _WIN32
5772 wtap_fdclose(cf->provider.wth);
5773 #endif
5774 /* Now do the rename. */
5775 if (ws_rename(fname_new, fname) == -1) {
5776 /* Well, the rename failed. */
5777 report_rename_failure(fname_new, fname, errno);
5778 #ifdef _WIN32
5779 /* Attempt to reopen the random file descriptor using the
5780 current file's filename. (At this point, the sequential
5781 file descriptor is closed.) */
5782 if (!wtap_fdreopen(cf->provider.wth, cf->filename, &err)) {
5783 /* Oh, well, we're screwed. */
5784 report_cfile_open_failure(cf->filename, err, NULL);
5786 #endif
5787 goto fail;
5789 g_free(fname_new);
5792 /* If this was a temporary file, and we didn't do the save by doing
5793 a move, so the tempoary file is still around under its old name,
5794 remove it. */
5795 if (cf->is_tempfile && how_to_save != SAVE_WITH_MOVE) {
5796 /* If this fails, there's not much we can do, so just ignore errors. */
5797 ws_unlink(cf->filename);
5800 cf_callback_invoke(cf_cb_file_save_finished, NULL);
5801 cf->unsaved_changes = false;
5803 if (!dont_reopen) {
5804 switch (how_to_save) {
5806 case SAVE_WITH_MOVE:
5807 /* We just moved the file, so the wtap structure refers to the
5808 new file, and all the information other than the filename
5809 and the "is temporary" status applies to the new file; just
5810 update that. */
5811 g_free(cf->filename);
5812 cf->filename = g_strdup(fname);
5813 cf->is_tempfile = false;
5814 cf_callback_invoke(cf_cb_file_fast_save_finished, cf);
5815 break;
5817 case SAVE_WITH_COPY:
5818 /* We just copied the file, so all the information other than
5819 the file descriptors, the filename, and the "is temporary"
5820 status applies to the new file; just update that. */
5821 wtap_fdclose(cf->provider.wth);
5822 /* Attempt to reopen the random file descriptor using the
5823 new file's filename. (At this point, the sequential
5824 file descriptor is closed.) */
5825 if (!wtap_fdreopen(cf->provider.wth, fname, &err)) {
5826 report_cfile_open_failure(fname, err, err_info);
5827 cf_close(cf);
5828 } else {
5829 g_free(cf->filename);
5830 cf->filename = g_strdup(fname);
5831 cf->is_tempfile = false;
5833 cf_callback_invoke(cf_cb_file_fast_save_finished, cf);
5834 break;
5836 case SAVE_WITH_WTAP:
5837 /* Open and read the file we saved to.
5839 XXX - this is somewhat of a waste; we already have the
5840 packets, all this gets us is updated file type information
5841 (which we could just stuff into "cf"), and having the new
5842 file be the one we have opened and from which we're reading
5843 the data, and it means we have to spend time opening and
5844 reading the file, which could be a significant amount of
5845 time if the file is large.
5847 If the capture-file-writing code were to return the
5848 seek offset of each packet it writes, we could save that
5849 in the frame_data structure for the frame, and just open
5850 the file without reading it again...
5852 ...as long as, for gzipped files, the process of writing
5853 out the file *also* generates the information needed to
5854 support fast random access to the compressed file. */
5855 /* rescan_file will cause us to try all open_routines, so
5856 reset cfile's open_type */
5857 cf->open_type = WTAP_TYPE_AUTO;
5858 /* There are cases when SAVE_WITH_WTAP can result in new packets
5859 being written to the file, e.g ERF records
5860 In that case, we need to reload the whole file */
5861 if(needs_reload) {
5862 if (cf_open(cf, fname, WTAP_TYPE_AUTO, false, &err) == CF_OK) {
5863 if (cf_read(cf, /*reloading=*/true) != CF_READ_OK) {
5864 /* The rescan failed; just close the file. Either
5865 a dialog was popped up for the failure, so the
5866 user knows what happened, or they stopped the
5867 rescan, in which case they know what happened. */
5868 /* XXX: This is inconsistent with normal open/reload behaviour. */
5869 cf_close(cf);
5873 else {
5874 if (rescan_file(cf, fname, false) != CF_READ_OK) {
5875 /* The rescan failed; just close the file. Either
5876 a dialog was popped up for the failure, so the
5877 user knows what happened, or they stopped the
5878 rescan, in which case they know what happened. */
5879 cf_close(cf);
5882 break;
5885 /* If we were told to discard the comments, do so. */
5886 if (discard_comments) {
5887 /* Remove SHB comment, if any. */
5888 wtap_write_shb_comment(cf->provider.wth, NULL);
5890 /* remove all user comments */
5891 for (framenum = 1; framenum <= cf->count; framenum++) {
5892 fdata = frame_data_sequence_find(cf->provider.frames, framenum);
5894 // XXX: This also ignores non-comment options like verdict
5895 fdata->has_modified_block = false;
5898 if (cf->provider.frames_modified_blocks) {
5899 g_tree_destroy(cf->provider.frames_modified_blocks);
5900 cf->provider.frames_modified_blocks = NULL;
5903 cf->packet_comment_count = 0;
5906 return CF_WRITE_OK;
5908 fail:
5909 if (fname_new != NULL) {
5910 /* We were trying to write to a temporary file; get rid of it if it
5911 exists. (We don't care whether this fails, as, if it fails,
5912 there's not much we can do about it. I guess if it failed for
5913 a reason other than "it doesn't exist", we could report an
5914 error, so the user knows there's a junk file that they might
5915 want to clean up.) */
5916 ws_unlink(fname_new);
5917 g_free(fname_new);
5919 cf_callback_invoke(cf_cb_file_save_failed, NULL);
5920 return CF_WRITE_ERROR;
5923 cf_write_status_t
5924 cf_export_specified_packets(capture_file *cf, const char *fname,
5925 packet_range_t *range, unsigned save_format,
5926 wtap_compression_type compression_type)
5928 char *fname_new = NULL;
5929 int err;
5930 char *err_info;
5931 wtap_dumper *pdh;
5932 save_callback_args_t callback_args;
5933 wtap_dump_params params;
5934 int encap;
5936 callback_args.export = true;
5937 packet_range_process_init(range);
5939 /* We're writing out specified packets from the specified capture
5940 file to another file. Even if all captured packets are to be
5941 written, don't special-case the operation - read each packet
5942 and then write it out if it's one of the specified ones. */
5944 wtap_dump_params_init(&params, cf->provider.wth);
5946 /* Determine what file encapsulation type we should use. */
5947 encap = wtap_dump_required_file_encap_type(cf->linktypes);
5948 params.encap = encap;
5950 /* Use the snaplen from cf (XXX - does wtap_dump_params_init handle that?) */
5951 params.snaplen = cf->snap;
5953 if (file_exists(fname)) {
5954 /* We're overwriting an existing file; write out to a new file,
5955 and, if that succeeds, rename the new file on top of the
5956 old file. That makes this a "safe save", so that we don't
5957 lose the old file if we have a problem writing out the new
5958 file. (If the existing file is the current capture file,
5959 we *HAVE* to do that, otherwise we're overwriting the file
5960 from which we're reading the packets that we're writing!) */
5961 fname_new = ws_strdup_printf("%s~", fname);
5962 pdh = wtap_dump_open(fname_new, save_format, compression_type, &params,
5963 &err, &err_info);
5964 } else {
5965 pdh = wtap_dump_open(fname, save_format, compression_type, &params,
5966 &err, &err_info);
5968 /* XXX idb_inf is documented to be used until wtap_dump_close. */
5969 g_free(params.idb_inf);
5970 params.idb_inf = NULL;
5972 if (pdh == NULL) {
5973 report_cfile_dump_open_failure(fname, err, err_info, save_format);
5974 goto fail;
5977 /* Add address resolution */
5978 wtap_dump_set_addrinfo_list(pdh, get_addrinfo_list());
5980 /* Iterate through the list of packets, processing the packets we were
5981 told to process.
5983 XXX - we've already called "packet_range_process_init(range)", but
5984 "process_specified_records()" will do it again. Fortunately,
5985 that's harmless in this case, as we haven't done anything to
5986 "range" since we initialized it. */
5987 callback_args.pdh = pdh;
5988 callback_args.fname = fname;
5989 callback_args.file_type = save_format;
5990 switch (process_specified_records(cf, range, "Writing", "specified records",
5991 true, save_record, &callback_args, true)) {
5993 case PSP_FINISHED:
5994 /* Completed successfully. */
5995 break;
5997 case PSP_STOPPED:
5998 /* The user decided to abort the saving.
5999 If we're writing to a temporary file, remove it.
6000 XXX - should we do so even if we're not writing to a
6001 temporary file? */
6002 wtap_dump_close(pdh, NULL, &err, &err_info);
6003 if (fname_new != NULL) {
6004 ws_unlink(fname_new);
6005 g_free(fname_new);
6007 wtap_dump_params_cleanup(&params);
6009 return CF_WRITE_ABORTED;
6011 case PSP_FAILED:
6012 /* Error while saving. */
6013 wtap_dump_close(pdh, NULL, &err, &err_info);
6015 * We don't report any error from closing; the error that caused
6016 * process_specified_records() to fail has already been reported.
6018 goto fail;
6021 if (!wtap_dump_close(pdh, NULL, &err, &err_info)) {
6022 report_cfile_close_failure(fname, err, err_info);
6023 goto fail;
6026 if (fname_new != NULL) {
6027 /* We wrote out to fname_new, and should rename it on top of
6028 fname; fname is now closed, so that should be possible even
6029 on Windows. Do the rename. */
6030 if (ws_rename(fname_new, fname) == -1) {
6031 /* Well, the rename failed. */
6032 report_rename_failure(fname_new, fname, errno);
6033 goto fail;
6035 g_free(fname_new);
6037 wtap_dump_params_cleanup(&params);
6039 return CF_WRITE_OK;
6041 fail:
6042 if (fname_new != NULL) {
6043 /* We were trying to write to a temporary file; get rid of it if it
6044 exists. (We don't care whether this fails, as, if it fails,
6045 there's not much we can do about it. I guess if it failed for
6046 a reason other than "it doesn't exist", we could report an
6047 error, so the user knows there's a junk file that they might
6048 want to clean up.) */
6049 ws_unlink(fname_new);
6050 g_free(fname_new);
6052 wtap_dump_params_cleanup(&params);
6054 return CF_WRITE_ERROR;
6057 /* Reload the current capture file. */
6058 cf_status_t
6059 cf_reload(capture_file *cf)
6061 char *filename;
6062 bool is_tempfile;
6063 cf_status_t cf_status = CF_OK;
6064 int err;
6066 if (cf->read_lock) {
6067 ws_warning("Failing cf_reload(\"%s\") since a read is in progress", cf->filename);
6068 return CF_ERROR;
6071 /* If the file could be opened, "cf_open()" calls "cf_close()"
6072 to get rid of state for the old capture file before filling in state
6073 for the new capture file. "cf_close()" will remove the file if
6074 it's a temporary file; we don't want that to happen (for one thing,
6075 it'd prevent subsequent reopens from working). Remember whether it's
6076 a temporary file, mark it as not being a temporary file, and then
6077 reopen it as the type of file it was.
6079 Also, "cf_close()" will free "cf->filename", so we must make
6080 a copy of it first. */
6081 filename = g_strdup(cf->filename);
6082 is_tempfile = cf->is_tempfile;
6083 cf->is_tempfile = false;
6084 if (cf_open(cf, filename, cf->open_type, is_tempfile, &err) == CF_OK) {
6085 switch (cf_read(cf, /*reloading=*/true)) {
6087 case CF_READ_OK:
6088 case CF_READ_ERROR:
6089 /* Just because we got an error, that doesn't mean we were unable
6090 to read any of the file; we handle what we could get from the
6091 file. */
6092 break;
6094 case CF_READ_ABORTED:
6095 /* The user bailed out of re-reading the capture file; the
6096 capture file has been closed. */
6097 break;
6099 } else {
6100 /* The open failed, so "cf->is_tempfile" wasn't set to "is_tempfile".
6101 Instead, the file was left open, so we should restore "cf->is_tempfile"
6102 ourselves.
6104 XXX - change the menu? Presumably "cf_open()" will do that;
6105 make sure it does! */
6106 cf->is_tempfile = is_tempfile;
6107 cf_status = CF_ERROR;
6109 /* "cf_open()" made a copy of the file name we handed it, so
6110 we should free up our copy. */
6111 g_free(filename);
6112 return cf_status;