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>
88 #include <epan/epan_dissect.h>
90 #include "tap_dfilter_dlg.h"
91 #include <epan/dissectors/packet-data.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(char *from_filename, 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(char *fname, gboolean is_tempfile, capture_file *cf)
155 wth = wtap_open_offline(fname, &err, &err_info, TRUE);
159 /* Find the size of the file. */
161 if (fstat(fd, &cf_stat) < 0) {
167 /* The open succeeded. Close whatever capture file we had open,
168 and fill in the information for this file. */
171 /* Initialize all data structures used for dissection. */
174 /* We're about to start reading the file. */
175 cf->state = FILE_READ_IN_PROGRESS;
179 cf->f_len = cf_stat.st_size;
181 /* Set the file name because we need it to set the follow stream filter.
182 XXX - is that still true? We need it for other reasons, though,
184 cf->filename = g_strdup(fname);
186 /* Indicate whether it's a permanent or temporary file. */
187 cf->is_tempfile = is_tempfile;
189 /* If it's a temporary capture buffer file, mark it as not saved. */
190 cf->user_saved = !is_tempfile;
192 cf->cd_t = wtap_file_type(cf->wth);
194 cf->displayed_count = 0;
195 cf->marked_count = 0;
196 cf->drops_known = FALSE;
200 cf->snap = wtap_snapshot_length(cf->wth);
202 /* Snapshot length not known. */
203 cf->has_snap = FALSE;
204 cf->snap = WTAP_MAX_PACKET_SIZE;
207 firstsec = 0, firstusec = 0;
208 prevsec = 0, prevusec = 0;
210 cf->plist_chunk = g_mem_chunk_new("frame_data_chunk",
212 FRAME_DATA_CHUNK_SIZE * sizeof(frame_data),
214 g_assert(cf->plist_chunk);
219 cf_open_failure_alert_box(fname, err, err_info, FALSE, 0);
223 /* Reset everything to a pristine state */
225 cf_close(capture_file *cf)
227 /* Die if we're in the middle of reading a file. */
228 g_assert(cf->state != FILE_READ_IN_PROGRESS);
230 /* Destroy all windows, which refer to the
231 capture file we're closing. */
232 destroy_cfile_wins();
238 /* We have no file open... */
239 if (cf->filename != NULL) {
240 /* If it's a temporary file, remove it. */
242 unlink(cf->filename);
243 g_free(cf->filename);
246 /* ...which means we have nothing to save. */
247 cf->user_saved = FALSE;
249 if (cf->plist_chunk != NULL) {
250 g_mem_chunk_destroy(cf->plist_chunk);
251 cf->plist_chunk = NULL;
253 if (cf->rfcode != NULL) {
254 dfilter_free(cf->rfcode);
258 cf->plist_end = NULL;
259 unselect_packet(cf); /* nothing to select */
260 cf->first_displayed = NULL;
261 cf->last_displayed = NULL;
263 /* No frame selected, no field in that frame selected. */
264 cf->current_frame = NULL;
265 cf->finfo_selected = NULL;
267 /* Clear the packet list. */
268 packet_list_freeze();
277 /* Clear any file-related status bar messages.
278 XXX - should be "clear *ALL* file-related status bar messages;
279 will there ever be more than one on the stack? */
280 statusbar_pop_file_msg();
282 /* Restore the standard title bar message. */
283 set_main_window_name("The Ethereal Network Analyzer");
285 /* Disable all menu items that make sense only if you have a capture. */
286 set_menus_for_capture_file(FALSE);
287 set_menus_for_unsaved_capture_file(FALSE);
288 set_menus_for_captured_packets(FALSE);
289 set_menus_for_selected_packet(cf);
290 set_menus_for_capture_in_progress(FALSE);
291 set_menus_for_selected_tree_row(cf);
293 reset_tap_listeners();
295 /* We have no file open. */
296 cf->state = FILE_CLOSED;
299 /* Set the file name in the status line, in the name for the main window,
300 and in the name for the main window's icon. */
302 set_display_filename(capture_file *cf)
306 static const gchar done_fmt_nodrops[] = " File: %s %s %02u:%02u:%02u";
307 static const gchar done_fmt_drops[] = " File: %s %s %02u:%02u:%02u Drops: %u";
309 gchar *win_name_fmt = "%s - Ethereal";
313 name_ptr = cf_get_display_name(cf);
315 if (!cf->is_tempfile) {
316 /* Add this filename to the list of recent files in the "Recent Files" submenu */
317 add_menu_recent_capture_file(cf->filename);
320 if (cf->f_len/1024/1024 > 10) {
321 size_str = g_strdup_printf("%ld MB", cf->f_len/1024/1024);
322 } else if (cf->f_len/1024 > 10) {
323 size_str = g_strdup_printf("%ld KB", cf->f_len/1024);
325 size_str = g_strdup_printf("%ld bytes", cf->f_len);
328 if (cf->drops_known) {
329 done_msg = g_strdup_printf(done_fmt_drops, name_ptr, size_str,
330 cf->esec/3600, cf->esec%3600/60, cf->esec%60, cf->drops);
332 done_msg = g_strdup_printf(done_fmt_nodrops, name_ptr, size_str,
333 cf->esec/3600, cf->esec%3600/60, cf->esec%60);
335 statusbar_push_file_msg(done_msg);
338 msg_len = strlen(name_ptr) + strlen(win_name_fmt) + 1;
339 win_name = g_malloc(msg_len);
340 snprintf(win_name, msg_len, win_name_fmt, name_ptr);
341 set_main_window_name(win_name);
346 cf_read(capture_file *cf)
350 gchar *name_ptr, *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 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 (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);
529 return (READ_SUCCESS);
534 cf_start_tail(char *fname, gboolean is_tempfile, capture_file *cf)
539 err = cf_open(fname, is_tempfile, cf);
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>", cf->iface);
551 statusbar_push_file_msg(capture_msg);
559 cf_continue_tail(capture_file *cf, int to_read, int *err)
561 long data_offset = 0;
566 packet_list_freeze();
568 while (to_read != 0 && (wtap_read(cf->wth, err, &err_info, &data_offset))) {
569 if (cf->state == FILE_READ_ABORTED) {
570 /* Well, the user decided to exit Ethereal. Break out of the
571 loop, and let the code below (which is called even if there
572 aren't any packets left to read) exit. */
575 read_packet(cf, data_offset);
581 /* XXX - this cheats and looks inside the packet list to find the final
583 if (auto_scroll_live && cf->plist_end != NULL)
584 packet_list_moveto_end();
586 if (cf->state == FILE_READ_ABORTED) {
587 /* Well, the user decided to exit Ethereal. Return READ_ABORTED
588 so that our caller can kill off the capture child process;
589 this will cause an EOF on the pipe from the child, so
590 "cf_finish_tail()" will be called, and it will clean up
593 } else if (*err != 0) {
594 /* We got an error reading the capture file.
595 XXX - pop up a dialog box? */
598 return (READ_SUCCESS);
602 cf_finish_tail(capture_file *cf, int *err)
609 packet_list_freeze();
611 while ((wtap_read(cf->wth, err, &err_info, &data_offset))) {
612 if (cf->state == FILE_READ_ABORTED) {
613 /* Well, the user decided to abort the read. Break out of the
614 loop, and let the code below (which is called even if there
615 aren't any packets left to read) exit. */
618 read_packet(cf, data_offset);
621 if (cf->state == FILE_READ_ABORTED) {
622 /* Well, the user decided to abort the read. We're only called
623 when the child capture process closes the pipe to us (meaning
624 it's probably exited), so we can just close the capture
625 file; we return READ_ABORTED so our caller can do whatever
626 is appropriate when that happens. */
632 if (auto_scroll_live && cf->plist_end != NULL)
633 /* XXX - this cheats and looks inside the packet list to find the final
635 packet_list_moveto_end();
637 /* We're done reading sequentially through the file. */
638 cf->state = FILE_READ_DONE;
640 /* we have to update the f_len field */
641 /* Find the size of the file. */
642 fd = wtap_fd(cf->wth);
643 if (fstat(fd, &cf_stat) >= 0) {
644 cf->f_len = cf_stat.st_size;
647 /* We're done reading sequentially through the file; close the
648 sequential I/O side, to free up memory it requires. */
649 wtap_sequential_close(cf->wth);
651 /* Allow the protocol dissectors to free up memory that they
652 * don't need after the sequential run-through of the packets. */
653 postseq_cleanup_all_protocols();
655 /* Set the file encapsulation type now; we don't know what it is until
656 we've looked at all the packets, as we don't know until then whether
657 there's more than one type (and thus whether it's
658 WTAP_ENCAP_PER_PACKET). */
659 cf->lnk_t = wtap_file_encap(cf->wth);
661 /* Pop the "<live capture in progress>" message off the status bar. */
662 statusbar_pop_file_msg();
664 set_display_filename(cf);
666 /* Enable menu items that make sense if you're not currently running
668 set_menus_for_capture_in_progress(FALSE);
670 /* Enable menu items that make sense if you have a capture file
671 you've finished reading. */
672 set_menus_for_capture_file(TRUE);
673 set_menus_for_unsaved_capture_file(!cf->user_saved);
676 /* We got an error reading the capture file.
677 XXX - pop up a dialog box? */
680 return (READ_SUCCESS);
683 #endif /* HAVE_LIBPCAP */
686 cf_get_display_name(capture_file *cf)
690 /* Return a name to use in displays */
691 if (!cf->is_tempfile) {
692 /* Get the last component of the file name, and use that. */
694 displayname = get_basename(cf->filename);
696 /* Add this filename to the list of recent files in the "Recent Files" submenu */
697 add_menu_recent_capture_file(cf->filename);
699 displayname="(No file)";
702 /* The file we read is a temporary file from a live capture;
703 we don't mention its name. */
704 displayname = "(Untitled)";
710 color_filter_t *colorf;
712 } apply_color_filter_args;
715 * If no color filter has been applied, apply this one.
716 * (The "if no color filter has been applied" is to handle the case where
717 * more than one color filter matches the packet.)
720 apply_color_filter(gpointer filter_arg, gpointer argp)
722 color_filter_t *colorf = filter_arg;
723 apply_color_filter_args *args = argp;
725 if (colorf->c_colorfilter != NULL && args->colorf == NULL) {
726 if (dfilter_apply_edt(colorf->c_colorfilter, args->edt))
727 args->colorf = colorf;
732 add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
733 union wtap_pseudo_header *pseudo_header, const guchar *buf,
736 apply_color_filter_args args;
738 gboolean create_proto_tree = FALSE;
741 /* just add some value here until we know if it is being displayed or not */
742 fdata->cum_bytes = cum_bytes + fdata->pkt_len;
744 /* We don't yet have a color filter to apply. */
747 /* If we don't have the time stamp of the first packet in the
748 capture, it's because this is the first packet. Save the time
749 stamp of this packet as the time stamp of the first packet. */
750 if (!firstsec && !firstusec) {
751 firstsec = fdata->abs_secs;
752 firstusec = fdata->abs_usecs;
754 /* if this frames is marked as a reference time frame, reset
755 firstsec and firstusec to this frame */
756 if(fdata->flags.ref_time){
757 firstsec = fdata->abs_secs;
758 firstusec = fdata->abs_usecs;
761 /* If we don't have the time stamp of the previous displayed packet,
762 it's because this is the first displayed packet. Save the time
763 stamp of this packet as the time stamp of the previous displayed
765 if (!prevsec && !prevusec) {
766 prevsec = fdata->abs_secs;
767 prevusec = fdata->abs_usecs;
770 /* Get the time elapsed between the first packet and this packet. */
771 compute_timestamp_diff(&fdata->rel_secs, &fdata->rel_usecs,
772 fdata->abs_secs, fdata->abs_usecs, firstsec, firstusec);
774 /* If it's greater than the current elapsed time, set the elapsed time
775 to it (we check for "greater than" so as not to be confused by
776 time moving backwards). */
777 if ((gint32)cf->esec < fdata->rel_secs
778 || ((gint32)cf->esec == fdata->rel_secs && (gint32)cf->eusec < fdata->rel_usecs)) {
779 cf->esec = fdata->rel_secs;
780 cf->eusec = fdata->rel_usecs;
783 /* Get the time elapsed between the previous displayed packet and
785 compute_timestamp_diff(&fdata->del_secs, &fdata->del_usecs,
786 fdata->abs_secs, fdata->abs_usecs, prevsec, prevusec);
790 we have a display filter and are re-applying it;
792 we have a list of color filters;
794 we have tap listeners;
796 allocate a protocol tree root node, so that we'll construct
797 a protocol tree against which a filter expression can be
799 if ((cf->dfcode != NULL && refilter) || filter_list != NULL
800 || num_tap_filters != 0)
801 create_proto_tree = TRUE;
803 /* Dissect the frame. */
804 edt = epan_dissect_new(create_proto_tree, FALSE);
806 if (cf->dfcode != NULL && refilter) {
807 epan_dissect_prime_dfilter(edt, cf->dfcode);
810 filter_list_prime_edt(edt);
813 epan_dissect_run(edt, pseudo_header, buf, fdata, &cf->cinfo);
814 tap_push_tapped_queue(edt);
816 /* If we have a display filter, apply it if we're refiltering, otherwise
817 leave the "passed_dfilter" flag alone.
819 If we don't have a display filter, set "passed_dfilter" to 1. */
820 if (cf->dfcode != NULL) {
822 if (cf->dfcode != NULL)
823 fdata->flags.passed_dfilter = dfilter_apply_edt(cf->dfcode, edt) ? 1 : 0;
825 fdata->flags.passed_dfilter = 1;
828 fdata->flags.passed_dfilter = 1;
830 /* If we have color filters, and the frame is to be displayed, apply
831 the color filters. */
832 if (fdata->flags.passed_dfilter) {
833 if (filter_list != NULL) {
835 g_slist_foreach(filter_list, apply_color_filter, &args);
840 if( (fdata->flags.passed_dfilter)
841 || (edt->pi.fd->flags.ref_time) ){
842 /* This frame either passed the display filter list or is marked as
843 a time reference frame. All time reference frames are displayed
844 even if they dont pass the display filter */
845 /* if this was a TIME REF frame we should reset the cul bytes field */
846 if(edt->pi.fd->flags.ref_time){
847 cum_bytes = fdata->pkt_len;
848 fdata->cum_bytes = cum_bytes;
851 /* increase cum_bytes with this packets length */
852 cum_bytes += fdata->pkt_len;
854 epan_dissect_fill_in_columns(edt);
856 /* If we haven't yet seen the first frame, this is it.
858 XXX - we must do this before we add the row to the display,
859 as, if the display's GtkCList's selection mode is
860 GTK_SELECTION_BROWSE, when the first entry is added to it,
861 "select_packet()" will be called, and it will fetch the row
862 data for the 0th row, and will get a null pointer rather than
863 "fdata", as "gtk_clist_append()" won't yet have returned and
864 thus "gtk_clist_set_row_data()" won't yet have been called.
866 We thus need to leave behind bread crumbs so that
867 "select_packet()" can find this frame. See the comment
868 in "select_packet()". */
869 if (cf->first_displayed == NULL)
870 cf->first_displayed = fdata;
872 /* This is the last frame we've seen so far. */
873 cf->last_displayed = fdata;
875 row = packet_list_append(cf->cinfo.col_data, fdata);
877 /* If the packet matches a color filter,
878 * store matching color_filter_t object in frame data. */
879 if (filter_list != NULL && (args.colorf != NULL)) {
880 /* add the matching colorfilter to the frame data */
881 fdata->color_filter = args.colorf;
882 /* If packet is marked, use colors from preferences */
883 if (fdata->flags.marked) {
884 packet_list_set_colors(row, &prefs.gui_marked_fg, &prefs.gui_marked_bg);
885 } else /* if (filter_list != NULL && (args.colorf != NULL)) */ {
886 packet_list_set_colors(row, &(args.colorf->fg_color),
887 &(args.colorf->bg_color));
890 /* No color filter match */
891 fdata->color_filter = NULL;
892 if (fdata->flags.marked) {
893 packet_list_set_colors(row, &prefs.gui_marked_fg, &prefs.gui_marked_bg);
897 /* Set the time of the previous displayed frame to the time of this
899 prevsec = fdata->abs_secs;
900 prevusec = fdata->abs_usecs;
902 cf->displayed_count++;
904 /* This frame didn't pass the display filter, so it's not being added
905 to the clist, and thus has no row. */
908 epan_dissect_free(edt);
913 read_packet(capture_file *cf, long offset)
915 const struct wtap_pkthdr *phdr = wtap_phdr(cf->wth);
916 union wtap_pseudo_header *pseudo_header = wtap_pseudoheader(cf->wth);
917 const guchar *buf = wtap_buf_ptr(cf->wth);
920 frame_data *plist_end;
923 /* Allocate the next list entry, and add it to the list. */
924 fdata = g_mem_chunk_alloc(cf->plist_chunk);
929 fdata->pkt_len = phdr->len;
930 fdata->cap_len = phdr->caplen;
931 fdata->file_off = offset;
932 fdata->lnk_t = phdr->pkt_encap;
933 fdata->abs_secs = phdr->ts.tv_sec;
934 fdata->abs_usecs = phdr->ts.tv_usec;
935 fdata->flags.encoding = CHAR_ASCII;
936 fdata->flags.visited = 0;
937 fdata->flags.marked = 0;
938 fdata->flags.ref_time = 0;
942 edt = epan_dissect_new(TRUE, FALSE);
943 epan_dissect_prime_dfilter(edt, cf->rfcode);
944 epan_dissect_run(edt, pseudo_header, buf, fdata, NULL);
945 passed = dfilter_apply_edt(cf->rfcode, edt);
946 epan_dissect_free(edt);
949 plist_end = cf->plist_end;
950 fdata->prev = plist_end;
951 if (plist_end != NULL)
952 plist_end->next = fdata;
955 cf->plist_end = fdata;
958 fdata->num = cf->count;
959 add_packet_to_packet_list(fdata, cf, pseudo_header, buf, TRUE);
961 /* XXX - if we didn't have read filters, or if we could avoid
962 allocating the "frame_data" structure until we knew whether
963 the frame passed the read filter, we could use a G_ALLOC_ONLY
966 ...but, at least in one test I did, where I just made the chunk
967 a G_ALLOC_ONLY chunk and read in a huge capture file, it didn't
968 seem to save a noticeable amount of time or space. */
969 g_mem_chunk_free(cf->plist_chunk, fdata);
974 cf_merge_files(const char *out_filename, int out_fd, int in_file_count,
975 char *const *in_filenames, int file_type, gboolean do_append)
977 merge_in_file_t *in_files;
980 int open_err, read_err, write_err, close_err;
984 char errmsg_errno[1024+1];
985 gchar err_str[2048+1];
987 gboolean got_read_error = FALSE, got_write_error = FALSE;
989 progdlg_t *progbar = NULL;
992 * XXX - should be "off_t", but Wiretap would need more work to handle
993 * the full size of "off_t" on platforms where it's more than a "long"
996 long f_len, file_pos;
999 gchar status_str[100];
1000 int progbar_nextstep;
1001 int progbar_quantum;
1003 /* open the input files */
1004 if (!merge_open_in_files(in_file_count, in_filenames, &in_files,
1005 &open_err, &err_info, &err_fileno)) {
1007 cf_open_failure_alert_box(in_filenames[err_fileno], open_err, err_info,
1012 pdh = wtap_dump_fdopen(out_fd, file_type,
1013 merge_select_frame_type(in_file_count, in_files),
1014 merge_max_snapshot_length(in_file_count, in_files), &open_err);
1016 merge_close_in_files(in_file_count, in_files);
1018 cf_open_failure_alert_box(out_filename, open_err, err_info, TRUE,
1023 /* Get the sum of the sizes of all the files. */
1025 for (i = 0; i < in_file_count; i++)
1026 f_len += in_files[i].size;
1028 /* Update the progress bar when it gets to this value. */
1029 progbar_nextstep = 0;
1030 /* When we reach the value that triggers a progress bar update,
1031 bump that value by this amount. */
1032 progbar_quantum = f_len/N_PROGBAR_UPDATES;
1035 g_get_current_time(&start_time);
1037 /* do the merge (or append) */
1040 wth = merge_append_read_packet(in_file_count, in_files, &read_err,
1043 wth = merge_read_packet(in_file_count, in_files, &read_err,
1047 got_read_error = TRUE;
1051 /* Get the sum of the data offsets in all of the files. */
1053 for (i = 0; i < in_file_count; i++)
1054 data_offset += in_files[i].data_offset;
1056 if (data_offset >= progbar_nextstep) {
1057 /* Get the sum of the seek positions in all of the files. */
1059 for (i = 0; i < in_file_count; i++)
1060 file_pos += lseek(wtap_fd(in_files[i].wth), 0, SEEK_CUR);
1061 prog_val = (gfloat) file_pos / (gfloat) f_len;
1062 if (prog_val > 1.0) {
1063 /* Some file probably grew while we were reading it.
1064 That "shouldn't happen", so we'll just clip the progress
1068 if (progbar == NULL) {
1069 /* Create the progress bar if necessary */
1070 progbar = delayed_create_progress_dlg("Merging", "files",
1071 &stop_flag, &start_time, prog_val);
1073 if (progbar != NULL) {
1074 g_snprintf(status_str, sizeof(status_str),
1075 "%luKB of %luKB", file_pos / 1024, f_len / 1024);
1076 update_progress_dlg(progbar, prog_val, status_str);
1078 progbar_nextstep += progbar_quantum;
1081 if (!wtap_dump(pdh, wtap_phdr(wth), wtap_pseudoheader(wth),
1082 wtap_buf_ptr(wth), &write_err)) {
1083 got_write_error = TRUE;
1088 /* We're done merging the files; destroy the progress bar if it was created. */
1089 if (progbar != NULL)
1090 destroy_progress_dlg(progbar);
1092 merge_close_in_files(in_file_count, in_files);
1093 if (!got_read_error && !got_write_error) {
1094 if (!wtap_dump_close(pdh, &write_err))
1095 got_write_error = TRUE;
1097 wtap_dump_close(pdh, &close_err);
1099 if (got_read_error) {
1101 * Find the file on which we got the error, and report the error.
1103 for (i = 0; i < in_file_count; i++) {
1104 if (in_files[i].state == GOT_ERROR) {
1105 /* Put up a message box noting that a read failed somewhere along
1109 case WTAP_ERR_UNSUPPORTED_ENCAP:
1110 snprintf(errmsg_errno, sizeof(errmsg_errno),
1111 "The capture file %%s has a packet with a network type that Ethereal doesn't support.\n(%s)",
1114 errmsg = errmsg_errno;
1117 case WTAP_ERR_CANT_READ:
1118 errmsg = "An attempt to read from the capture file %s failed for"
1119 " some unknown reason.";
1122 case WTAP_ERR_SHORT_READ:
1123 errmsg = "The capture file %s appears to have been cut short"
1124 " in the middle of a packet.";
1127 case WTAP_ERR_BAD_RECORD:
1128 snprintf(errmsg_errno, sizeof(errmsg_errno),
1129 "The capture file %%s appears to be damaged or corrupt.\n(%s)",
1132 errmsg = errmsg_errno;
1136 snprintf(errmsg_errno, sizeof(errmsg_errno),
1137 "An error occurred while reading the"
1138 " capture file %%s: %s.", wtap_strerror(read_err));
1139 errmsg = errmsg_errno;
1142 snprintf(err_str, sizeof err_str, errmsg, in_files[i].filename);
1143 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, err_str);
1148 if (got_write_error) {
1149 /* Put up an alert box for the write error. */
1150 cf_write_failure_alert_box(out_filename, write_err);
1153 return (!got_read_error && !got_write_error);
1157 filter_packets(capture_file *cf, gchar *dftext, gboolean force)
1160 char *filter_new = dftext ? dftext : "";
1161 char *filter_old = cf->dfilter ? cf->dfilter : "";
1163 /* if new filter equals old one, do nothing unless told to do so */
1164 if (!force && strcmp(filter_new, filter_old) == 0) {
1168 if (dftext == NULL) {
1169 /* The new filter is an empty filter (i.e., display all packets). */
1173 * We have a filter; make a copy of it (as we'll be saving it),
1174 * and try to compile it.
1176 dftext = g_strdup(dftext);
1177 if (!dfilter_compile(dftext, &dfcode)) {
1178 /* The attempt failed; report an error. */
1179 gchar *safe_dftext = simple_dialog_format_message(dftext);
1180 gchar *safe_dfilter_error_msg = simple_dialog_format_message(
1182 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1185 "The following display filter is not a valid display filter:\n%s\n"
1186 "See the help for a description of the display filter syntax.",
1187 simple_dialog_primary_start(), safe_dfilter_error_msg,
1188 simple_dialog_primary_end(), safe_dftext);
1189 g_free(safe_dfilter_error_msg);
1190 g_free(safe_dftext);
1196 if (dfcode == NULL) {
1197 /* Yes - free the filter text, and set it to null. */
1203 /* We have a valid filter. Replace the current filter. */
1204 if (cf->dfilter != NULL)
1205 g_free(cf->dfilter);
1206 cf->dfilter = dftext;
1207 if (cf->dfcode != NULL)
1208 dfilter_free(cf->dfcode);
1209 cf->dfcode = dfcode;
1211 /* Now rescan the packet list, applying the new filter, but not
1212 throwing away information constructed on a previous pass. */
1213 if (dftext == NULL) {
1214 rescan_packets(cf, "Resetting", "Filter", TRUE, FALSE);
1216 rescan_packets(cf, "Filtering", dftext, TRUE, FALSE);
1222 colorize_packets(capture_file *cf)
1224 rescan_packets(cf, "Colorizing", "all packets", FALSE, FALSE);
1228 reftime_packets(capture_file *cf)
1230 rescan_packets(cf, "Updating Reftime", "all packets", FALSE, FALSE);
1234 redissect_packets(capture_file *cf)
1236 rescan_packets(cf, "Reprocessing", "all packets", TRUE, TRUE);
1239 /* Rescan the list of packets, reconstructing the CList.
1241 "action" describes why we're doing this; it's used in the progress
1244 "action_item" describes what we're doing; it's used in the progress
1247 "refilter" is TRUE if we need to re-evaluate the filter expression.
1249 "redissect" is TRUE if we need to make the dissectors reconstruct
1250 any state information they have (because a preference that affects
1251 some dissector has changed, meaning some dissector might construct
1252 its state differently from the way it was constructed the last time). */
1254 rescan_packets(capture_file *cf, const char *action, const char *action_item,
1255 gboolean refilter, gboolean redissect)
1258 progdlg_t *progbar = NULL;
1263 frame_data *selected_frame, *preceding_frame, *following_frame, *prev_frame;
1264 int selected_row, prev_row, preceding_row, following_row;
1265 gboolean selected_frame_seen;
1268 GTimeVal start_time;
1269 gchar status_str[100];
1270 int progbar_nextstep;
1271 int progbar_quantum;
1274 reset_tap_listeners();
1275 /* Which frame, if any, is the currently selected frame?
1276 XXX - should the selected frame or the focus frame be the "current"
1277 frame, that frame being the one from which "Find Frame" searches
1279 selected_frame = cf->current_frame;
1281 /* We don't yet know what row that frame will be on, if any, after we
1282 rebuild the clist, however. */
1286 /* We need to re-initialize all the state information that protocols
1287 keep, because some preference that controls a dissector has changed,
1288 which might cause the state information to be constructed differently
1289 by that dissector. */
1291 /* Initialize all data structures used for dissection. */
1295 /* Freeze the packet list while we redo it, so we don't get any
1296 screen updates while it happens. */
1297 packet_list_freeze();
1300 packet_list_clear();
1302 /* We don't yet know which will be the first and last frames displayed. */
1303 cf->first_displayed = NULL;
1304 cf->last_displayed = NULL;
1306 /* We currently don't display any packets */
1307 cf->displayed_count = 0;
1309 /* Iterate through the list of frames. Call a routine for each frame
1310 to check whether it should be displayed and, if so, add it to
1311 the display list. */
1317 /* Update the progress bar when it gets to this value. */
1318 progbar_nextstep = 0;
1319 /* When we reach the value that triggers a progress bar update,
1320 bump that value by this amount. */
1321 progbar_quantum = cf->count/N_PROGBAR_UPDATES;
1322 /* Count of packets at which we've looked. */
1326 g_get_current_time(&start_time);
1328 row = -1; /* no previous row yet */
1333 preceding_frame = NULL;
1335 following_frame = NULL;
1337 selected_frame_seen = FALSE;
1339 for (fdata = cf->plist; fdata != NULL; fdata = fdata->next) {
1340 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
1341 when we update it, we have to run the GTK+ main loop to get it
1342 to repaint what's pending, and doing so may involve an "ioctl()"
1343 to see if there's any pending input from an X server, and doing
1344 that for every packet can be costly, especially on a big file. */
1345 if (count >= progbar_nextstep) {
1346 /* let's not divide by zero. I should never be started
1347 * with count == 0, so let's assert that
1349 g_assert(cf->count > 0);
1350 prog_val = (gfloat) count / cf->count;
1352 if (progbar == NULL)
1353 /* Create the progress bar if necessary */
1354 progbar = delayed_create_progress_dlg(action, action_item, &stop_flag,
1355 &start_time, prog_val);
1357 if (progbar != NULL) {
1358 g_snprintf(status_str, sizeof(status_str),
1359 "%4u of %u frames", count, cf->count);
1360 update_progress_dlg(progbar, prog_val, status_str);
1363 progbar_nextstep += progbar_quantum;
1367 /* Well, the user decided to abort the filtering. Just stop.
1369 XXX - go back to the previous filter? Users probably just
1370 want not to wait for a filtering operation to finish;
1371 unless we cancel by having no filter, reverting to the
1372 previous filter will probably be even more expensive than
1373 continuing the filtering, as it involves going back to the
1374 beginning and filtering, and even with no filter we currently
1375 have to re-generate the entire clist, which is also expensive.
1377 I'm not sure what Network Monitor does, but it doesn't appear
1378 to give you an unfiltered display if you cancel. */
1385 /* Since all state for the frame was destroyed, mark the frame
1386 * as not visited, free the GSList referring to the state
1387 * data (the per-frame data itself was freed by
1388 * "init_dissection()"), and null out the GSList pointer. */
1389 fdata->flags.visited = 0;
1391 g_slist_free(fdata->pfd);
1396 if (!wtap_seek_read (cf->wth, fdata->file_off, &cf->pseudo_header,
1397 cf->pd, fdata->cap_len, &err, &err_info)) {
1398 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1399 cf_read_error_message(err, err_info), cf->filename);
1403 /* If the previous frame is displayed, and we haven't yet seen the
1404 selected frame, remember that frame - it's the closest one we've
1405 yet seen before the selected frame. */
1406 if (prev_row != -1 && !selected_frame_seen) {
1407 preceding_row = prev_row;
1408 preceding_frame = prev_frame;
1410 row = add_packet_to_packet_list(fdata, cf, &cf->pseudo_header, cf->pd,
1413 /* If this frame is displayed, and this is the first frame we've
1414 seen displayed after the selected frame, remember this frame -
1415 it's the closest one we've yet seen at or after the selected
1417 if (row != -1 && selected_frame_seen && following_row == -1) {
1418 following_row = row;
1419 following_frame = fdata;
1421 if (fdata == selected_frame) {
1423 selected_frame_seen = TRUE;
1426 /* Remember this row/frame - it'll be the previous row/frame
1427 on the next pass through the loop. */
1433 /* Clear out what remains of the visited flags and per-frame data
1436 XXX - that may cause various forms of bogosity when dissecting
1437 these frames, as they won't have been seen by this sequential
1438 pass, but the only alternative I see is to keep scanning them
1439 even though the user requested that the scan stop, and that
1440 would leave the user stuck with an Ethereal grinding on
1441 until it finishes. Should we just stick them with that? */
1442 for (; fdata != NULL; fdata = fdata->next) {
1443 fdata->flags.visited = 0;
1445 g_slist_free(fdata->pfd);
1451 /* We're done filtering the packets; destroy the progress bar if it
1453 if (progbar != NULL)
1454 destroy_progress_dlg(progbar);
1456 /* Unfreeze the packet list. */
1459 if (selected_row == -1) {
1460 /* The selected frame didn't pass the filter. */
1461 if (selected_frame == NULL) {
1462 /* That's because there *was* no selected frame. Make the first
1463 displayed frame the current frame. */
1466 /* Find the nearest displayed frame to the selected frame (whether
1467 it's before or after that frame) and make that the current frame.
1468 If the next and previous displayed frames are equidistant from the
1469 selected frame, choose the next one. */
1470 g_assert(following_frame == NULL ||
1471 following_frame->num >= selected_frame->num);
1472 g_assert(preceding_frame == NULL ||
1473 preceding_frame->num <= selected_frame->num);
1474 if (following_frame == NULL) {
1475 /* No frame after the selected frame passed the filter, so we
1476 have to select the last displayed frame before the selected
1478 selected_row = preceding_row;
1479 } else if (preceding_frame == NULL) {
1480 /* No frame before the selected frame passed the filter, so we
1481 have to select the first displayed frame after the selected
1483 selected_row = following_row;
1485 /* Choose the closer of the last displayed frame before the
1486 selected frame and the first displayed frame after the
1487 selected frame; in case of a tie, choose the first displayed
1488 frame after the selected frame. */
1489 if (following_frame->num - selected_frame->num <=
1490 selected_frame->num - preceding_frame->num) {
1491 selected_row = following_row;
1493 /* The previous frame is closer to the selected frame than the
1495 selected_row = preceding_row;
1501 if (selected_row == -1) {
1502 /* There are no frames displayed at all. */
1503 unselect_packet(cf);
1505 /* Either the frame that was selected passed the filter, or we've
1506 found the nearest displayed frame to that frame. Select it, make
1507 it the focus row, and make it visible. */
1508 packet_list_set_selected_row(selected_row);
1519 process_specified_packets(capture_file *cf, packet_range_t *range,
1520 const char *string1, const char *string2,
1521 gboolean (*callback)(capture_file *, frame_data *,
1522 union wtap_pseudo_header *, const guint8 *, void *),
1523 void *callback_args)
1528 union wtap_pseudo_header pseudo_header;
1529 guint8 pd[WTAP_MAX_PACKET_SIZE+1];
1530 psp_return_t ret = PSP_FINISHED;
1532 progdlg_t *progbar = NULL;
1535 gboolean progbar_stop_flag;
1536 GTimeVal progbar_start_time;
1537 gchar progbar_status_str[100];
1538 int progbar_nextstep;
1539 int progbar_quantum;
1540 range_process_e process_this;
1542 /* Update the progress bar when it gets to this value. */
1543 progbar_nextstep = 0;
1544 /* When we reach the value that triggers a progress bar update,
1545 bump that value by this amount. */
1546 progbar_quantum = cf->count/N_PROGBAR_UPDATES;
1547 /* Count of packets at which we've looked. */
1550 progbar_stop_flag = FALSE;
1551 g_get_current_time(&progbar_start_time);
1553 packet_range_process_init(range);
1555 /* Iterate through the list of packets, printing the packets that
1556 were selected by the current display filter. */
1557 for (fdata = cf->plist; fdata != NULL; fdata = fdata->next) {
1558 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
1559 when we update it, we have to run the GTK+ main loop to get it
1560 to repaint what's pending, and doing so may involve an "ioctl()"
1561 to see if there's any pending input from an X server, and doing
1562 that for every packet can be costly, especially on a big file. */
1563 if (progbar_count >= progbar_nextstep) {
1564 /* let's not divide by zero. I should never be started
1565 * with count == 0, so let's assert that
1567 g_assert(cf->count > 0);
1568 progbar_val = (gfloat) progbar_count / cf->count;
1570 if (progbar == NULL)
1571 /* Create the progress bar if necessary */
1572 progbar = delayed_create_progress_dlg(string1, string2,
1574 &progbar_start_time,
1577 if (progbar != NULL) {
1578 g_snprintf(progbar_status_str, sizeof(progbar_status_str),
1579 "%4u of %u packets", progbar_count, cf->count);
1580 update_progress_dlg(progbar, progbar_val, progbar_status_str);
1583 progbar_nextstep += progbar_quantum;
1586 if (progbar_stop_flag) {
1587 /* Well, the user decided to abort the operation. Just stop,
1588 and arrange to return TRUE to our caller, so they know it
1589 was stopped explicitly. */
1596 /* do we have to process this packet? */
1597 process_this = packet_range_process_packet(range, fdata);
1598 if (process_this == range_process_next) {
1599 /* this packet uninteresting, continue with next one */
1601 } else if (process_this == range_processing_finished) {
1602 /* all interesting packets processed, stop the loop */
1606 /* Get the packet */
1607 if (!wtap_seek_read(cf->wth, fdata->file_off, &pseudo_header,
1608 pd, fdata->cap_len, &err, &err_info)) {
1609 /* Attempt to get the packet failed. */
1610 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1611 cf_read_error_message(err, err_info), cf->filename);
1615 /* Process the packet */
1616 if (!callback(cf, fdata, &pseudo_header, pd, callback_args)) {
1617 /* Callback failed. We assume it reported the error appropriately. */
1623 /* We're done printing the packets; destroy the progress bar if
1625 if (progbar != NULL)
1626 destroy_progress_dlg(progbar);
1632 retap_packet(capture_file *cf _U_, frame_data *fdata,
1633 union wtap_pseudo_header *pseudo_header, const guint8 *pd,
1636 epan_dissect_t *edt;
1638 /* If we have tap listeners, allocate a protocol tree root node, so that
1639 we'll construct a protocol tree against which a filter expression can
1641 edt = epan_dissect_new(num_tap_filters != 0, FALSE);
1642 tap_queue_init(edt);
1643 epan_dissect_run(edt, pseudo_header, pd, fdata, NULL);
1644 tap_push_tapped_queue(edt);
1645 epan_dissect_free(edt);
1651 retap_packets(capture_file *cf)
1653 packet_range_t range;
1655 /* Reset the tap listeners. */
1656 reset_tap_listeners();
1658 /* Iterate through the list of packets, dissecting all packets and
1659 re-running the taps. */
1660 packet_range_init(&range);
1661 packet_range_process_init(&range);
1662 switch (process_specified_packets(cf, &range, "Refiltering statistics on",
1663 "all packets", retap_packet,
1666 /* Completed successfully. */
1670 /* Well, the user decided to abort the refiltering.
1671 Return FALSE so our caller knows they did that. */
1675 /* Error while retapping. */
1683 print_args_t *print_args;
1684 gboolean print_header_line;
1685 char *header_line_buf;
1686 int header_line_buf_len;
1687 gboolean print_formfeed;
1688 gboolean print_separator;
1692 } print_callback_args_t;
1695 print_packet(capture_file *cf, frame_data *fdata,
1696 union wtap_pseudo_header *pseudo_header, const guint8 *pd,
1699 print_callback_args_t *args = argsp;
1700 epan_dissect_t *edt;
1706 gboolean proto_tree_needed;
1707 char bookmark_name[9+10+1]; /* "__frameNNNNNNNNNN__\0" */
1708 char bookmark_title[6+10+1]; /* "Frame NNNNNNNNNN__\0" */
1710 /* Create the protocol tree, and make it visible, if we're printing
1711 the dissection or the hex data.
1712 XXX - do we need it if we're just printing the hex data? */
1714 args->print_args->print_dissections != print_dissections_none || args->print_args->print_hex;
1715 edt = epan_dissect_new(proto_tree_needed, proto_tree_needed);
1717 /* Fill in the column information if we're printing the summary
1719 if (args->print_args->print_summary) {
1720 epan_dissect_run(edt, pseudo_header, pd, fdata, &cf->cinfo);
1721 epan_dissect_fill_in_columns(edt);
1723 epan_dissect_run(edt, pseudo_header, pd, fdata, NULL);
1725 if (args->print_formfeed) {
1726 if (!new_page(args->print_args->stream))
1729 if (args->print_separator) {
1730 if (!print_line(args->print_args->stream, 0, ""))
1736 * We generate bookmarks, if the output format supports them.
1737 * The name is "__frameN__".
1739 sprintf(bookmark_name, "__frame%u__", fdata->num);
1741 if (args->print_args->print_summary) {
1742 if (args->print_header_line) {
1743 if (!print_line(args->print_args->stream, 0, args->header_line_buf))
1745 args->print_header_line = FALSE; /* we might not need to print any more */
1747 cp = &args->line_buf[0];
1749 for (i = 0; i < cf->cinfo.num_cols; i++) {
1750 /* Find the length of the string for this column. */
1751 column_len = strlen(cf->cinfo.col_data[i]);
1752 if (args->col_widths[i] > column_len)
1753 column_len = args->col_widths[i];
1755 /* Make sure there's room in the line buffer for the column; if not,
1756 double its length. */
1757 line_len += column_len + 1; /* "+1" for space */
1758 if (line_len > args->line_buf_len) {
1759 cp_off = cp - args->line_buf;
1760 args->line_buf_len = 2 * line_len;
1761 args->line_buf = g_realloc(args->line_buf, args->line_buf_len + 1);
1762 cp = args->line_buf + cp_off;
1765 /* Right-justify the packet number column. */
1766 if (cf->cinfo.col_fmt[i] == COL_NUMBER)
1767 sprintf(cp, "%*s", args->col_widths[i], cf->cinfo.col_data[i]);
1769 sprintf(cp, "%-*s", args->col_widths[i], cf->cinfo.col_data[i]);
1771 if (i != cf->cinfo.num_cols - 1)
1777 * Generate a bookmark, using the summary line as the title.
1779 if (!print_bookmark(args->print_args->stream, bookmark_name,
1783 if (!print_line(args->print_args->stream, 0, args->line_buf))
1787 * Generate a bookmark, using "Frame N" as the title, as we're not
1788 * printing the summary line.
1790 sprintf(bookmark_title, "Frame %u", fdata->num);
1791 if (!print_bookmark(args->print_args->stream, bookmark_name,
1794 } /* if (print_summary) */
1796 if (args->print_args->print_dissections != print_dissections_none) {
1797 if (args->print_args->print_summary) {
1798 /* Separate the summary line from the tree with a blank line. */
1799 if (!print_line(args->print_args->stream, 0, ""))
1803 /* Print the information in that tree. */
1804 if (!proto_tree_print(args->print_args, edt, args->print_args->stream))
1807 /* Print a blank line if we print anything after this (aka more than one packet). */
1808 args->print_separator = TRUE;
1810 /* Print a header line if we print any more packet summaries */
1811 args->print_header_line = TRUE;
1814 if (args->print_args->print_hex) {
1815 /* Print the full packet data as hex. */
1816 if (!print_hex_data(args->print_args->stream, edt))
1819 /* Print a blank line if we print anything after this (aka more than one packet). */
1820 args->print_separator = TRUE;
1822 /* Print a header line if we print any more packet summaries */
1823 args->print_header_line = TRUE;
1824 } /* if (args->print_args->print_dissections != print_dissections_none) */
1826 epan_dissect_free(edt);
1828 /* do we want to have a formfeed between each packet from now on? */
1829 if(args->print_args->print_formfeed) {
1830 args->print_formfeed = TRUE;
1836 epan_dissect_free(edt);
1841 print_packets(capture_file *cf, print_args_t *print_args)
1844 print_callback_args_t callback_args;
1852 callback_args.print_args = print_args;
1853 callback_args.print_header_line = TRUE;
1854 callback_args.header_line_buf = NULL;
1855 callback_args.header_line_buf_len = 256;
1856 callback_args.print_formfeed = FALSE;
1857 callback_args.print_separator = FALSE;
1858 callback_args.line_buf = NULL;
1859 callback_args.line_buf_len = 256;
1860 callback_args.col_widths = NULL;
1862 if (!print_preamble(print_args->stream, cf->filename)) {
1863 destroy_print_stream(print_args->stream);
1864 return PP_WRITE_ERROR;
1867 if (print_args->print_summary) {
1868 /* We're printing packet summaries. Allocate the header line buffer
1869 and get the column widths. */
1870 callback_args.header_line_buf = g_malloc(callback_args.header_line_buf_len + 1);
1872 /* Find the widths for each of the columns - maximum of the
1873 width of the title and the width of the data - and construct
1874 a buffer with a line containing the column titles. */
1875 callback_args.col_widths = (gint *) g_malloc(sizeof(gint) * cf->cinfo.num_cols);
1876 cp = &callback_args.header_line_buf[0];
1878 for (i = 0; i < cf->cinfo.num_cols; i++) {
1879 /* Don't pad the last column. */
1880 if (i == cf->cinfo.num_cols - 1)
1881 callback_args.col_widths[i] = 0;
1883 callback_args.col_widths[i] = strlen(cf->cinfo.col_title[i]);
1884 data_width = get_column_char_width(get_column_format(i));
1885 if (data_width > callback_args.col_widths[i])
1886 callback_args.col_widths[i] = data_width;
1889 /* Find the length of the string for this column. */
1890 column_len = strlen(cf->cinfo.col_title[i]);
1891 if (callback_args.col_widths[i] > column_len)
1892 column_len = callback_args.col_widths[i];
1894 /* Make sure there's room in the line buffer for the column; if not,
1895 double its length. */
1896 line_len += column_len + 1; /* "+1" for space */
1897 if (line_len > callback_args.header_line_buf_len) {
1898 cp_off = cp - callback_args.header_line_buf;
1899 callback_args.header_line_buf_len = 2 * line_len;
1900 callback_args.header_line_buf = g_realloc(callback_args.header_line_buf,
1901 callback_args.header_line_buf_len + 1);
1902 cp = callback_args.header_line_buf + cp_off;
1905 /* Right-justify the packet number column. */
1906 /* if (cf->cinfo.col_fmt[i] == COL_NUMBER)
1907 sprintf(cp, "%*s", callback_args.col_widths[i], cf->cinfo.col_title[i]);
1909 sprintf(cp, "%-*s", callback_args.col_widths[i], cf->cinfo.col_title[i]);
1911 if (i != cf->cinfo.num_cols - 1)
1916 /* Now start out the main line buffer with the same length as the
1917 header line buffer. */
1918 callback_args.line_buf_len = callback_args.header_line_buf_len;
1919 callback_args.line_buf = g_malloc(callback_args.line_buf_len + 1);
1920 } /* if (print_summary) */
1922 /* Iterate through the list of packets, printing the packets we were
1924 ret = process_specified_packets(cf, &print_args->range, "Printing",
1925 "selected packets", print_packet,
1928 if (callback_args.header_line_buf != NULL)
1929 g_free(callback_args.header_line_buf);
1930 if (callback_args.line_buf != NULL)
1931 g_free(callback_args.line_buf);
1932 if (callback_args.col_widths != NULL)
1933 g_free(callback_args.col_widths);
1938 /* Completed successfully. */
1942 /* Well, the user decided to abort the printing.
1944 XXX - note that what got generated before they did that
1945 will get printed if we're piping to a print program; we'd
1946 have to write to a file and then hand that to the print
1947 program to make it actually not print anything. */
1951 /* Error while printing.
1953 XXX - note that what got generated before they did that
1954 will get printed if we're piping to a print program; we'd
1955 have to write to a file and then hand that to the print
1956 program to make it actually not print anything. */
1957 destroy_print_stream(print_args->stream);
1958 return PP_WRITE_ERROR;
1961 if (!print_finale(print_args->stream)) {
1962 destroy_print_stream(print_args->stream);
1963 return PP_WRITE_ERROR;
1966 if (!destroy_print_stream(print_args->stream))
1967 return PP_WRITE_ERROR;
1973 write_pdml_packet(capture_file *cf _U_, frame_data *fdata,
1974 union wtap_pseudo_header *pseudo_header, const guint8 *pd,
1978 epan_dissect_t *edt;
1980 /* Create the protocol tree, but don't fill in the column information. */
1981 edt = epan_dissect_new(TRUE, TRUE);
1982 epan_dissect_run(edt, pseudo_header, pd, fdata, NULL);
1984 /* Write out the information in that tree. */
1985 proto_tree_write_pdml(edt, fh);
1987 epan_dissect_free(edt);
1993 write_pdml_packets(capture_file *cf, print_args_t *print_args)
1998 fh = fopen(print_args->file, "w");
2000 return PP_OPEN_ERROR; /* attempt to open destination failed */
2002 write_pdml_preamble(fh);
2005 return PP_WRITE_ERROR;
2008 /* Iterate through the list of packets, printing the packets we were
2010 ret = process_specified_packets(cf, &print_args->range, "Writing PDML",
2011 "selected packets", write_pdml_packet,
2017 /* Completed successfully. */
2021 /* Well, the user decided to abort the printing. */
2025 /* Error while printing. */
2027 return PP_WRITE_ERROR;
2030 write_pdml_finale(fh);
2033 return PP_WRITE_ERROR;
2036 /* XXX - check for an error */
2043 write_psml_packet(capture_file *cf, frame_data *fdata,
2044 union wtap_pseudo_header *pseudo_header, const guint8 *pd,
2048 epan_dissect_t *edt;
2050 /* Fill in the column information, but don't create the protocol tree. */
2051 edt = epan_dissect_new(FALSE, FALSE);
2052 epan_dissect_run(edt, pseudo_header, pd, fdata, &cf->cinfo);
2054 /* Write out the information in that tree. */
2055 proto_tree_write_psml(edt, fh);
2057 epan_dissect_free(edt);
2063 write_psml_packets(capture_file *cf, print_args_t *print_args)
2068 fh = fopen(print_args->file, "w");
2070 return PP_OPEN_ERROR; /* attempt to open destination failed */
2072 write_psml_preamble(fh);
2075 return PP_WRITE_ERROR;
2078 /* Iterate through the list of packets, printing the packets we were
2080 ret = process_specified_packets(cf, &print_args->range, "Writing PSML",
2081 "selected packets", write_psml_packet,
2087 /* Completed successfully. */
2091 /* Well, the user decided to abort the printing. */
2095 /* Error while printing. */
2097 return PP_WRITE_ERROR;
2100 write_psml_finale(fh);
2103 return PP_WRITE_ERROR;
2106 /* XXX - check for an error */
2112 /* Scan through the packet list and change all columns that use the
2113 "command-line-specified" time stamp format to use the current
2114 value of that format. */
2116 change_time_formats(capture_file *cf)
2119 progdlg_t *progbar = NULL;
2125 GTimeVal start_time;
2126 gchar status_str[100];
2127 int progbar_nextstep;
2128 int progbar_quantum;
2130 gboolean sorted_by_frame_column;
2132 /* Are there any columns with time stamps in the "command-line-specified"
2135 XXX - we have to force the "column is writable" flag on, as it
2136 might be off from the last frame that was dissected. */
2137 col_set_writable(&cf->cinfo, TRUE);
2138 if (!check_col(&cf->cinfo, COL_CLS_TIME)) {
2139 /* No, there aren't any columns in that format, so we have no work
2143 first = cf->cinfo.col_first[COL_CLS_TIME];
2144 g_assert(first >= 0);
2145 last = cf->cinfo.col_last[COL_CLS_TIME];
2147 /* Freeze the packet list while we redo it, so we don't get any
2148 screen updates while it happens. */
2149 packet_list_freeze();
2151 /* Update the progress bar when it gets to this value. */
2152 progbar_nextstep = 0;
2153 /* When we reach the value that triggers a progress bar update,
2154 bump that value by this amount. */
2155 progbar_quantum = cf->count/N_PROGBAR_UPDATES;
2156 /* Count of packets at which we've looked. */
2159 /* If the rows are currently sorted by the frame column then we know
2160 * the row number of each packet: it's the row number of the previously
2161 * displayed packet + 1.
2163 * Otherwise, if the display is sorted by a different column then we have
2164 * to use the O(N) packet_list_find_row_from_data() (thus making the job
2165 * of changing the time display format O(N**2)).
2167 * (XXX - In fact it's still O(N**2) because gtk_clist_set_text() takes
2168 * the row number and walks that many elements down the clist to find
2169 * the appropriate element.)
2171 sorted_by_frame_column = FALSE;
2172 for (i = 0; i < cf->cinfo.num_cols; i++) {
2173 if (cf->cinfo.col_fmt[i] == COL_NUMBER)
2175 sorted_by_frame_column = (i == packet_list_get_sort_column());
2181 g_get_current_time(&start_time);
2183 /* Iterate through the list of packets, checking whether the packet
2184 is in a row of the summary list and, if so, whether there are
2185 any columns that show the time in the "command-line-specified"
2186 format and, if so, update that row. */
2187 for (fdata = cf->plist, row = -1; fdata != NULL; fdata = fdata->next) {
2188 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
2189 when we update it, we have to run the GTK+ main loop to get it
2190 to repaint what's pending, and doing so may involve an "ioctl()"
2191 to see if there's any pending input from an X server, and doing
2192 that for every packet can be costly, especially on a big file. */
2193 if (count >= progbar_nextstep) {
2194 /* let's not divide by zero. I should never be started
2195 * with count == 0, so let's assert that
2197 g_assert(cf->count > 0);
2199 prog_val = (gfloat) count / cf->count;
2201 if (progbar == NULL)
2202 /* Create the progress bar if necessary */
2203 progbar = delayed_create_progress_dlg("Changing", "time display",
2204 &stop_flag, &start_time, prog_val);
2206 if (progbar != NULL) {
2207 g_snprintf(status_str, sizeof(status_str),
2208 "%4u of %u packets", count, cf->count);
2209 update_progress_dlg(progbar, prog_val, status_str);
2212 progbar_nextstep += progbar_quantum;
2216 /* Well, the user decided to abort the redisplay. Just stop.
2218 XXX - this leaves the time field in the old format in
2219 frames we haven't yet processed. So it goes; should we
2220 simply not offer them the option of stopping? */
2226 /* Find what row this packet is in. */
2227 if (!sorted_by_frame_column) {
2228 /* This function is O(N), so we try to avoid using it... */
2229 row = packet_list_find_row_from_data(fdata);
2231 /* ...which we do by maintaining a count of packets that are
2232 being displayed (i.e., that have passed the display filter),
2233 and using the current value of that count as the row number
2234 (which is why we can only do it when the display is sorted
2235 by the frame number). */
2236 if (fdata->flags.passed_dfilter)
2243 /* This packet is in the summary list, on row "row". */
2245 for (i = first; i <= last; i++) {
2246 if (cf->cinfo.fmt_matx[i][COL_CLS_TIME]) {
2247 /* This is one of the columns that shows the time in
2248 "command-line-specified" format; update it. */
2249 cf->cinfo.col_buf[i][0] = '\0';
2250 col_set_cls_time(fdata, &cf->cinfo, i);
2251 packet_list_set_text(row, i, cf->cinfo.col_data[i]);
2257 /* We're done redisplaying the packets; destroy the progress bar if it
2259 if (progbar != NULL)
2260 destroy_progress_dlg(progbar);
2262 /* Set the column widths of those columns that show the time in
2263 "command-line-specified" format. */
2264 for (i = first; i <= last; i++) {
2265 if (cf->cinfo.fmt_matx[i][COL_CLS_TIME]) {
2266 packet_list_set_cls_time_width(i);
2270 /* Unfreeze the packet list. */
2278 gboolean frame_matched;
2282 find_packet_protocol_tree(capture_file *cf, const char *string)
2286 mdata.string = string;
2287 mdata.string_len = strlen(string);
2288 return find_packet(cf, match_protocol_tree, &mdata);
2292 match_protocol_tree(capture_file *cf, frame_data *fdata, void *criterion)
2294 match_data *mdata = criterion;
2295 epan_dissect_t *edt;
2297 /* Construct the protocol tree, including the displayed text */
2298 edt = epan_dissect_new(TRUE, TRUE);
2299 /* We don't need the column information */
2300 epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, NULL);
2302 /* Iterate through all the nodes, seeing if they have text that matches. */
2304 mdata->frame_matched = FALSE;
2305 proto_tree_children_foreach(edt->tree, match_subtree_text, mdata);
2306 epan_dissect_free(edt);
2307 return mdata->frame_matched;
2311 match_subtree_text(proto_node *node, gpointer data)
2313 match_data *mdata = (match_data*) data;
2314 const gchar *string = mdata->string;
2315 size_t string_len = mdata->string_len;
2316 capture_file *cf = mdata->cf;
2317 field_info *fi = PITEM_FINFO(node);
2318 gchar label_str[ITEM_LABEL_LENGTH];
2325 if (mdata->frame_matched) {
2326 /* We already had a match; don't bother doing any more work. */
2330 /* Don't match invisible entries. */
2331 if (PROTO_ITEM_IS_HIDDEN(node))
2334 /* was a free format label produced? */
2336 label_ptr = fi->rep->representation;
2338 /* no, make a generic label */
2339 label_ptr = label_str;
2340 proto_item_fill_label(fi, label_str);
2343 /* Does that label match? */
2344 label_len = strlen(label_ptr);
2345 for (i = 0; i < label_len; i++) {
2346 c_char = label_ptr[i];
2348 c_char = toupper(c_char);
2349 if (c_char == string[c_match]) {
2351 if (c_match == string_len) {
2352 /* No need to look further; we have a match */
2353 mdata->frame_matched = TRUE;
2360 /* Recurse into the subtree, if it exists */
2361 if (node->first_child != NULL)
2362 proto_tree_children_foreach(node, match_subtree_text, mdata);
2366 find_packet_summary_line(capture_file *cf, const char *string)
2370 mdata.string = string;
2371 mdata.string_len = strlen(string);
2372 return find_packet(cf, match_summary_line, &mdata);
2376 match_summary_line(capture_file *cf, frame_data *fdata, void *criterion)
2378 match_data *mdata = criterion;
2379 const gchar *string = mdata->string;
2380 size_t string_len = mdata->string_len;
2381 epan_dissect_t *edt;
2382 const char *info_column;
2383 size_t info_column_len;
2384 gboolean frame_matched = FALSE;
2390 /* Don't bother constructing the protocol tree */
2391 edt = epan_dissect_new(FALSE, FALSE);
2392 /* Get the column information */
2393 epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, &cf->cinfo);
2395 /* Find the Info column */
2396 for (colx = 0; colx < cf->cinfo.num_cols; colx++) {
2397 if (cf->cinfo.fmt_matx[colx][COL_INFO]) {
2398 /* Found it. See if we match. */
2399 info_column = edt->pi.cinfo->col_data[colx];
2400 info_column_len = strlen(info_column);
2401 for (i = 0; i < info_column_len; i++) {
2402 c_char = info_column[i];
2404 c_char = toupper(c_char);
2405 if (c_char == string[c_match]) {
2407 if (c_match == string_len) {
2408 frame_matched = TRUE;
2417 epan_dissect_free(edt);
2418 return frame_matched;
2424 } cbs_t; /* "Counted byte string" */
2427 find_packet_data(capture_file *cf, const guint8 *string, size_t string_size)
2432 info.data_len = string_size;
2434 /* String or hex search? */
2436 /* String search - what type of string? */
2437 switch (cf->scs_type) {
2439 case SCS_ASCII_AND_UNICODE:
2440 return find_packet(cf, match_ascii_and_unicode, &info);
2443 return find_packet(cf, match_ascii, &info);
2446 return find_packet(cf, match_unicode, &info);
2449 g_assert_not_reached();
2453 return find_packet(cf, match_binary, &info);
2457 match_ascii_and_unicode(capture_file *cf, frame_data *fdata, void *criterion)
2459 cbs_t *info = criterion;
2460 const char *ascii_text = info->data;
2461 size_t textlen = info->data_len;
2462 gboolean frame_matched;
2468 frame_matched = FALSE;
2469 buf_len = fdata->pkt_len;
2470 for (i = 0; i < buf_len; i++) {
2473 c_char = toupper(c_char);
2475 if (c_char == ascii_text[c_match]) {
2477 if (c_match == textlen) {
2478 frame_matched = TRUE;
2485 return frame_matched;
2489 match_ascii(capture_file *cf, frame_data *fdata, void *criterion)
2491 cbs_t *info = criterion;
2492 const char *ascii_text = info->data;
2493 size_t textlen = info->data_len;
2494 gboolean frame_matched;
2500 frame_matched = FALSE;
2501 buf_len = fdata->pkt_len;
2502 for (i = 0; i < buf_len; i++) {
2505 c_char = toupper(c_char);
2506 if (c_char == ascii_text[c_match]) {
2508 if (c_match == textlen) {
2509 frame_matched = TRUE;
2515 return frame_matched;
2519 match_unicode(capture_file *cf, frame_data *fdata, void *criterion)
2521 cbs_t *info = criterion;
2522 const char *ascii_text = info->data;
2523 size_t textlen = info->data_len;
2524 gboolean frame_matched;
2530 frame_matched = FALSE;
2531 buf_len = fdata->pkt_len;
2532 for (i = 0; i < buf_len; i++) {
2535 c_char = toupper(c_char);
2536 if (c_char == ascii_text[c_match]) {
2539 if (c_match == textlen) {
2540 frame_matched = TRUE;
2546 return frame_matched;
2550 match_binary(capture_file *cf, frame_data *fdata, void *criterion)
2552 cbs_t *info = criterion;
2553 const guint8 *binary_data = info->data;
2554 size_t datalen = info->data_len;
2555 gboolean frame_matched;
2560 frame_matched = FALSE;
2561 buf_len = fdata->pkt_len;
2562 for (i = 0; i < buf_len; i++) {
2563 if (cf->pd[i] == binary_data[c_match]) {
2565 if (c_match == datalen) {
2566 frame_matched = TRUE;
2572 return frame_matched;
2576 find_packet_dfilter(capture_file *cf, dfilter_t *sfcode)
2578 return find_packet(cf, match_dfilter, sfcode);
2582 match_dfilter(capture_file *cf, frame_data *fdata, void *criterion)
2584 dfilter_t *sfcode = criterion;
2585 epan_dissect_t *edt;
2586 gboolean frame_matched;
2588 edt = epan_dissect_new(TRUE, FALSE);
2589 epan_dissect_prime_dfilter(edt, sfcode);
2590 epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, NULL);
2591 frame_matched = dfilter_apply_edt(sfcode, edt);
2592 epan_dissect_free(edt);
2593 return frame_matched;
2597 find_packet(capture_file *cf,
2598 gboolean (*match_function)(capture_file *, frame_data *, void *),
2601 frame_data *start_fd;
2603 frame_data *new_fd = NULL;
2604 progdlg_t *progbar = NULL;
2611 GTimeVal start_time;
2612 gchar status_str[100];
2613 int progbar_nextstep;
2614 int progbar_quantum;
2616 start_fd = cf->current_frame;
2617 if (start_fd != NULL) {
2618 /* Iterate through the list of packets, starting at the packet we've
2619 picked, calling a routine to run the filter on the packet, see if
2620 it matches, and stop if so. */
2624 progbar_nextstep = 0;
2625 /* When we reach the value that triggers a progress bar update,
2626 bump that value by this amount. */
2627 progbar_quantum = cf->count/N_PROGBAR_UPDATES;
2630 g_get_current_time(&start_time);
2634 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
2635 when we update it, we have to run the GTK+ main loop to get it
2636 to repaint what's pending, and doing so may involve an "ioctl()"
2637 to see if there's any pending input from an X server, and doing
2638 that for every packet can be costly, especially on a big file. */
2639 if (count >= progbar_nextstep) {
2640 /* let's not divide by zero. I should never be started
2641 * with count == 0, so let's assert that
2643 g_assert(cf->count > 0);
2645 prog_val = (gfloat) count / cf->count;
2647 /* Create the progress bar if necessary */
2648 if (progbar == NULL)
2649 progbar = delayed_create_progress_dlg("Searching", cf->sfilter,
2650 &stop_flag, &start_time, prog_val);
2652 if (progbar != NULL) {
2653 g_snprintf(status_str, sizeof(status_str),
2654 "%4u of %u packets", count, cf->count);
2655 update_progress_dlg(progbar, prog_val, status_str);
2658 progbar_nextstep += progbar_quantum;
2662 /* Well, the user decided to abort the search. Go back to the
2663 frame where we started. */
2668 /* Go past the current frame. */
2669 if (cf->sbackward) {
2670 /* Go on to the previous frame. */
2671 fdata = fdata->prev;
2672 if (fdata == NULL) {
2674 * XXX - other apps have a bit more of a detailed message
2675 * for this, and instead of offering "OK" and "Cancel",
2676 * they offer things such as "Continue" and "Cancel";
2677 * we need an API for popping up alert boxes with
2678 * {Verb} and "Cancel".
2681 if (prefs.gui_find_wrap)
2683 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
2684 "%sBeginning of capture exceeded!%s\n\n"
2685 "Search is continued from the end of the capture.",
2686 simple_dialog_primary_start(), simple_dialog_primary_end());
2687 fdata = cf->plist_end; /* wrap around */
2691 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
2692 "%sBeginning of capture exceeded!%s\n\n"
2693 "Try searching forwards.",
2694 simple_dialog_primary_start(), simple_dialog_primary_end());
2695 fdata = start_fd; /* stay on previous packet */
2699 /* Go on to the next frame. */
2700 fdata = fdata->next;
2701 if (fdata == NULL) {
2702 if (prefs.gui_find_wrap)
2704 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
2705 "%sEnd of capture exceeded!%s\n\n"
2706 "Search is continued from the start of the capture.",
2707 simple_dialog_primary_start(), simple_dialog_primary_end());
2708 fdata = cf->plist; /* wrap around */
2712 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
2713 "%sEnd of capture exceeded!%s\n\n"
2714 "Try searching backwards.",
2715 simple_dialog_primary_start(), simple_dialog_primary_end());
2716 fdata = start_fd; /* stay on previous packet */
2723 /* Is this packet in the display? */
2724 if (fdata->flags.passed_dfilter) {
2725 /* Yes. Load its data. */
2726 if (!wtap_seek_read(cf->wth, fdata->file_off, &cf->pseudo_header,
2727 cf->pd, fdata->cap_len, &err, &err_info)) {
2728 /* Read error. Report the error, and go back to the frame
2729 where we started. */
2730 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
2731 cf_read_error_message(err, err_info), cf->filename);
2736 /* Does it match the search criterion? */
2737 if ((*match_function)(cf, fdata, criterion)) {
2739 break; /* found it! */
2743 if (fdata == start_fd) {
2744 /* We're back to the frame we were on originally, and that frame
2745 doesn't match the search filter. The search failed. */
2750 /* We're done scanning the packets; destroy the progress bar if it
2752 if (progbar != NULL)
2753 destroy_progress_dlg(progbar);
2756 if (new_fd != NULL) {
2757 /* We found a frame. Find what row it's in. */
2758 row = packet_list_find_row_from_data(new_fd);
2759 g_assert(row != -1);
2761 /* Select that row, make it the focus row, and make it visible. */
2762 packet_list_set_selected_row(row);
2763 return TRUE; /* success */
2765 return FALSE; /* failure */
2769 goto_frame(capture_file *cf, guint fnumber)
2774 for (fdata = cf->plist; fdata != NULL && fdata->num < fnumber; fdata = fdata->next)
2777 if (fdata == NULL) {
2778 /* we didn't find a packet with that packet number */
2779 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
2780 "There is no packet with that packet number.");
2781 return FALSE; /* we failed to go to that packet */
2783 if (!fdata->flags.passed_dfilter) {
2784 /* that packet currently isn't displayed */
2785 /* XXX - add it to the set of displayed packets? */
2786 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
2787 "That packet is not currently being displayed.");
2788 return FALSE; /* we failed to go to that packet */
2791 /* We found that packet, and it's currently being displayed.
2792 Find what row it's in. */
2793 row = packet_list_find_row_from_data(fdata);
2794 g_assert(row != -1);
2796 /* Select that row, make it the focus row, and make it visible. */
2797 packet_list_set_selected_row(row);
2798 return TRUE; /* we got to that packet */
2802 goto_top_frame(capture_file *cf)
2806 frame_data *lowest_fdata = NULL;
2808 for (fdata = cf->plist; fdata != NULL; fdata = fdata->next) {
2809 if (fdata->flags.passed_dfilter) {
2810 lowest_fdata = fdata;
2815 if (lowest_fdata == NULL) {
2819 /* We found that packet, and it's currently being displayed.
2820 Find what row it's in. */
2821 row = packet_list_find_row_from_data(lowest_fdata);
2822 g_assert(row != -1);
2824 /* Select that row, make it the focus row, and make it visible. */
2825 packet_list_set_selected_row(row);
2826 return TRUE; /* we got to that packet */
2830 goto_bottom_frame(capture_file *cf)
2834 frame_data *highest_fdata = NULL;
2836 for (fdata = cf->plist; fdata != NULL; fdata = fdata->next) {
2837 if (fdata->flags.passed_dfilter) {
2838 highest_fdata = fdata;
2842 if (highest_fdata == NULL) {
2846 /* We found that packet, and it's currently being displayed.
2847 Find what row it's in. */
2848 row = packet_list_find_row_from_data(highest_fdata);
2849 g_assert(row != -1);
2851 /* Select that row, make it the focus row, and make it visible. */
2852 packet_list_set_selected_row(row);
2853 return TRUE; /* we got to that packet */
2857 * Go to frame specified by currently selected protocol tree item.
2860 goto_framenum(capture_file *cf)
2862 header_field_info *hfinfo;
2865 if (cf->finfo_selected) {
2866 hfinfo = cf->finfo_selected->hfinfo;
2868 if (hfinfo->type == FT_FRAMENUM) {
2869 framenum = fvalue_get_integer(&cf->finfo_selected->value);
2871 goto_frame(cf, framenum);
2876 /* Select the packet on a given row. */
2878 select_packet(capture_file *cf, int row)
2884 /* Get the frame data struct pointer for this frame */
2885 fdata = (frame_data *)packet_list_get_row_data(row);
2887 if (fdata == NULL) {
2888 /* XXX - if a GtkCList's selection mode is GTK_SELECTION_BROWSE, when
2889 the first entry is added to it by "real_insert_row()", that row
2890 is selected (see "real_insert_row()", in "gtk/gtkclist.c", in both
2891 our version and the vanilla GTK+ version).
2893 This means that a "select-row" signal is emitted; this causes
2894 "packet_list_select_cb()" to be called, which causes "select_packet()"
2897 "select_packet()" fetches, above, the data associated with the
2898 row that was selected; however, as "gtk_clist_append()", which
2899 called "real_insert_row()", hasn't yet returned, we haven't yet
2900 associated any data with that row, so we get back a null pointer.
2902 We can't assume that there's only one frame in the frame list,
2903 either, as we may be filtering the display.
2905 We therefore assume that, if "row" is 0, i.e. the first row
2906 is being selected, and "cf->first_displayed" equals
2907 "cf->last_displayed", i.e. there's only one frame being
2908 displayed, that frame is the frame we want.
2910 This means we have to set "cf->first_displayed" and
2911 "cf->last_displayed" before adding the row to the
2912 GtkCList; see the comment in "add_packet_to_packet_list()". */
2914 if (row == 0 && cf->first_displayed == cf->last_displayed)
2915 fdata = cf->first_displayed;
2918 /* Get the data in that frame. */
2919 if (!wtap_seek_read (cf->wth, fdata->file_off, &cf->pseudo_header,
2920 cf->pd, fdata->cap_len, &err, &err_info)) {
2921 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
2922 cf_read_error_message(err, err_info), cf->filename);
2926 /* Record that this frame is the current frame. */
2927 cf->current_frame = fdata;
2929 /* Create the logical protocol tree. */
2930 if (cf->edt != NULL) {
2931 epan_dissect_free(cf->edt);
2934 /* We don't need the columns here. */
2935 cf->edt = epan_dissect_new(TRUE, TRUE);
2936 epan_dissect_run(cf->edt, &cf->pseudo_header, cf->pd, cf->current_frame,
2939 /* Display the GUI protocol tree and hex dump.
2940 XXX - why do we dump core if we call "proto_tree_draw()"
2941 before calling "add_byte_views()"? */
2942 add_main_byte_views(cf->edt);
2943 main_proto_tree_draw(cf->edt->tree);
2945 /* A packet is selected. */
2946 set_menus_for_selected_packet(cf);
2949 /* Unselect the selected packet, if any. */
2951 unselect_packet(capture_file *cf)
2953 /* Destroy the epan_dissect_t for the unselected packet. */
2954 if (cf->edt != NULL) {
2955 epan_dissect_free(cf->edt);
2959 /* Clear out the display of that packet. */
2960 clear_tree_and_hex_views();
2962 /* No packet is selected. */
2963 cf->current_frame = NULL;
2964 set_menus_for_selected_packet(cf);
2966 /* No protocol tree means no selected field. */
2970 /* Unset the selected protocol tree field, if any. */
2972 unselect_field(capture_file *cf)
2974 statusbar_pop_field_msg();
2975 cf->finfo_selected = NULL;
2976 set_menus_for_selected_tree_row(cf);
2980 * Mark a particular frame.
2983 mark_frame(capture_file *cf, frame_data *frame)
2985 if (! frame->flags.marked) {
2986 frame->flags.marked = TRUE;
2987 if (cf->count > cf->marked_count)
2993 * Unmark a particular frame.
2996 unmark_frame(capture_file *cf, frame_data *frame)
2998 if (frame->flags.marked) {
2999 frame->flags.marked = FALSE;
3000 if (cf->marked_count > 0)
3008 } save_callback_args_t;
3011 * Save a capture to a file, in a particular format, saving either
3012 * all packets, all currently-displayed packets, or all marked packets.
3014 * Returns TRUE if it succeeds, FALSE otherwise; if it fails, it pops
3015 * up a message box for the failure.
3018 save_packet(capture_file *cf _U_, frame_data *fdata,
3019 union wtap_pseudo_header *pseudo_header, const guint8 *pd,
3022 save_callback_args_t *args = argsp;
3023 struct wtap_pkthdr hdr;
3026 /* init the wtap header for saving */
3027 hdr.ts.tv_sec = fdata->abs_secs;
3028 hdr.ts.tv_usec = fdata->abs_usecs;
3029 hdr.caplen = fdata->cap_len;
3030 hdr.len = fdata->pkt_len;
3031 hdr.pkt_encap = fdata->lnk_t;
3033 /* and save the packet */
3034 if (!wtap_dump(args->pdh, &hdr, pseudo_header, pd, &err)) {
3035 cf_write_failure_alert_box(args->fname, err);
3042 cf_save(char *fname, capture_file *cf, packet_range_t *range, guint save_format)
3044 gchar *from_filename;
3045 gchar *name_ptr, *save_msg, *save_fmt = " Saving: %s...";
3050 struct stat infile, outfile;
3051 save_callback_args_t callback_args;
3053 name_ptr = get_basename(fname);
3054 msg_len = strlen(name_ptr) + strlen(save_fmt) + 2;
3055 save_msg = g_malloc(msg_len);
3056 snprintf(save_msg, msg_len, save_fmt, name_ptr);
3057 statusbar_push_file_msg(save_msg);
3061 * Check that the from file is not the same as to file
3062 * We do it here so we catch all cases ...
3063 * Unfortunately, the file requester gives us an absolute file
3064 * name and the read file name may be relative (if supplied on
3065 * the command line). From Joerg Mayer.
3067 * This is a bit tricky on win32. The st_ino field is documented as:
3068 * "The inode, and therefore st_ino, has no meaning in the FAT, ..."
3069 * but it *is* set to zero if stat() returns without an error,
3070 * so this is working, but maybe not quite the way expected. ULFL
3072 infile.st_ino = 1; /* These prevent us from getting equality */
3073 outfile.st_ino = 2; /* If one or other of the files is not accessible */
3074 stat(cf->filename, &infile);
3075 stat(fname, &outfile);
3076 if (infile.st_ino == outfile.st_ino) {
3077 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3078 "%sCapture file: \"%s\" already exists!%s\n\n"
3079 "Please choose a different filename.",
3080 simple_dialog_primary_start(), fname, simple_dialog_primary_end());
3084 packet_range_process_init(range);
3087 * if (!save_filtered && !save_marked && !save_manual_range &&
3088 * !save_marked_range && !save_curr && save_format == cf->cd_t) {
3091 if (packet_range_process_all(range) && save_format == cf->cd_t) {
3092 /* We're not filtering packets, and we're saving it in the format
3093 it's already in, so we can just move or copy the raw data. */
3095 if (cf->is_tempfile) {
3096 /* The file being saved is a temporary file from a live
3097 capture, so it doesn't need to stay around under that name;
3098 first, try renaming the capture buffer file to the new name. */
3100 if (rename(cf->filename, fname) == 0) {
3101 /* That succeeded - there's no need to copy the source file. */
3102 from_filename = NULL;
3105 if (errno == EXDEV) {
3106 /* They're on different file systems, so we have to copy the
3109 from_filename = cf->filename;
3111 /* The rename failed, but not because they're on different
3112 file systems - put up an error message. (Or should we
3113 just punt and try to copy? The only reason why I'd
3114 expect the rename to fail and the copy to succeed would
3115 be if we didn't have permission to remove the file from
3116 the temporary directory, and that might be fixable - but
3117 is it worth requiring the user to go off and fix it?) */
3118 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3119 file_rename_error_message(errno), fname);
3125 from_filename = cf->filename;
3128 /* It's a permanent file, so we should copy it, and not remove the
3131 from_filename = cf->filename;
3135 /* Copy the file, if we haven't moved it. */
3136 if (!copy_binary_file(from_filename, fname))
3140 /* Either we're filtering packets, or we're saving in a different
3141 format; we can't do that by copying or moving the capture file,
3142 we have to do it by writing the packets out in Wiretap. */
3143 pdh = wtap_dump_open(fname, save_format, cf->lnk_t, cf->snap, &err);
3145 cf_open_failure_alert_box(fname, err, NULL, TRUE, save_format);
3149 /* XXX - we let the user save a subset of the packets.
3151 If we do that, should we make that file the current file? If so,
3152 it means we can no longer get at the other packets. What does
3155 /* Iterate through the list of packets, processing the packets we were
3158 XXX - we've already called "packet_range_process_init(range)", but
3159 "process_specified_packets()" will do it again. Fortunately,
3160 that's harmless in this case, as we haven't done anything to
3161 "range" since we initialized it. */
3162 callback_args.pdh = pdh;
3163 callback_args.fname = fname;
3164 switch (process_specified_packets(cf, range, "Saving",
3165 "selected packets", save_packet,
3169 /* Completed successfully. */
3173 /* The user decided to abort the saving.
3174 XXX - remove the output file? */
3178 /* Error while saving. */
3179 wtap_dump_close(pdh, &err);
3183 if (!wtap_dump_close(pdh, &err)) {
3184 cf_close_failure_alert_box(fname, err);
3189 /* Pop the "Saving:" message off the status bar. */
3190 statusbar_pop_file_msg();
3192 if (packet_range_process_all(range)) {
3193 /* We saved the entire capture, not just some packets from it.
3194 Open and read the file we saved it to.
3196 XXX - this is somewhat of a waste; we already have the
3197 packets, all this gets us is updated file type information
3198 (which we could just stuff into "cf"), and having the new
3199 file be the one we have opened and from which we're reading
3200 the data, and it means we have to spend time opening and
3201 reading the file, which could be a significant amount of
3202 time if the file is large. */
3203 cf->user_saved = TRUE;
3205 if ((err = cf_open(fname, FALSE, cf)) == 0) {
3206 /* XXX - report errors if this fails?
3207 What should we return if it fails or is aborted? */
3208 switch (cf_read(cf)) {
3212 /* Just because we got an error, that doesn't mean we were unable
3213 to read any of the file; we handle what we could get from the
3218 /* The user bailed out of re-reading the capture file; the
3219 capture file has been closed - just return (without
3220 changing any menu settings; "cf_close()" set them
3221 correctly for the "no capture file open" state). */
3224 set_menus_for_unsaved_capture_file(FALSE);
3230 /* Pop the "Saving:" message off the status bar. */
3231 statusbar_pop_file_msg();
3236 cf_open_failure_alert_box(const char *filename, int err, gchar *err_info,
3237 gboolean for_writing, int file_type)
3240 /* Wiretap error. */
3243 case WTAP_ERR_NOT_REGULAR_FILE:
3244 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3245 "The file \"%s\" is a \"special file\" or socket or other non-regular file.",
3249 case WTAP_ERR_RANDOM_OPEN_PIPE:
3250 /* Seen only when opening a capture file for reading. */
3251 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3252 "The file \"%s\" is a pipe or FIFO; Ethereal cannot read pipe or FIFO files.",
3256 case WTAP_ERR_FILE_UNKNOWN_FORMAT:
3257 /* Seen only when opening a capture file for reading. */
3258 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3259 "The file \"%s\" is not a capture file in a format Ethereal understands.",
3263 case WTAP_ERR_UNSUPPORTED:
3264 /* Seen only when opening a capture file for reading. */
3265 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3266 "The file \"%s\" is not a capture file in a format Ethereal understands.\n"
3268 filename, err_info);
3272 case WTAP_ERR_CANT_WRITE_TO_PIPE:
3273 /* Seen only when opening a capture file for writing. */
3274 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3275 "The file \"%s\" is a pipe, and %s capture files cannot be "
3276 "written to a pipe.",
3277 filename, wtap_file_type_string(file_type));
3280 case WTAP_ERR_UNSUPPORTED_FILE_TYPE:
3281 /* Seen only when opening a capture file for writing. */
3282 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3283 "Ethereal does not support writing capture files in that format.");
3286 case WTAP_ERR_UNSUPPORTED_ENCAP:
3288 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3289 "Ethereal cannot save this capture in that format.");
3291 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3292 "The file \"%s\" is a capture for a network type that Ethereal doesn't support.\n"
3294 filename, err_info);
3299 case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED:
3301 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3302 "Ethereal cannot save this capture in that format.");
3304 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3305 "The file \"%s\" is a capture for a network type that Ethereal doesn't support.",
3310 case WTAP_ERR_BAD_RECORD:
3311 /* Seen only when opening a capture file for reading. */
3312 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3313 "The file \"%s\" appears to be damaged or corrupt.\n"
3315 filename, err_info);
3319 case WTAP_ERR_CANT_OPEN:
3321 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3322 "The file \"%s\" could not be created for some unknown reason.",
3325 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3326 "The file \"%s\" could not be opened for some unknown reason.",
3331 case WTAP_ERR_SHORT_READ:
3332 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3333 "The file \"%s\" appears to have been cut short"
3334 " in the middle of a packet or other data.",
3338 case WTAP_ERR_SHORT_WRITE:
3339 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3340 "A full header couldn't be written to the file \"%s\".",
3345 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3346 "The file \"%s\" could not be %s: %s.",
3348 for_writing ? "created" : "opened",
3349 wtap_strerror(err));
3354 open_failure_alert_box(filename, err, for_writing);
3359 file_rename_error_message(int err)
3362 static char errmsg_errno[1024+1];
3367 errmsg = "The path to the file \"%s\" does not exist.";
3371 errmsg = "You do not have permission to move the capture file to \"%s\".";
3375 snprintf(errmsg_errno, sizeof(errmsg_errno),
3376 "The file \"%%s\" could not be moved: %s.",
3377 wtap_strerror(err));
3378 errmsg = errmsg_errno;
3385 cf_read_error_message(int err, gchar *err_info)
3387 static char errmsg_errno[1024+1];
3391 case WTAP_ERR_UNSUPPORTED_ENCAP:
3392 snprintf(errmsg_errno, sizeof(errmsg_errno),
3393 "The file \"%%s\" has a packet with a network type that Ethereal doesn't support.\n(%s)",
3397 case WTAP_ERR_BAD_RECORD:
3398 snprintf(errmsg_errno, sizeof(errmsg_errno),
3399 "An error occurred while reading from the file \"%%s\": %s.\n(%s)",
3400 wtap_strerror(err), err_info);
3404 snprintf(errmsg_errno, sizeof(errmsg_errno),
3405 "An error occurred while reading from the file \"%%s\": %s.",
3406 wtap_strerror(err));
3409 return errmsg_errno;
3413 cf_write_failure_alert_box(const char *filename, int err)
3416 /* Wiretap error. */
3417 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3418 "An error occurred while writing to the file \"%s\": %s.",
3419 filename, wtap_strerror(err));
3422 write_failure_alert_box(filename, err);
3426 /* Check for write errors - if the file is being written to an NFS server,
3427 a write error may not show up until the file is closed, as NFS clients
3428 might not send writes to the server until the "write()" call finishes,
3429 so that the write may fail on the server but the "write()" may succeed. */
3431 cf_close_failure_alert_box(const char *filename, int err)
3434 /* Wiretap error. */
3437 case WTAP_ERR_CANT_CLOSE:
3438 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3439 "The file \"%s\" couldn't be closed for some unknown reason.",
3443 case WTAP_ERR_SHORT_WRITE:
3444 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3445 "Not all the packets could be written to the file \"%s\".",
3450 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3451 "An error occurred while closing the file \"%s\": %s.",
3452 filename, wtap_strerror(err));
3457 We assume that a close error from the OS is really a write error. */
3458 write_failure_alert_box(filename, err);
3462 /* Reload the current capture file. */
3466 gboolean is_tempfile;
3468 /* If the file could be opened, "cf_open()" calls "cf_close()"
3469 to get rid of state for the old capture file before filling in state
3470 for the new capture file. "cf_close()" will remove the file if
3471 it's a temporary file; we don't want that to happen (for one thing,
3472 it'd prevent subsequent reopens from working). Remember whether it's
3473 a temporary file, mark it as not being a temporary file, and then
3474 reopen it as the type of file it was.
3476 Also, "cf_close()" will free "cfile.filename", so we must make
3477 a copy of it first. */
3478 filename = g_strdup(cfile.filename);
3479 is_tempfile = cfile.is_tempfile;
3480 cfile.is_tempfile = FALSE;
3481 if (cf_open(filename, is_tempfile, &cfile) == 0) {
3482 switch (cf_read(&cfile)) {
3486 /* Just because we got an error, that doesn't mean we were unable
3487 to read any of the file; we handle what we could get from the
3492 /* The user bailed out of re-reading the capture file; the
3493 capture file has been closed - just free the capture file name
3494 string and return (without changing the last containing
3500 /* The open failed, so "cfile.is_tempfile" wasn't set to "is_tempfile".
3501 Instead, the file was left open, so we should restore "cfile.is_tempfile"
3504 XXX - change the menu? Presumably "cf_open()" will do that;
3505 make sure it does! */
3506 cfile.is_tempfile = is_tempfile;
3508 /* "cf_open()" made a copy of the file name we handed it, so
3509 we should free up our copy. */
3513 /* Copies a file in binary mode, for those operating systems that care about
3515 * Returns TRUE on success, FALSE on failure. If a failure, it also
3516 * displays a simple dialog window with the error message.
3519 copy_binary_file(char *from_filename, char *to_filename)
3521 int from_fd, to_fd, nread, nwritten, err;
3524 /* Copy the raw bytes of the file. */
3525 from_fd = open(from_filename, O_RDONLY | O_BINARY);
3527 open_failure_alert_box(from_filename, errno, FALSE);
3531 /* Use open() instead of creat() so that we can pass the O_BINARY
3532 flag, which is relevant on Win32; it appears that "creat()"
3533 may open the file in text mode, not binary mode, but we want
3534 to copy the raw bytes of the file, so we need the output file
3535 to be open in binary mode. */
3536 to_fd = open(to_filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
3538 open_failure_alert_box(to_filename, errno, TRUE);
3543 while ((nread = read(from_fd, pd, sizeof pd)) > 0) {
3544 nwritten = write(to_fd, pd, nread);
3545 if (nwritten < nread) {
3549 err = WTAP_ERR_SHORT_WRITE;
3550 write_failure_alert_box(to_filename, err);
3558 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3559 "An error occurred while reading from the file \"%s\": %s.",
3560 from_filename, strerror(err));
3566 if (close(to_fd) < 0) {
3567 write_failure_alert_box(to_filename, errno);