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.
25 /* With MSVC and a libethereal.dll this file needs to import some variables
26 in a special way. Therefore _NEED_VAR_IMPORT_ is defined. */
27 #define _NEED_VAR_IMPORT_
50 #ifdef HAVE_SYS_STAT_H
58 #ifdef NEED_SNPRINTF_H
59 # include "snprintf.h"
62 #ifdef NEED_STRERROR_H
66 #include <epan/epan.h>
67 #include <epan/filesystem.h>
70 #include "color_filters.h"
71 #include <epan/column.h>
72 #include <epan/packet.h>
73 #include "packet-range.h"
79 #include "alert_box.h"
80 #include "simple_dialog.h"
81 #include "progress_dlg.h"
83 #include "statusbar.h"
84 #include <epan/prefs.h>
85 #include <epan/dfilter/dfilter.h>
86 #include <epan/conversation.h>
87 #include <epan/epan_dissect.h>
89 #include "tap_dfilter_dlg.h"
90 #include <epan/dissectors/packet-data.h>
91 #include "capture_ui_utils.h"
93 /* Win32 needs the O_BINARY flag for open() */
99 gboolean auto_scroll_live;
102 static guint32 firstsec, firstusec;
103 static guint32 prevsec, prevusec;
104 static guint32 cum_bytes = 0;
106 static void read_packet(capture_file *cf, long offset);
108 static void rescan_packets(capture_file *cf, const char *action, const char *action_item,
109 gboolean refilter, gboolean redissect);
111 static gboolean match_protocol_tree(capture_file *cf, frame_data *fdata,
113 static void match_subtree_text(proto_node *node, gpointer data);
114 static gboolean match_summary_line(capture_file *cf, frame_data *fdata,
116 static gboolean match_ascii_and_unicode(capture_file *cf, frame_data *fdata,
118 static gboolean match_ascii(capture_file *cf, frame_data *fdata,
120 static gboolean match_unicode(capture_file *cf, frame_data *fdata,
122 static gboolean match_binary(capture_file *cf, frame_data *fdata,
124 static gboolean match_dfilter(capture_file *cf, frame_data *fdata,
126 static gboolean find_packet(capture_file *cf,
127 gboolean (*match_function)(capture_file *, frame_data *, void *),
130 static void cf_open_failure_alert_box(const char *filename, int err,
131 gchar *err_info, gboolean for_writing,
133 static char *file_rename_error_message(int err);
134 static void cf_write_failure_alert_box(const char *filename, int err);
135 static void cf_close_failure_alert_box(const char *filename, int err);
136 static gboolean copy_binary_file(const char *from_filename, const char *to_filename);
138 /* Update the progress bar this many times when reading a file. */
139 #define N_PROGBAR_UPDATES 100
141 /* Number of "frame_data" structures per memory chunk.
142 XXX - is this the right number? */
143 #define FRAME_DATA_CHUNK_SIZE 1024
147 cf_open(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
154 wth = wtap_open_offline(fname, err, &err_info, TRUE);
158 /* Find the size of the file. */
160 if (fstat(fd, &cf_stat) < 0) {
166 /* The open succeeded. Close whatever capture file we had open,
167 and fill in the information for this file. */
170 /* Initialize all data structures used for dissection. */
173 /* We're about to start reading the file. */
174 cf->state = FILE_READ_IN_PROGRESS;
178 cf->f_len = cf_stat.st_size;
180 /* Set the file name because we need it to set the follow stream filter.
181 XXX - is that still true? We need it for other reasons, though,
183 cf->filename = g_strdup(fname);
185 /* Indicate whether it's a permanent or temporary file. */
186 cf->is_tempfile = is_tempfile;
188 /* If it's a temporary capture buffer file, mark it as not saved. */
189 cf->user_saved = !is_tempfile;
191 cf->cd_t = wtap_file_type(cf->wth);
193 cf->displayed_count = 0;
194 cf->marked_count = 0;
195 cf->drops_known = FALSE;
199 cf->snap = wtap_snapshot_length(cf->wth);
201 /* Snapshot length not known. */
202 cf->has_snap = FALSE;
203 cf->snap = WTAP_MAX_PACKET_SIZE;
206 firstsec = 0, firstusec = 0;
207 prevsec = 0, prevusec = 0;
209 cf->plist_chunk = g_mem_chunk_new("frame_data_chunk",
211 FRAME_DATA_CHUNK_SIZE * sizeof(frame_data),
213 g_assert(cf->plist_chunk);
218 cf_open_failure_alert_box(fname, *err, err_info, FALSE, 0);
222 /* Reset everything to a pristine state */
224 cf_close(capture_file *cf)
226 /* Die if we're in the middle of reading a file. */
227 g_assert(cf->state != FILE_READ_IN_PROGRESS);
229 /* Destroy all windows, which refer to the
230 capture file we're closing. */
231 destroy_cfile_wins();
237 /* We have no file open... */
238 if (cf->filename != NULL) {
239 /* If it's a temporary file, remove it. */
241 unlink(cf->filename);
242 g_free(cf->filename);
245 /* ...which means we have nothing to save. */
246 cf->user_saved = FALSE;
248 if (cf->plist_chunk != NULL) {
249 g_mem_chunk_destroy(cf->plist_chunk);
250 cf->plist_chunk = NULL;
252 if (cf->rfcode != NULL) {
253 dfilter_free(cf->rfcode);
257 cf->plist_end = NULL;
258 cf_unselect_packet(cf); /* nothing to select */
259 cf->first_displayed = NULL;
260 cf->last_displayed = NULL;
262 /* No frame selected, no field in that frame selected. */
263 cf->current_frame = NULL;
264 cf->finfo_selected = NULL;
266 /* Clear the packet list. */
267 packet_list_freeze();
276 /* Clear any file-related status bar messages.
277 XXX - should be "clear *ALL* file-related status bar messages;
278 will there ever be more than one on the stack? */
279 statusbar_pop_file_msg();
281 /* Restore the standard title bar message. */
282 set_main_window_name("The Ethereal Network Analyzer");
284 /* Disable all menu items that make sense only if you have a capture. */
285 set_menus_for_capture_file(FALSE);
286 set_menus_for_unsaved_capture_file(FALSE);
287 set_menus_for_captured_packets(FALSE);
288 set_menus_for_selected_packet(cf);
289 set_menus_for_capture_in_progress(FALSE);
290 set_menus_for_selected_tree_row(cf);
292 reset_tap_listeners();
294 /* We have no file open. */
295 cf->state = FILE_CLOSED;
298 /* Set the file name in the status line, in the name for the main window,
299 and in the name for the main window's icon. */
301 set_display_filename(capture_file *cf)
303 const gchar *name_ptr;
305 static const gchar done_fmt_nodrops[] = " File: %s %s %02u:%02u:%02u";
306 static const gchar done_fmt_drops[] = " File: %s %s %02u:%02u:%02u Drops: %u";
308 gchar *win_name_fmt = "%s - Ethereal";
312 name_ptr = cf_get_display_name(cf);
314 if (!cf->is_tempfile) {
315 /* Add this filename to the list of recent files in the "Recent Files" submenu */
316 add_menu_recent_capture_file(cf->filename);
319 if (cf->f_len/1024/1024 > 10) {
320 size_str = g_strdup_printf("%ld MB", cf->f_len/1024/1024);
321 } else if (cf->f_len/1024 > 10) {
322 size_str = g_strdup_printf("%ld KB", cf->f_len/1024);
324 size_str = g_strdup_printf("%ld bytes", cf->f_len);
327 if (cf->drops_known) {
328 done_msg = g_strdup_printf(done_fmt_drops, name_ptr, size_str,
329 cf->esec/3600, cf->esec%3600/60, cf->esec%60, cf->drops);
331 done_msg = g_strdup_printf(done_fmt_nodrops, name_ptr, size_str,
332 cf->esec/3600, cf->esec%3600/60, cf->esec%60);
334 statusbar_push_file_msg(done_msg);
337 msg_len = strlen(name_ptr) + strlen(win_name_fmt) + 1;
338 win_name = g_malloc(msg_len);
339 snprintf(win_name, msg_len, win_name_fmt, name_ptr);
340 set_main_window_name(win_name);
345 cf_read(capture_file *cf)
349 const gchar *name_ptr;
350 gchar *load_msg, *load_fmt = "%s";
352 char errmsg_errno[1024+1];
353 gchar err_str[2048+1];
355 progdlg_t *progbar = NULL;
358 * XXX - should be "off_t", but Wiretap would need more work to handle
359 * the full size of "off_t" on platforms where it's more than a "long"
367 gchar status_str[100];
368 int progbar_nextstep;
372 reset_tap_listeners();
373 tap_dfilter_dlg_update();
374 name_ptr = get_basename(cf->filename);
376 load_msg = g_strdup_printf(" Loading: %s", name_ptr);
377 statusbar_push_file_msg(load_msg);
380 load_msg = g_strdup_printf(load_fmt, name_ptr);
382 /* Update the progress bar when it gets to this value. */
383 progbar_nextstep = 0;
384 /* When we reach the value that triggers a progress bar update,
385 bump that value by this amount. */
386 progbar_quantum = cf->f_len/N_PROGBAR_UPDATES;
388 packet_list_freeze();
391 g_get_current_time(&start_time);
393 while ((wtap_read(cf->wth, &err, &err_info, &data_offset))) {
394 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
395 when we update it, we have to run the GTK+ main loop to get it
396 to repaint what's pending, and doing so may involve an "ioctl()"
397 to see if there's any pending input from an X server, and doing
398 that for every packet can be costly, especially on a big file. */
399 if (data_offset >= progbar_nextstep) {
400 file_pos = lseek(cf->filed, 0, SEEK_CUR);
401 prog_val = (gfloat) file_pos / (gfloat) cf->f_len;
402 if (prog_val > 1.0) {
403 /* The file probably grew while we were reading it.
404 Update "cf->f_len", and try again. */
405 fd = wtap_fd(cf->wth);
406 if (fstat(fd, &cf_stat) >= 0) {
407 cf->f_len = cf_stat.st_size;
408 prog_val = (gfloat) file_pos / (gfloat) cf->f_len;
410 /* If it's still > 1, either the "fstat()" failed (in which
411 case there's not much we can do about it), or the file
412 *shrank* (in which case there's not much we can do about
413 it); just clip the progress value at 1.0. */
417 if (progbar == NULL) {
418 /* Create the progress bar if necessary */
419 progbar = delayed_create_progress_dlg("Loading", load_msg,
420 &stop_flag, &start_time, prog_val);
424 if (progbar != NULL) {
425 g_snprintf(status_str, sizeof(status_str),
426 "%luKB of %luKB", file_pos / 1024, cf->f_len / 1024);
427 update_progress_dlg(progbar, prog_val, status_str);
429 progbar_nextstep += progbar_quantum;
433 /* Well, the user decided to abort the read. Destroy the progress
434 bar, close the capture file, and return CF_READ_ABORTED so our caller
435 can do whatever is appropriate when that happens. */
436 destroy_progress_dlg(progbar);
437 cf->state = FILE_READ_ABORTED; /* so that we're allowed to close it */
438 packet_list_thaw(); /* undo our freeze */
440 return CF_READ_ABORTED;
442 read_packet(cf, data_offset);
445 /* We're done reading the file; destroy the progress bar if it was created. */
449 destroy_progress_dlg(progbar);
451 /* We're done reading sequentially through the file. */
452 cf->state = FILE_READ_DONE;
454 /* Close the sequential I/O side, to free up memory it requires. */
455 wtap_sequential_close(cf->wth);
457 /* Allow the protocol dissectors to free up memory that they
458 * don't need after the sequential run-through of the packets. */
459 postseq_cleanup_all_protocols();
461 /* Set the file encapsulation type now; we don't know what it is until
462 we've looked at all the packets, as we don't know until then whether
463 there's more than one type (and thus whether it's
464 WTAP_ENCAP_PER_PACKET). */
465 cf->lnk_t = wtap_file_encap(cf->wth);
467 cf->current_frame = cf->first_displayed;
470 statusbar_pop_file_msg();
471 set_display_filename(cf);
473 /* Enable menu items that make sense if you have a capture file you've
475 set_menus_for_capture_file(TRUE);
476 set_menus_for_unsaved_capture_file(!cf->user_saved);
478 /* Enable menu items that make sense if you have some captured packets. */
479 set_menus_for_captured_packets(TRUE);
481 /* If we have any displayed packets to select, select the first of those
482 packets by making the first row the selected row. */
483 if (cf->first_displayed != NULL)
484 packet_list_select_row(0);
487 /* Put up a message box noting that the read failed somewhere along
488 the line. Don't throw out the stuff we managed to read, though,
492 case WTAP_ERR_UNSUPPORTED_ENCAP:
493 snprintf(errmsg_errno, sizeof(errmsg_errno),
494 "The capture file has a packet with a network type that Ethereal doesn't support.\n(%s)",
497 errmsg = errmsg_errno;
500 case WTAP_ERR_CANT_READ:
501 errmsg = "An attempt to read from the capture file failed for"
502 " some unknown reason.";
505 case WTAP_ERR_SHORT_READ:
506 errmsg = "The capture file appears to have been cut short"
507 " in the middle of a packet.";
510 case WTAP_ERR_BAD_RECORD:
511 snprintf(errmsg_errno, sizeof(errmsg_errno),
512 "The capture file appears to be damaged or corrupt.\n(%s)",
515 errmsg = errmsg_errno;
519 snprintf(errmsg_errno, sizeof(errmsg_errno),
520 "An error occurred while reading the"
521 " capture file: %s.", wtap_strerror(err));
522 errmsg = errmsg_errno;
525 snprintf(err_str, sizeof err_str, errmsg);
526 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, err_str);
527 return CF_READ_ERROR;
534 cf_start_tail(capture_file *cf, const char *fname, const char *iface, gboolean is_tempfile, int *err)
537 cf_status_t cf_status;
539 cf_status = cf_open(cf, fname, is_tempfile, err);
540 if (cf_status == CF_OK) {
541 /* Disable menu items that make no sense if you're currently running
543 set_menus_for_capture_in_progress(TRUE);
545 /* Enable menu items that make sense if you have some captured
546 packets (yes, I know, we don't have any *yet*). */
547 set_menus_for_captured_packets(TRUE);
549 capture_msg = g_strdup_printf(" %s: <live capture in progress>", get_interface_descriptive_name(iface));
551 statusbar_push_file_msg(capture_msg);
560 cf_continue_tail(capture_file *cf, int to_read, int *err)
562 long data_offset = 0;
567 packet_list_freeze();
569 while (to_read != 0 && (wtap_read(cf->wth, err, &err_info, &data_offset))) {
570 if (cf->state == FILE_READ_ABORTED) {
571 /* Well, the user decided to exit Ethereal. Break out of the
572 loop, and let the code below (which is called even if there
573 aren't any packets left to read) exit. */
576 read_packet(cf, data_offset);
582 /* XXX - this cheats and looks inside the packet list to find the final
584 if (auto_scroll_live && cf->plist_end != NULL)
585 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? */
597 return CF_READ_ERROR;
603 cf_finish_tail(capture_file *cf, int *err)
610 packet_list_freeze();
612 while ((wtap_read(cf->wth, err, &err_info, &data_offset))) {
613 if (cf->state == FILE_READ_ABORTED) {
614 /* Well, the user decided to abort the read. Break out of the
615 loop, and let the code below (which is called even if there
616 aren't any packets left to read) exit. */
619 read_packet(cf, data_offset);
622 if (cf->state == FILE_READ_ABORTED) {
623 /* Well, the user decided to abort the read. We're only called
624 when the child capture process closes the pipe to us (meaning
625 it's probably exited), so we can just close the capture
626 file; we return CF_READ_ABORTED so our caller can do whatever
627 is appropriate when that happens. */
629 return CF_READ_ABORTED;
633 if (auto_scroll_live && cf->plist_end != NULL)
634 /* XXX - this cheats and looks inside the packet list to find the final
636 packet_list_moveto_end();
638 /* We're done reading sequentially through the file. */
639 cf->state = FILE_READ_DONE;
641 /* we have to update the f_len field */
642 /* Find the size of the file. */
643 fd = wtap_fd(cf->wth);
644 if (fstat(fd, &cf_stat) >= 0) {
645 cf->f_len = cf_stat.st_size;
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);
662 /* Pop the "<live capture in progress>" message off the status bar. */
663 statusbar_pop_file_msg();
665 set_display_filename(cf);
667 /* Enable menu items that make sense if you're not currently running
669 set_menus_for_capture_in_progress(FALSE);
671 /* Enable menu items that make sense if you have a capture file
672 you've finished reading. */
673 set_menus_for_capture_file(TRUE);
674 set_menus_for_unsaved_capture_file(!cf->user_saved);
677 /* We got an error reading the capture file.
678 XXX - pop up a dialog box? */
679 return CF_READ_ERROR;
684 #endif /* HAVE_LIBPCAP */
687 cf_get_display_name(capture_file *cf)
689 const gchar *displayname;
691 /* Return a name to use in displays */
692 if (!cf->is_tempfile) {
693 /* Get the last component of the file name, and use that. */
695 displayname = get_basename(cf->filename);
697 /* Add this filename to the list of recent files in the "Recent Files" submenu */
698 add_menu_recent_capture_file(cf->filename);
700 displayname="(No file)";
703 /* The file we read is a temporary file from a live capture;
704 we don't mention its name. */
705 displayname = "(Untitled)";
710 /* XXX - use a macro instead? */
712 cf_packet_count(capture_file *cf)
717 /* XXX - use a macro instead? */
719 cf_is_tempfile(capture_file *cf)
721 return cf->is_tempfile;
724 /* XXX - use a macro instead? */
725 void cf_set_drops_known(capture_file *cf, gboolean drops_known)
727 cf->drops_known = drops_known;
730 /* XXX - use a macro instead? */
731 void cf_set_drops(capture_file *cf, guint32 drops)
736 void cf_set_rfcode(capture_file *cf, dfilter_t *rfcode)
742 color_filter_t *colorf;
744 } apply_color_filter_args;
747 * If no color filter has been applied, apply this one.
748 * (The "if no color filter has been applied" is to handle the case where
749 * more than one color filter matches the packet.)
752 apply_color_filter(gpointer filter_arg, gpointer argp)
754 color_filter_t *colorf = filter_arg;
755 apply_color_filter_args *args = argp;
757 if (colorf->c_colorfilter != NULL && args->colorf == NULL) {
758 if (dfilter_apply_edt(colorf->c_colorfilter, args->edt))
759 args->colorf = colorf;
764 add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
765 union wtap_pseudo_header *pseudo_header, const guchar *buf,
768 apply_color_filter_args args;
770 gboolean create_proto_tree = FALSE;
773 /* just add some value here until we know if it is being displayed or not */
774 fdata->cum_bytes = cum_bytes + fdata->pkt_len;
776 /* We don't yet have a color filter to apply. */
779 /* If we don't have the time stamp of the first packet in the
780 capture, it's because this is the first packet. Save the time
781 stamp of this packet as the time stamp of the first packet. */
782 if (!firstsec && !firstusec) {
783 firstsec = fdata->abs_secs;
784 firstusec = fdata->abs_usecs;
786 /* if this frames is marked as a reference time frame, reset
787 firstsec and firstusec to this frame */
788 if(fdata->flags.ref_time){
789 firstsec = fdata->abs_secs;
790 firstusec = fdata->abs_usecs;
793 /* If we don't have the time stamp of the previous displayed packet,
794 it's because this is the first displayed packet. Save the time
795 stamp of this packet as the time stamp of the previous displayed
797 if (!prevsec && !prevusec) {
798 prevsec = fdata->abs_secs;
799 prevusec = fdata->abs_usecs;
802 /* Get the time elapsed between the first packet and this packet. */
803 compute_timestamp_diff(&fdata->rel_secs, &fdata->rel_usecs,
804 fdata->abs_secs, fdata->abs_usecs, firstsec, firstusec);
806 /* If it's greater than the current elapsed time, set the elapsed time
807 to it (we check for "greater than" so as not to be confused by
808 time moving backwards). */
809 if ((gint32)cf->esec < fdata->rel_secs
810 || ((gint32)cf->esec == fdata->rel_secs && (gint32)cf->eusec < fdata->rel_usecs)) {
811 cf->esec = fdata->rel_secs;
812 cf->eusec = fdata->rel_usecs;
815 /* Get the time elapsed between the previous displayed packet and
817 compute_timestamp_diff(&fdata->del_secs, &fdata->del_usecs,
818 fdata->abs_secs, fdata->abs_usecs, prevsec, prevusec);
822 we have a display filter and are re-applying it;
824 we have a list of color filters;
826 we have tap listeners;
828 allocate a protocol tree root node, so that we'll construct
829 a protocol tree against which a filter expression can be
831 if ((cf->dfcode != NULL && refilter) || filter_list != NULL
832 || num_tap_filters != 0)
833 create_proto_tree = TRUE;
835 /* Dissect the frame. */
836 edt = epan_dissect_new(create_proto_tree, FALSE);
838 if (cf->dfcode != NULL && refilter) {
839 epan_dissect_prime_dfilter(edt, cf->dfcode);
842 filter_list_prime_edt(edt);
845 epan_dissect_run(edt, pseudo_header, buf, fdata, &cf->cinfo);
846 tap_push_tapped_queue(edt);
848 /* If we have a display filter, apply it if we're refiltering, otherwise
849 leave the "passed_dfilter" flag alone.
851 If we don't have a display filter, set "passed_dfilter" to 1. */
852 if (cf->dfcode != NULL) {
854 if (cf->dfcode != NULL)
855 fdata->flags.passed_dfilter = dfilter_apply_edt(cf->dfcode, edt) ? 1 : 0;
857 fdata->flags.passed_dfilter = 1;
860 fdata->flags.passed_dfilter = 1;
862 /* If we have color filters, and the frame is to be displayed, apply
863 the color filters. */
864 if (fdata->flags.passed_dfilter) {
865 if (filter_list != NULL) {
867 g_slist_foreach(filter_list, apply_color_filter, &args);
872 if( (fdata->flags.passed_dfilter)
873 || (edt->pi.fd->flags.ref_time) ){
874 /* This frame either passed the display filter list or is marked as
875 a time reference frame. All time reference frames are displayed
876 even if they dont pass the display filter */
877 /* if this was a TIME REF frame we should reset the cul bytes field */
878 if(edt->pi.fd->flags.ref_time){
879 cum_bytes = fdata->pkt_len;
880 fdata->cum_bytes = cum_bytes;
883 /* increase cum_bytes with this packets length */
884 cum_bytes += fdata->pkt_len;
886 epan_dissect_fill_in_columns(edt);
888 /* If we haven't yet seen the first frame, this is it.
890 XXX - we must do this before we add the row to the display,
891 as, if the display's GtkCList's selection mode is
892 GTK_SELECTION_BROWSE, when the first entry is added to it,
893 "cf_select_packet()" will be called, and it will fetch the row
894 data for the 0th row, and will get a null pointer rather than
895 "fdata", as "gtk_clist_append()" won't yet have returned and
896 thus "gtk_clist_set_row_data()" won't yet have been called.
898 We thus need to leave behind bread crumbs so that
899 "cf_select_packet()" can find this frame. See the comment
900 in "cf_select_packet()". */
901 if (cf->first_displayed == NULL)
902 cf->first_displayed = fdata;
904 /* This is the last frame we've seen so far. */
905 cf->last_displayed = fdata;
907 row = packet_list_append(cf->cinfo.col_data, fdata);
909 /* If the packet matches a color filter,
910 * store matching color_filter_t object in frame data. */
911 if (filter_list != NULL && (args.colorf != NULL)) {
912 /* add the matching colorfilter to the frame data */
913 fdata->color_filter = args.colorf;
914 /* If packet is marked, use colors from preferences */
915 if (fdata->flags.marked) {
916 packet_list_set_colors(row, &prefs.gui_marked_fg, &prefs.gui_marked_bg);
917 } else /* if (filter_list != NULL && (args.colorf != NULL)) */ {
918 packet_list_set_colors(row, &(args.colorf->fg_color),
919 &(args.colorf->bg_color));
922 /* No color filter match */
923 fdata->color_filter = NULL;
924 if (fdata->flags.marked) {
925 packet_list_set_colors(row, &prefs.gui_marked_fg, &prefs.gui_marked_bg);
929 /* Set the time of the previous displayed frame to the time of this
931 prevsec = fdata->abs_secs;
932 prevusec = fdata->abs_usecs;
934 cf->displayed_count++;
936 /* This frame didn't pass the display filter, so it's not being added
937 to the clist, and thus has no row. */
940 epan_dissect_free(edt);
945 read_packet(capture_file *cf, long offset)
947 const struct wtap_pkthdr *phdr = wtap_phdr(cf->wth);
948 union wtap_pseudo_header *pseudo_header = wtap_pseudoheader(cf->wth);
949 const guchar *buf = wtap_buf_ptr(cf->wth);
952 frame_data *plist_end;
955 /* Allocate the next list entry, and add it to the list. */
956 fdata = g_mem_chunk_alloc(cf->plist_chunk);
961 fdata->pkt_len = phdr->len;
962 fdata->cap_len = phdr->caplen;
963 fdata->file_off = offset;
964 fdata->lnk_t = phdr->pkt_encap;
965 fdata->abs_secs = phdr->ts.tv_sec;
966 fdata->abs_usecs = phdr->ts.tv_usec;
967 fdata->flags.encoding = CHAR_ASCII;
968 fdata->flags.visited = 0;
969 fdata->flags.marked = 0;
970 fdata->flags.ref_time = 0;
974 edt = epan_dissect_new(TRUE, FALSE);
975 epan_dissect_prime_dfilter(edt, cf->rfcode);
976 epan_dissect_run(edt, pseudo_header, buf, fdata, NULL);
977 passed = dfilter_apply_edt(cf->rfcode, edt);
978 epan_dissect_free(edt);
981 plist_end = cf->plist_end;
982 fdata->prev = plist_end;
983 if (plist_end != NULL)
984 plist_end->next = fdata;
987 cf->plist_end = fdata;
990 fdata->num = cf->count;
991 add_packet_to_packet_list(fdata, cf, pseudo_header, buf, TRUE);
993 /* XXX - if we didn't have read filters, or if we could avoid
994 allocating the "frame_data" structure until we knew whether
995 the frame passed the read filter, we could use a G_ALLOC_ONLY
998 ...but, at least in one test I did, where I just made the chunk
999 a G_ALLOC_ONLY chunk and read in a huge capture file, it didn't
1000 seem to save a noticeable amount of time or space. */
1001 g_mem_chunk_free(cf->plist_chunk, fdata);
1006 cf_merge_files(const char *out_filename, int out_fd, int in_file_count,
1007 char *const *in_filenames, int file_type, gboolean do_append)
1009 merge_in_file_t *in_files;
1012 int open_err, read_err, write_err, close_err;
1016 char errmsg_errno[1024+1];
1017 gchar err_str[2048+1];
1019 gboolean got_read_error = FALSE, got_write_error = FALSE;
1021 progdlg_t *progbar = NULL;
1024 * XXX - should be "off_t", but Wiretap would need more work to handle
1025 * the full size of "off_t" on platforms where it's more than a "long"
1028 long f_len, file_pos;
1030 GTimeVal start_time;
1031 gchar status_str[100];
1032 int progbar_nextstep;
1033 int progbar_quantum;
1035 /* open the input files */
1036 if (!merge_open_in_files(in_file_count, in_filenames, &in_files,
1037 &open_err, &err_info, &err_fileno)) {
1039 cf_open_failure_alert_box(in_filenames[err_fileno], open_err, err_info,
1044 pdh = wtap_dump_fdopen(out_fd, file_type,
1045 merge_select_frame_type(in_file_count, in_files),
1046 merge_max_snapshot_length(in_file_count, in_files), &open_err);
1048 merge_close_in_files(in_file_count, in_files);
1050 cf_open_failure_alert_box(out_filename, open_err, err_info, TRUE,
1055 /* Get the sum of the sizes of all the files. */
1057 for (i = 0; i < in_file_count; i++)
1058 f_len += in_files[i].size;
1060 /* Update the progress bar when it gets to this value. */
1061 progbar_nextstep = 0;
1062 /* When we reach the value that triggers a progress bar update,
1063 bump that value by this amount. */
1064 progbar_quantum = f_len/N_PROGBAR_UPDATES;
1067 g_get_current_time(&start_time);
1069 /* do the merge (or append) */
1072 wth = merge_append_read_packet(in_file_count, in_files, &read_err,
1075 wth = merge_read_packet(in_file_count, in_files, &read_err,
1079 got_read_error = TRUE;
1083 /* Get the sum of the data offsets in all of the files. */
1085 for (i = 0; i < in_file_count; i++)
1086 data_offset += in_files[i].data_offset;
1088 if (data_offset >= progbar_nextstep) {
1089 /* Get the sum of the seek positions in all of the files. */
1091 for (i = 0; i < in_file_count; i++)
1092 file_pos += lseek(wtap_fd(in_files[i].wth), 0, SEEK_CUR);
1093 prog_val = (gfloat) file_pos / (gfloat) f_len;
1094 if (prog_val > 1.0) {
1095 /* Some file probably grew while we were reading it.
1096 That "shouldn't happen", so we'll just clip the progress
1100 if (progbar == NULL) {
1101 /* Create the progress bar if necessary */
1102 progbar = delayed_create_progress_dlg("Merging", "files",
1103 &stop_flag, &start_time, prog_val);
1105 if (progbar != NULL) {
1106 g_snprintf(status_str, sizeof(status_str),
1107 "%luKB of %luKB", file_pos / 1024, f_len / 1024);
1108 update_progress_dlg(progbar, prog_val, status_str);
1110 progbar_nextstep += progbar_quantum;
1113 if (!wtap_dump(pdh, wtap_phdr(wth), wtap_pseudoheader(wth),
1114 wtap_buf_ptr(wth), &write_err)) {
1115 got_write_error = TRUE;
1120 /* We're done merging the files; destroy the progress bar if it was created. */
1121 if (progbar != NULL)
1122 destroy_progress_dlg(progbar);
1124 merge_close_in_files(in_file_count, in_files);
1125 if (!got_read_error && !got_write_error) {
1126 if (!wtap_dump_close(pdh, &write_err))
1127 got_write_error = TRUE;
1129 wtap_dump_close(pdh, &close_err);
1131 if (got_read_error) {
1133 * Find the file on which we got the error, and report the error.
1135 for (i = 0; i < in_file_count; i++) {
1136 if (in_files[i].state == GOT_ERROR) {
1137 /* Put up a message box noting that a read failed somewhere along
1141 case WTAP_ERR_UNSUPPORTED_ENCAP:
1142 snprintf(errmsg_errno, sizeof(errmsg_errno),
1143 "The capture file %%s has a packet with a network type that Ethereal doesn't support.\n(%s)",
1146 errmsg = errmsg_errno;
1149 case WTAP_ERR_CANT_READ:
1150 errmsg = "An attempt to read from the capture file %s failed for"
1151 " some unknown reason.";
1154 case WTAP_ERR_SHORT_READ:
1155 errmsg = "The capture file %s appears to have been cut short"
1156 " in the middle of a packet.";
1159 case WTAP_ERR_BAD_RECORD:
1160 snprintf(errmsg_errno, sizeof(errmsg_errno),
1161 "The capture file %%s appears to be damaged or corrupt.\n(%s)",
1164 errmsg = errmsg_errno;
1168 snprintf(errmsg_errno, sizeof(errmsg_errno),
1169 "An error occurred while reading the"
1170 " capture file %%s: %s.", wtap_strerror(read_err));
1171 errmsg = errmsg_errno;
1174 snprintf(err_str, sizeof err_str, errmsg, in_files[i].filename);
1175 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, err_str);
1180 if (got_write_error) {
1181 /* Put up an alert box for the write error. */
1182 cf_write_failure_alert_box(out_filename, write_err);
1185 return (!got_read_error && !got_write_error) ? CF_OK : CF_ERROR;
1189 cf_filter_packets(capture_file *cf, gchar *dftext, gboolean force)
1192 char *filter_new = dftext ? dftext : "";
1193 char *filter_old = cf->dfilter ? cf->dfilter : "";
1195 /* if new filter equals old one, do nothing unless told to do so */
1196 if (!force && strcmp(filter_new, filter_old) == 0) {
1200 if (dftext == NULL) {
1201 /* The new filter is an empty filter (i.e., display all packets). */
1205 * We have a filter; make a copy of it (as we'll be saving it),
1206 * and try to compile it.
1208 dftext = g_strdup(dftext);
1209 if (!dfilter_compile(dftext, &dfcode)) {
1210 /* The attempt failed; report an error. */
1211 gchar *safe_dftext = simple_dialog_format_message(dftext);
1212 gchar *safe_dfilter_error_msg = simple_dialog_format_message(
1214 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1217 "The following display filter isn't a valid display filter:\n%s\n"
1218 "See the help for a description of the display filter syntax.",
1219 simple_dialog_primary_start(), safe_dfilter_error_msg,
1220 simple_dialog_primary_end(), safe_dftext);
1221 g_free(safe_dfilter_error_msg);
1222 g_free(safe_dftext);
1228 if (dfcode == NULL) {
1229 /* Yes - free the filter text, and set it to null. */
1235 /* We have a valid filter. Replace the current filter. */
1236 if (cf->dfilter != NULL)
1237 g_free(cf->dfilter);
1238 cf->dfilter = dftext;
1239 if (cf->dfcode != NULL)
1240 dfilter_free(cf->dfcode);
1241 cf->dfcode = dfcode;
1243 /* Now rescan the packet list, applying the new filter, but not
1244 throwing away information constructed on a previous pass. */
1245 if (dftext == NULL) {
1246 rescan_packets(cf, "Resetting", "Filter", TRUE, FALSE);
1248 rescan_packets(cf, "Filtering", dftext, TRUE, FALSE);
1254 cf_colorize_packets(capture_file *cf)
1256 rescan_packets(cf, "Colorizing", "all packets", FALSE, FALSE);
1260 cf_reftime_packets(capture_file *cf)
1262 rescan_packets(cf, "Updating Reftime", "all packets", FALSE, FALSE);
1266 cf_redissect_packets(capture_file *cf)
1268 rescan_packets(cf, "Reprocessing", "all packets", TRUE, TRUE);
1271 /* Rescan the list of packets, reconstructing the CList.
1273 "action" describes why we're doing this; it's used in the progress
1276 "action_item" describes what we're doing; it's used in the progress
1279 "refilter" is TRUE if we need to re-evaluate the filter expression.
1281 "redissect" is TRUE if we need to make the dissectors reconstruct
1282 any state information they have (because a preference that affects
1283 some dissector has changed, meaning some dissector might construct
1284 its state differently from the way it was constructed the last time). */
1286 rescan_packets(capture_file *cf, const char *action, const char *action_item,
1287 gboolean refilter, gboolean redissect)
1290 progdlg_t *progbar = NULL;
1295 frame_data *selected_frame, *preceding_frame, *following_frame, *prev_frame;
1296 int selected_row, prev_row, preceding_row, following_row;
1297 gboolean selected_frame_seen;
1300 GTimeVal start_time;
1301 gchar status_str[100];
1302 int progbar_nextstep;
1303 int progbar_quantum;
1306 reset_tap_listeners();
1307 /* Which frame, if any, is the currently selected frame?
1308 XXX - should the selected frame or the focus frame be the "current"
1309 frame, that frame being the one from which "Find Frame" searches
1311 selected_frame = cf->current_frame;
1313 /* We don't yet know what row that frame will be on, if any, after we
1314 rebuild the clist, however. */
1318 /* We need to re-initialize all the state information that protocols
1319 keep, because some preference that controls a dissector has changed,
1320 which might cause the state information to be constructed differently
1321 by that dissector. */
1323 /* Initialize all data structures used for dissection. */
1327 /* Freeze the packet list while we redo it, so we don't get any
1328 screen updates while it happens. */
1329 packet_list_freeze();
1332 packet_list_clear();
1334 /* We don't yet know which will be the first and last frames displayed. */
1335 cf->first_displayed = NULL;
1336 cf->last_displayed = NULL;
1338 /* We currently don't display any packets */
1339 cf->displayed_count = 0;
1341 /* Iterate through the list of frames. Call a routine for each frame
1342 to check whether it should be displayed and, if so, add it to
1343 the display list. */
1349 /* Update the progress bar when it gets to this value. */
1350 progbar_nextstep = 0;
1351 /* When we reach the value that triggers a progress bar update,
1352 bump that value by this amount. */
1353 progbar_quantum = cf->count/N_PROGBAR_UPDATES;
1354 /* Count of packets at which we've looked. */
1358 g_get_current_time(&start_time);
1360 row = -1; /* no previous row yet */
1365 preceding_frame = NULL;
1367 following_frame = NULL;
1369 selected_frame_seen = FALSE;
1371 for (fdata = cf->plist; fdata != NULL; fdata = fdata->next) {
1372 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
1373 when we update it, we have to run the GTK+ main loop to get it
1374 to repaint what's pending, and doing so may involve an "ioctl()"
1375 to see if there's any pending input from an X server, and doing
1376 that for every packet can be costly, especially on a big file. */
1377 if (count >= progbar_nextstep) {
1378 /* let's not divide by zero. I should never be started
1379 * with count == 0, so let's assert that
1381 g_assert(cf->count > 0);
1382 prog_val = (gfloat) count / cf->count;
1384 if (progbar == NULL)
1385 /* Create the progress bar if necessary */
1386 progbar = delayed_create_progress_dlg(action, action_item, &stop_flag,
1387 &start_time, prog_val);
1389 if (progbar != NULL) {
1390 g_snprintf(status_str, sizeof(status_str),
1391 "%4u of %u frames", count, cf->count);
1392 update_progress_dlg(progbar, prog_val, status_str);
1395 progbar_nextstep += progbar_quantum;
1399 /* Well, the user decided to abort the filtering. Just stop.
1401 XXX - go back to the previous filter? Users probably just
1402 want not to wait for a filtering operation to finish;
1403 unless we cancel by having no filter, reverting to the
1404 previous filter will probably be even more expensive than
1405 continuing the filtering, as it involves going back to the
1406 beginning and filtering, and even with no filter we currently
1407 have to re-generate the entire clist, which is also expensive.
1409 I'm not sure what Network Monitor does, but it doesn't appear
1410 to give you an unfiltered display if you cancel. */
1417 /* Since all state for the frame was destroyed, mark the frame
1418 * as not visited, free the GSList referring to the state
1419 * data (the per-frame data itself was freed by
1420 * "init_dissection()"), and null out the GSList pointer. */
1421 fdata->flags.visited = 0;
1423 g_slist_free(fdata->pfd);
1428 if (!wtap_seek_read (cf->wth, fdata->file_off, &cf->pseudo_header,
1429 cf->pd, fdata->cap_len, &err, &err_info)) {
1430 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1431 cf_read_error_message(err, err_info), cf->filename);
1435 /* If the previous frame is displayed, and we haven't yet seen the
1436 selected frame, remember that frame - it's the closest one we've
1437 yet seen before the selected frame. */
1438 if (prev_row != -1 && !selected_frame_seen) {
1439 preceding_row = prev_row;
1440 preceding_frame = prev_frame;
1442 row = add_packet_to_packet_list(fdata, cf, &cf->pseudo_header, cf->pd,
1445 /* If this frame is displayed, and this is the first frame we've
1446 seen displayed after the selected frame, remember this frame -
1447 it's the closest one we've yet seen at or after the selected
1449 if (row != -1 && selected_frame_seen && following_row == -1) {
1450 following_row = row;
1451 following_frame = fdata;
1453 if (fdata == selected_frame) {
1455 selected_frame_seen = TRUE;
1458 /* Remember this row/frame - it'll be the previous row/frame
1459 on the next pass through the loop. */
1465 /* Clear out what remains of the visited flags and per-frame data
1468 XXX - that may cause various forms of bogosity when dissecting
1469 these frames, as they won't have been seen by this sequential
1470 pass, but the only alternative I see is to keep scanning them
1471 even though the user requested that the scan stop, and that
1472 would leave the user stuck with an Ethereal grinding on
1473 until it finishes. Should we just stick them with that? */
1474 for (; fdata != NULL; fdata = fdata->next) {
1475 fdata->flags.visited = 0;
1477 g_slist_free(fdata->pfd);
1483 /* We're done filtering the packets; destroy the progress bar if it
1485 if (progbar != NULL)
1486 destroy_progress_dlg(progbar);
1488 /* Unfreeze the packet list. */
1491 if (selected_row == -1) {
1492 /* The selected frame didn't pass the filter. */
1493 if (selected_frame == NULL) {
1494 /* That's because there *was* no selected frame. Make the first
1495 displayed frame the current frame. */
1498 /* Find the nearest displayed frame to the selected frame (whether
1499 it's before or after that frame) and make that the current frame.
1500 If the next and previous displayed frames are equidistant from the
1501 selected frame, choose the next one. */
1502 g_assert(following_frame == NULL ||
1503 following_frame->num >= selected_frame->num);
1504 g_assert(preceding_frame == NULL ||
1505 preceding_frame->num <= selected_frame->num);
1506 if (following_frame == NULL) {
1507 /* No frame after the selected frame passed the filter, so we
1508 have to select the last displayed frame before the selected
1510 selected_row = preceding_row;
1511 } else if (preceding_frame == NULL) {
1512 /* No frame before the selected frame passed the filter, so we
1513 have to select the first displayed frame after the selected
1515 selected_row = following_row;
1517 /* Choose the closer of the last displayed frame before the
1518 selected frame and the first displayed frame after the
1519 selected frame; in case of a tie, choose the first displayed
1520 frame after the selected frame. */
1521 if (following_frame->num - selected_frame->num <=
1522 selected_frame->num - preceding_frame->num) {
1523 selected_row = following_row;
1525 /* The previous frame is closer to the selected frame than the
1527 selected_row = preceding_row;
1533 if (selected_row == -1) {
1534 /* There are no frames displayed at all. */
1535 cf_unselect_packet(cf);
1537 /* Either the frame that was selected passed the filter, or we've
1538 found the nearest displayed frame to that frame. Select it, make
1539 it the focus row, and make it visible. */
1540 packet_list_set_selected_row(selected_row);
1551 process_specified_packets(capture_file *cf, packet_range_t *range,
1552 const char *string1, const char *string2,
1553 gboolean (*callback)(capture_file *, frame_data *,
1554 union wtap_pseudo_header *, const guint8 *, void *),
1555 void *callback_args)
1560 union wtap_pseudo_header pseudo_header;
1561 guint8 pd[WTAP_MAX_PACKET_SIZE+1];
1562 psp_return_t ret = PSP_FINISHED;
1564 progdlg_t *progbar = NULL;
1567 gboolean progbar_stop_flag;
1568 GTimeVal progbar_start_time;
1569 gchar progbar_status_str[100];
1570 int progbar_nextstep;
1571 int progbar_quantum;
1572 range_process_e process_this;
1574 /* Update the progress bar when it gets to this value. */
1575 progbar_nextstep = 0;
1576 /* When we reach the value that triggers a progress bar update,
1577 bump that value by this amount. */
1578 progbar_quantum = cf->count/N_PROGBAR_UPDATES;
1579 /* Count of packets at which we've looked. */
1582 progbar_stop_flag = FALSE;
1583 g_get_current_time(&progbar_start_time);
1585 packet_range_process_init(range);
1587 /* Iterate through the list of packets, printing the packets that
1588 were selected by the current display filter. */
1589 for (fdata = cf->plist; fdata != NULL; fdata = fdata->next) {
1590 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
1591 when we update it, we have to run the GTK+ main loop to get it
1592 to repaint what's pending, and doing so may involve an "ioctl()"
1593 to see if there's any pending input from an X server, and doing
1594 that for every packet can be costly, especially on a big file. */
1595 if (progbar_count >= progbar_nextstep) {
1596 /* let's not divide by zero. I should never be started
1597 * with count == 0, so let's assert that
1599 g_assert(cf->count > 0);
1600 progbar_val = (gfloat) progbar_count / cf->count;
1602 if (progbar == NULL)
1603 /* Create the progress bar if necessary */
1604 progbar = delayed_create_progress_dlg(string1, string2,
1606 &progbar_start_time,
1609 if (progbar != NULL) {
1610 g_snprintf(progbar_status_str, sizeof(progbar_status_str),
1611 "%4u of %u packets", progbar_count, cf->count);
1612 update_progress_dlg(progbar, progbar_val, progbar_status_str);
1615 progbar_nextstep += progbar_quantum;
1618 if (progbar_stop_flag) {
1619 /* Well, the user decided to abort the operation. Just stop,
1620 and arrange to return TRUE to our caller, so they know it
1621 was stopped explicitly. */
1628 /* do we have to process this packet? */
1629 process_this = packet_range_process_packet(range, fdata);
1630 if (process_this == range_process_next) {
1631 /* this packet uninteresting, continue with next one */
1633 } else if (process_this == range_processing_finished) {
1634 /* all interesting packets processed, stop the loop */
1638 /* Get the packet */
1639 if (!wtap_seek_read(cf->wth, fdata->file_off, &pseudo_header,
1640 pd, fdata->cap_len, &err, &err_info)) {
1641 /* Attempt to get the packet failed. */
1642 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1643 cf_read_error_message(err, err_info), cf->filename);
1647 /* Process the packet */
1648 if (!callback(cf, fdata, &pseudo_header, pd, callback_args)) {
1649 /* Callback failed. We assume it reported the error appropriately. */
1655 /* We're done printing the packets; destroy the progress bar if
1657 if (progbar != NULL)
1658 destroy_progress_dlg(progbar);
1664 retap_packet(capture_file *cf _U_, frame_data *fdata,
1665 union wtap_pseudo_header *pseudo_header, const guint8 *pd,
1668 epan_dissect_t *edt;
1670 /* If we have tap listeners, allocate a protocol tree root node, so that
1671 we'll construct a protocol tree against which a filter expression can
1673 edt = epan_dissect_new(num_tap_filters != 0, FALSE);
1674 tap_queue_init(edt);
1675 epan_dissect_run(edt, pseudo_header, pd, fdata, NULL);
1676 tap_push_tapped_queue(edt);
1677 epan_dissect_free(edt);
1683 cf_retap_packets(capture_file *cf)
1685 packet_range_t range;
1687 /* Reset the tap listeners. */
1688 reset_tap_listeners();
1690 /* Iterate through the list of packets, dissecting all packets and
1691 re-running the taps. */
1692 packet_range_init(&range);
1693 packet_range_process_init(&range);
1694 switch (process_specified_packets(cf, &range, "Refiltering statistics on",
1695 "all packets", retap_packet,
1698 /* Completed successfully. */
1702 /* Well, the user decided to abort the refiltering.
1703 Return CF_READ_ABORTED so our caller knows they did that. */
1704 return CF_READ_ABORTED;
1707 /* Error while retapping. */
1708 return CF_READ_ERROR;
1711 g_assert_not_reached();
1716 print_args_t *print_args;
1717 gboolean print_header_line;
1718 char *header_line_buf;
1719 int header_line_buf_len;
1720 gboolean print_formfeed;
1721 gboolean print_separator;
1725 } print_callback_args_t;
1728 print_packet(capture_file *cf, frame_data *fdata,
1729 union wtap_pseudo_header *pseudo_header, const guint8 *pd,
1732 print_callback_args_t *args = argsp;
1733 epan_dissect_t *edt;
1739 gboolean proto_tree_needed;
1740 char bookmark_name[9+10+1]; /* "__frameNNNNNNNNNN__\0" */
1741 char bookmark_title[6+10+1]; /* "Frame NNNNNNNNNN__\0" */
1743 /* Create the protocol tree, and make it visible, if we're printing
1744 the dissection or the hex data.
1745 XXX - do we need it if we're just printing the hex data? */
1747 args->print_args->print_dissections != print_dissections_none || args->print_args->print_hex;
1748 edt = epan_dissect_new(proto_tree_needed, proto_tree_needed);
1750 /* Fill in the column information if we're printing the summary
1752 if (args->print_args->print_summary) {
1753 epan_dissect_run(edt, pseudo_header, pd, fdata, &cf->cinfo);
1754 epan_dissect_fill_in_columns(edt);
1756 epan_dissect_run(edt, pseudo_header, pd, fdata, NULL);
1758 if (args->print_formfeed) {
1759 if (!new_page(args->print_args->stream))
1762 if (args->print_separator) {
1763 if (!print_line(args->print_args->stream, 0, ""))
1769 * We generate bookmarks, if the output format supports them.
1770 * The name is "__frameN__".
1772 sprintf(bookmark_name, "__frame%u__", fdata->num);
1774 if (args->print_args->print_summary) {
1775 if (args->print_header_line) {
1776 if (!print_line(args->print_args->stream, 0, args->header_line_buf))
1778 args->print_header_line = FALSE; /* we might not need to print any more */
1780 cp = &args->line_buf[0];
1782 for (i = 0; i < cf->cinfo.num_cols; i++) {
1783 /* Find the length of the string for this column. */
1784 column_len = strlen(cf->cinfo.col_data[i]);
1785 if (args->col_widths[i] > column_len)
1786 column_len = args->col_widths[i];
1788 /* Make sure there's room in the line buffer for the column; if not,
1789 double its length. */
1790 line_len += column_len + 1; /* "+1" for space */
1791 if (line_len > args->line_buf_len) {
1792 cp_off = cp - args->line_buf;
1793 args->line_buf_len = 2 * line_len;
1794 args->line_buf = g_realloc(args->line_buf, args->line_buf_len + 1);
1795 cp = args->line_buf + cp_off;
1798 /* Right-justify the packet number column. */
1799 if (cf->cinfo.col_fmt[i] == COL_NUMBER)
1800 sprintf(cp, "%*s", args->col_widths[i], cf->cinfo.col_data[i]);
1802 sprintf(cp, "%-*s", args->col_widths[i], cf->cinfo.col_data[i]);
1804 if (i != cf->cinfo.num_cols - 1)
1810 * Generate a bookmark, using the summary line as the title.
1812 if (!print_bookmark(args->print_args->stream, bookmark_name,
1816 if (!print_line(args->print_args->stream, 0, args->line_buf))
1820 * Generate a bookmark, using "Frame N" as the title, as we're not
1821 * printing the summary line.
1823 sprintf(bookmark_title, "Frame %u", fdata->num);
1824 if (!print_bookmark(args->print_args->stream, bookmark_name,
1827 } /* if (print_summary) */
1829 if (args->print_args->print_dissections != print_dissections_none) {
1830 if (args->print_args->print_summary) {
1831 /* Separate the summary line from the tree with a blank line. */
1832 if (!print_line(args->print_args->stream, 0, ""))
1836 /* Print the information in that tree. */
1837 if (!proto_tree_print(args->print_args, edt, args->print_args->stream))
1840 /* Print a blank line if we print anything after this (aka more than one packet). */
1841 args->print_separator = TRUE;
1843 /* Print a header line if we print any more packet summaries */
1844 args->print_header_line = TRUE;
1847 if (args->print_args->print_hex) {
1848 /* Print the full packet data as hex. */
1849 if (!print_hex_data(args->print_args->stream, edt))
1852 /* Print a blank line if we print anything after this (aka more than one packet). */
1853 args->print_separator = TRUE;
1855 /* Print a header line if we print any more packet summaries */
1856 args->print_header_line = TRUE;
1857 } /* if (args->print_args->print_dissections != print_dissections_none) */
1859 epan_dissect_free(edt);
1861 /* do we want to have a formfeed between each packet from now on? */
1862 if(args->print_args->print_formfeed) {
1863 args->print_formfeed = TRUE;
1869 epan_dissect_free(edt);
1874 cf_print_packets(capture_file *cf, print_args_t *print_args)
1877 print_callback_args_t callback_args;
1885 callback_args.print_args = print_args;
1886 callback_args.print_header_line = TRUE;
1887 callback_args.header_line_buf = NULL;
1888 callback_args.header_line_buf_len = 256;
1889 callback_args.print_formfeed = FALSE;
1890 callback_args.print_separator = FALSE;
1891 callback_args.line_buf = NULL;
1892 callback_args.line_buf_len = 256;
1893 callback_args.col_widths = NULL;
1895 if (!print_preamble(print_args->stream, cf->filename)) {
1896 destroy_print_stream(print_args->stream);
1897 return CF_PRINT_WRITE_ERROR;
1900 if (print_args->print_summary) {
1901 /* We're printing packet summaries. Allocate the header line buffer
1902 and get the column widths. */
1903 callback_args.header_line_buf = g_malloc(callback_args.header_line_buf_len + 1);
1905 /* Find the widths for each of the columns - maximum of the
1906 width of the title and the width of the data - and construct
1907 a buffer with a line containing the column titles. */
1908 callback_args.col_widths = (gint *) g_malloc(sizeof(gint) * cf->cinfo.num_cols);
1909 cp = &callback_args.header_line_buf[0];
1911 for (i = 0; i < cf->cinfo.num_cols; i++) {
1912 /* Don't pad the last column. */
1913 if (i == cf->cinfo.num_cols - 1)
1914 callback_args.col_widths[i] = 0;
1916 callback_args.col_widths[i] = strlen(cf->cinfo.col_title[i]);
1917 data_width = get_column_char_width(get_column_format(i));
1918 if (data_width > callback_args.col_widths[i])
1919 callback_args.col_widths[i] = data_width;
1922 /* Find the length of the string for this column. */
1923 column_len = strlen(cf->cinfo.col_title[i]);
1924 if (callback_args.col_widths[i] > column_len)
1925 column_len = callback_args.col_widths[i];
1927 /* Make sure there's room in the line buffer for the column; if not,
1928 double its length. */
1929 line_len += column_len + 1; /* "+1" for space */
1930 if (line_len > callback_args.header_line_buf_len) {
1931 cp_off = cp - callback_args.header_line_buf;
1932 callback_args.header_line_buf_len = 2 * line_len;
1933 callback_args.header_line_buf = g_realloc(callback_args.header_line_buf,
1934 callback_args.header_line_buf_len + 1);
1935 cp = callback_args.header_line_buf + cp_off;
1938 /* Right-justify the packet number column. */
1939 /* if (cf->cinfo.col_fmt[i] == COL_NUMBER)
1940 sprintf(cp, "%*s", callback_args.col_widths[i], cf->cinfo.col_title[i]);
1942 sprintf(cp, "%-*s", callback_args.col_widths[i], cf->cinfo.col_title[i]);
1944 if (i != cf->cinfo.num_cols - 1)
1949 /* Now start out the main line buffer with the same length as the
1950 header line buffer. */
1951 callback_args.line_buf_len = callback_args.header_line_buf_len;
1952 callback_args.line_buf = g_malloc(callback_args.line_buf_len + 1);
1953 } /* if (print_summary) */
1955 /* Iterate through the list of packets, printing the packets we were
1957 ret = process_specified_packets(cf, &print_args->range, "Printing",
1958 "selected packets", print_packet,
1961 if (callback_args.header_line_buf != NULL)
1962 g_free(callback_args.header_line_buf);
1963 if (callback_args.line_buf != NULL)
1964 g_free(callback_args.line_buf);
1965 if (callback_args.col_widths != NULL)
1966 g_free(callback_args.col_widths);
1971 /* Completed successfully. */
1975 /* Well, the user decided to abort the printing.
1977 XXX - note that what got generated before they did that
1978 will get printed if we're piping to a print program; we'd
1979 have to write to a file and then hand that to the print
1980 program to make it actually not print anything. */
1984 /* Error while printing.
1986 XXX - note that what got generated before they did that
1987 will get printed if we're piping to a print program; we'd
1988 have to write to a file and then hand that to the print
1989 program to make it actually not print anything. */
1990 destroy_print_stream(print_args->stream);
1991 return CF_PRINT_WRITE_ERROR;
1994 if (!print_finale(print_args->stream)) {
1995 destroy_print_stream(print_args->stream);
1996 return CF_PRINT_WRITE_ERROR;
1999 if (!destroy_print_stream(print_args->stream))
2000 return CF_PRINT_WRITE_ERROR;
2006 write_pdml_packet(capture_file *cf _U_, frame_data *fdata,
2007 union wtap_pseudo_header *pseudo_header, const guint8 *pd,
2011 epan_dissect_t *edt;
2013 /* Create the protocol tree, but don't fill in the column information. */
2014 edt = epan_dissect_new(TRUE, TRUE);
2015 epan_dissect_run(edt, pseudo_header, pd, fdata, NULL);
2017 /* Write out the information in that tree. */
2018 proto_tree_write_pdml(edt, fh);
2020 epan_dissect_free(edt);
2026 cf_write_pdml_packets(capture_file *cf, print_args_t *print_args)
2031 fh = fopen(print_args->file, "w");
2033 return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
2035 write_pdml_preamble(fh);
2038 return CF_PRINT_WRITE_ERROR;
2041 /* Iterate through the list of packets, printing the packets we were
2043 ret = process_specified_packets(cf, &print_args->range, "Writing PDML",
2044 "selected packets", write_pdml_packet,
2050 /* Completed successfully. */
2054 /* Well, the user decided to abort the printing. */
2058 /* Error while printing. */
2060 return CF_PRINT_WRITE_ERROR;
2063 write_pdml_finale(fh);
2066 return CF_PRINT_WRITE_ERROR;
2069 /* XXX - check for an error */
2076 write_psml_packet(capture_file *cf, frame_data *fdata,
2077 union wtap_pseudo_header *pseudo_header, const guint8 *pd,
2081 epan_dissect_t *edt;
2083 /* Fill in the column information, but don't create the protocol tree. */
2084 edt = epan_dissect_new(FALSE, FALSE);
2085 epan_dissect_run(edt, pseudo_header, pd, fdata, &cf->cinfo);
2087 /* Write out the information in that tree. */
2088 proto_tree_write_psml(edt, fh);
2090 epan_dissect_free(edt);
2096 cf_write_psml_packets(capture_file *cf, print_args_t *print_args)
2101 fh = fopen(print_args->file, "w");
2103 return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
2105 write_psml_preamble(fh);
2108 return CF_PRINT_WRITE_ERROR;
2111 /* Iterate through the list of packets, printing the packets we were
2113 ret = process_specified_packets(cf, &print_args->range, "Writing PSML",
2114 "selected packets", write_psml_packet,
2120 /* Completed successfully. */
2124 /* Well, the user decided to abort the printing. */
2128 /* Error while printing. */
2130 return CF_PRINT_WRITE_ERROR;
2133 write_psml_finale(fh);
2136 return CF_PRINT_WRITE_ERROR;
2139 /* XXX - check for an error */
2145 /* Scan through the packet list and change all columns that use the
2146 "command-line-specified" time stamp format to use the current
2147 value of that format. */
2149 cf_change_time_formats(capture_file *cf)
2152 progdlg_t *progbar = NULL;
2158 GTimeVal start_time;
2159 gchar status_str[100];
2160 int progbar_nextstep;
2161 int progbar_quantum;
2163 gboolean sorted_by_frame_column;
2165 /* Are there any columns with time stamps in the "command-line-specified"
2168 XXX - we have to force the "column is writable" flag on, as it
2169 might be off from the last frame that was dissected. */
2170 col_set_writable(&cf->cinfo, TRUE);
2171 if (!check_col(&cf->cinfo, COL_CLS_TIME)) {
2172 /* No, there aren't any columns in that format, so we have no work
2176 first = cf->cinfo.col_first[COL_CLS_TIME];
2177 g_assert(first >= 0);
2178 last = cf->cinfo.col_last[COL_CLS_TIME];
2180 /* Freeze the packet list while we redo it, so we don't get any
2181 screen updates while it happens. */
2182 packet_list_freeze();
2184 /* Update the progress bar when it gets to this value. */
2185 progbar_nextstep = 0;
2186 /* When we reach the value that triggers a progress bar update,
2187 bump that value by this amount. */
2188 progbar_quantum = cf->count/N_PROGBAR_UPDATES;
2189 /* Count of packets at which we've looked. */
2192 /* If the rows are currently sorted by the frame column then we know
2193 * the row number of each packet: it's the row number of the previously
2194 * displayed packet + 1.
2196 * Otherwise, if the display is sorted by a different column then we have
2197 * to use the O(N) packet_list_find_row_from_data() (thus making the job
2198 * of changing the time display format O(N**2)).
2200 * (XXX - In fact it's still O(N**2) because gtk_clist_set_text() takes
2201 * the row number and walks that many elements down the clist to find
2202 * the appropriate element.)
2204 sorted_by_frame_column = FALSE;
2205 for (i = 0; i < cf->cinfo.num_cols; i++) {
2206 if (cf->cinfo.col_fmt[i] == COL_NUMBER)
2208 sorted_by_frame_column = (i == packet_list_get_sort_column());
2214 g_get_current_time(&start_time);
2216 /* Iterate through the list of packets, checking whether the packet
2217 is in a row of the summary list and, if so, whether there are
2218 any columns that show the time in the "command-line-specified"
2219 format and, if so, update that row. */
2220 for (fdata = cf->plist, row = -1; fdata != NULL; fdata = fdata->next) {
2221 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
2222 when we update it, we have to run the GTK+ main loop to get it
2223 to repaint what's pending, and doing so may involve an "ioctl()"
2224 to see if there's any pending input from an X server, and doing
2225 that for every packet can be costly, especially on a big file. */
2226 if (count >= progbar_nextstep) {
2227 /* let's not divide by zero. I should never be started
2228 * with count == 0, so let's assert that
2230 g_assert(cf->count > 0);
2232 prog_val = (gfloat) count / cf->count;
2234 if (progbar == NULL)
2235 /* Create the progress bar if necessary */
2236 progbar = delayed_create_progress_dlg("Changing", "time display",
2237 &stop_flag, &start_time, prog_val);
2239 if (progbar != NULL) {
2240 g_snprintf(status_str, sizeof(status_str),
2241 "%4u of %u packets", count, cf->count);
2242 update_progress_dlg(progbar, prog_val, status_str);
2245 progbar_nextstep += progbar_quantum;
2249 /* Well, the user decided to abort the redisplay. Just stop.
2251 XXX - this leaves the time field in the old format in
2252 frames we haven't yet processed. So it goes; should we
2253 simply not offer them the option of stopping? */
2259 /* Find what row this packet is in. */
2260 if (!sorted_by_frame_column) {
2261 /* This function is O(N), so we try to avoid using it... */
2262 row = packet_list_find_row_from_data(fdata);
2264 /* ...which we do by maintaining a count of packets that are
2265 being displayed (i.e., that have passed the display filter),
2266 and using the current value of that count as the row number
2267 (which is why we can only do it when the display is sorted
2268 by the frame number). */
2269 if (fdata->flags.passed_dfilter)
2276 /* This packet is in the summary list, on row "row". */
2278 for (i = first; i <= last; i++) {
2279 if (cf->cinfo.fmt_matx[i][COL_CLS_TIME]) {
2280 /* This is one of the columns that shows the time in
2281 "command-line-specified" format; update it. */
2282 cf->cinfo.col_buf[i][0] = '\0';
2283 col_set_cls_time(fdata, &cf->cinfo, i);
2284 packet_list_set_text(row, i, cf->cinfo.col_data[i]);
2290 /* We're done redisplaying the packets; destroy the progress bar if it
2292 if (progbar != NULL)
2293 destroy_progress_dlg(progbar);
2295 /* Set the column widths of those columns that show the time in
2296 "command-line-specified" format. */
2297 for (i = first; i <= last; i++) {
2298 if (cf->cinfo.fmt_matx[i][COL_CLS_TIME]) {
2299 packet_list_set_cls_time_width(i);
2303 /* Unfreeze the packet list. */
2311 gboolean frame_matched;
2315 cf_find_packet_protocol_tree(capture_file *cf, const char *string)
2319 mdata.string = string;
2320 mdata.string_len = strlen(string);
2321 return find_packet(cf, match_protocol_tree, &mdata);
2325 match_protocol_tree(capture_file *cf, frame_data *fdata, void *criterion)
2327 match_data *mdata = criterion;
2328 epan_dissect_t *edt;
2330 /* Construct the protocol tree, including the displayed text */
2331 edt = epan_dissect_new(TRUE, TRUE);
2332 /* We don't need the column information */
2333 epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, NULL);
2335 /* Iterate through all the nodes, seeing if they have text that matches. */
2337 mdata->frame_matched = FALSE;
2338 proto_tree_children_foreach(edt->tree, match_subtree_text, mdata);
2339 epan_dissect_free(edt);
2340 return mdata->frame_matched;
2344 match_subtree_text(proto_node *node, gpointer data)
2346 match_data *mdata = (match_data*) data;
2347 const gchar *string = mdata->string;
2348 size_t string_len = mdata->string_len;
2349 capture_file *cf = mdata->cf;
2350 field_info *fi = PITEM_FINFO(node);
2351 gchar label_str[ITEM_LABEL_LENGTH];
2358 if (mdata->frame_matched) {
2359 /* We already had a match; don't bother doing any more work. */
2363 /* Don't match invisible entries. */
2364 if (PROTO_ITEM_IS_HIDDEN(node))
2367 /* was a free format label produced? */
2369 label_ptr = fi->rep->representation;
2371 /* no, make a generic label */
2372 label_ptr = label_str;
2373 proto_item_fill_label(fi, label_str);
2376 /* Does that label match? */
2377 label_len = strlen(label_ptr);
2378 for (i = 0; i < label_len; i++) {
2379 c_char = label_ptr[i];
2381 c_char = toupper(c_char);
2382 if (c_char == string[c_match]) {
2384 if (c_match == string_len) {
2385 /* No need to look further; we have a match */
2386 mdata->frame_matched = TRUE;
2393 /* Recurse into the subtree, if it exists */
2394 if (node->first_child != NULL)
2395 proto_tree_children_foreach(node, match_subtree_text, mdata);
2399 cf_find_packet_summary_line(capture_file *cf, const char *string)
2403 mdata.string = string;
2404 mdata.string_len = strlen(string);
2405 return find_packet(cf, match_summary_line, &mdata);
2409 match_summary_line(capture_file *cf, frame_data *fdata, void *criterion)
2411 match_data *mdata = criterion;
2412 const gchar *string = mdata->string;
2413 size_t string_len = mdata->string_len;
2414 epan_dissect_t *edt;
2415 const char *info_column;
2416 size_t info_column_len;
2417 gboolean frame_matched = FALSE;
2423 /* Don't bother constructing the protocol tree */
2424 edt = epan_dissect_new(FALSE, FALSE);
2425 /* Get the column information */
2426 epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, &cf->cinfo);
2428 /* Find the Info column */
2429 for (colx = 0; colx < cf->cinfo.num_cols; colx++) {
2430 if (cf->cinfo.fmt_matx[colx][COL_INFO]) {
2431 /* Found it. See if we match. */
2432 info_column = edt->pi.cinfo->col_data[colx];
2433 info_column_len = strlen(info_column);
2434 for (i = 0; i < info_column_len; i++) {
2435 c_char = info_column[i];
2437 c_char = toupper(c_char);
2438 if (c_char == string[c_match]) {
2440 if (c_match == string_len) {
2441 frame_matched = TRUE;
2450 epan_dissect_free(edt);
2451 return frame_matched;
2457 } cbs_t; /* "Counted byte string" */
2460 cf_find_packet_data(capture_file *cf, const guint8 *string, size_t string_size)
2465 info.data_len = string_size;
2467 /* String or hex search? */
2469 /* String search - what type of string? */
2470 switch (cf->scs_type) {
2472 case SCS_ASCII_AND_UNICODE:
2473 return find_packet(cf, match_ascii_and_unicode, &info);
2476 return find_packet(cf, match_ascii, &info);
2479 return find_packet(cf, match_unicode, &info);
2482 g_assert_not_reached();
2486 return find_packet(cf, match_binary, &info);
2490 match_ascii_and_unicode(capture_file *cf, frame_data *fdata, void *criterion)
2492 cbs_t *info = criterion;
2493 const char *ascii_text = info->data;
2494 size_t textlen = info->data_len;
2495 gboolean frame_matched;
2501 frame_matched = FALSE;
2502 buf_len = fdata->pkt_len;
2503 for (i = 0; i < buf_len; i++) {
2506 c_char = toupper(c_char);
2508 if (c_char == ascii_text[c_match]) {
2510 if (c_match == textlen) {
2511 frame_matched = TRUE;
2518 return frame_matched;
2522 match_ascii(capture_file *cf, frame_data *fdata, void *criterion)
2524 cbs_t *info = criterion;
2525 const char *ascii_text = info->data;
2526 size_t textlen = info->data_len;
2527 gboolean frame_matched;
2533 frame_matched = FALSE;
2534 buf_len = fdata->pkt_len;
2535 for (i = 0; i < buf_len; i++) {
2538 c_char = toupper(c_char);
2539 if (c_char == ascii_text[c_match]) {
2541 if (c_match == textlen) {
2542 frame_matched = TRUE;
2548 return frame_matched;
2552 match_unicode(capture_file *cf, frame_data *fdata, void *criterion)
2554 cbs_t *info = criterion;
2555 const char *ascii_text = info->data;
2556 size_t textlen = info->data_len;
2557 gboolean frame_matched;
2563 frame_matched = FALSE;
2564 buf_len = fdata->pkt_len;
2565 for (i = 0; i < buf_len; i++) {
2568 c_char = toupper(c_char);
2569 if (c_char == ascii_text[c_match]) {
2572 if (c_match == textlen) {
2573 frame_matched = TRUE;
2579 return frame_matched;
2583 match_binary(capture_file *cf, frame_data *fdata, void *criterion)
2585 cbs_t *info = criterion;
2586 const guint8 *binary_data = info->data;
2587 size_t datalen = info->data_len;
2588 gboolean frame_matched;
2593 frame_matched = FALSE;
2594 buf_len = fdata->pkt_len;
2595 for (i = 0; i < buf_len; i++) {
2596 if (cf->pd[i] == binary_data[c_match]) {
2598 if (c_match == datalen) {
2599 frame_matched = TRUE;
2605 return frame_matched;
2609 cf_find_packet_dfilter(capture_file *cf, dfilter_t *sfcode)
2611 return find_packet(cf, match_dfilter, sfcode);
2615 match_dfilter(capture_file *cf, frame_data *fdata, void *criterion)
2617 dfilter_t *sfcode = criterion;
2618 epan_dissect_t *edt;
2619 gboolean frame_matched;
2621 edt = epan_dissect_new(TRUE, FALSE);
2622 epan_dissect_prime_dfilter(edt, sfcode);
2623 epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, NULL);
2624 frame_matched = dfilter_apply_edt(sfcode, edt);
2625 epan_dissect_free(edt);
2626 return frame_matched;
2630 find_packet(capture_file *cf,
2631 gboolean (*match_function)(capture_file *, frame_data *, void *),
2634 frame_data *start_fd;
2636 frame_data *new_fd = NULL;
2637 progdlg_t *progbar = NULL;
2644 GTimeVal start_time;
2645 gchar status_str[100];
2646 int progbar_nextstep;
2647 int progbar_quantum;
2649 start_fd = cf->current_frame;
2650 if (start_fd != NULL) {
2651 /* Iterate through the list of packets, starting at the packet we've
2652 picked, calling a routine to run the filter on the packet, see if
2653 it matches, and stop if so. */
2657 progbar_nextstep = 0;
2658 /* When we reach the value that triggers a progress bar update,
2659 bump that value by this amount. */
2660 progbar_quantum = cf->count/N_PROGBAR_UPDATES;
2663 g_get_current_time(&start_time);
2667 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
2668 when we update it, we have to run the GTK+ main loop to get it
2669 to repaint what's pending, and doing so may involve an "ioctl()"
2670 to see if there's any pending input from an X server, and doing
2671 that for every packet can be costly, especially on a big file. */
2672 if (count >= progbar_nextstep) {
2673 /* let's not divide by zero. I should never be started
2674 * with count == 0, so let's assert that
2676 g_assert(cf->count > 0);
2678 prog_val = (gfloat) count / cf->count;
2680 /* Create the progress bar if necessary */
2681 if (progbar == NULL)
2682 progbar = delayed_create_progress_dlg("Searching", cf->sfilter,
2683 &stop_flag, &start_time, prog_val);
2685 if (progbar != NULL) {
2686 g_snprintf(status_str, sizeof(status_str),
2687 "%4u of %u packets", count, cf->count);
2688 update_progress_dlg(progbar, prog_val, status_str);
2691 progbar_nextstep += progbar_quantum;
2695 /* Well, the user decided to abort the search. Go back to the
2696 frame where we started. */
2701 /* Go past the current frame. */
2702 if (cf->sbackward) {
2703 /* Go on to the previous frame. */
2704 fdata = fdata->prev;
2705 if (fdata == NULL) {
2707 * XXX - other apps have a bit more of a detailed message
2708 * for this, and instead of offering "OK" and "Cancel",
2709 * they offer things such as "Continue" and "Cancel";
2710 * we need an API for popping up alert boxes with
2711 * {Verb} and "Cancel".
2714 if (prefs.gui_find_wrap)
2716 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
2717 "%sBeginning of capture exceeded!%s\n\n"
2718 "Search is continued from the end of the capture.",
2719 simple_dialog_primary_start(), simple_dialog_primary_end());
2720 fdata = cf->plist_end; /* wrap around */
2724 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
2725 "%sBeginning of capture exceeded!%s\n\n"
2726 "Try searching forwards.",
2727 simple_dialog_primary_start(), simple_dialog_primary_end());
2728 fdata = start_fd; /* stay on previous packet */
2732 /* Go on to the next frame. */
2733 fdata = fdata->next;
2734 if (fdata == NULL) {
2735 if (prefs.gui_find_wrap)
2737 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
2738 "%sEnd of capture exceeded!%s\n\n"
2739 "Search is continued from the start of the capture.",
2740 simple_dialog_primary_start(), simple_dialog_primary_end());
2741 fdata = cf->plist; /* wrap around */
2745 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
2746 "%sEnd of capture exceeded!%s\n\n"
2747 "Try searching backwards.",
2748 simple_dialog_primary_start(), simple_dialog_primary_end());
2749 fdata = start_fd; /* stay on previous packet */
2756 /* Is this packet in the display? */
2757 if (fdata->flags.passed_dfilter) {
2758 /* Yes. Load its data. */
2759 if (!wtap_seek_read(cf->wth, fdata->file_off, &cf->pseudo_header,
2760 cf->pd, fdata->cap_len, &err, &err_info)) {
2761 /* Read error. Report the error, and go back to the frame
2762 where we started. */
2763 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
2764 cf_read_error_message(err, err_info), cf->filename);
2769 /* Does it match the search criterion? */
2770 if ((*match_function)(cf, fdata, criterion)) {
2772 break; /* found it! */
2776 if (fdata == start_fd) {
2777 /* We're back to the frame we were on originally, and that frame
2778 doesn't match the search filter. The search failed. */
2783 /* We're done scanning the packets; destroy the progress bar if it
2785 if (progbar != NULL)
2786 destroy_progress_dlg(progbar);
2789 if (new_fd != NULL) {
2790 /* We found a frame. Find what row it's in. */
2791 row = packet_list_find_row_from_data(new_fd);
2792 g_assert(row != -1);
2794 /* Select that row, make it the focus row, and make it visible. */
2795 packet_list_set_selected_row(row);
2796 return TRUE; /* success */
2798 return FALSE; /* failure */
2802 cf_goto_frame(capture_file *cf, guint fnumber)
2807 for (fdata = cf->plist; fdata != NULL && fdata->num < fnumber; fdata = fdata->next)
2810 if (fdata == NULL) {
2811 /* we didn't find a packet with that packet number */
2812 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
2813 "There is no packet with that packet number.");
2814 return FALSE; /* we failed to go to that packet */
2816 if (!fdata->flags.passed_dfilter) {
2817 /* that packet currently isn't displayed */
2818 /* XXX - add it to the set of displayed packets? */
2819 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
2820 "That packet isn't currently being displayed.");
2821 return FALSE; /* we failed to go to that packet */
2824 /* We found that packet, and it's currently being displayed.
2825 Find what row it's in. */
2826 row = packet_list_find_row_from_data(fdata);
2827 g_assert(row != -1);
2829 /* Select that row, make it the focus row, and make it visible. */
2830 packet_list_set_selected_row(row);
2831 return TRUE; /* we got to that packet */
2835 cf_goto_top_frame(capture_file *cf)
2839 frame_data *lowest_fdata = NULL;
2841 for (fdata = cf->plist; fdata != NULL; fdata = fdata->next) {
2842 if (fdata->flags.passed_dfilter) {
2843 lowest_fdata = fdata;
2848 if (lowest_fdata == NULL) {
2852 /* We found that packet, and it's currently being displayed.
2853 Find what row it's in. */
2854 row = packet_list_find_row_from_data(lowest_fdata);
2855 g_assert(row != -1);
2857 /* Select that row, make it the focus row, and make it visible. */
2858 packet_list_set_selected_row(row);
2859 return TRUE; /* we got to that packet */
2863 cf_goto_bottom_frame(capture_file *cf)
2867 frame_data *highest_fdata = NULL;
2869 for (fdata = cf->plist; fdata != NULL; fdata = fdata->next) {
2870 if (fdata->flags.passed_dfilter) {
2871 highest_fdata = fdata;
2875 if (highest_fdata == NULL) {
2879 /* We found that packet, and it's currently being displayed.
2880 Find what row it's in. */
2881 row = packet_list_find_row_from_data(highest_fdata);
2882 g_assert(row != -1);
2884 /* Select that row, make it the focus row, and make it visible. */
2885 packet_list_set_selected_row(row);
2886 return TRUE; /* we got to that packet */
2890 * Go to frame specified by currently selected protocol tree item.
2893 cf_goto_framenum(capture_file *cf)
2895 header_field_info *hfinfo;
2898 if (cf->finfo_selected) {
2899 hfinfo = cf->finfo_selected->hfinfo;
2901 if (hfinfo->type == FT_FRAMENUM) {
2902 framenum = fvalue_get_integer(&cf->finfo_selected->value);
2904 return cf_goto_frame(cf, framenum);
2911 /* Select the packet on a given row. */
2913 cf_select_packet(capture_file *cf, int row)
2919 /* Get the frame data struct pointer for this frame */
2920 fdata = (frame_data *)packet_list_get_row_data(row);
2922 if (fdata == NULL) {
2923 /* XXX - if a GtkCList's selection mode is GTK_SELECTION_BROWSE, when
2924 the first entry is added to it by "real_insert_row()", that row
2925 is selected (see "real_insert_row()", in "gtk/gtkclist.c", in both
2926 our version and the vanilla GTK+ version).
2928 This means that a "select-row" signal is emitted; this causes
2929 "packet_list_select_cb()" to be called, which causes "cf_select_packet()"
2932 "cf_select_packet()" fetches, above, the data associated with the
2933 row that was selected; however, as "gtk_clist_append()", which
2934 called "real_insert_row()", hasn't yet returned, we haven't yet
2935 associated any data with that row, so we get back a null pointer.
2937 We can't assume that there's only one frame in the frame list,
2938 either, as we may be filtering the display.
2940 We therefore assume that, if "row" is 0, i.e. the first row
2941 is being selected, and "cf->first_displayed" equals
2942 "cf->last_displayed", i.e. there's only one frame being
2943 displayed, that frame is the frame we want.
2945 This means we have to set "cf->first_displayed" and
2946 "cf->last_displayed" before adding the row to the
2947 GtkCList; see the comment in "add_packet_to_packet_list()". */
2949 if (row == 0 && cf->first_displayed == cf->last_displayed)
2950 fdata = cf->first_displayed;
2953 /* Get the data in that frame. */
2954 if (!wtap_seek_read (cf->wth, fdata->file_off, &cf->pseudo_header,
2955 cf->pd, fdata->cap_len, &err, &err_info)) {
2956 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
2957 cf_read_error_message(err, err_info), cf->filename);
2961 /* Record that this frame is the current frame. */
2962 cf->current_frame = fdata;
2964 /* Create the logical protocol tree. */
2965 if (cf->edt != NULL) {
2966 epan_dissect_free(cf->edt);
2969 /* We don't need the columns here. */
2970 cf->edt = epan_dissect_new(TRUE, TRUE);
2971 epan_dissect_run(cf->edt, &cf->pseudo_header, cf->pd, cf->current_frame,
2974 /* Display the GUI protocol tree and hex dump.
2975 XXX - why do we dump core if we call "proto_tree_draw()"
2976 before calling "add_byte_views()"? */
2977 add_main_byte_views(cf->edt);
2978 main_proto_tree_draw(cf->edt->tree);
2980 /* A packet is selected. */
2981 set_menus_for_selected_packet(cf);
2984 /* Unselect the selected packet, if any. */
2986 cf_unselect_packet(capture_file *cf)
2988 /* Destroy the epan_dissect_t for the unselected packet. */
2989 if (cf->edt != NULL) {
2990 epan_dissect_free(cf->edt);
2994 /* Clear out the display of that packet. */
2995 clear_tree_and_hex_views();
2997 /* No packet is selected. */
2998 cf->current_frame = NULL;
2999 set_menus_for_selected_packet(cf);
3001 /* No protocol tree means no selected field. */
3002 cf_unselect_field(cf);
3005 /* Unset the selected protocol tree field, if any. */
3007 cf_unselect_field(capture_file *cf)
3009 statusbar_pop_field_msg();
3010 cf->finfo_selected = NULL;
3011 set_menus_for_selected_tree_row(cf);
3015 * Mark a particular frame.
3018 cf_mark_frame(capture_file *cf, frame_data *frame)
3020 if (! frame->flags.marked) {
3021 frame->flags.marked = TRUE;
3022 if (cf->count > cf->marked_count)
3028 * Unmark a particular frame.
3031 cf_unmark_frame(capture_file *cf, frame_data *frame)
3033 if (frame->flags.marked) {
3034 frame->flags.marked = FALSE;
3035 if (cf->marked_count > 0)
3043 } save_callback_args_t;
3046 * Save a capture to a file, in a particular format, saving either
3047 * all packets, all currently-displayed packets, or all marked packets.
3049 * Returns TRUE if it succeeds, FALSE otherwise; if it fails, it pops
3050 * up a message box for the failure.
3053 save_packet(capture_file *cf _U_, frame_data *fdata,
3054 union wtap_pseudo_header *pseudo_header, const guint8 *pd,
3057 save_callback_args_t *args = argsp;
3058 struct wtap_pkthdr hdr;
3061 /* init the wtap header for saving */
3062 hdr.ts.tv_sec = fdata->abs_secs;
3063 hdr.ts.tv_usec = fdata->abs_usecs;
3064 hdr.caplen = fdata->cap_len;
3065 hdr.len = fdata->pkt_len;
3066 hdr.pkt_encap = fdata->lnk_t;
3068 /* and save the packet */
3069 if (!wtap_dump(args->pdh, &hdr, pseudo_header, pd, &err)) {
3070 cf_write_failure_alert_box(args->fname, err);
3077 cf_save(capture_file *cf, const char *fname, packet_range_t *range, guint save_format)
3079 gchar *from_filename;
3080 const gchar *name_ptr;
3081 gchar *save_msg, *save_fmt = " Saving: %s...";
3086 struct stat infile, outfile;
3087 save_callback_args_t callback_args;
3089 name_ptr = get_basename(fname);
3090 msg_len = strlen(name_ptr) + strlen(save_fmt) + 2;
3091 save_msg = g_malloc(msg_len);
3092 snprintf(save_msg, msg_len, save_fmt, name_ptr);
3093 statusbar_push_file_msg(save_msg);
3097 * Check that the from file is not the same as to file
3098 * We do it here so we catch all cases ...
3099 * Unfortunately, the file requester gives us an absolute file
3100 * name and the read file name may be relative (if supplied on
3101 * the command line). From Joerg Mayer.
3103 * This is a bit tricky on win32. The st_ino field is documented as:
3104 * "The inode, and therefore st_ino, has no meaning in the FAT, ..."
3105 * but it *is* set to zero if stat() returns without an error,
3106 * so this is working, but maybe not quite the way expected. ULFL
3108 infile.st_ino = 1; /* These prevent us from getting equality */
3109 outfile.st_ino = 2; /* If one or other of the files is not accessible */
3110 stat(cf->filename, &infile);
3111 stat(fname, &outfile);
3112 if (infile.st_ino == outfile.st_ino) {
3113 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3114 "%sCapture file: \"%s\" already exists!%s\n\n"
3115 "Please choose a different filename.",
3116 simple_dialog_primary_start(), fname, simple_dialog_primary_end());
3120 packet_range_process_init(range);
3123 * if (!save_filtered && !save_marked && !save_manual_range &&
3124 * !save_marked_range && !save_curr && save_format == cf->cd_t) {
3127 if (packet_range_process_all(range) && save_format == cf->cd_t) {
3128 /* We're not filtering packets, and we're saving it in the format
3129 it's already in, so we can just move or copy the raw data. */
3131 if (cf->is_tempfile) {
3132 /* The file being saved is a temporary file from a live
3133 capture, so it doesn't need to stay around under that name;
3134 first, try renaming the capture buffer file to the new name. */
3136 if (rename(cf->filename, fname) == 0) {
3137 /* That succeeded - there's no need to copy the source file. */
3138 from_filename = NULL;
3141 if (errno == EXDEV) {
3142 /* They're on different file systems, so we have to copy the
3145 from_filename = cf->filename;
3147 /* The rename failed, but not because they're on different
3148 file systems - put up an error message. (Or should we
3149 just punt and try to copy? The only reason why I'd
3150 expect the rename to fail and the copy to succeed would
3151 be if we didn't have permission to remove the file from
3152 the temporary directory, and that might be fixable - but
3153 is it worth requiring the user to go off and fix it?) */
3154 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3155 file_rename_error_message(errno), fname);
3161 from_filename = cf->filename;
3164 /* It's a permanent file, so we should copy it, and not remove the
3167 from_filename = cf->filename;
3171 /* Copy the file, if we haven't moved it. */
3172 if (!copy_binary_file(from_filename, fname))
3176 /* Either we're filtering packets, or we're saving in a different
3177 format; we can't do that by copying or moving the capture file,
3178 we have to do it by writing the packets out in Wiretap. */
3179 pdh = wtap_dump_open(fname, save_format, cf->lnk_t, cf->snap, &err);
3181 cf_open_failure_alert_box(fname, err, NULL, TRUE, save_format);
3185 /* XXX - we let the user save a subset of the packets.
3187 If we do that, should we make that file the current file? If so,
3188 it means we can no longer get at the other packets. What does
3191 /* Iterate through the list of packets, processing the packets we were
3194 XXX - we've already called "packet_range_process_init(range)", but
3195 "process_specified_packets()" will do it again. Fortunately,
3196 that's harmless in this case, as we haven't done anything to
3197 "range" since we initialized it. */
3198 callback_args.pdh = pdh;
3199 callback_args.fname = fname;
3200 switch (process_specified_packets(cf, range, "Saving",
3201 "selected packets", save_packet,
3205 /* Completed successfully. */
3209 /* The user decided to abort the saving.
3210 XXX - remove the output file? */
3214 /* Error while saving. */
3215 wtap_dump_close(pdh, &err);
3219 if (!wtap_dump_close(pdh, &err)) {
3220 cf_close_failure_alert_box(fname, err);
3225 /* Pop the "Saving:" message off the status bar. */
3226 statusbar_pop_file_msg();
3228 if (packet_range_process_all(range)) {
3229 /* We saved the entire capture, not just some packets from it.
3230 Open and read the file we saved it to.
3232 XXX - this is somewhat of a waste; we already have the
3233 packets, all this gets us is updated file type information
3234 (which we could just stuff into "cf"), and having the new
3235 file be the one we have opened and from which we're reading
3236 the data, and it means we have to spend time opening and
3237 reading the file, which could be a significant amount of
3238 time if the file is large. */
3239 cf->user_saved = TRUE;
3241 if ((cf_open(cf, fname, FALSE, &err)) == CF_OK) {
3242 /* XXX - report errors if this fails?
3243 What should we return if it fails or is aborted? */
3244 switch (cf_read(cf)) {
3248 /* Just because we got an error, that doesn't mean we were unable
3249 to read any of the file; we handle what we could get from the
3253 case CF_READ_ABORTED:
3254 /* The user bailed out of re-reading the capture file; the
3255 capture file has been closed - just return (without
3256 changing any menu settings; "cf_close()" set them
3257 correctly for the "no capture file open" state). */
3260 set_menus_for_unsaved_capture_file(FALSE);
3266 /* Pop the "Saving:" message off the status bar. */
3267 statusbar_pop_file_msg();
3272 cf_open_failure_alert_box(const char *filename, int err, gchar *err_info,
3273 gboolean for_writing, int file_type)
3276 /* Wiretap error. */
3279 case WTAP_ERR_NOT_REGULAR_FILE:
3280 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3281 "The file \"%s\" is a \"special file\" or socket or other non-regular file.",
3285 case WTAP_ERR_RANDOM_OPEN_PIPE:
3286 /* Seen only when opening a capture file for reading. */
3287 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3288 "The file \"%s\" is a pipe or FIFO; Ethereal can't read pipe or FIFO files.",
3292 case WTAP_ERR_FILE_UNKNOWN_FORMAT:
3293 /* Seen only when opening a capture file for reading. */
3294 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3295 "The file \"%s\" isn't a capture file in a format Ethereal understands.",
3299 case WTAP_ERR_UNSUPPORTED:
3300 /* Seen only when opening a capture file for reading. */
3301 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3302 "The file \"%s\" isn't a capture file in a format Ethereal understands.\n"
3304 filename, err_info);
3308 case WTAP_ERR_CANT_WRITE_TO_PIPE:
3309 /* Seen only when opening a capture file for writing. */
3310 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3311 "The file \"%s\" is a pipe, and %s capture files can't be "
3312 "written to a pipe.",
3313 filename, wtap_file_type_string(file_type));
3316 case WTAP_ERR_UNSUPPORTED_FILE_TYPE:
3317 /* Seen only when opening a capture file for writing. */
3318 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3319 "Ethereal doesn't support writing capture files in that format.");
3322 case WTAP_ERR_UNSUPPORTED_ENCAP:
3324 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3325 "Ethereal can't save this capture in that format.");
3327 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3328 "The file \"%s\" is a capture for a network type that Ethereal doesn't support.\n"
3330 filename, err_info);
3335 case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED:
3337 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3338 "Ethereal can't save this capture in that format.");
3340 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3341 "The file \"%s\" is a capture for a network type that Ethereal doesn't support.",
3346 case WTAP_ERR_BAD_RECORD:
3347 /* Seen only when opening a capture file for reading. */
3348 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3349 "The file \"%s\" appears to be damaged or corrupt.\n"
3351 filename, err_info);
3355 case WTAP_ERR_CANT_OPEN:
3357 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3358 "The file \"%s\" could not be created for some unknown reason.",
3361 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3362 "The file \"%s\" could not be opened for some unknown reason.",
3367 case WTAP_ERR_SHORT_READ:
3368 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3369 "The file \"%s\" appears to have been cut short"
3370 " in the middle of a packet or other data.",
3374 case WTAP_ERR_SHORT_WRITE:
3375 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3376 "A full header couldn't be written to the file \"%s\".",
3381 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3382 "The file \"%s\" could not be %s: %s.",
3384 for_writing ? "created" : "opened",
3385 wtap_strerror(err));
3390 open_failure_alert_box(filename, err, for_writing);
3395 file_rename_error_message(int err)
3398 static char errmsg_errno[1024+1];
3403 errmsg = "The path to the file \"%s\" doesn't exist.";
3407 errmsg = "You don't have permission to move the capture file to \"%s\".";
3411 snprintf(errmsg_errno, sizeof(errmsg_errno),
3412 "The file \"%%s\" could not be moved: %s.",
3413 wtap_strerror(err));
3414 errmsg = errmsg_errno;
3421 cf_read_error_message(int err, const gchar *err_info)
3423 static char errmsg_errno[1024+1];
3427 case WTAP_ERR_UNSUPPORTED_ENCAP:
3428 snprintf(errmsg_errno, sizeof(errmsg_errno),
3429 "The file \"%%s\" has a packet with a network type that Ethereal doesn't support.\n(%s)",
3433 case WTAP_ERR_BAD_RECORD:
3434 snprintf(errmsg_errno, sizeof(errmsg_errno),
3435 "An error occurred while reading from the file \"%%s\": %s.\n(%s)",
3436 wtap_strerror(err), err_info);
3440 snprintf(errmsg_errno, sizeof(errmsg_errno),
3441 "An error occurred while reading from the file \"%%s\": %s.",
3442 wtap_strerror(err));
3445 return errmsg_errno;
3449 cf_write_failure_alert_box(const char *filename, int err)
3452 /* Wiretap error. */
3453 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3454 "An error occurred while writing to the file \"%s\": %s.",
3455 filename, wtap_strerror(err));
3458 write_failure_alert_box(filename, err);
3462 /* Check for write errors - if the file is being written to an NFS server,
3463 a write error may not show up until the file is closed, as NFS clients
3464 might not send writes to the server until the "write()" call finishes,
3465 so that the write may fail on the server but the "write()" may succeed. */
3467 cf_close_failure_alert_box(const char *filename, int err)
3470 /* Wiretap error. */
3473 case WTAP_ERR_CANT_CLOSE:
3474 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3475 "The file \"%s\" couldn't be closed for some unknown reason.",
3479 case WTAP_ERR_SHORT_WRITE:
3480 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3481 "Not all the packets could be written to the file \"%s\".",
3486 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3487 "An error occurred while closing the file \"%s\": %s.",
3488 filename, wtap_strerror(err));
3493 We assume that a close error from the OS is really a write error. */
3494 write_failure_alert_box(filename, err);
3498 /* Reload the current capture file. */
3500 cf_reload(capture_file *cf) {
3502 gboolean is_tempfile;
3505 /* If the file could be opened, "cf_open()" calls "cf_close()"
3506 to get rid of state for the old capture file before filling in state
3507 for the new capture file. "cf_close()" will remove the file if
3508 it's a temporary file; we don't want that to happen (for one thing,
3509 it'd prevent subsequent reopens from working). Remember whether it's
3510 a temporary file, mark it as not being a temporary file, and then
3511 reopen it as the type of file it was.
3513 Also, "cf_close()" will free "cf->filename", so we must make
3514 a copy of it first. */
3515 filename = g_strdup(cf->filename);
3516 is_tempfile = cf->is_tempfile;
3517 cf->is_tempfile = FALSE;
3518 if (cf_open(cf, filename, is_tempfile, &err) == CF_OK) {
3519 switch (cf_read(cf)) {
3523 /* Just because we got an error, that doesn't mean we were unable
3524 to read any of the file; we handle what we could get from the
3528 case CF_READ_ABORTED:
3529 /* The user bailed out of re-reading the capture file; the
3530 capture file has been closed - just free the capture file name
3531 string and return (without changing the last containing
3537 /* The open failed, so "cf->is_tempfile" wasn't set to "is_tempfile".
3538 Instead, the file was left open, so we should restore "cf->is_tempfile"
3541 XXX - change the menu? Presumably "cf_open()" will do that;
3542 make sure it does! */
3543 cf->is_tempfile = is_tempfile;
3545 /* "cf_open()" made a copy of the file name we handed it, so
3546 we should free up our copy. */
3550 /* Copies a file in binary mode, for those operating systems that care about
3552 * Returns TRUE on success, FALSE on failure. If a failure, it also
3553 * displays a simple dialog window with the error message.
3556 copy_binary_file(const char *from_filename, const char *to_filename)
3558 int from_fd, to_fd, nread, nwritten, err;
3561 /* Copy the raw bytes of the file. */
3562 from_fd = open(from_filename, O_RDONLY | O_BINARY);
3564 open_failure_alert_box(from_filename, errno, FALSE);
3568 /* Use open() instead of creat() so that we can pass the O_BINARY
3569 flag, which is relevant on Win32; it appears that "creat()"
3570 may open the file in text mode, not binary mode, but we want
3571 to copy the raw bytes of the file, so we need the output file
3572 to be open in binary mode. */
3573 to_fd = open(to_filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
3575 open_failure_alert_box(to_filename, errno, TRUE);
3580 while ((nread = read(from_fd, pd, sizeof pd)) > 0) {
3581 nwritten = write(to_fd, pd, nread);
3582 if (nwritten < nread) {
3586 err = WTAP_ERR_SHORT_WRITE;
3587 write_failure_alert_box(to_filename, err);
3595 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3596 "An error occurred while reading from the file \"%s\": %s.",
3597 from_filename, strerror(err));
3603 if (close(to_fd) < 0) {
3604 write_failure_alert_box(to_filename, errno);