6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@ethereal.com>
8 * Copyright 1998 Gerald Combs
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
50 #ifdef NEED_STRERROR_H
54 #include <epan/epan.h>
55 #include <epan/filesystem.h>
58 #include "color_filters.h"
59 #include <epan/column.h>
60 #include <epan/packet.h>
61 #include "packet-range.h"
67 #include "alert_box.h"
68 #include "simple_dialog.h"
69 #include "progress_dlg.h"
71 #include <epan/prefs.h>
72 #include <epan/dfilter/dfilter.h>
73 #include <epan/conversation.h>
74 #include <epan/epan_dissect.h>
76 #include "stat_menu.h"
77 #include "tap_dfilter_dlg.h"
78 #include <epan/dissectors/packet-data.h>
79 #include <epan/timestamp.h>
82 /* Win32 needs the O_BINARY flag for open() */
88 gboolean auto_scroll_live;
91 static nstime_t first_ts;
92 static nstime_t prev_ts;
93 static guint32 cum_bytes = 0;
95 static void cf_reset_state(capture_file *cf);
97 static void read_packet(capture_file *cf, long offset);
99 static void rescan_packets(capture_file *cf, const char *action, const char *action_item,
100 gboolean refilter, gboolean redissect);
102 static gboolean match_protocol_tree(capture_file *cf, frame_data *fdata,
104 static void match_subtree_text(proto_node *node, gpointer data);
105 static gboolean match_summary_line(capture_file *cf, frame_data *fdata,
107 static gboolean match_ascii_and_unicode(capture_file *cf, frame_data *fdata,
109 static gboolean match_ascii(capture_file *cf, frame_data *fdata,
111 static gboolean match_unicode(capture_file *cf, frame_data *fdata,
113 static gboolean match_binary(capture_file *cf, frame_data *fdata,
115 static gboolean match_dfilter(capture_file *cf, frame_data *fdata,
117 static gboolean find_packet(capture_file *cf,
118 gboolean (*match_function)(capture_file *, frame_data *, void *),
121 static void cf_open_failure_alert_box(const char *filename, int err,
122 gchar *err_info, gboolean for_writing,
124 static const char *file_rename_error_message(int err);
125 static void cf_write_failure_alert_box(const char *filename, int err);
126 static void cf_close_failure_alert_box(const char *filename, int err);
127 static gboolean copy_binary_file(const char *from_filename, const char *to_filename);
129 /* Update the progress bar this many times when reading a file. */
130 #define N_PROGBAR_UPDATES 100
132 /* Number of "frame_data" structures per memory chunk.
133 XXX - is this the right number? */
134 #define FRAME_DATA_CHUNK_SIZE 1024
137 /* one callback for now, we could have a list later */
138 static cf_callback_t cf_cb = NULL;
139 static gpointer cf_cb_user_data = NULL;
142 cf_callback_invoke(int event, gpointer data)
144 g_assert(cf_cb != NULL);
145 cf_cb(event, data, cf_cb_user_data);
150 cf_callback_add(cf_callback_t func, gpointer user_data)
152 /* More than one callback listener is currently not implemented,
153 but should be easy to do. */
154 g_assert(cf_cb == NULL);
156 cf_cb_user_data = user_data;
160 cf_callback_remove(cf_callback_t func _U_)
162 g_assert(cf_cb != NULL);
164 cf_cb_user_data = NULL;
168 cf_timestamp_auto_precision(capture_file *cf)
170 int prec = timestamp_get_precision();
173 /* don't try to get the file's precision if none is opened */
174 if(cf->state == FILE_CLOSED) {
178 /* if we are in auto mode, set precision of current file */
179 if(prec == TS_PREC_AUTO ||
180 prec == TS_PREC_AUTO_SEC ||
181 prec == TS_PREC_AUTO_DSEC ||
182 prec == TS_PREC_AUTO_CSEC ||
183 prec == TS_PREC_AUTO_MSEC ||
184 prec == TS_PREC_AUTO_USEC ||
185 prec == TS_PREC_AUTO_NSEC)
187 switch(wtap_file_tsprecision(cf->wth)) {
188 case(WTAP_FILE_TSPREC_SEC):
189 timestamp_set_precision(TS_PREC_AUTO_SEC);
191 case(WTAP_FILE_TSPREC_DSEC):
192 timestamp_set_precision(TS_PREC_AUTO_DSEC);
194 case(WTAP_FILE_TSPREC_CSEC):
195 timestamp_set_precision(TS_PREC_AUTO_CSEC);
197 case(WTAP_FILE_TSPREC_MSEC):
198 timestamp_set_precision(TS_PREC_AUTO_MSEC);
200 case(WTAP_FILE_TSPREC_USEC):
201 timestamp_set_precision(TS_PREC_AUTO_USEC);
203 case(WTAP_FILE_TSPREC_NSEC):
204 timestamp_set_precision(TS_PREC_AUTO_NSEC);
207 g_assert_not_reached();
214 cf_open(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
219 wth = wtap_open_offline(fname, err, &err_info, TRUE);
223 /* The open succeeded. Close whatever capture file we had open,
224 and fill in the information for this file. */
227 /* Initialize all data structures used for dissection. */
230 /* We're about to start reading the file. */
231 cf->state = FILE_READ_IN_PROGRESS;
236 /* Set the file name because we need it to set the follow stream filter.
237 XXX - is that still true? We need it for other reasons, though,
239 cf->filename = g_strdup(fname);
241 /* Indicate whether it's a permanent or temporary file. */
242 cf->is_tempfile = is_tempfile;
244 /* If it's a temporary capture buffer file, mark it as not saved. */
245 cf->user_saved = !is_tempfile;
247 cf->cd_t = wtap_file_type(cf->wth);
249 cf->displayed_count = 0;
250 cf->marked_count = 0;
251 cf->drops_known = FALSE;
253 cf->snap = wtap_snapshot_length(cf->wth);
255 /* Snapshot length not known. */
256 cf->has_snap = FALSE;
257 cf->snap = WTAP_MAX_PACKET_SIZE;
260 nstime_set_zero(&cf->elapsed_time);
261 nstime_set_zero(&first_ts);
262 nstime_set_zero(&prev_ts);
264 cf->plist_chunk = g_mem_chunk_new("frame_data_chunk",
266 FRAME_DATA_CHUNK_SIZE * sizeof(frame_data),
268 g_assert(cf->plist_chunk);
270 /* change the time formats now, as we might have a new precision */
271 cf_change_time_formats(cf);
273 fileset_file_opened(fname);
278 cf_open_failure_alert_box(fname, *err, err_info, FALSE, 0);
284 * Reset the state for the currently closed file, but don't do the
285 * UI callbacks; this is for use in "cf_open()", where we don't
286 * want the UI to go from "file open" to "file closed" back to
287 * "file open", we want it to go from "old file open" to "new file
288 * open and being read".
291 cf_reset_state(capture_file *cf)
293 /* Die if we're in the middle of reading a file. */
294 g_assert(cf->state != FILE_READ_IN_PROGRESS);
300 /* We have no file open... */
301 if (cf->filename != NULL) {
302 /* If it's a temporary file, remove it. */
304 unlink(cf->filename);
305 g_free(cf->filename);
308 /* ...which means we have nothing to save. */
309 cf->user_saved = FALSE;
311 if (cf->plist_chunk != NULL) {
312 g_mem_chunk_destroy(cf->plist_chunk);
313 cf->plist_chunk = NULL;
315 if (cf->rfcode != NULL) {
316 dfilter_free(cf->rfcode);
320 cf->plist_end = NULL;
321 cf_unselect_packet(cf); /* nothing to select */
322 cf->first_displayed = NULL;
323 cf->last_displayed = NULL;
325 /* No frame selected, no field in that frame selected. */
326 cf->current_frame = NULL;
327 cf->finfo_selected = NULL;
329 /* Clear the packet list. */
330 packet_list_freeze();
336 nstime_set_zero(&cf->elapsed_time);
338 reset_tap_listeners();
340 /* We have no file open. */
341 cf->state = FILE_CLOSED;
343 fileset_file_closed();
346 /* Reset everything to a pristine state */
348 cf_close(capture_file *cf)
350 /* do GUI things even if file is already closed,
351 * e.g. to cleanup things if a capture couldn't be started */
352 cf_callback_invoke(cf_cb_file_closing, cf);
354 /* close things, if not already closed before */
355 if(cf->state != FILE_CLOSED) {
359 cleanup_dissection();
362 cf_callback_invoke(cf_cb_file_closed, cf);
366 cf_read(capture_file *cf)
370 const gchar *name_ptr;
372 char errmsg_errno[1024+1];
373 gchar err_str[2048+1];
375 progdlg_t *progbar = NULL;
377 gint64 size, file_pos;
380 gchar status_str[100];
381 gint64 progbar_nextstep;
382 gint64 progbar_quantum;
386 reset_tap_listeners();
387 tap_dfilter_dlg_update();
389 cf_callback_invoke(cf_cb_file_read_start, cf);
391 name_ptr = get_basename(cf->filename);
393 /* Find the size of the file. */
394 size = wtap_file_size(cf->wth, NULL);
396 /* Update the progress bar when it gets to this value. */
397 progbar_nextstep = 0;
398 /* When we reach the value that triggers a progress bar update,
399 bump that value by this amount. */
401 progbar_quantum = size/N_PROGBAR_UPDATES;
404 /* Progress so far. */
407 packet_list_freeze();
410 g_get_current_time(&start_time);
412 while ((wtap_read(cf->wth, &err, &err_info, &data_offset))) {
414 /* Create the progress bar if necessary.
415 We check on every iteration of the loop, so that it takes no
416 longer than the standard time to create it (otherwise, for a
417 large file, we might take considerably longer than that standard
418 time in order to get to the next progress bar step). */
419 if (progbar == NULL) {
420 progbar = delayed_create_progress_dlg("Loading", name_ptr,
421 &stop_flag, &start_time, progbar_val);
424 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
425 when we update it, we have to run the GTK+ main loop to get it
426 to repaint what's pending, and doing so may involve an "ioctl()"
427 to see if there's any pending input from an X server, and doing
428 that for every packet can be costly, especially on a big file. */
429 if (data_offset >= progbar_nextstep) {
430 file_pos = wtap_read_so_far(cf->wth, NULL);
431 progbar_val = (gfloat) file_pos / (gfloat) size;
432 if (progbar_val > 1.0) {
433 /* The file probably grew while we were reading it.
434 Update file size, and try again. */
435 size = wtap_file_size(cf->wth, NULL);
437 progbar_val = (gfloat) file_pos / (gfloat) size;
438 /* If it's still > 1, either "wtap_file_size()" failed (in which
439 case there's not much we can do about it), or the file
440 *shrank* (in which case there's not much we can do about
441 it); just clip the progress value at 1.0. */
442 if (progbar_val > 1.0)
445 if (progbar != NULL) {
446 g_snprintf(status_str, sizeof(status_str),
447 "%" PRId64 "KB of %" PRId64 "KB",
448 file_pos / 1024, size / 1024);
449 update_progress_dlg(progbar, progbar_val, status_str);
451 progbar_nextstep += progbar_quantum;
456 /* Well, the user decided to abort the read. Destroy the progress
457 bar, close the capture file, and return CF_READ_ABORTED so our caller
458 can do whatever is appropriate when that happens. */
459 destroy_progress_dlg(progbar);
460 cf->state = FILE_READ_ABORTED; /* so that we're allowed to close it */
461 packet_list_thaw(); /* undo our freeze */
463 return CF_READ_ABORTED;
465 read_packet(cf, data_offset);
468 /* We're done reading the file; destroy the progress bar if it was created. */
470 destroy_progress_dlg(progbar);
472 /* We're done reading sequentially through the file. */
473 cf->state = FILE_READ_DONE;
475 /* Close the sequential I/O side, to free up memory it requires. */
476 wtap_sequential_close(cf->wth);
478 /* Allow the protocol dissectors to free up memory that they
479 * don't need after the sequential run-through of the packets. */
480 postseq_cleanup_all_protocols();
482 /* Set the file encapsulation type now; we don't know what it is until
483 we've looked at all the packets, as we don't know until then whether
484 there's more than one type (and thus whether it's
485 WTAP_ENCAP_PER_PACKET). */
486 cf->lnk_t = wtap_file_encap(cf->wth);
488 cf->current_frame = cf->first_displayed;
491 cf_callback_invoke(cf_cb_file_read_finished, cf);
493 /* If we have any displayed packets to select, select the first of those
494 packets by making the first row the selected row. */
495 if (cf->first_displayed != NULL)
496 packet_list_select_row(0);
499 /* Put up a message box noting that the read failed somewhere along
500 the line. Don't throw out the stuff we managed to read, though,
504 case WTAP_ERR_UNSUPPORTED_ENCAP:
505 g_snprintf(errmsg_errno, sizeof(errmsg_errno),
506 "The capture file has a packet with a network type that Ethereal doesn't support.\n(%s)",
509 errmsg = errmsg_errno;
512 case WTAP_ERR_CANT_READ:
513 errmsg = "An attempt to read from the capture file failed for"
514 " some unknown reason.";
517 case WTAP_ERR_SHORT_READ:
518 errmsg = "The capture file appears to have been cut short"
519 " in the middle of a packet.";
522 case WTAP_ERR_BAD_RECORD:
523 g_snprintf(errmsg_errno, sizeof(errmsg_errno),
524 "The capture file appears to be damaged or corrupt.\n(%s)",
527 errmsg = errmsg_errno;
531 g_snprintf(errmsg_errno, sizeof(errmsg_errno),
532 "An error occurred while reading the"
533 " capture file: %s.", wtap_strerror(err));
534 errmsg = errmsg_errno;
537 g_snprintf(err_str, sizeof err_str, errmsg);
538 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, err_str);
539 return CF_READ_ERROR;
546 cf_start_tail(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
548 cf_status_t cf_status;
550 cf_status = cf_open(cf, fname, is_tempfile, err);
555 cf_continue_tail(capture_file *cf, int to_read, int *err)
557 long data_offset = 0;
562 packet_list_freeze();
564 /*g_log(NULL, G_LOG_LEVEL_MESSAGE, "cf_continue_tail: %u new: %u", cf->count, to_read);*/
566 while (to_read != 0 && (wtap_read(cf->wth, err, &err_info, &data_offset))) {
567 if (cf->state == FILE_READ_ABORTED) {
568 /* Well, the user decided to exit Ethereal. Break out of the
569 loop, and let the code below (which is called even if there
570 aren't any packets left to read) exit. */
573 read_packet(cf, data_offset);
577 /*g_log(NULL, G_LOG_LEVEL_MESSAGE, "cf_continue_tail: count %u state: %u err: %u",
578 cf->count, cf->state, *err);*/
580 /* XXX - this cheats and looks inside the packet list to find the final
582 if (auto_scroll_live && cf->plist_end != NULL)
583 packet_list_moveto_end();
587 if (cf->state == FILE_READ_ABORTED) {
588 /* Well, the user decided to exit Ethereal. Return CF_READ_ABORTED
589 so that our caller can kill off the capture child process;
590 this will cause an EOF on the pipe from the child, so
591 "cf_finish_tail()" will be called, and it will clean up
593 return CF_READ_ABORTED;
594 } else if (*err != 0) {
595 /* We got an error reading the capture file.
596 XXX - pop up a dialog box instead? */
597 g_warning("Error \"%s\" while reading: \"%s\"\n",
598 wtap_strerror(*err), cf->filename);
600 return CF_READ_ERROR;
606 cf_finish_tail(capture_file *cf, int *err)
611 if(cf->wth == NULL) {
613 return CF_READ_ERROR;
616 packet_list_freeze();
618 while ((wtap_read(cf->wth, err, &err_info, &data_offset))) {
619 if (cf->state == FILE_READ_ABORTED) {
620 /* Well, the user decided to abort the read. Break out of the
621 loop, and let the code below (which is called even if there
622 aren't any packets left to read) exit. */
625 read_packet(cf, data_offset);
630 if (cf->state == FILE_READ_ABORTED) {
631 /* Well, the user decided to abort the read. We're only called
632 when the child capture process closes the pipe to us (meaning
633 it's probably exited), so we can just close the capture
634 file; we return CF_READ_ABORTED so our caller can do whatever
635 is appropriate when that happens. */
637 return CF_READ_ABORTED;
640 if (auto_scroll_live && cf->plist_end != NULL)
641 /* XXX - this cheats and looks inside the packet list to find the final
643 packet_list_moveto_end();
645 /* We're done reading sequentially through the file. */
646 cf->state = FILE_READ_DONE;
648 /* We're done reading sequentially through the file; close the
649 sequential I/O side, to free up memory it requires. */
650 wtap_sequential_close(cf->wth);
652 /* Allow the protocol dissectors to free up memory that they
653 * don't need after the sequential run-through of the packets. */
654 postseq_cleanup_all_protocols();
656 /* Set the file encapsulation type now; we don't know what it is until
657 we've looked at all the packets, as we don't know until then whether
658 there's more than one type (and thus whether it's
659 WTAP_ENCAP_PER_PACKET). */
660 cf->lnk_t = wtap_file_encap(cf->wth);
663 /* We got an error reading the capture file.
664 XXX - pop up a dialog box? */
665 return CF_READ_ERROR;
670 #endif /* HAVE_LIBPCAP */
673 cf_get_display_name(capture_file *cf)
675 const gchar *displayname;
677 /* Return a name to use in displays */
678 if (!cf->is_tempfile) {
679 /* Get the last component of the file name, and use that. */
681 displayname = get_basename(cf->filename);
683 displayname="(No file)";
686 /* The file we read is a temporary file from a live capture;
687 we don't mention its name. */
688 displayname = "(Untitled)";
693 /* XXX - use a macro instead? */
695 cf_packet_count(capture_file *cf)
700 /* XXX - use a macro instead? */
702 cf_is_tempfile(capture_file *cf)
704 return cf->is_tempfile;
707 void cf_set_tempfile(capture_file *cf, gboolean is_tempfile)
709 cf->is_tempfile = is_tempfile;
713 /* XXX - use a macro instead? */
714 void cf_set_drops_known(capture_file *cf, gboolean drops_known)
716 cf->drops_known = drops_known;
719 /* XXX - use a macro instead? */
720 void cf_set_drops(capture_file *cf, guint32 drops)
725 /* XXX - use a macro instead? */
726 gboolean cf_get_drops_known(capture_file *cf)
728 return cf->drops_known;
731 /* XXX - use a macro instead? */
732 guint32 cf_get_drops(capture_file *cf)
737 void cf_set_rfcode(capture_file *cf, dfilter_t *rfcode)
743 add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
744 union wtap_pseudo_header *pseudo_header, const guchar *buf,
748 gboolean create_proto_tree = FALSE;
751 /* just add some value here until we know if it is being displayed or not */
752 fdata->cum_bytes = cum_bytes + fdata->pkt_len;
754 /* If we don't have the time stamp of the first packet in the
755 capture, it's because this is the first packet. Save the time
756 stamp of this packet as the time stamp of the first packet. */
757 if (nstime_is_zero(&first_ts)) {
758 first_ts = fdata->abs_ts;
760 /* if this frames is marked as a reference time frame, reset
761 firstsec and firstusec to this frame */
762 if(fdata->flags.ref_time){
763 first_ts = fdata->abs_ts;
766 /* If we don't have the time stamp of the previous displayed packet,
767 it's because this is the first displayed packet. Save the time
768 stamp of this packet as the time stamp of the previous displayed
770 if (nstime_is_zero(&prev_ts)) {
771 prev_ts = fdata->abs_ts;
774 /* Get the time elapsed between the first packet and this packet. */
775 nstime_delta(&fdata->rel_ts, &fdata->abs_ts, &first_ts);
777 /* If it's greater than the current elapsed time, set the elapsed time
778 to it (we check for "greater than" so as not to be confused by
779 time moving backwards). */
780 if ((gint32)cf->elapsed_time.secs < fdata->rel_ts.secs
781 || ((gint32)cf->elapsed_time.secs == fdata->rel_ts.secs && (gint32)cf->elapsed_time.nsecs < fdata->rel_ts.nsecs)) {
782 cf->elapsed_time = fdata->rel_ts;
785 /* Get the time elapsed between the previous displayed packet and
787 nstime_delta(&fdata->del_ts, &fdata->abs_ts, &prev_ts);
791 we have a display filter and are re-applying it;
793 we have a list of color filters;
795 we have tap listeners;
797 allocate a protocol tree root node, so that we'll construct
798 a protocol tree against which a filter expression can be
800 if ((cf->dfcode != NULL && refilter) || color_filters_used()
801 || num_tap_filters != 0)
802 create_proto_tree = TRUE;
804 /* Dissect the frame. */
805 edt = epan_dissect_new(create_proto_tree, FALSE);
807 if (cf->dfcode != NULL && refilter) {
808 epan_dissect_prime_dfilter(edt, cf->dfcode);
810 if (color_filters_used()) {
811 color_filters_prime_edt(edt);
814 epan_dissect_run(edt, pseudo_header, buf, fdata, &cf->cinfo);
815 tap_push_tapped_queue(edt);
817 /* If we have a display filter, apply it if we're refiltering, otherwise
818 leave the "passed_dfilter" flag alone.
820 If we don't have a display filter, set "passed_dfilter" to 1. */
821 if (cf->dfcode != NULL) {
823 fdata->flags.passed_dfilter = dfilter_apply_edt(cf->dfcode, edt) ? 1 : 0;
826 fdata->flags.passed_dfilter = 1;
828 if( (fdata->flags.passed_dfilter)
829 || (edt->pi.fd->flags.ref_time) ){
830 /* This frame either passed the display filter list or is marked as
831 a time reference frame. All time reference frames are displayed
832 even if they dont pass the display filter */
833 /* if this was a TIME REF frame we should reset the cul bytes field */
834 if(edt->pi.fd->flags.ref_time){
835 cum_bytes = fdata->pkt_len;
836 fdata->cum_bytes = cum_bytes;
839 /* increase cum_bytes with this packets length */
840 cum_bytes += fdata->pkt_len;
842 epan_dissect_fill_in_columns(edt);
844 /* If we haven't yet seen the first frame, this is it.
846 XXX - we must do this before we add the row to the display,
847 as, if the display's GtkCList's selection mode is
848 GTK_SELECTION_BROWSE, when the first entry is added to it,
849 "cf_select_packet()" will be called, and it will fetch the row
850 data for the 0th row, and will get a null pointer rather than
851 "fdata", as "gtk_clist_append()" won't yet have returned and
852 thus "gtk_clist_set_row_data()" won't yet have been called.
854 We thus need to leave behind bread crumbs so that
855 "cf_select_packet()" can find this frame. See the comment
856 in "cf_select_packet()". */
857 if (cf->first_displayed == NULL)
858 cf->first_displayed = fdata;
860 /* This is the last frame we've seen so far. */
861 cf->last_displayed = fdata;
863 row = packet_list_append(cf->cinfo.col_data, fdata);
865 /* colorize packet: if packet is marked, use preferences,
866 otherwise try to apply color filters */
867 if (fdata->flags.marked) {
868 fdata->color_filter = NULL;
869 packet_list_set_colors(row, &prefs.gui_marked_fg, &prefs.gui_marked_bg);
871 fdata->color_filter = color_filters_colorize_packet(row, edt);
874 /* Set the time of the previous displayed frame to the time of this
876 prev_ts = fdata->abs_ts;
878 cf->displayed_count++;
880 /* This frame didn't pass the display filter, so it's not being added
881 to the clist, and thus has no row. */
884 epan_dissect_free(edt);
889 read_packet(capture_file *cf, long offset)
891 const struct wtap_pkthdr *phdr = wtap_phdr(cf->wth);
892 union wtap_pseudo_header *pseudo_header = wtap_pseudoheader(cf->wth);
893 const guchar *buf = wtap_buf_ptr(cf->wth);
896 frame_data *plist_end;
899 /* Allocate the next list entry, and add it to the list. */
900 fdata = g_mem_chunk_alloc(cf->plist_chunk);
906 fdata->pkt_len = phdr->len;
907 fdata->cap_len = phdr->caplen;
908 fdata->file_off = offset;
909 fdata->lnk_t = phdr->pkt_encap;
910 fdata->flags.encoding = CHAR_ASCII;
911 fdata->flags.visited = 0;
912 fdata->flags.marked = 0;
913 fdata->flags.ref_time = 0;
915 fdata->abs_ts = *((nstime_t *) &phdr->ts);
919 edt = epan_dissect_new(TRUE, FALSE);
920 epan_dissect_prime_dfilter(edt, cf->rfcode);
921 epan_dissect_run(edt, pseudo_header, buf, fdata, NULL);
922 passed = dfilter_apply_edt(cf->rfcode, edt);
923 epan_dissect_free(edt);
926 plist_end = cf->plist_end;
927 fdata->prev = plist_end;
928 if (plist_end != NULL)
929 plist_end->next = fdata;
932 cf->plist_end = fdata;
935 cf->f_datalen = offset + phdr->caplen;
936 fdata->num = cf->count;
937 add_packet_to_packet_list(fdata, cf, pseudo_header, buf, TRUE);
939 /* XXX - if we didn't have read filters, or if we could avoid
940 allocating the "frame_data" structure until we knew whether
941 the frame passed the read filter, we could use a G_ALLOC_ONLY
944 ...but, at least in one test I did, where I just made the chunk
945 a G_ALLOC_ONLY chunk and read in a huge capture file, it didn't
946 seem to save a noticeable amount of time or space. */
947 g_mem_chunk_free(cf->plist_chunk, fdata);
952 cf_merge_files(char **out_filenamep, int in_file_count,
953 char *const *in_filenames, int file_type, gboolean do_append)
955 merge_in_file_t *in_files;
961 int open_err, read_err, write_err, close_err;
965 char errmsg_errno[1024+1];
966 gchar err_str[2048+1];
968 gboolean got_read_error = FALSE, got_write_error = FALSE;
970 progdlg_t *progbar = NULL;
972 gint64 f_len, file_pos;
975 gchar status_str[100];
976 gint64 progbar_nextstep;
977 gint64 progbar_quantum;
979 /* open the input files */
980 if (!merge_open_in_files(in_file_count, in_filenames, &in_files,
981 &open_err, &err_info, &err_fileno)) {
983 cf_open_failure_alert_box(in_filenames[err_fileno], open_err, err_info,
988 if (*out_filenamep != NULL) {
989 out_filename = *out_filenamep;
990 out_fd = open(out_filename, O_CREAT|O_TRUNC|O_BINARY, 0600);
994 out_fd = create_tempfile(tmpname, sizeof tmpname, "ether");
997 out_filename = g_strdup(tmpname);
998 *out_filenamep = out_filename;
1002 merge_close_in_files(in_file_count, in_files);
1004 cf_open_failure_alert_box(out_filename, open_err, NULL, TRUE, file_type);
1008 pdh = wtap_dump_fdopen(out_fd, file_type,
1009 merge_select_frame_type(in_file_count, in_files),
1010 merge_max_snapshot_length(in_file_count, in_files),
1011 FALSE /* compressed */, &open_err);
1014 merge_close_in_files(in_file_count, in_files);
1016 cf_open_failure_alert_box(out_filename, open_err, err_info, TRUE,
1021 /* Get the sum of the sizes of all the files. */
1023 for (i = 0; i < in_file_count; i++)
1024 f_len += in_files[i].size;
1026 /* Update the progress bar when it gets to this value. */
1027 progbar_nextstep = 0;
1028 /* When we reach the value that triggers a progress bar update,
1029 bump that value by this amount. */
1030 progbar_quantum = f_len/N_PROGBAR_UPDATES;
1031 /* Progress so far. */
1035 g_get_current_time(&start_time);
1037 /* do the merge (or append) */
1040 wth = merge_append_read_packet(in_file_count, in_files, &read_err,
1043 wth = merge_read_packet(in_file_count, in_files, &read_err,
1047 got_read_error = TRUE;
1051 /* Get the sum of the data offsets in all of the files. */
1053 for (i = 0; i < in_file_count; i++)
1054 data_offset += in_files[i].data_offset;
1056 /* Create the progress bar if necessary.
1057 We check on every iteration of the loop, so that it takes no
1058 longer than the standard time to create it (otherwise, for a
1059 large file, we might take considerably longer than that standard
1060 time in order to get to the next progress bar step). */
1061 if (progbar == NULL) {
1062 progbar = delayed_create_progress_dlg("Merging", "files",
1063 &stop_flag, &start_time, progbar_val);
1066 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
1067 when we update it, we have to run the GTK+ main loop to get it
1068 to repaint what's pending, and doing so may involve an "ioctl()"
1069 to see if there's any pending input from an X server, and doing
1070 that for every packet can be costly, especially on a big file. */
1071 if (data_offset >= progbar_nextstep) {
1072 /* Get the sum of the seek positions in all of the files. */
1074 for (i = 0; i < in_file_count; i++)
1075 file_pos += wtap_read_so_far(in_files[i].wth, NULL);
1076 progbar_val = (gfloat) file_pos / (gfloat) f_len;
1077 if (progbar_val > 1.0) {
1078 /* Some file probably grew while we were reading it.
1079 That "shouldn't happen", so we'll just clip the progress
1083 if (progbar != NULL) {
1084 g_snprintf(status_str, sizeof(status_str),
1085 "%" PRId64 "KB of %" PRId64 "KB",
1086 file_pos / 1024, f_len / 1024);
1087 update_progress_dlg(progbar, progbar_val, status_str);
1089 progbar_nextstep += progbar_quantum;
1092 if (!wtap_dump(pdh, wtap_phdr(wth), wtap_pseudoheader(wth),
1093 wtap_buf_ptr(wth), &write_err)) {
1094 got_write_error = TRUE;
1099 /* We're done merging the files; destroy the progress bar if it was created. */
1100 if (progbar != NULL)
1101 destroy_progress_dlg(progbar);
1103 merge_close_in_files(in_file_count, in_files);
1104 if (!got_read_error && !got_write_error) {
1105 if (!wtap_dump_close(pdh, &write_err))
1106 got_write_error = TRUE;
1108 wtap_dump_close(pdh, &close_err);
1110 if (got_read_error) {
1112 * Find the file on which we got the error, and report the error.
1114 for (i = 0; i < in_file_count; i++) {
1115 if (in_files[i].state == GOT_ERROR) {
1116 /* Put up a message box noting that a read failed somewhere along
1120 case WTAP_ERR_UNSUPPORTED_ENCAP:
1121 g_snprintf(errmsg_errno, sizeof(errmsg_errno),
1122 "The capture file %%s has a packet with a network type that Ethereal doesn't support.\n(%s)",
1125 errmsg = errmsg_errno;
1128 case WTAP_ERR_CANT_READ:
1129 errmsg = "An attempt to read from the capture file %s failed for"
1130 " some unknown reason.";
1133 case WTAP_ERR_SHORT_READ:
1134 errmsg = "The capture file %s appears to have been cut short"
1135 " in the middle of a packet.";
1138 case WTAP_ERR_BAD_RECORD:
1139 g_snprintf(errmsg_errno, sizeof(errmsg_errno),
1140 "The capture file %%s appears to be damaged or corrupt.\n(%s)",
1143 errmsg = errmsg_errno;
1147 g_snprintf(errmsg_errno, sizeof(errmsg_errno),
1148 "An error occurred while reading the"
1149 " capture file %%s: %s.", wtap_strerror(read_err));
1150 errmsg = errmsg_errno;
1153 g_snprintf(err_str, sizeof err_str, errmsg, in_files[i].filename);
1154 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, err_str);
1159 if (got_write_error) {
1160 /* Put up an alert box for the write error. */
1161 cf_write_failure_alert_box(out_filename, write_err);
1164 return (!got_read_error && !got_write_error) ? CF_OK : CF_ERROR;
1168 cf_filter_packets(capture_file *cf, gchar *dftext, gboolean force)
1171 const char *filter_new = dftext ? dftext : "";
1172 const char *filter_old = cf->dfilter ? cf->dfilter : "";
1174 /* if new filter equals old one, do nothing unless told to do so */
1175 if (!force && strcmp(filter_new, filter_old) == 0) {
1179 if (dftext == NULL) {
1180 /* The new filter is an empty filter (i.e., display all packets). */
1184 * We have a filter; make a copy of it (as we'll be saving it),
1185 * and try to compile it.
1187 dftext = g_strdup(dftext);
1188 if (!dfilter_compile(dftext, &dfcode)) {
1189 /* The attempt failed; report an error. */
1190 gchar *safe_dftext = simple_dialog_format_message(dftext);
1191 gchar *safe_dfilter_error_msg = simple_dialog_format_message(
1193 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1196 "The following display filter isn't a valid display filter:\n%s\n"
1197 "See the help for a description of the display filter syntax.",
1198 simple_dialog_primary_start(), safe_dfilter_error_msg,
1199 simple_dialog_primary_end(), safe_dftext);
1200 g_free(safe_dfilter_error_msg);
1201 g_free(safe_dftext);
1207 if (dfcode == NULL) {
1208 /* Yes - free the filter text, and set it to null. */
1214 /* We have a valid filter. Replace the current filter. */
1215 if (cf->dfilter != NULL)
1216 g_free(cf->dfilter);
1217 cf->dfilter = dftext;
1218 if (cf->dfcode != NULL)
1219 dfilter_free(cf->dfcode);
1220 cf->dfcode = dfcode;
1222 /* Now rescan the packet list, applying the new filter, but not
1223 throwing away information constructed on a previous pass. */
1224 if (dftext == NULL) {
1225 rescan_packets(cf, "Resetting", "Filter", TRUE, FALSE);
1227 rescan_packets(cf, "Filtering", dftext, TRUE, FALSE);
1233 cf_colorize_packets(capture_file *cf)
1235 rescan_packets(cf, "Colorizing", "all packets", FALSE, FALSE);
1239 cf_reftime_packets(capture_file *cf)
1241 rescan_packets(cf, "Updating Reftime", "all packets", FALSE, FALSE);
1245 cf_redissect_packets(capture_file *cf)
1247 rescan_packets(cf, "Reprocessing", "all packets", TRUE, TRUE);
1250 /* Rescan the list of packets, reconstructing the CList.
1252 "action" describes why we're doing this; it's used in the progress
1255 "action_item" describes what we're doing; it's used in the progress
1258 "refilter" is TRUE if we need to re-evaluate the filter expression.
1260 "redissect" is TRUE if we need to make the dissectors reconstruct
1261 any state information they have (because a preference that affects
1262 some dissector has changed, meaning some dissector might construct
1263 its state differently from the way it was constructed the last time). */
1265 rescan_packets(capture_file *cf, const char *action, const char *action_item,
1266 gboolean refilter, gboolean redissect)
1269 progdlg_t *progbar = NULL;
1274 frame_data *selected_frame, *preceding_frame, *following_frame, *prev_frame;
1275 int selected_row, prev_row, preceding_row, following_row;
1276 gboolean selected_frame_seen;
1279 GTimeVal start_time;
1280 gchar status_str[100];
1281 int progbar_nextstep;
1282 int progbar_quantum;
1285 reset_tap_listeners();
1286 /* Which frame, if any, is the currently selected frame?
1287 XXX - should the selected frame or the focus frame be the "current"
1288 frame, that frame being the one from which "Find Frame" searches
1290 selected_frame = cf->current_frame;
1292 /* We don't yet know what row that frame will be on, if any, after we
1293 rebuild the clist, however. */
1297 /* We need to re-initialize all the state information that protocols
1298 keep, because some preference that controls a dissector has changed,
1299 which might cause the state information to be constructed differently
1300 by that dissector. */
1302 /* Initialize all data structures used for dissection. */
1306 /* Freeze the packet list while we redo it, so we don't get any
1307 screen updates while it happens. */
1308 packet_list_freeze();
1311 packet_list_clear();
1313 /* We don't yet know which will be the first and last frames displayed. */
1314 cf->first_displayed = NULL;
1315 cf->last_displayed = NULL;
1317 /* We currently don't display any packets */
1318 cf->displayed_count = 0;
1320 /* Iterate through the list of frames. Call a routine for each frame
1321 to check whether it should be displayed and, if so, add it to
1322 the display list. */
1323 nstime_set_zero(&first_ts);
1324 nstime_set_zero(&prev_ts);
1326 /* Update the progress bar when it gets to this value. */
1327 progbar_nextstep = 0;
1328 /* When we reach the value that triggers a progress bar update,
1329 bump that value by this amount. */
1330 progbar_quantum = cf->count/N_PROGBAR_UPDATES;
1331 /* Count of packets at which we've looked. */
1333 /* Progress so far. */
1337 g_get_current_time(&start_time);
1339 row = -1; /* no previous row yet */
1344 preceding_frame = NULL;
1346 following_frame = NULL;
1348 selected_frame_seen = FALSE;
1350 for (fdata = cf->plist; fdata != NULL; fdata = fdata->next) {
1351 /* Create the progress bar if necessary.
1352 We check on every iteration of the loop, so that it takes no
1353 longer than the standard time to create it (otherwise, for a
1354 large file, we might take considerably longer than that standard
1355 time in order to get to the next progress bar step). */
1356 if (progbar == NULL)
1357 progbar = delayed_create_progress_dlg(action, action_item, &stop_flag,
1358 &start_time, progbar_val);
1360 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
1361 when we update it, we have to run the GTK+ main loop to get it
1362 to repaint what's pending, and doing so may involve an "ioctl()"
1363 to see if there's any pending input from an X server, and doing
1364 that for every packet can be costly, especially on a big file. */
1365 if (count >= progbar_nextstep) {
1366 /* let's not divide by zero. I should never be started
1367 * with count == 0, so let's assert that
1369 g_assert(cf->count > 0);
1370 progbar_val = (gfloat) count / cf->count;
1372 if (progbar != NULL) {
1373 g_snprintf(status_str, sizeof(status_str),
1374 "%4u of %u frames", count, cf->count);
1375 update_progress_dlg(progbar, progbar_val, status_str);
1378 progbar_nextstep += progbar_quantum;
1382 /* Well, the user decided to abort the filtering. Just stop.
1384 XXX - go back to the previous filter? Users probably just
1385 want not to wait for a filtering operation to finish;
1386 unless we cancel by having no filter, reverting to the
1387 previous filter will probably be even more expensive than
1388 continuing the filtering, as it involves going back to the
1389 beginning and filtering, and even with no filter we currently
1390 have to re-generate the entire clist, which is also expensive.
1392 I'm not sure what Network Monitor does, but it doesn't appear
1393 to give you an unfiltered display if you cancel. */
1400 /* Since all state for the frame was destroyed, mark the frame
1401 * as not visited, free the GSList referring to the state
1402 * data (the per-frame data itself was freed by
1403 * "init_dissection()"), and null out the GSList pointer. */
1404 fdata->flags.visited = 0;
1406 g_slist_free(fdata->pfd);
1411 if (!wtap_seek_read (cf->wth, fdata->file_off, &cf->pseudo_header,
1412 cf->pd, fdata->cap_len, &err, &err_info)) {
1413 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1414 cf_read_error_message(err, err_info), cf->filename);
1418 /* If the previous frame is displayed, and we haven't yet seen the
1419 selected frame, remember that frame - it's the closest one we've
1420 yet seen before the selected frame. */
1421 if (prev_row != -1 && !selected_frame_seen) {
1422 preceding_row = prev_row;
1423 preceding_frame = prev_frame;
1425 row = add_packet_to_packet_list(fdata, cf, &cf->pseudo_header, cf->pd,
1428 /* If this frame is displayed, and this is the first frame we've
1429 seen displayed after the selected frame, remember this frame -
1430 it's the closest one we've yet seen at or after the selected
1432 if (row != -1 && selected_frame_seen && following_row == -1) {
1433 following_row = row;
1434 following_frame = fdata;
1436 if (fdata == selected_frame) {
1438 selected_frame_seen = TRUE;
1441 /* Remember this row/frame - it'll be the previous row/frame
1442 on the next pass through the loop. */
1448 /* Clear out what remains of the visited flags and per-frame data
1451 XXX - that may cause various forms of bogosity when dissecting
1452 these frames, as they won't have been seen by this sequential
1453 pass, but the only alternative I see is to keep scanning them
1454 even though the user requested that the scan stop, and that
1455 would leave the user stuck with an Ethereal grinding on
1456 until it finishes. Should we just stick them with that? */
1457 for (; fdata != NULL; fdata = fdata->next) {
1458 fdata->flags.visited = 0;
1460 g_slist_free(fdata->pfd);
1466 /* We're done filtering the packets; destroy the progress bar if it
1468 if (progbar != NULL)
1469 destroy_progress_dlg(progbar);
1471 /* Unfreeze the packet list. */
1474 if (selected_row == -1) {
1475 /* The selected frame didn't pass the filter. */
1476 if (selected_frame == NULL) {
1477 /* That's because there *was* no selected frame. Make the first
1478 displayed frame the current frame. */
1481 /* Find the nearest displayed frame to the selected frame (whether
1482 it's before or after that frame) and make that the current frame.
1483 If the next and previous displayed frames are equidistant from the
1484 selected frame, choose the next one. */
1485 g_assert(following_frame == NULL ||
1486 following_frame->num >= selected_frame->num);
1487 g_assert(preceding_frame == NULL ||
1488 preceding_frame->num <= selected_frame->num);
1489 if (following_frame == NULL) {
1490 /* No frame after the selected frame passed the filter, so we
1491 have to select the last displayed frame before the selected
1493 selected_row = preceding_row;
1494 } else if (preceding_frame == NULL) {
1495 /* No frame before the selected frame passed the filter, so we
1496 have to select the first displayed frame after the selected
1498 selected_row = following_row;
1500 /* Choose the closer of the last displayed frame before the
1501 selected frame and the first displayed frame after the
1502 selected frame; in case of a tie, choose the first displayed
1503 frame after the selected frame. */
1504 if (following_frame->num - selected_frame->num <=
1505 selected_frame->num - preceding_frame->num) {
1506 selected_row = following_row;
1508 /* The previous frame is closer to the selected frame than the
1510 selected_row = preceding_row;
1516 if (selected_row == -1) {
1517 /* There are no frames displayed at all. */
1518 cf_unselect_packet(cf);
1520 /* Either the frame that was selected passed the filter, or we've
1521 found the nearest displayed frame to that frame. Select it, make
1522 it the focus row, and make it visible. */
1523 packet_list_set_selected_row(selected_row);
1534 process_specified_packets(capture_file *cf, packet_range_t *range,
1535 const char *string1, const char *string2,
1536 gboolean (*callback)(capture_file *, frame_data *,
1537 union wtap_pseudo_header *, const guint8 *, void *),
1538 void *callback_args)
1543 union wtap_pseudo_header pseudo_header;
1544 guint8 pd[WTAP_MAX_PACKET_SIZE+1];
1545 psp_return_t ret = PSP_FINISHED;
1547 progdlg_t *progbar = NULL;
1550 gboolean progbar_stop_flag;
1551 GTimeVal progbar_start_time;
1552 gchar progbar_status_str[100];
1553 int progbar_nextstep;
1554 int progbar_quantum;
1555 range_process_e process_this;
1557 /* Update the progress bar when it gets to this value. */
1558 progbar_nextstep = 0;
1559 /* When we reach the value that triggers a progress bar update,
1560 bump that value by this amount. */
1561 progbar_quantum = cf->count/N_PROGBAR_UPDATES;
1562 /* Count of packets at which we've looked. */
1564 /* Progress so far. */
1567 progbar_stop_flag = FALSE;
1568 g_get_current_time(&progbar_start_time);
1570 packet_range_process_init(range);
1572 /* Iterate through the list of packets, printing the packets that
1573 were selected by the current display filter. */
1574 for (fdata = cf->plist; fdata != NULL; fdata = fdata->next) {
1575 /* Create the progress bar if necessary.
1576 We check on every iteration of the loop, so that it takes no
1577 longer than the standard time to create it (otherwise, for a
1578 large file, we might take considerably longer than that standard
1579 time in order to get to the next progress bar step). */
1580 if (progbar == NULL)
1581 progbar = delayed_create_progress_dlg(string1, string2,
1583 &progbar_start_time,
1586 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
1587 when we update it, we have to run the GTK+ main loop to get it
1588 to repaint what's pending, and doing so may involve an "ioctl()"
1589 to see if there's any pending input from an X server, and doing
1590 that for every packet can be costly, especially on a big file. */
1591 if (progbar_count >= progbar_nextstep) {
1592 /* let's not divide by zero. I should never be started
1593 * with count == 0, so let's assert that
1595 g_assert(cf->count > 0);
1596 progbar_val = (gfloat) progbar_count / cf->count;
1598 if (progbar != NULL) {
1599 g_snprintf(progbar_status_str, sizeof(progbar_status_str),
1600 "%4u of %u packets", progbar_count, cf->count);
1601 update_progress_dlg(progbar, progbar_val, progbar_status_str);
1604 progbar_nextstep += progbar_quantum;
1607 if (progbar_stop_flag) {
1608 /* Well, the user decided to abort the operation. Just stop,
1609 and arrange to return TRUE to our caller, so they know it
1610 was stopped explicitly. */
1617 /* do we have to process this packet? */
1618 process_this = packet_range_process_packet(range, fdata);
1619 if (process_this == range_process_next) {
1620 /* this packet uninteresting, continue with next one */
1622 } else if (process_this == range_processing_finished) {
1623 /* all interesting packets processed, stop the loop */
1627 /* Get the packet */
1628 if (!wtap_seek_read(cf->wth, fdata->file_off, &pseudo_header,
1629 pd, fdata->cap_len, &err, &err_info)) {
1630 /* Attempt to get the packet failed. */
1631 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1632 cf_read_error_message(err, err_info), cf->filename);
1636 /* Process the packet */
1637 if (!callback(cf, fdata, &pseudo_header, pd, callback_args)) {
1638 /* Callback failed. We assume it reported the error appropriately. */
1644 /* We're done printing the packets; destroy the progress bar if
1646 if (progbar != NULL)
1647 destroy_progress_dlg(progbar);
1653 retap_packet(capture_file *cf _U_, frame_data *fdata,
1654 union wtap_pseudo_header *pseudo_header, const guint8 *pd,
1657 column_info *cinfo = argsp;
1658 epan_dissect_t *edt;
1660 /* If we have tap listeners, allocate a protocol tree root node, so that
1661 we'll construct a protocol tree against which a filter expression can
1663 edt = epan_dissect_new(num_tap_filters != 0, FALSE);
1664 tap_queue_init(edt);
1665 epan_dissect_run(edt, pseudo_header, pd, fdata, cinfo);
1666 tap_push_tapped_queue(edt);
1667 epan_dissect_free(edt);
1673 cf_retap_packets(capture_file *cf, gboolean do_columns)
1675 packet_range_t range;
1677 /* Reset the tap listeners. */
1678 reset_tap_listeners();
1680 /* Iterate through the list of packets, dissecting all packets and
1681 re-running the taps. */
1682 packet_range_init(&range);
1683 packet_range_process_init(&range);
1684 switch (process_specified_packets(cf, &range, "Refiltering statistics on",
1685 "all packets", retap_packet,
1686 do_columns ? &cf->cinfo : NULL)) {
1688 /* Completed successfully. */
1692 /* Well, the user decided to abort the refiltering.
1693 Return CF_READ_ABORTED so our caller knows they did that. */
1694 return CF_READ_ABORTED;
1697 /* Error while retapping. */
1698 return CF_READ_ERROR;
1701 g_assert_not_reached();
1706 print_args_t *print_args;
1707 gboolean print_header_line;
1708 char *header_line_buf;
1709 int header_line_buf_len;
1710 gboolean print_formfeed;
1711 gboolean print_separator;
1715 } print_callback_args_t;
1718 print_packet(capture_file *cf, frame_data *fdata,
1719 union wtap_pseudo_header *pseudo_header, const guint8 *pd,
1722 print_callback_args_t *args = argsp;
1723 epan_dissect_t *edt;
1729 gboolean proto_tree_needed;
1730 char bookmark_name[9+10+1]; /* "__frameNNNNNNNNNN__\0" */
1731 char bookmark_title[6+10+1]; /* "Frame NNNNNNNNNN__\0" */
1733 /* Create the protocol tree, and make it visible, if we're printing
1734 the dissection or the hex data.
1735 XXX - do we need it if we're just printing the hex data? */
1737 args->print_args->print_dissections != print_dissections_none || args->print_args->print_hex;
1738 edt = epan_dissect_new(proto_tree_needed, proto_tree_needed);
1740 /* Fill in the column information if we're printing the summary
1742 if (args->print_args->print_summary) {
1743 epan_dissect_run(edt, pseudo_header, pd, fdata, &cf->cinfo);
1744 epan_dissect_fill_in_columns(edt);
1746 epan_dissect_run(edt, pseudo_header, pd, fdata, NULL);
1748 if (args->print_formfeed) {
1749 if (!new_page(args->print_args->stream))
1752 if (args->print_separator) {
1753 if (!print_line(args->print_args->stream, 0, ""))
1759 * We generate bookmarks, if the output format supports them.
1760 * The name is "__frameN__".
1762 g_snprintf(bookmark_name, sizeof bookmark_name, "__frame%u__", fdata->num);
1764 if (args->print_args->print_summary) {
1765 if (args->print_header_line) {
1766 if (!print_line(args->print_args->stream, 0, args->header_line_buf))
1768 args->print_header_line = FALSE; /* we might not need to print any more */
1770 cp = &args->line_buf[0];
1772 for (i = 0; i < cf->cinfo.num_cols; i++) {
1773 /* Find the length of the string for this column. */
1774 column_len = strlen(cf->cinfo.col_data[i]);
1775 if (args->col_widths[i] > column_len)
1776 column_len = args->col_widths[i];
1778 /* Make sure there's room in the line buffer for the column; if not,
1779 double its length. */
1780 line_len += column_len + 1; /* "+1" for space */
1781 if (line_len > args->line_buf_len) {
1782 cp_off = cp - args->line_buf;
1783 args->line_buf_len = 2 * line_len;
1784 args->line_buf = g_realloc(args->line_buf, args->line_buf_len + 1);
1785 cp = args->line_buf + cp_off;
1788 /* Right-justify the packet number column. */
1789 if (cf->cinfo.col_fmt[i] == COL_NUMBER)
1790 sprintf(cp, "%*s", args->col_widths[i], cf->cinfo.col_data[i]);
1792 sprintf(cp, "%-*s", args->col_widths[i], cf->cinfo.col_data[i]);
1794 if (i != cf->cinfo.num_cols - 1)
1800 * Generate a bookmark, using the summary line as the title.
1802 if (!print_bookmark(args->print_args->stream, bookmark_name,
1806 if (!print_line(args->print_args->stream, 0, args->line_buf))
1810 * Generate a bookmark, using "Frame N" as the title, as we're not
1811 * printing the summary line.
1813 g_snprintf(bookmark_title, sizeof bookmark_title, "Frame %u", fdata->num);
1814 if (!print_bookmark(args->print_args->stream, bookmark_name,
1817 } /* if (print_summary) */
1819 if (args->print_args->print_dissections != print_dissections_none) {
1820 if (args->print_args->print_summary) {
1821 /* Separate the summary line from the tree with a blank line. */
1822 if (!print_line(args->print_args->stream, 0, ""))
1826 /* Print the information in that tree. */
1827 if (!proto_tree_print(args->print_args, edt, args->print_args->stream))
1830 /* Print a blank line if we print anything after this (aka more than one packet). */
1831 args->print_separator = TRUE;
1833 /* Print a header line if we print any more packet summaries */
1834 args->print_header_line = TRUE;
1837 if (args->print_args->print_hex) {
1838 /* Print the full packet data as hex. */
1839 if (!print_hex_data(args->print_args->stream, edt))
1842 /* Print a blank line if we print anything after this (aka more than one packet). */
1843 args->print_separator = TRUE;
1845 /* Print a header line if we print any more packet summaries */
1846 args->print_header_line = TRUE;
1847 } /* if (args->print_args->print_dissections != print_dissections_none) */
1849 epan_dissect_free(edt);
1851 /* do we want to have a formfeed between each packet from now on? */
1852 if(args->print_args->print_formfeed) {
1853 args->print_formfeed = TRUE;
1859 epan_dissect_free(edt);
1864 cf_print_packets(capture_file *cf, print_args_t *print_args)
1867 print_callback_args_t callback_args;
1875 callback_args.print_args = print_args;
1876 callback_args.print_header_line = TRUE;
1877 callback_args.header_line_buf = NULL;
1878 callback_args.header_line_buf_len = 256;
1879 callback_args.print_formfeed = FALSE;
1880 callback_args.print_separator = FALSE;
1881 callback_args.line_buf = NULL;
1882 callback_args.line_buf_len = 256;
1883 callback_args.col_widths = NULL;
1885 if (!print_preamble(print_args->stream, cf->filename)) {
1886 destroy_print_stream(print_args->stream);
1887 return CF_PRINT_WRITE_ERROR;
1890 if (print_args->print_summary) {
1891 /* We're printing packet summaries. Allocate the header line buffer
1892 and get the column widths. */
1893 callback_args.header_line_buf = g_malloc(callback_args.header_line_buf_len + 1);
1895 /* Find the widths for each of the columns - maximum of the
1896 width of the title and the width of the data - and construct
1897 a buffer with a line containing the column titles. */
1898 callback_args.col_widths = (gint *) g_malloc(sizeof(gint) * cf->cinfo.num_cols);
1899 cp = &callback_args.header_line_buf[0];
1901 for (i = 0; i < cf->cinfo.num_cols; i++) {
1902 /* Don't pad the last column. */
1903 if (i == cf->cinfo.num_cols - 1)
1904 callback_args.col_widths[i] = 0;
1906 callback_args.col_widths[i] = strlen(cf->cinfo.col_title[i]);
1907 data_width = get_column_char_width(get_column_format(i));
1908 if (data_width > callback_args.col_widths[i])
1909 callback_args.col_widths[i] = data_width;
1912 /* Find the length of the string for this column. */
1913 column_len = strlen(cf->cinfo.col_title[i]);
1914 if (callback_args.col_widths[i] > column_len)
1915 column_len = callback_args.col_widths[i];
1917 /* Make sure there's room in the line buffer for the column; if not,
1918 double its length. */
1919 line_len += column_len + 1; /* "+1" for space */
1920 if (line_len > callback_args.header_line_buf_len) {
1921 cp_off = cp - callback_args.header_line_buf;
1922 callback_args.header_line_buf_len = 2 * line_len;
1923 callback_args.header_line_buf = g_realloc(callback_args.header_line_buf,
1924 callback_args.header_line_buf_len + 1);
1925 cp = callback_args.header_line_buf + cp_off;
1928 /* Right-justify the packet number column. */
1929 /* if (cf->cinfo.col_fmt[i] == COL_NUMBER)
1930 sprintf(cp, "%*s", callback_args.col_widths[i], cf->cinfo.col_title[i]);
1932 sprintf(cp, "%-*s", callback_args.col_widths[i], cf->cinfo.col_title[i]);
1934 if (i != cf->cinfo.num_cols - 1)
1939 /* Now start out the main line buffer with the same length as the
1940 header line buffer. */
1941 callback_args.line_buf_len = callback_args.header_line_buf_len;
1942 callback_args.line_buf = g_malloc(callback_args.line_buf_len + 1);
1943 } /* if (print_summary) */
1945 /* Iterate through the list of packets, printing the packets we were
1947 ret = process_specified_packets(cf, &print_args->range, "Printing",
1948 "selected packets", print_packet,
1951 if (callback_args.header_line_buf != NULL)
1952 g_free(callback_args.header_line_buf);
1953 if (callback_args.line_buf != NULL)
1954 g_free(callback_args.line_buf);
1955 if (callback_args.col_widths != NULL)
1956 g_free(callback_args.col_widths);
1961 /* Completed successfully. */
1965 /* Well, the user decided to abort the printing.
1967 XXX - note that what got generated before they did that
1968 will get printed if we're piping to a print program; we'd
1969 have to write to a file and then hand that to the print
1970 program to make it actually not print anything. */
1974 /* Error while printing.
1976 XXX - note that what got generated before they did that
1977 will get printed if we're piping to a print program; we'd
1978 have to write to a file and then hand that to the print
1979 program to make it actually not print anything. */
1980 destroy_print_stream(print_args->stream);
1981 return CF_PRINT_WRITE_ERROR;
1984 if (!print_finale(print_args->stream)) {
1985 destroy_print_stream(print_args->stream);
1986 return CF_PRINT_WRITE_ERROR;
1989 if (!destroy_print_stream(print_args->stream))
1990 return CF_PRINT_WRITE_ERROR;
1996 write_pdml_packet(capture_file *cf _U_, frame_data *fdata,
1997 union wtap_pseudo_header *pseudo_header, const guint8 *pd,
2001 epan_dissect_t *edt;
2003 /* Create the protocol tree, but don't fill in the column information. */
2004 edt = epan_dissect_new(TRUE, TRUE);
2005 epan_dissect_run(edt, pseudo_header, pd, fdata, NULL);
2007 /* Write out the information in that tree. */
2008 proto_tree_write_pdml(edt, fh);
2010 epan_dissect_free(edt);
2016 cf_write_pdml_packets(capture_file *cf, print_args_t *print_args)
2021 fh = fopen(print_args->file, "w");
2023 return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
2025 write_pdml_preamble(fh);
2028 return CF_PRINT_WRITE_ERROR;
2031 /* Iterate through the list of packets, printing the packets we were
2033 ret = process_specified_packets(cf, &print_args->range, "Writing PDML",
2034 "selected packets", write_pdml_packet,
2040 /* Completed successfully. */
2044 /* Well, the user decided to abort the printing. */
2048 /* Error while printing. */
2050 return CF_PRINT_WRITE_ERROR;
2053 write_pdml_finale(fh);
2056 return CF_PRINT_WRITE_ERROR;
2059 /* XXX - check for an error */
2066 write_psml_packet(capture_file *cf, frame_data *fdata,
2067 union wtap_pseudo_header *pseudo_header, const guint8 *pd,
2071 epan_dissect_t *edt;
2073 /* Fill in the column information, but don't create the protocol tree. */
2074 edt = epan_dissect_new(FALSE, FALSE);
2075 epan_dissect_run(edt, pseudo_header, pd, fdata, &cf->cinfo);
2076 epan_dissect_fill_in_columns(edt);
2078 /* Write out the information in that tree. */
2079 proto_tree_write_psml(edt, fh);
2081 epan_dissect_free(edt);
2087 cf_write_psml_packets(capture_file *cf, print_args_t *print_args)
2092 fh = fopen(print_args->file, "w");
2094 return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
2096 write_psml_preamble(fh);
2099 return CF_PRINT_WRITE_ERROR;
2102 /* Iterate through the list of packets, printing the packets we were
2104 ret = process_specified_packets(cf, &print_args->range, "Writing PSML",
2105 "selected packets", write_psml_packet,
2111 /* Completed successfully. */
2115 /* Well, the user decided to abort the printing. */
2119 /* Error while printing. */
2121 return CF_PRINT_WRITE_ERROR;
2124 write_psml_finale(fh);
2127 return CF_PRINT_WRITE_ERROR;
2130 /* XXX - check for an error */
2137 write_csv_packet(capture_file *cf, frame_data *fdata,
2138 union wtap_pseudo_header *pseudo_header, const guint8 *pd,
2142 epan_dissect_t *edt;
2144 /* Fill in the column information, but don't create the protocol tree. */
2145 edt = epan_dissect_new(FALSE, FALSE);
2146 epan_dissect_run(edt, pseudo_header, pd, fdata, &cf->cinfo);
2147 epan_dissect_fill_in_columns(edt);
2149 /* Write out the information in that tree. */
2150 proto_tree_write_csv(edt, fh);
2152 epan_dissect_free(edt);
2158 cf_write_csv_packets(capture_file *cf, print_args_t *print_args)
2163 fh = fopen(print_args->file, "w");
2165 return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
2167 write_csv_preamble(fh);
2170 return CF_PRINT_WRITE_ERROR;
2173 /* Iterate through the list of packets, printing the packets we were
2175 ret = process_specified_packets(cf, &print_args->range, "Writing CSV",
2176 "selected packets", write_csv_packet,
2182 /* Completed successfully. */
2186 /* Well, the user decided to abort the printing. */
2190 /* Error while printing. */
2192 return CF_PRINT_WRITE_ERROR;
2195 write_csv_finale(fh);
2198 return CF_PRINT_WRITE_ERROR;
2201 /* XXX - check for an error */
2207 /* Scan through the packet list and change all columns that use the
2208 "command-line-specified" time stamp format to use the current
2209 value of that format. */
2211 cf_change_time_formats(capture_file *cf)
2214 progdlg_t *progbar = NULL;
2220 GTimeVal start_time;
2221 gchar status_str[100];
2222 int progbar_nextstep;
2223 int progbar_quantum;
2225 gboolean sorted_by_frame_column;
2228 /* adjust timestamp precision if auto is selected */
2229 cf_timestamp_auto_precision(cf);
2231 /* Are there any columns with time stamps in the "command-line-specified"
2234 XXX - we have to force the "column is writable" flag on, as it
2235 might be off from the last frame that was dissected. */
2236 col_set_writable(&cf->cinfo, TRUE);
2237 if (!check_col(&cf->cinfo, COL_CLS_TIME)) {
2238 /* No, there aren't any columns in that format, so we have no work
2242 first = cf->cinfo.col_first[COL_CLS_TIME];
2243 g_assert(first >= 0);
2244 last = cf->cinfo.col_last[COL_CLS_TIME];
2246 /* Freeze the packet list while we redo it, so we don't get any
2247 screen updates while it happens. */
2248 packet_list_freeze();
2250 /* Update the progress bar when it gets to this value. */
2251 progbar_nextstep = 0;
2252 /* When we reach the value that triggers a progress bar update,
2253 bump that value by this amount. */
2254 progbar_quantum = cf->count/N_PROGBAR_UPDATES;
2255 /* Count of packets at which we've looked. */
2257 /* Progress so far. */
2260 /* If the rows are currently sorted by the frame column then we know
2261 * the row number of each packet: it's the row number of the previously
2262 * displayed packet + 1.
2264 * Otherwise, if the display is sorted by a different column then we have
2265 * to use the O(N) packet_list_find_row_from_data() (thus making the job
2266 * of changing the time display format O(N**2)).
2268 * (XXX - In fact it's still O(N**2) because gtk_clist_set_text() takes
2269 * the row number and walks that many elements down the clist to find
2270 * the appropriate element.)
2272 sorted_by_frame_column = FALSE;
2273 for (i = 0; i < cf->cinfo.num_cols; i++) {
2274 if (cf->cinfo.col_fmt[i] == COL_NUMBER)
2276 sorted_by_frame_column = (i == packet_list_get_sort_column());
2282 g_get_current_time(&start_time);
2284 /* Iterate through the list of packets, checking whether the packet
2285 is in a row of the summary list and, if so, whether there are
2286 any columns that show the time in the "command-line-specified"
2287 format and, if so, update that row. */
2288 for (fdata = cf->plist, row = -1; fdata != NULL; fdata = fdata->next) {
2289 /* Create the progress bar if necessary.
2290 We check on every iteration of the loop, so that it takes no
2291 longer than the standard time to create it (otherwise, for a
2292 large file, we might take considerably longer than that standard
2293 time in order to get to the next progress bar step). */
2294 if (progbar == NULL)
2295 progbar = delayed_create_progress_dlg("Changing", "time display",
2296 &stop_flag, &start_time, progbar_val);
2298 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
2299 when we update it, we have to run the GTK+ main loop to get it
2300 to repaint what's pending, and doing so may involve an "ioctl()"
2301 to see if there's any pending input from an X server, and doing
2302 that for every packet can be costly, especially on a big file. */
2303 if (count >= progbar_nextstep) {
2304 /* let's not divide by zero. I should never be started
2305 * with count == 0, so let's assert that
2307 g_assert(cf->count > 0);
2309 progbar_val = (gfloat) count / cf->count;
2311 if (progbar != NULL) {
2312 g_snprintf(status_str, sizeof(status_str),
2313 "%4u of %u packets", count, cf->count);
2314 update_progress_dlg(progbar, progbar_val, status_str);
2317 progbar_nextstep += progbar_quantum;
2321 /* Well, the user decided to abort the redisplay. Just stop.
2323 XXX - this leaves the time field in the old format in
2324 frames we haven't yet processed. So it goes; should we
2325 simply not offer them the option of stopping? */
2331 /* Find what row this packet is in. */
2332 if (!sorted_by_frame_column) {
2333 /* This function is O(N), so we try to avoid using it... */
2334 row = packet_list_find_row_from_data(fdata);
2336 /* ...which we do by maintaining a count of packets that are
2337 being displayed (i.e., that have passed the display filter),
2338 and using the current value of that count as the row number
2339 (which is why we can only do it when the display is sorted
2340 by the frame number). */
2341 if (fdata->flags.passed_dfilter)
2348 /* This packet is in the summary list, on row "row". */
2350 for (i = first; i <= last; i++) {
2351 if (cf->cinfo.fmt_matx[i][COL_CLS_TIME]) {
2352 /* This is one of the columns that shows the time in
2353 "command-line-specified" format; update it. */
2354 cf->cinfo.col_buf[i][0] = '\0';
2355 col_set_cls_time(fdata, &cf->cinfo, i);
2356 packet_list_set_text(row, i, cf->cinfo.col_data[i]);
2362 /* We're done redisplaying the packets; destroy the progress bar if it
2364 if (progbar != NULL)
2365 destroy_progress_dlg(progbar);
2367 /* Set the column widths of those columns that show the time in
2368 "command-line-specified" format. */
2369 for (i = first; i <= last; i++) {
2370 if (cf->cinfo.fmt_matx[i][COL_CLS_TIME]) {
2371 packet_list_set_cls_time_width(i);
2375 /* Unfreeze the packet list. */
2383 gboolean frame_matched;
2387 cf_find_packet_protocol_tree(capture_file *cf, const char *string)
2391 mdata.string = string;
2392 mdata.string_len = strlen(string);
2393 return find_packet(cf, match_protocol_tree, &mdata);
2397 match_protocol_tree(capture_file *cf, frame_data *fdata, void *criterion)
2399 match_data *mdata = criterion;
2400 epan_dissect_t *edt;
2402 /* Construct the protocol tree, including the displayed text */
2403 edt = epan_dissect_new(TRUE, TRUE);
2404 /* We don't need the column information */
2405 epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, NULL);
2407 /* Iterate through all the nodes, seeing if they have text that matches. */
2409 mdata->frame_matched = FALSE;
2410 proto_tree_children_foreach(edt->tree, match_subtree_text, mdata);
2411 epan_dissect_free(edt);
2412 return mdata->frame_matched;
2416 match_subtree_text(proto_node *node, gpointer data)
2418 match_data *mdata = (match_data*) data;
2419 const gchar *string = mdata->string;
2420 size_t string_len = mdata->string_len;
2421 capture_file *cf = mdata->cf;
2422 field_info *fi = PITEM_FINFO(node);
2423 gchar label_str[ITEM_LABEL_LENGTH];
2430 if (mdata->frame_matched) {
2431 /* We already had a match; don't bother doing any more work. */
2435 /* Don't match invisible entries. */
2436 if (PROTO_ITEM_IS_HIDDEN(node))
2439 /* was a free format label produced? */
2441 label_ptr = fi->rep->representation;
2443 /* no, make a generic label */
2444 label_ptr = label_str;
2445 proto_item_fill_label(fi, label_str);
2448 /* Does that label match? */
2449 label_len = strlen(label_ptr);
2450 for (i = 0; i < label_len; i++) {
2451 c_char = label_ptr[i];
2453 c_char = toupper(c_char);
2454 if (c_char == string[c_match]) {
2456 if (c_match == string_len) {
2457 /* No need to look further; we have a match */
2458 mdata->frame_matched = TRUE;
2465 /* Recurse into the subtree, if it exists */
2466 if (node->first_child != NULL)
2467 proto_tree_children_foreach(node, match_subtree_text, mdata);
2471 cf_find_packet_summary_line(capture_file *cf, const char *string)
2475 mdata.string = string;
2476 mdata.string_len = strlen(string);
2477 return find_packet(cf, match_summary_line, &mdata);
2481 match_summary_line(capture_file *cf, frame_data *fdata, void *criterion)
2483 match_data *mdata = criterion;
2484 const gchar *string = mdata->string;
2485 size_t string_len = mdata->string_len;
2486 epan_dissect_t *edt;
2487 const char *info_column;
2488 size_t info_column_len;
2489 gboolean frame_matched = FALSE;
2495 /* Don't bother constructing the protocol tree */
2496 edt = epan_dissect_new(FALSE, FALSE);
2497 /* Get the column information */
2498 epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, &cf->cinfo);
2500 /* Find the Info column */
2501 for (colx = 0; colx < cf->cinfo.num_cols; colx++) {
2502 if (cf->cinfo.fmt_matx[colx][COL_INFO]) {
2503 /* Found it. See if we match. */
2504 info_column = edt->pi.cinfo->col_data[colx];
2505 info_column_len = strlen(info_column);
2506 for (i = 0; i < info_column_len; i++) {
2507 c_char = info_column[i];
2509 c_char = toupper(c_char);
2510 if (c_char == string[c_match]) {
2512 if (c_match == string_len) {
2513 frame_matched = TRUE;
2522 epan_dissect_free(edt);
2523 return frame_matched;
2529 } cbs_t; /* "Counted byte string" */
2532 cf_find_packet_data(capture_file *cf, const guint8 *string, size_t string_size)
2537 info.data_len = string_size;
2539 /* String or hex search? */
2541 /* String search - what type of string? */
2542 switch (cf->scs_type) {
2544 case SCS_ASCII_AND_UNICODE:
2545 return find_packet(cf, match_ascii_and_unicode, &info);
2548 return find_packet(cf, match_ascii, &info);
2551 return find_packet(cf, match_unicode, &info);
2554 g_assert_not_reached();
2558 return find_packet(cf, match_binary, &info);
2562 match_ascii_and_unicode(capture_file *cf, frame_data *fdata, void *criterion)
2564 cbs_t *info = criterion;
2565 const char *ascii_text = info->data;
2566 size_t textlen = info->data_len;
2567 gboolean frame_matched;
2573 frame_matched = FALSE;
2574 buf_len = fdata->pkt_len;
2575 for (i = 0; i < buf_len; i++) {
2578 c_char = toupper(c_char);
2580 if (c_char == ascii_text[c_match]) {
2582 if (c_match == textlen) {
2583 frame_matched = TRUE;
2590 return frame_matched;
2594 match_ascii(capture_file *cf, frame_data *fdata, void *criterion)
2596 cbs_t *info = criterion;
2597 const char *ascii_text = info->data;
2598 size_t textlen = info->data_len;
2599 gboolean frame_matched;
2605 frame_matched = FALSE;
2606 buf_len = fdata->pkt_len;
2607 for (i = 0; i < buf_len; i++) {
2610 c_char = toupper(c_char);
2611 if (c_char == ascii_text[c_match]) {
2613 if (c_match == textlen) {
2614 frame_matched = TRUE;
2620 return frame_matched;
2624 match_unicode(capture_file *cf, frame_data *fdata, void *criterion)
2626 cbs_t *info = criterion;
2627 const char *ascii_text = info->data;
2628 size_t textlen = info->data_len;
2629 gboolean frame_matched;
2635 frame_matched = FALSE;
2636 buf_len = fdata->pkt_len;
2637 for (i = 0; i < buf_len; i++) {
2640 c_char = toupper(c_char);
2641 if (c_char == ascii_text[c_match]) {
2644 if (c_match == textlen) {
2645 frame_matched = TRUE;
2651 return frame_matched;
2655 match_binary(capture_file *cf, frame_data *fdata, void *criterion)
2657 cbs_t *info = criterion;
2658 const guint8 *binary_data = info->data;
2659 size_t datalen = info->data_len;
2660 gboolean frame_matched;
2665 frame_matched = FALSE;
2666 buf_len = fdata->pkt_len;
2667 for (i = 0; i < buf_len; i++) {
2668 if (cf->pd[i] == binary_data[c_match]) {
2670 if (c_match == datalen) {
2671 frame_matched = TRUE;
2677 return frame_matched;
2681 cf_find_packet_dfilter(capture_file *cf, dfilter_t *sfcode)
2683 return find_packet(cf, match_dfilter, sfcode);
2687 match_dfilter(capture_file *cf, frame_data *fdata, void *criterion)
2689 dfilter_t *sfcode = criterion;
2690 epan_dissect_t *edt;
2691 gboolean frame_matched;
2693 edt = epan_dissect_new(TRUE, FALSE);
2694 epan_dissect_prime_dfilter(edt, sfcode);
2695 epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, NULL);
2696 frame_matched = dfilter_apply_edt(sfcode, edt);
2697 epan_dissect_free(edt);
2698 return frame_matched;
2702 find_packet(capture_file *cf,
2703 gboolean (*match_function)(capture_file *, frame_data *, void *),
2706 frame_data *start_fd;
2708 frame_data *new_fd = NULL;
2709 progdlg_t *progbar = NULL;
2716 GTimeVal start_time;
2717 gchar status_str[100];
2718 int progbar_nextstep;
2719 int progbar_quantum;
2721 start_fd = cf->current_frame;
2722 if (start_fd != NULL) {
2723 /* Iterate through the list of packets, starting at the packet we've
2724 picked, calling a routine to run the filter on the packet, see if
2725 it matches, and stop if so. */
2729 /* Update the progress bar when it gets to this value. */
2730 progbar_nextstep = 0;
2731 /* When we reach the value that triggers a progress bar update,
2732 bump that value by this amount. */
2733 progbar_quantum = cf->count/N_PROGBAR_UPDATES;
2734 /* Progress so far. */
2738 g_get_current_time(&start_time);
2742 /* Create the progress bar if necessary.
2743 We check on every iteration of the loop, so that it takes no
2744 longer than the standard time to create it (otherwise, for a
2745 large file, we might take considerably longer than that standard
2746 time in order to get to the next progress bar step). */
2747 if (progbar == NULL)
2748 progbar = delayed_create_progress_dlg("Searching", cf->sfilter,
2749 &stop_flag, &start_time, progbar_val);
2751 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
2752 when we update it, we have to run the GTK+ main loop to get it
2753 to repaint what's pending, and doing so may involve an "ioctl()"
2754 to see if there's any pending input from an X server, and doing
2755 that for every packet can be costly, especially on a big file. */
2756 if (count >= progbar_nextstep) {
2757 /* let's not divide by zero. I should never be started
2758 * with count == 0, so let's assert that
2760 g_assert(cf->count > 0);
2762 progbar_val = (gfloat) count / cf->count;
2764 if (progbar != NULL) {
2765 g_snprintf(status_str, sizeof(status_str),
2766 "%4u of %u packets", count, cf->count);
2767 update_progress_dlg(progbar, progbar_val, status_str);
2770 progbar_nextstep += progbar_quantum;
2774 /* Well, the user decided to abort the search. Go back to the
2775 frame where we started. */
2780 /* Go past the current frame. */
2781 if (cf->sbackward) {
2782 /* Go on to the previous frame. */
2783 fdata = fdata->prev;
2784 if (fdata == NULL) {
2786 * XXX - other apps have a bit more of a detailed message
2787 * for this, and instead of offering "OK" and "Cancel",
2788 * they offer things such as "Continue" and "Cancel";
2789 * we need an API for popping up alert boxes with
2790 * {Verb} and "Cancel".
2793 if (prefs.gui_find_wrap)
2795 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
2796 "%sBeginning of capture exceeded!%s\n\n"
2797 "Search is continued from the end of the capture.",
2798 simple_dialog_primary_start(), simple_dialog_primary_end());
2799 fdata = cf->plist_end; /* wrap around */
2803 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
2804 "%sBeginning of capture exceeded!%s\n\n"
2805 "Try searching forwards.",
2806 simple_dialog_primary_start(), simple_dialog_primary_end());
2807 fdata = start_fd; /* stay on previous packet */
2811 /* Go on to the next frame. */
2812 fdata = fdata->next;
2813 if (fdata == NULL) {
2814 if (prefs.gui_find_wrap)
2816 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
2817 "%sEnd of capture exceeded!%s\n\n"
2818 "Search is continued from the start of the capture.",
2819 simple_dialog_primary_start(), simple_dialog_primary_end());
2820 fdata = cf->plist; /* wrap around */
2824 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
2825 "%sEnd of capture exceeded!%s\n\n"
2826 "Try searching backwards.",
2827 simple_dialog_primary_start(), simple_dialog_primary_end());
2828 fdata = start_fd; /* stay on previous packet */
2835 /* Is this packet in the display? */
2836 if (fdata->flags.passed_dfilter) {
2837 /* Yes. Load its data. */
2838 if (!wtap_seek_read(cf->wth, fdata->file_off, &cf->pseudo_header,
2839 cf->pd, fdata->cap_len, &err, &err_info)) {
2840 /* Read error. Report the error, and go back to the frame
2841 where we started. */
2842 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
2843 cf_read_error_message(err, err_info), cf->filename);
2848 /* Does it match the search criterion? */
2849 if ((*match_function)(cf, fdata, criterion)) {
2851 break; /* found it! */
2855 if (fdata == start_fd) {
2856 /* We're back to the frame we were on originally, and that frame
2857 doesn't match the search filter. The search failed. */
2862 /* We're done scanning the packets; destroy the progress bar if it
2864 if (progbar != NULL)
2865 destroy_progress_dlg(progbar);
2868 if (new_fd != NULL) {
2869 /* We found a frame. Find what row it's in. */
2870 row = packet_list_find_row_from_data(new_fd);
2871 g_assert(row != -1);
2873 /* Select that row, make it the focus row, and make it visible. */
2874 packet_list_set_selected_row(row);
2875 return TRUE; /* success */
2877 return FALSE; /* failure */
2881 cf_goto_frame(capture_file *cf, guint fnumber)
2886 for (fdata = cf->plist; fdata != NULL && fdata->num < fnumber; fdata = fdata->next)
2889 if (fdata == NULL) {
2890 /* we didn't find a packet with that packet number */
2891 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
2892 "There is no packet with the packet number %u.", fnumber);
2893 return FALSE; /* we failed to go to that packet */
2895 if (!fdata->flags.passed_dfilter) {
2896 /* that packet currently isn't displayed */
2897 /* XXX - add it to the set of displayed packets? */
2898 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
2899 "The packet number %u isn't currently being displayed.", fnumber);
2900 return FALSE; /* we failed to go to that packet */
2903 /* We found that packet, and it's currently being displayed.
2904 Find what row it's in. */
2905 row = packet_list_find_row_from_data(fdata);
2906 g_assert(row != -1);
2908 /* Select that row, make it the focus row, and make it visible. */
2909 packet_list_set_selected_row(row);
2910 return TRUE; /* we got to that packet */
2914 cf_goto_top_frame(capture_file *cf)
2918 frame_data *lowest_fdata = NULL;
2920 for (fdata = cf->plist; fdata != NULL; fdata = fdata->next) {
2921 if (fdata->flags.passed_dfilter) {
2922 lowest_fdata = fdata;
2927 if (lowest_fdata == NULL) {
2931 /* We found that packet, and it's currently being displayed.
2932 Find what row it's in. */
2933 row = packet_list_find_row_from_data(lowest_fdata);
2934 g_assert(row != -1);
2936 /* Select that row, make it the focus row, and make it visible. */
2937 packet_list_set_selected_row(row);
2938 return TRUE; /* we got to that packet */
2942 cf_goto_bottom_frame(capture_file *cf)
2946 frame_data *highest_fdata = NULL;
2948 for (fdata = cf->plist; fdata != NULL; fdata = fdata->next) {
2949 if (fdata->flags.passed_dfilter) {
2950 highest_fdata = fdata;
2954 if (highest_fdata == NULL) {
2958 /* We found that packet, and it's currently being displayed.
2959 Find what row it's in. */
2960 row = packet_list_find_row_from_data(highest_fdata);
2961 g_assert(row != -1);
2963 /* Select that row, make it the focus row, and make it visible. */
2964 packet_list_set_selected_row(row);
2965 return TRUE; /* we got to that packet */
2969 * Go to frame specified by currently selected protocol tree item.
2972 cf_goto_framenum(capture_file *cf)
2974 header_field_info *hfinfo;
2977 if (cf->finfo_selected) {
2978 hfinfo = cf->finfo_selected->hfinfo;
2980 if (hfinfo->type == FT_FRAMENUM) {
2981 framenum = fvalue_get_integer(&cf->finfo_selected->value);
2983 return cf_goto_frame(cf, framenum);
2990 /* Select the packet on a given row. */
2992 cf_select_packet(capture_file *cf, int row)
2998 /* Get the frame data struct pointer for this frame */
2999 fdata = (frame_data *)packet_list_get_row_data(row);
3001 if (fdata == NULL) {
3002 /* XXX - if a GtkCList's selection mode is GTK_SELECTION_BROWSE, when
3003 the first entry is added to it by "real_insert_row()", that row
3004 is selected (see "real_insert_row()", in "gtk/gtkclist.c", in both
3005 our version and the vanilla GTK+ version).
3007 This means that a "select-row" signal is emitted; this causes
3008 "packet_list_select_cb()" to be called, which causes "cf_select_packet()"
3011 "cf_select_packet()" fetches, above, the data associated with the
3012 row that was selected; however, as "gtk_clist_append()", which
3013 called "real_insert_row()", hasn't yet returned, we haven't yet
3014 associated any data with that row, so we get back a null pointer.
3016 We can't assume that there's only one frame in the frame list,
3017 either, as we may be filtering the display.
3019 We therefore assume that, if "row" is 0, i.e. the first row
3020 is being selected, and "cf->first_displayed" equals
3021 "cf->last_displayed", i.e. there's only one frame being
3022 displayed, that frame is the frame we want.
3024 This means we have to set "cf->first_displayed" and
3025 "cf->last_displayed" before adding the row to the
3026 GtkCList; see the comment in "add_packet_to_packet_list()". */
3028 if (row == 0 && cf->first_displayed == cf->last_displayed)
3029 fdata = cf->first_displayed;
3032 /* Get the data in that frame. */
3033 if (!wtap_seek_read (cf->wth, fdata->file_off, &cf->pseudo_header,
3034 cf->pd, fdata->cap_len, &err, &err_info)) {
3035 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3036 cf_read_error_message(err, err_info), cf->filename);
3040 /* Record that this frame is the current frame. */
3041 cf->current_frame = fdata;
3043 /* Create the logical protocol tree. */
3044 if (cf->edt != NULL) {
3045 epan_dissect_free(cf->edt);
3048 /* We don't need the columns here. */
3049 cf->edt = epan_dissect_new(TRUE, TRUE);
3050 epan_dissect_run(cf->edt, &cf->pseudo_header, cf->pd, cf->current_frame,
3053 cf_callback_invoke(cf_cb_packet_selected, cf);
3056 /* Unselect the selected packet, if any. */
3058 cf_unselect_packet(capture_file *cf)
3060 /* Destroy the epan_dissect_t for the unselected packet. */
3061 if (cf->edt != NULL) {
3062 epan_dissect_free(cf->edt);
3066 /* No packet is selected. */
3067 cf->current_frame = NULL;
3069 cf_callback_invoke(cf_cb_packet_unselected, cf);
3071 /* No protocol tree means no selected field. */
3072 cf_unselect_field(cf);
3075 /* Unset the selected protocol tree field, if any. */
3077 cf_unselect_field(capture_file *cf)
3079 cf->finfo_selected = NULL;
3081 cf_callback_invoke(cf_cb_field_unselected, cf);
3085 * Mark a particular frame.
3088 cf_mark_frame(capture_file *cf, frame_data *frame)
3090 if (! frame->flags.marked) {
3091 frame->flags.marked = TRUE;
3092 if (cf->count > cf->marked_count)
3098 * Unmark a particular frame.
3101 cf_unmark_frame(capture_file *cf, frame_data *frame)
3103 if (frame->flags.marked) {
3104 frame->flags.marked = FALSE;
3105 if (cf->marked_count > 0)
3113 } save_callback_args_t;
3116 * Save a capture to a file, in a particular format, saving either
3117 * all packets, all currently-displayed packets, or all marked packets.
3119 * Returns TRUE if it succeeds, FALSE otherwise; if it fails, it pops
3120 * up a message box for the failure.
3123 save_packet(capture_file *cf _U_, frame_data *fdata,
3124 union wtap_pseudo_header *pseudo_header, const guint8 *pd,
3127 save_callback_args_t *args = argsp;
3128 struct wtap_pkthdr hdr;
3131 /* init the wtap header for saving */
3132 hdr.ts = *(struct wtap_nstime *) &fdata->abs_ts;
3133 hdr.caplen = fdata->cap_len;
3134 hdr.len = fdata->pkt_len;
3135 hdr.pkt_encap = fdata->lnk_t;
3137 /* and save the packet */
3138 if (!wtap_dump(args->pdh, &hdr, pseudo_header, pd, &err)) {
3139 cf_write_failure_alert_box(args->fname, err);
3146 cf_save(capture_file *cf, const char *fname, packet_range_t *range, guint save_format, gboolean compressed)
3148 gchar *from_filename;
3152 save_callback_args_t callback_args;
3154 cf_callback_invoke(cf_cb_file_safe_started, (gpointer) fname);
3156 /* don't write over an existing file. */
3157 /* this should've been already checked by our caller, just to be sure... */
3158 if (file_exists(fname)) {
3159 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3160 "%sCapture file: \"%s\" already exists!%s\n\n"
3161 "Please choose a different filename.",
3162 simple_dialog_primary_start(), fname, simple_dialog_primary_end());
3166 packet_range_process_init(range);
3169 if (packet_range_process_all(range) && save_format == cf->cd_t) {
3170 /* We're not filtering packets, and we're saving it in the format
3171 it's already in, so we can just move or copy the raw data. */
3173 if (cf->is_tempfile) {
3174 /* The file being saved is a temporary file from a live
3175 capture, so it doesn't need to stay around under that name;
3176 first, try renaming the capture buffer file to the new name. */
3178 if (rename(cf->filename, fname) == 0) {
3179 /* That succeeded - there's no need to copy the source file. */
3180 from_filename = NULL;
3183 if (errno == EXDEV) {
3184 /* They're on different file systems, so we have to copy the
3187 from_filename = cf->filename;
3189 /* The rename failed, but not because they're on different
3190 file systems - put up an error message. (Or should we
3191 just punt and try to copy? The only reason why I'd
3192 expect the rename to fail and the copy to succeed would
3193 be if we didn't have permission to remove the file from
3194 the temporary directory, and that might be fixable - but
3195 is it worth requiring the user to go off and fix it?) */
3196 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3197 file_rename_error_message(errno), fname);
3203 from_filename = cf->filename;
3206 /* It's a permanent file, so we should copy it, and not remove the
3209 from_filename = cf->filename;
3213 /* Copy the file, if we haven't moved it. */
3214 if (!copy_binary_file(from_filename, fname))
3218 /* Either we're filtering packets, or we're saving in a different
3219 format; we can't do that by copying or moving the capture file,
3220 we have to do it by writing the packets out in Wiretap. */
3221 pdh = wtap_dump_open(fname, save_format, cf->lnk_t, cf->snap,
3224 cf_open_failure_alert_box(fname, err, NULL, TRUE, save_format);
3228 /* XXX - we let the user save a subset of the packets.
3230 If we do that, should we make that file the current file? If so,
3231 it means we can no longer get at the other packets. What does
3234 /* Iterate through the list of packets, processing the packets we were
3237 XXX - we've already called "packet_range_process_init(range)", but
3238 "process_specified_packets()" will do it again. Fortunately,
3239 that's harmless in this case, as we haven't done anything to
3240 "range" since we initialized it. */
3241 callback_args.pdh = pdh;
3242 callback_args.fname = fname;
3243 switch (process_specified_packets(cf, range, "Saving",
3244 "selected packets", save_packet,
3248 /* Completed successfully. */
3252 /* The user decided to abort the saving.
3253 XXX - remove the output file? */
3257 /* Error while saving. */
3258 wtap_dump_close(pdh, &err);
3262 if (!wtap_dump_close(pdh, &err)) {
3263 cf_close_failure_alert_box(fname, err);
3268 cf_callback_invoke(cf_cb_file_safe_finished, NULL);
3270 if (packet_range_process_all(range)) {
3271 /* We saved the entire capture, not just some packets from it.
3272 Open and read the file we saved it to.
3274 XXX - this is somewhat of a waste; we already have the
3275 packets, all this gets us is updated file type information
3276 (which we could just stuff into "cf"), and having the new
3277 file be the one we have opened and from which we're reading
3278 the data, and it means we have to spend time opening and
3279 reading the file, which could be a significant amount of
3280 time if the file is large. */
3281 cf->user_saved = TRUE;
3283 if ((cf_open(cf, fname, FALSE, &err)) == CF_OK) {
3284 /* XXX - report errors if this fails?
3285 What should we return if it fails or is aborted? */
3286 switch (cf_read(cf)) {
3290 /* Just because we got an error, that doesn't mean we were unable
3291 to read any of the file; we handle what we could get from the
3295 case CF_READ_ABORTED:
3296 /* The user bailed out of re-reading the capture file; the
3297 capture file has been closed - just return (without
3298 changing any menu settings; "cf_close()" set them
3299 correctly for the "no capture file open" state). */
3302 cf_callback_invoke(cf_cb_file_safe_reload_finished, NULL);
3308 cf_callback_invoke(cf_cb_file_safe_failed, NULL);
3313 cf_open_failure_alert_box(const char *filename, int err, gchar *err_info,
3314 gboolean for_writing, int file_type)
3317 /* Wiretap error. */
3320 case WTAP_ERR_NOT_REGULAR_FILE:
3321 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3322 "The file \"%s\" is a \"special file\" or socket or other non-regular file.",
3326 case WTAP_ERR_RANDOM_OPEN_PIPE:
3327 /* Seen only when opening a capture file for reading. */
3328 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3329 "The file \"%s\" is a pipe or FIFO; Ethereal can't read pipe or FIFO files.",
3333 case WTAP_ERR_FILE_UNKNOWN_FORMAT:
3334 /* Seen only when opening a capture file for reading. */
3335 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3336 "The file \"%s\" isn't a capture file in a format Ethereal understands.",
3340 case WTAP_ERR_UNSUPPORTED:
3341 /* Seen only when opening a capture file for reading. */
3342 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3343 "The file \"%s\" isn't a capture file in a format Ethereal understands.\n"
3345 filename, err_info);
3349 case WTAP_ERR_CANT_WRITE_TO_PIPE:
3350 /* Seen only when opening a capture file for writing. */
3351 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3352 "The file \"%s\" is a pipe, and %s capture files can't be "
3353 "written to a pipe.",
3354 filename, wtap_file_type_string(file_type));
3357 case WTAP_ERR_UNSUPPORTED_FILE_TYPE:
3358 /* Seen only when opening a capture file for writing. */
3359 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3360 "Ethereal doesn't support writing capture files in that format.");
3363 case WTAP_ERR_UNSUPPORTED_ENCAP:
3365 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3366 "Ethereal can't save this capture in that format.");
3368 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3369 "The file \"%s\" is a capture for a network type that Ethereal doesn't support.\n"
3371 filename, err_info);
3376 case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED:
3378 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3379 "Ethereal can't save this capture in that format.");
3381 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3382 "The file \"%s\" is a capture for a network type that Ethereal doesn't support.",
3387 case WTAP_ERR_BAD_RECORD:
3388 /* Seen only when opening a capture file for reading. */
3389 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3390 "The file \"%s\" appears to be damaged or corrupt.\n"
3392 filename, err_info);
3396 case WTAP_ERR_CANT_OPEN:
3398 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3399 "The file \"%s\" could not be created for some unknown reason.",
3402 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3403 "The file \"%s\" could not be opened for some unknown reason.",
3408 case WTAP_ERR_SHORT_READ:
3409 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3410 "The file \"%s\" appears to have been cut short"
3411 " in the middle of a packet or other data.",
3415 case WTAP_ERR_SHORT_WRITE:
3416 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3417 "A full header couldn't be written to the file \"%s\".",
3421 case WTAP_ERR_COMPRESSION_NOT_SUPPORTED:
3422 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3423 "Gzip compression not supported by this file type.");
3427 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3428 "The file \"%s\" could not be %s: %s.",
3430 for_writing ? "created" : "opened",
3431 wtap_strerror(err));
3436 open_failure_alert_box(filename, err, for_writing);
3441 file_rename_error_message(int err)
3444 static char errmsg_errno[1024+1];
3449 errmsg = "The path to the file \"%s\" doesn't exist.";
3453 errmsg = "You don't have permission to move the capture file to \"%s\".";
3457 g_snprintf(errmsg_errno, sizeof(errmsg_errno),
3458 "The file \"%%s\" could not be moved: %s.",
3459 wtap_strerror(err));
3460 errmsg = errmsg_errno;
3467 cf_read_error_message(int err, const gchar *err_info)
3469 static char errmsg_errno[1024+1];
3473 case WTAP_ERR_UNSUPPORTED_ENCAP:
3474 g_snprintf(errmsg_errno, sizeof(errmsg_errno),
3475 "The file \"%%s\" has a packet with a network type that Ethereal doesn't support.\n(%s)",
3479 case WTAP_ERR_BAD_RECORD:
3480 g_snprintf(errmsg_errno, sizeof(errmsg_errno),
3481 "An error occurred while reading from the file \"%%s\": %s.\n(%s)",
3482 wtap_strerror(err), err_info);
3486 g_snprintf(errmsg_errno, sizeof(errmsg_errno),
3487 "An error occurred while reading from the file \"%%s\": %s.",
3488 wtap_strerror(err));
3491 return errmsg_errno;
3495 cf_write_failure_alert_box(const char *filename, int err)
3498 /* Wiretap error. */
3499 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3500 "An error occurred while writing to the file \"%s\": %s.",
3501 filename, wtap_strerror(err));
3504 write_failure_alert_box(filename, err);
3508 /* Check for write errors - if the file is being written to an NFS server,
3509 a write error may not show up until the file is closed, as NFS clients
3510 might not send writes to the server until the "write()" call finishes,
3511 so that the write may fail on the server but the "write()" may succeed. */
3513 cf_close_failure_alert_box(const char *filename, int err)
3516 /* Wiretap error. */
3519 case WTAP_ERR_CANT_CLOSE:
3520 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3521 "The file \"%s\" couldn't be closed for some unknown reason.",
3525 case WTAP_ERR_SHORT_WRITE:
3526 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3527 "Not all the packets could be written to the file \"%s\".",
3532 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3533 "An error occurred while closing the file \"%s\": %s.",
3534 filename, wtap_strerror(err));
3539 We assume that a close error from the OS is really a write error. */
3540 write_failure_alert_box(filename, err);
3544 /* Reload the current capture file. */
3546 cf_reload(capture_file *cf) {
3548 gboolean is_tempfile;
3551 /* If the file could be opened, "cf_open()" calls "cf_close()"
3552 to get rid of state for the old capture file before filling in state
3553 for the new capture file. "cf_close()" will remove the file if
3554 it's a temporary file; we don't want that to happen (for one thing,
3555 it'd prevent subsequent reopens from working). Remember whether it's
3556 a temporary file, mark it as not being a temporary file, and then
3557 reopen it as the type of file it was.
3559 Also, "cf_close()" will free "cf->filename", so we must make
3560 a copy of it first. */
3561 filename = g_strdup(cf->filename);
3562 is_tempfile = cf->is_tempfile;
3563 cf->is_tempfile = FALSE;
3564 if (cf_open(cf, filename, is_tempfile, &err) == CF_OK) {
3565 switch (cf_read(cf)) {
3569 /* Just because we got an error, that doesn't mean we were unable
3570 to read any of the file; we handle what we could get from the
3574 case CF_READ_ABORTED:
3575 /* The user bailed out of re-reading the capture file; the
3576 capture file has been closed - just free the capture file name
3577 string and return (without changing the last containing
3583 /* The open failed, so "cf->is_tempfile" wasn't set to "is_tempfile".
3584 Instead, the file was left open, so we should restore "cf->is_tempfile"
3587 XXX - change the menu? Presumably "cf_open()" will do that;
3588 make sure it does! */
3589 cf->is_tempfile = is_tempfile;
3591 /* "cf_open()" made a copy of the file name we handed it, so
3592 we should free up our copy. */
3596 /* Copies a file in binary mode, for those operating systems that care about
3598 * Returns TRUE on success, FALSE on failure. If a failure, it also
3599 * displays a simple dialog window with the error message.
3602 copy_binary_file(const char *from_filename, const char *to_filename)
3604 int from_fd, to_fd, nread, nwritten, err;
3607 /* Copy the raw bytes of the file. */
3608 from_fd = open(from_filename, O_RDONLY | O_BINARY);
3610 open_failure_alert_box(from_filename, errno, FALSE);
3614 /* Use open() instead of creat() so that we can pass the O_BINARY
3615 flag, which is relevant on Win32; it appears that "creat()"
3616 may open the file in text mode, not binary mode, but we want
3617 to copy the raw bytes of the file, so we need the output file
3618 to be open in binary mode. */
3619 to_fd = open(to_filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
3621 open_failure_alert_box(to_filename, errno, TRUE);
3626 while ((nread = read(from_fd, pd, sizeof pd)) > 0) {
3627 nwritten = write(to_fd, pd, nread);
3628 if (nwritten < nread) {
3632 err = WTAP_ERR_SHORT_WRITE;
3633 write_failure_alert_box(to_filename, err);
3641 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3642 "An error occurred while reading from the file \"%s\": %s.",
3643 from_filename, strerror(err));
3649 if (close(to_fd) < 0) {
3650 write_failure_alert_box(to_filename, errno);