6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@ethereal.com>
8 * Copyright 1998 Gerald Combs
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
50 #ifdef NEED_STRERROR_H
54 #include <epan/epan.h>
55 #include <epan/filesystem.h>
58 #include "color_filters.h"
59 #include <epan/column.h>
60 #include <epan/packet.h>
61 #include "packet-range.h"
67 #include "alert_box.h"
68 #include "simple_dialog.h"
69 #include "progress_dlg.h"
71 #include <epan/prefs.h>
72 #include <epan/dfilter/dfilter.h>
73 #include <epan/conversation.h>
74 #include <epan/epan_dissect.h>
76 #include "stat_menu.h"
77 #include "tap_dfilter_dlg.h"
78 #include <epan/dissectors/packet-data.h>
79 #include <epan/timestamp.h>
82 /* Win32 needs the O_BINARY flag for open() */
88 gboolean auto_scroll_live;
91 static nstime_t first_ts;
92 static nstime_t prev_ts;
93 static guint32 cum_bytes = 0;
95 static void cf_reset_state(capture_file *cf);
97 static void read_packet(capture_file *cf, long offset);
99 static void rescan_packets(capture_file *cf, const char *action, const char *action_item,
100 gboolean refilter, gboolean redissect);
102 static gboolean match_protocol_tree(capture_file *cf, frame_data *fdata,
104 static void match_subtree_text(proto_node *node, gpointer data);
105 static gboolean match_summary_line(capture_file *cf, frame_data *fdata,
107 static gboolean match_ascii_and_unicode(capture_file *cf, frame_data *fdata,
109 static gboolean match_ascii(capture_file *cf, frame_data *fdata,
111 static gboolean match_unicode(capture_file *cf, frame_data *fdata,
113 static gboolean match_binary(capture_file *cf, frame_data *fdata,
115 static gboolean match_dfilter(capture_file *cf, frame_data *fdata,
117 static gboolean find_packet(capture_file *cf,
118 gboolean (*match_function)(capture_file *, frame_data *, void *),
121 static void cf_open_failure_alert_box(const char *filename, int err,
122 gchar *err_info, gboolean for_writing,
124 static const char *file_rename_error_message(int err);
125 static void cf_write_failure_alert_box(const char *filename, int err);
126 static void cf_close_failure_alert_box(const char *filename, int err);
127 static gboolean copy_binary_file(const char *from_filename, const char *to_filename);
129 /* Update the progress bar this many times when reading a file. */
130 #define N_PROGBAR_UPDATES 100
132 /* Number of "frame_data" structures per memory chunk.
133 XXX - is this the right number? */
134 #define FRAME_DATA_CHUNK_SIZE 1024
137 /* one callback for now, we could have a list later */
138 static cf_callback_t cf_cb = NULL;
139 static gpointer cf_cb_user_data = NULL;
142 cf_callback_invoke(int event, gpointer data)
144 g_assert(cf_cb != NULL);
145 cf_cb(event, data, cf_cb_user_data);
150 cf_callback_add(cf_callback_t func, gpointer user_data)
152 /* More than one callback listener is currently not implemented,
153 but should be easy to do. */
154 g_assert(cf_cb == NULL);
156 cf_cb_user_data = user_data;
160 cf_callback_remove(cf_callback_t func _U_)
162 g_assert(cf_cb != NULL);
164 cf_cb_user_data = NULL;
168 cf_timestamp_auto_precision(capture_file *cf)
170 int prec = timestamp_get_precision();
173 /* don't try to get the file's precision if none is opened */
174 if(cf->state == FILE_CLOSED) {
178 /* if we are in auto mode, set precision of current file */
179 if(prec == TS_PREC_AUTO ||
180 prec == TS_PREC_AUTO_SEC ||
181 prec == TS_PREC_AUTO_DSEC ||
182 prec == TS_PREC_AUTO_CSEC ||
183 prec == TS_PREC_AUTO_MSEC ||
184 prec == TS_PREC_AUTO_USEC ||
185 prec == TS_PREC_AUTO_NSEC)
187 switch(wtap_file_tsprecision(cf->wth)) {
188 case(WTAP_FILE_TSPREC_SEC):
189 timestamp_set_precision(TS_PREC_AUTO_SEC);
191 case(WTAP_FILE_TSPREC_DSEC):
192 timestamp_set_precision(TS_PREC_AUTO_DSEC);
194 case(WTAP_FILE_TSPREC_CSEC):
195 timestamp_set_precision(TS_PREC_AUTO_CSEC);
197 case(WTAP_FILE_TSPREC_MSEC):
198 timestamp_set_precision(TS_PREC_AUTO_MSEC);
200 case(WTAP_FILE_TSPREC_USEC):
201 timestamp_set_precision(TS_PREC_AUTO_USEC);
203 case(WTAP_FILE_TSPREC_NSEC):
204 timestamp_set_precision(TS_PREC_AUTO_NSEC);
207 g_assert_not_reached();
214 cf_open(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
219 wth = wtap_open_offline(fname, err, &err_info, TRUE);
223 /* The open succeeded. Close whatever capture file we had open,
224 and fill in the information for this file. */
227 /* Initialize all data structures used for dissection. */
230 /* We're about to start reading the file. */
231 cf->state = FILE_READ_IN_PROGRESS;
236 /* Set the file name because we need it to set the follow stream filter.
237 XXX - is that still true? We need it for other reasons, though,
239 cf->filename = g_strdup(fname);
241 /* Indicate whether it's a permanent or temporary file. */
242 cf->is_tempfile = is_tempfile;
244 /* If it's a temporary capture buffer file, mark it as not saved. */
245 cf->user_saved = !is_tempfile;
247 cf->cd_t = wtap_file_type(cf->wth);
249 cf->displayed_count = 0;
250 cf->marked_count = 0;
251 cf->drops_known = FALSE;
253 cf->snap = wtap_snapshot_length(cf->wth);
255 /* Snapshot length not known. */
256 cf->has_snap = FALSE;
257 cf->snap = WTAP_MAX_PACKET_SIZE;
260 nstime_set_zero(&cf->elapsed_time);
261 nstime_set_zero(&first_ts);
262 nstime_set_zero(&prev_ts);
264 cf->plist_chunk = g_mem_chunk_new("frame_data_chunk",
266 FRAME_DATA_CHUNK_SIZE * sizeof(frame_data),
268 g_assert(cf->plist_chunk);
270 /* change the time formats now, as we might have a new precision */
271 cf_change_time_formats(cf);
273 fileset_file_opened(fname);
278 cf_open_failure_alert_box(fname, *err, err_info, FALSE, 0);
284 * Reset the state for the currently closed file, but don't do the
285 * UI callbacks; this is for use in "cf_open()", where we don't
286 * want the UI to go from "file open" to "file closed" back to
287 * "file open", we want it to go from "old file open" to "new file
288 * open and being read".
291 cf_reset_state(capture_file *cf)
293 /* Die if we're in the middle of reading a file. */
294 g_assert(cf->state != FILE_READ_IN_PROGRESS);
300 /* We have no file open... */
301 if (cf->filename != NULL) {
302 /* If it's a temporary file, remove it. */
304 unlink(cf->filename);
305 g_free(cf->filename);
308 /* ...which means we have nothing to save. */
309 cf->user_saved = FALSE;
311 if (cf->plist_chunk != NULL) {
312 g_mem_chunk_destroy(cf->plist_chunk);
313 cf->plist_chunk = NULL;
315 if (cf->rfcode != NULL) {
316 dfilter_free(cf->rfcode);
320 cf->plist_end = NULL;
321 cf_unselect_packet(cf); /* nothing to select */
322 cf->first_displayed = NULL;
323 cf->last_displayed = NULL;
325 /* No frame selected, no field in that frame selected. */
326 cf->current_frame = NULL;
327 cf->finfo_selected = NULL;
329 /* Clear the packet list. */
330 packet_list_freeze();
336 nstime_set_zero(&cf->elapsed_time);
338 reset_tap_listeners();
340 /* We have no file open. */
341 cf->state = FILE_CLOSED;
343 fileset_file_closed();
346 /* Reset everything to a pristine state */
348 cf_close(capture_file *cf)
352 cleanup_dissection();
354 cf_callback_invoke(cf_cb_file_closed, cf);
358 cf_read(capture_file *cf)
362 const gchar *name_ptr;
364 char errmsg_errno[1024+1];
365 gchar err_str[2048+1];
367 progdlg_t *progbar = NULL;
369 gint64 size, file_pos;
372 gchar status_str[100];
373 gint64 progbar_nextstep;
374 gint64 progbar_quantum;
378 reset_tap_listeners();
379 tap_dfilter_dlg_update();
381 cf_callback_invoke(cf_cb_file_read_start, cf);
383 name_ptr = get_basename(cf->filename);
385 /* Find the size of the file. */
386 size = wtap_file_size(cf->wth, NULL);
388 /* Update the progress bar when it gets to this value. */
389 progbar_nextstep = 0;
390 /* When we reach the value that triggers a progress bar update,
391 bump that value by this amount. */
393 progbar_quantum = size/N_PROGBAR_UPDATES;
397 packet_list_freeze();
400 g_get_current_time(&start_time);
402 while ((wtap_read(cf->wth, &err, &err_info, &data_offset))) {
404 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
405 when we update it, we have to run the GTK+ main loop to get it
406 to repaint what's pending, and doing so may involve an "ioctl()"
407 to see if there's any pending input from an X server, and doing
408 that for every packet can be costly, especially on a big file. */
409 if (data_offset >= progbar_nextstep) {
410 file_pos = wtap_read_so_far(cf->wth, NULL);
411 prog_val = (gfloat) file_pos / (gfloat) size;
412 if (prog_val > 1.0) {
413 /* The file probably grew while we were reading it.
414 Update file size, and try again. */
415 size = wtap_file_size(cf->wth, NULL);
417 prog_val = (gfloat) file_pos / (gfloat) size;
418 /* If it's still > 1, either "wtap_file_size()" failed (in which
419 case there's not much we can do about it), or the file
420 *shrank* (in which case there's not much we can do about
421 it); just clip the progress value at 1.0. */
425 if (progbar == NULL) {
426 /* Create the progress bar if necessary */
427 progbar = delayed_create_progress_dlg("Loading", name_ptr,
428 &stop_flag, &start_time, prog_val);
430 if (progbar != NULL) {
431 g_snprintf(status_str, sizeof(status_str),
432 "%" PRId64 "KB of %" PRId64 "KB",
433 file_pos / 1024, size / 1024);
434 update_progress_dlg(progbar, prog_val, status_str);
436 progbar_nextstep += progbar_quantum;
441 /* Well, the user decided to abort the read. Destroy the progress
442 bar, close the capture file, and return CF_READ_ABORTED so our caller
443 can do whatever is appropriate when that happens. */
444 destroy_progress_dlg(progbar);
445 cf->state = FILE_READ_ABORTED; /* so that we're allowed to close it */
446 packet_list_thaw(); /* undo our freeze */
448 return CF_READ_ABORTED;
450 read_packet(cf, data_offset);
453 /* We're done reading the file; destroy the progress bar if it was created. */
455 destroy_progress_dlg(progbar);
457 /* We're done reading sequentially through the file. */
458 cf->state = FILE_READ_DONE;
460 /* Close the sequential I/O side, to free up memory it requires. */
461 wtap_sequential_close(cf->wth);
463 /* Allow the protocol dissectors to free up memory that they
464 * don't need after the sequential run-through of the packets. */
465 postseq_cleanup_all_protocols();
467 /* Set the file encapsulation type now; we don't know what it is until
468 we've looked at all the packets, as we don't know until then whether
469 there's more than one type (and thus whether it's
470 WTAP_ENCAP_PER_PACKET). */
471 cf->lnk_t = wtap_file_encap(cf->wth);
473 cf->current_frame = cf->first_displayed;
476 cf_callback_invoke(cf_cb_file_read_finished, cf);
478 /* If we have any displayed packets to select, select the first of those
479 packets by making the first row the selected row. */
480 if (cf->first_displayed != NULL)
481 packet_list_select_row(0);
484 /* Put up a message box noting that the read failed somewhere along
485 the line. Don't throw out the stuff we managed to read, though,
489 case WTAP_ERR_UNSUPPORTED_ENCAP:
490 g_snprintf(errmsg_errno, sizeof(errmsg_errno),
491 "The capture file has a packet with a network type that Ethereal doesn't support.\n(%s)",
494 errmsg = errmsg_errno;
497 case WTAP_ERR_CANT_READ:
498 errmsg = "An attempt to read from the capture file failed for"
499 " some unknown reason.";
502 case WTAP_ERR_SHORT_READ:
503 errmsg = "The capture file appears to have been cut short"
504 " in the middle of a packet.";
507 case WTAP_ERR_BAD_RECORD:
508 g_snprintf(errmsg_errno, sizeof(errmsg_errno),
509 "The capture file appears to be damaged or corrupt.\n(%s)",
512 errmsg = errmsg_errno;
516 g_snprintf(errmsg_errno, sizeof(errmsg_errno),
517 "An error occurred while reading the"
518 " capture file: %s.", wtap_strerror(err));
519 errmsg = errmsg_errno;
522 g_snprintf(err_str, sizeof err_str, errmsg);
523 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, err_str);
524 return CF_READ_ERROR;
531 cf_start_tail(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
533 cf_status_t cf_status;
535 cf_status = cf_open(cf, fname, is_tempfile, err);
540 cf_continue_tail(capture_file *cf, int to_read, int *err)
542 long data_offset = 0;
547 packet_list_freeze();
549 while (to_read != 0 && (wtap_read(cf->wth, err, &err_info, &data_offset))) {
550 if (cf->state == FILE_READ_ABORTED) {
551 /* Well, the user decided to exit Ethereal. Break out of the
552 loop, and let the code below (which is called even if there
553 aren't any packets left to read) exit. */
556 read_packet(cf, data_offset);
562 /* XXX - this cheats and looks inside the packet list to find the final
564 if (auto_scroll_live && cf->plist_end != NULL)
565 packet_list_moveto_end();
567 if (cf->state == FILE_READ_ABORTED) {
568 /* Well, the user decided to exit Ethereal. Return CF_READ_ABORTED
569 so that our caller can kill off the capture child process;
570 this will cause an EOF on the pipe from the child, so
571 "cf_finish_tail()" will be called, and it will clean up
573 return CF_READ_ABORTED;
574 } else if (*err != 0) {
575 /* We got an error reading the capture file.
576 XXX - pop up a dialog box? */
577 return CF_READ_ERROR;
583 cf_finish_tail(capture_file *cf, int *err)
588 if(cf->wth == NULL) {
590 return CF_READ_ERROR;
593 packet_list_freeze();
595 while ((wtap_read(cf->wth, err, &err_info, &data_offset))) {
596 if (cf->state == FILE_READ_ABORTED) {
597 /* Well, the user decided to abort the read. Break out of the
598 loop, and let the code below (which is called even if there
599 aren't any packets left to read) exit. */
602 read_packet(cf, data_offset);
605 if (cf->state == FILE_READ_ABORTED) {
606 /* Well, the user decided to abort the read. We're only called
607 when the child capture process closes the pipe to us (meaning
608 it's probably exited), so we can just close the capture
609 file; we return CF_READ_ABORTED so our caller can do whatever
610 is appropriate when that happens. */
612 return CF_READ_ABORTED;
616 if (auto_scroll_live && cf->plist_end != NULL)
617 /* XXX - this cheats and looks inside the packet list to find the final
619 packet_list_moveto_end();
621 /* We're done reading sequentially through the file. */
622 cf->state = FILE_READ_DONE;
624 /* We're done reading sequentially through the file; close the
625 sequential I/O side, to free up memory it requires. */
626 wtap_sequential_close(cf->wth);
628 /* Allow the protocol dissectors to free up memory that they
629 * don't need after the sequential run-through of the packets. */
630 postseq_cleanup_all_protocols();
632 /* Set the file encapsulation type now; we don't know what it is until
633 we've looked at all the packets, as we don't know until then whether
634 there's more than one type (and thus whether it's
635 WTAP_ENCAP_PER_PACKET). */
636 cf->lnk_t = wtap_file_encap(cf->wth);
639 /* We got an error reading the capture file.
640 XXX - pop up a dialog box? */
641 return CF_READ_ERROR;
646 #endif /* HAVE_LIBPCAP */
649 cf_get_display_name(capture_file *cf)
651 const gchar *displayname;
653 /* Return a name to use in displays */
654 if (!cf->is_tempfile) {
655 /* Get the last component of the file name, and use that. */
657 displayname = get_basename(cf->filename);
659 displayname="(No file)";
662 /* The file we read is a temporary file from a live capture;
663 we don't mention its name. */
664 displayname = "(Untitled)";
669 /* XXX - use a macro instead? */
671 cf_packet_count(capture_file *cf)
676 /* XXX - use a macro instead? */
678 cf_is_tempfile(capture_file *cf)
680 return cf->is_tempfile;
683 void cf_set_tempfile(capture_file *cf, gboolean is_tempfile)
685 cf->is_tempfile = is_tempfile;
689 /* XXX - use a macro instead? */
690 void cf_set_drops_known(capture_file *cf, gboolean drops_known)
692 cf->drops_known = drops_known;
695 /* XXX - use a macro instead? */
696 void cf_set_drops(capture_file *cf, guint32 drops)
701 /* XXX - use a macro instead? */
702 gboolean cf_get_drops_known(capture_file *cf)
704 return cf->drops_known;
707 /* XXX - use a macro instead? */
708 guint32 cf_get_drops(capture_file *cf)
713 void cf_set_rfcode(capture_file *cf, dfilter_t *rfcode)
719 add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
720 union wtap_pseudo_header *pseudo_header, const guchar *buf,
724 gboolean create_proto_tree = FALSE;
727 /* just add some value here until we know if it is being displayed or not */
728 fdata->cum_bytes = cum_bytes + fdata->pkt_len;
730 /* If we don't have the time stamp of the first packet in the
731 capture, it's because this is the first packet. Save the time
732 stamp of this packet as the time stamp of the first packet. */
733 if (nstime_is_zero(&first_ts)) {
734 first_ts = fdata->abs_ts;
736 /* if this frames is marked as a reference time frame, reset
737 firstsec and firstusec to this frame */
738 if(fdata->flags.ref_time){
739 first_ts = fdata->abs_ts;
742 /* If we don't have the time stamp of the previous displayed packet,
743 it's because this is the first displayed packet. Save the time
744 stamp of this packet as the time stamp of the previous displayed
746 if (nstime_is_zero(&prev_ts)) {
747 prev_ts = fdata->abs_ts;
750 /* Get the time elapsed between the first packet and this packet. */
751 nstime_delta(&fdata->rel_ts, &fdata->abs_ts, &first_ts);
753 /* If it's greater than the current elapsed time, set the elapsed time
754 to it (we check for "greater than" so as not to be confused by
755 time moving backwards). */
756 if ((gint32)cf->elapsed_time.secs < fdata->rel_ts.secs
757 || ((gint32)cf->elapsed_time.secs == fdata->rel_ts.secs && (gint32)cf->elapsed_time.nsecs < fdata->rel_ts.nsecs)) {
758 cf->elapsed_time = fdata->rel_ts;
761 /* Get the time elapsed between the previous displayed packet and
763 nstime_delta(&fdata->del_ts, &fdata->abs_ts, &prev_ts);
767 we have a display filter and are re-applying it;
769 we have a list of color filters;
771 we have tap listeners;
773 allocate a protocol tree root node, so that we'll construct
774 a protocol tree against which a filter expression can be
776 if ((cf->dfcode != NULL && refilter) || color_filters_used()
777 || num_tap_filters != 0)
778 create_proto_tree = TRUE;
780 /* Dissect the frame. */
781 edt = epan_dissect_new(create_proto_tree, FALSE);
783 if (cf->dfcode != NULL && refilter) {
784 epan_dissect_prime_dfilter(edt, cf->dfcode);
786 if (color_filters_used()) {
787 color_filters_prime_edt(edt);
790 epan_dissect_run(edt, pseudo_header, buf, fdata, &cf->cinfo);
791 tap_push_tapped_queue(edt);
793 /* If we have a display filter, apply it if we're refiltering, otherwise
794 leave the "passed_dfilter" flag alone.
796 If we don't have a display filter, set "passed_dfilter" to 1. */
797 if (cf->dfcode != NULL) {
799 fdata->flags.passed_dfilter = dfilter_apply_edt(cf->dfcode, edt) ? 1 : 0;
802 fdata->flags.passed_dfilter = 1;
804 if( (fdata->flags.passed_dfilter)
805 || (edt->pi.fd->flags.ref_time) ){
806 /* This frame either passed the display filter list or is marked as
807 a time reference frame. All time reference frames are displayed
808 even if they dont pass the display filter */
809 /* if this was a TIME REF frame we should reset the cul bytes field */
810 if(edt->pi.fd->flags.ref_time){
811 cum_bytes = fdata->pkt_len;
812 fdata->cum_bytes = cum_bytes;
815 /* increase cum_bytes with this packets length */
816 cum_bytes += fdata->pkt_len;
818 epan_dissect_fill_in_columns(edt);
820 /* If we haven't yet seen the first frame, this is it.
822 XXX - we must do this before we add the row to the display,
823 as, if the display's GtkCList's selection mode is
824 GTK_SELECTION_BROWSE, when the first entry is added to it,
825 "cf_select_packet()" will be called, and it will fetch the row
826 data for the 0th row, and will get a null pointer rather than
827 "fdata", as "gtk_clist_append()" won't yet have returned and
828 thus "gtk_clist_set_row_data()" won't yet have been called.
830 We thus need to leave behind bread crumbs so that
831 "cf_select_packet()" can find this frame. See the comment
832 in "cf_select_packet()". */
833 if (cf->first_displayed == NULL)
834 cf->first_displayed = fdata;
836 /* This is the last frame we've seen so far. */
837 cf->last_displayed = fdata;
839 row = packet_list_append(cf->cinfo.col_data, fdata);
841 /* colorize packet: if packet is marked, use preferences,
842 otherwise try to apply color filters */
843 if (fdata->flags.marked) {
844 fdata->color_filter = NULL;
845 packet_list_set_colors(row, &prefs.gui_marked_fg, &prefs.gui_marked_bg);
847 fdata->color_filter = color_filters_colorize_packet(row, edt);
850 /* Set the time of the previous displayed frame to the time of this
852 prev_ts = fdata->abs_ts;
854 cf->displayed_count++;
856 /* This frame didn't pass the display filter, so it's not being added
857 to the clist, and thus has no row. */
860 epan_dissect_free(edt);
865 read_packet(capture_file *cf, long offset)
867 const struct wtap_pkthdr *phdr = wtap_phdr(cf->wth);
868 union wtap_pseudo_header *pseudo_header = wtap_pseudoheader(cf->wth);
869 const guchar *buf = wtap_buf_ptr(cf->wth);
872 frame_data *plist_end;
875 /* Allocate the next list entry, and add it to the list. */
876 fdata = g_mem_chunk_alloc(cf->plist_chunk);
882 fdata->pkt_len = phdr->len;
883 fdata->cap_len = phdr->caplen;
884 fdata->file_off = offset;
885 fdata->lnk_t = phdr->pkt_encap;
886 fdata->flags.encoding = CHAR_ASCII;
887 fdata->flags.visited = 0;
888 fdata->flags.marked = 0;
889 fdata->flags.ref_time = 0;
891 fdata->abs_ts = *((nstime_t *) &phdr->ts);
895 edt = epan_dissect_new(TRUE, FALSE);
896 epan_dissect_prime_dfilter(edt, cf->rfcode);
897 epan_dissect_run(edt, pseudo_header, buf, fdata, NULL);
898 passed = dfilter_apply_edt(cf->rfcode, edt);
899 epan_dissect_free(edt);
902 plist_end = cf->plist_end;
903 fdata->prev = plist_end;
904 if (plist_end != NULL)
905 plist_end->next = fdata;
908 cf->plist_end = fdata;
911 cf->f_datalen = offset + phdr->caplen;
912 fdata->num = cf->count;
913 add_packet_to_packet_list(fdata, cf, pseudo_header, buf, TRUE);
915 /* XXX - if we didn't have read filters, or if we could avoid
916 allocating the "frame_data" structure until we knew whether
917 the frame passed the read filter, we could use a G_ALLOC_ONLY
920 ...but, at least in one test I did, where I just made the chunk
921 a G_ALLOC_ONLY chunk and read in a huge capture file, it didn't
922 seem to save a noticeable amount of time or space. */
923 g_mem_chunk_free(cf->plist_chunk, fdata);
928 cf_merge_files(char **out_filenamep, int in_file_count,
929 char *const *in_filenames, int file_type, gboolean do_append)
931 merge_in_file_t *in_files;
937 int open_err, read_err, write_err, close_err;
941 char errmsg_errno[1024+1];
942 gchar err_str[2048+1];
944 gboolean got_read_error = FALSE, got_write_error = FALSE;
946 progdlg_t *progbar = NULL;
948 gint64 f_len, file_pos;
951 gchar status_str[100];
952 gint64 progbar_nextstep;
953 gint64 progbar_quantum;
955 /* open the input files */
956 if (!merge_open_in_files(in_file_count, in_filenames, &in_files,
957 &open_err, &err_info, &err_fileno)) {
959 cf_open_failure_alert_box(in_filenames[err_fileno], open_err, err_info,
964 if (*out_filenamep != NULL) {
965 out_filename = *out_filenamep;
966 out_fd = open(out_filename, O_CREAT|O_TRUNC|O_BINARY, 0600);
970 out_fd = create_tempfile(tmpname, sizeof tmpname, "ether");
973 out_filename = g_strdup(tmpname);
974 *out_filenamep = out_filename;
978 merge_close_in_files(in_file_count, in_files);
980 cf_open_failure_alert_box(out_filename, open_err, NULL, TRUE, file_type);
984 pdh = wtap_dump_fdopen(out_fd, file_type,
985 merge_select_frame_type(in_file_count, in_files),
986 merge_max_snapshot_length(in_file_count, in_files),
987 FALSE /* compressed */, &open_err);
990 merge_close_in_files(in_file_count, in_files);
992 cf_open_failure_alert_box(out_filename, open_err, err_info, TRUE,
997 /* Get the sum of the sizes of all the files. */
999 for (i = 0; i < in_file_count; i++)
1000 f_len += in_files[i].size;
1002 /* Update the progress bar when it gets to this value. */
1003 progbar_nextstep = 0;
1004 /* When we reach the value that triggers a progress bar update,
1005 bump that value by this amount. */
1006 progbar_quantum = f_len/N_PROGBAR_UPDATES;
1009 g_get_current_time(&start_time);
1011 /* do the merge (or append) */
1014 wth = merge_append_read_packet(in_file_count, in_files, &read_err,
1017 wth = merge_read_packet(in_file_count, in_files, &read_err,
1021 got_read_error = TRUE;
1025 /* Get the sum of the data offsets in all of the files. */
1027 for (i = 0; i < in_file_count; i++)
1028 data_offset += in_files[i].data_offset;
1030 if (data_offset >= progbar_nextstep) {
1031 /* Get the sum of the seek positions in all of the files. */
1033 for (i = 0; i < in_file_count; i++)
1034 file_pos += wtap_read_so_far(in_files[i].wth, NULL);
1035 prog_val = (gfloat) file_pos / (gfloat) f_len;
1036 if (prog_val > 1.0) {
1037 /* Some file probably grew while we were reading it.
1038 That "shouldn't happen", so we'll just clip the progress
1042 if (progbar == NULL) {
1043 /* Create the progress bar if necessary */
1044 progbar = delayed_create_progress_dlg("Merging", "files",
1045 &stop_flag, &start_time, prog_val);
1047 if (progbar != NULL) {
1048 g_snprintf(status_str, sizeof(status_str),
1049 "%" PRId64 "KB of %" PRId64 "KB",
1050 file_pos / 1024, f_len / 1024);
1051 update_progress_dlg(progbar, prog_val, status_str);
1053 progbar_nextstep += progbar_quantum;
1056 if (!wtap_dump(pdh, wtap_phdr(wth), wtap_pseudoheader(wth),
1057 wtap_buf_ptr(wth), &write_err)) {
1058 got_write_error = TRUE;
1063 /* We're done merging the files; destroy the progress bar if it was created. */
1064 if (progbar != NULL)
1065 destroy_progress_dlg(progbar);
1067 merge_close_in_files(in_file_count, in_files);
1068 if (!got_read_error && !got_write_error) {
1069 if (!wtap_dump_close(pdh, &write_err))
1070 got_write_error = TRUE;
1072 wtap_dump_close(pdh, &close_err);
1074 if (got_read_error) {
1076 * Find the file on which we got the error, and report the error.
1078 for (i = 0; i < in_file_count; i++) {
1079 if (in_files[i].state == GOT_ERROR) {
1080 /* Put up a message box noting that a read failed somewhere along
1084 case WTAP_ERR_UNSUPPORTED_ENCAP:
1085 g_snprintf(errmsg_errno, sizeof(errmsg_errno),
1086 "The capture file %%s has a packet with a network type that Ethereal doesn't support.\n(%s)",
1089 errmsg = errmsg_errno;
1092 case WTAP_ERR_CANT_READ:
1093 errmsg = "An attempt to read from the capture file %s failed for"
1094 " some unknown reason.";
1097 case WTAP_ERR_SHORT_READ:
1098 errmsg = "The capture file %s appears to have been cut short"
1099 " in the middle of a packet.";
1102 case WTAP_ERR_BAD_RECORD:
1103 g_snprintf(errmsg_errno, sizeof(errmsg_errno),
1104 "The capture file %%s appears to be damaged or corrupt.\n(%s)",
1107 errmsg = errmsg_errno;
1111 g_snprintf(errmsg_errno, sizeof(errmsg_errno),
1112 "An error occurred while reading the"
1113 " capture file %%s: %s.", wtap_strerror(read_err));
1114 errmsg = errmsg_errno;
1117 g_snprintf(err_str, sizeof err_str, errmsg, in_files[i].filename);
1118 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, err_str);
1123 if (got_write_error) {
1124 /* Put up an alert box for the write error. */
1125 cf_write_failure_alert_box(out_filename, write_err);
1128 return (!got_read_error && !got_write_error) ? CF_OK : CF_ERROR;
1132 cf_filter_packets(capture_file *cf, gchar *dftext, gboolean force)
1135 const char *filter_new = dftext ? dftext : "";
1136 const char *filter_old = cf->dfilter ? cf->dfilter : "";
1138 /* if new filter equals old one, do nothing unless told to do so */
1139 if (!force && strcmp(filter_new, filter_old) == 0) {
1143 if (dftext == NULL) {
1144 /* The new filter is an empty filter (i.e., display all packets). */
1148 * We have a filter; make a copy of it (as we'll be saving it),
1149 * and try to compile it.
1151 dftext = g_strdup(dftext);
1152 if (!dfilter_compile(dftext, &dfcode)) {
1153 /* The attempt failed; report an error. */
1154 gchar *safe_dftext = simple_dialog_format_message(dftext);
1155 gchar *safe_dfilter_error_msg = simple_dialog_format_message(
1157 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1160 "The following display filter isn't a valid display filter:\n%s\n"
1161 "See the help for a description of the display filter syntax.",
1162 simple_dialog_primary_start(), safe_dfilter_error_msg,
1163 simple_dialog_primary_end(), safe_dftext);
1164 g_free(safe_dfilter_error_msg);
1165 g_free(safe_dftext);
1171 if (dfcode == NULL) {
1172 /* Yes - free the filter text, and set it to null. */
1178 /* We have a valid filter. Replace the current filter. */
1179 if (cf->dfilter != NULL)
1180 g_free(cf->dfilter);
1181 cf->dfilter = dftext;
1182 if (cf->dfcode != NULL)
1183 dfilter_free(cf->dfcode);
1184 cf->dfcode = dfcode;
1186 /* Now rescan the packet list, applying the new filter, but not
1187 throwing away information constructed on a previous pass. */
1188 if (dftext == NULL) {
1189 rescan_packets(cf, "Resetting", "Filter", TRUE, FALSE);
1191 rescan_packets(cf, "Filtering", dftext, TRUE, FALSE);
1197 cf_colorize_packets(capture_file *cf)
1199 rescan_packets(cf, "Colorizing", "all packets", FALSE, FALSE);
1203 cf_reftime_packets(capture_file *cf)
1205 rescan_packets(cf, "Updating Reftime", "all packets", FALSE, FALSE);
1209 cf_redissect_packets(capture_file *cf)
1211 rescan_packets(cf, "Reprocessing", "all packets", TRUE, TRUE);
1214 /* Rescan the list of packets, reconstructing the CList.
1216 "action" describes why we're doing this; it's used in the progress
1219 "action_item" describes what we're doing; it's used in the progress
1222 "refilter" is TRUE if we need to re-evaluate the filter expression.
1224 "redissect" is TRUE if we need to make the dissectors reconstruct
1225 any state information they have (because a preference that affects
1226 some dissector has changed, meaning some dissector might construct
1227 its state differently from the way it was constructed the last time). */
1229 rescan_packets(capture_file *cf, const char *action, const char *action_item,
1230 gboolean refilter, gboolean redissect)
1233 progdlg_t *progbar = NULL;
1238 frame_data *selected_frame, *preceding_frame, *following_frame, *prev_frame;
1239 int selected_row, prev_row, preceding_row, following_row;
1240 gboolean selected_frame_seen;
1243 GTimeVal start_time;
1244 gchar status_str[100];
1245 int progbar_nextstep;
1246 int progbar_quantum;
1249 reset_tap_listeners();
1250 /* Which frame, if any, is the currently selected frame?
1251 XXX - should the selected frame or the focus frame be the "current"
1252 frame, that frame being the one from which "Find Frame" searches
1254 selected_frame = cf->current_frame;
1256 /* We don't yet know what row that frame will be on, if any, after we
1257 rebuild the clist, however. */
1261 /* We need to re-initialize all the state information that protocols
1262 keep, because some preference that controls a dissector has changed,
1263 which might cause the state information to be constructed differently
1264 by that dissector. */
1266 /* Initialize all data structures used for dissection. */
1270 /* Freeze the packet list while we redo it, so we don't get any
1271 screen updates while it happens. */
1272 packet_list_freeze();
1275 packet_list_clear();
1277 /* We don't yet know which will be the first and last frames displayed. */
1278 cf->first_displayed = NULL;
1279 cf->last_displayed = NULL;
1281 /* We currently don't display any packets */
1282 cf->displayed_count = 0;
1284 /* Iterate through the list of frames. Call a routine for each frame
1285 to check whether it should be displayed and, if so, add it to
1286 the display list. */
1287 nstime_set_zero(&first_ts);
1288 nstime_set_zero(&prev_ts);
1290 /* Update the progress bar when it gets to this value. */
1291 progbar_nextstep = 0;
1292 /* When we reach the value that triggers a progress bar update,
1293 bump that value by this amount. */
1294 progbar_quantum = cf->count/N_PROGBAR_UPDATES;
1295 /* Count of packets at which we've looked. */
1299 g_get_current_time(&start_time);
1301 row = -1; /* no previous row yet */
1306 preceding_frame = NULL;
1308 following_frame = NULL;
1310 selected_frame_seen = FALSE;
1312 for (fdata = cf->plist; fdata != NULL; fdata = fdata->next) {
1313 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
1314 when we update it, we have to run the GTK+ main loop to get it
1315 to repaint what's pending, and doing so may involve an "ioctl()"
1316 to see if there's any pending input from an X server, and doing
1317 that for every packet can be costly, especially on a big file. */
1318 if (count >= progbar_nextstep) {
1319 /* let's not divide by zero. I should never be started
1320 * with count == 0, so let's assert that
1322 g_assert(cf->count > 0);
1323 prog_val = (gfloat) count / cf->count;
1325 if (progbar == NULL)
1326 /* Create the progress bar if necessary */
1327 progbar = delayed_create_progress_dlg(action, action_item, &stop_flag,
1328 &start_time, prog_val);
1330 if (progbar != NULL) {
1331 g_snprintf(status_str, sizeof(status_str),
1332 "%4u of %u frames", count, cf->count);
1333 update_progress_dlg(progbar, prog_val, status_str);
1336 progbar_nextstep += progbar_quantum;
1340 /* Well, the user decided to abort the filtering. Just stop.
1342 XXX - go back to the previous filter? Users probably just
1343 want not to wait for a filtering operation to finish;
1344 unless we cancel by having no filter, reverting to the
1345 previous filter will probably be even more expensive than
1346 continuing the filtering, as it involves going back to the
1347 beginning and filtering, and even with no filter we currently
1348 have to re-generate the entire clist, which is also expensive.
1350 I'm not sure what Network Monitor does, but it doesn't appear
1351 to give you an unfiltered display if you cancel. */
1358 /* Since all state for the frame was destroyed, mark the frame
1359 * as not visited, free the GSList referring to the state
1360 * data (the per-frame data itself was freed by
1361 * "init_dissection()"), and null out the GSList pointer. */
1362 fdata->flags.visited = 0;
1364 g_slist_free(fdata->pfd);
1369 if (!wtap_seek_read (cf->wth, fdata->file_off, &cf->pseudo_header,
1370 cf->pd, fdata->cap_len, &err, &err_info)) {
1371 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1372 cf_read_error_message(err, err_info), cf->filename);
1376 /* If the previous frame is displayed, and we haven't yet seen the
1377 selected frame, remember that frame - it's the closest one we've
1378 yet seen before the selected frame. */
1379 if (prev_row != -1 && !selected_frame_seen) {
1380 preceding_row = prev_row;
1381 preceding_frame = prev_frame;
1383 row = add_packet_to_packet_list(fdata, cf, &cf->pseudo_header, cf->pd,
1386 /* If this frame is displayed, and this is the first frame we've
1387 seen displayed after the selected frame, remember this frame -
1388 it's the closest one we've yet seen at or after the selected
1390 if (row != -1 && selected_frame_seen && following_row == -1) {
1391 following_row = row;
1392 following_frame = fdata;
1394 if (fdata == selected_frame) {
1396 selected_frame_seen = TRUE;
1399 /* Remember this row/frame - it'll be the previous row/frame
1400 on the next pass through the loop. */
1406 /* Clear out what remains of the visited flags and per-frame data
1409 XXX - that may cause various forms of bogosity when dissecting
1410 these frames, as they won't have been seen by this sequential
1411 pass, but the only alternative I see is to keep scanning them
1412 even though the user requested that the scan stop, and that
1413 would leave the user stuck with an Ethereal grinding on
1414 until it finishes. Should we just stick them with that? */
1415 for (; fdata != NULL; fdata = fdata->next) {
1416 fdata->flags.visited = 0;
1418 g_slist_free(fdata->pfd);
1424 /* We're done filtering the packets; destroy the progress bar if it
1426 if (progbar != NULL)
1427 destroy_progress_dlg(progbar);
1429 /* Unfreeze the packet list. */
1432 if (selected_row == -1) {
1433 /* The selected frame didn't pass the filter. */
1434 if (selected_frame == NULL) {
1435 /* That's because there *was* no selected frame. Make the first
1436 displayed frame the current frame. */
1439 /* Find the nearest displayed frame to the selected frame (whether
1440 it's before or after that frame) and make that the current frame.
1441 If the next and previous displayed frames are equidistant from the
1442 selected frame, choose the next one. */
1443 g_assert(following_frame == NULL ||
1444 following_frame->num >= selected_frame->num);
1445 g_assert(preceding_frame == NULL ||
1446 preceding_frame->num <= selected_frame->num);
1447 if (following_frame == NULL) {
1448 /* No frame after the selected frame passed the filter, so we
1449 have to select the last displayed frame before the selected
1451 selected_row = preceding_row;
1452 } else if (preceding_frame == NULL) {
1453 /* No frame before the selected frame passed the filter, so we
1454 have to select the first displayed frame after the selected
1456 selected_row = following_row;
1458 /* Choose the closer of the last displayed frame before the
1459 selected frame and the first displayed frame after the
1460 selected frame; in case of a tie, choose the first displayed
1461 frame after the selected frame. */
1462 if (following_frame->num - selected_frame->num <=
1463 selected_frame->num - preceding_frame->num) {
1464 selected_row = following_row;
1466 /* The previous frame is closer to the selected frame than the
1468 selected_row = preceding_row;
1474 if (selected_row == -1) {
1475 /* There are no frames displayed at all. */
1476 cf_unselect_packet(cf);
1478 /* Either the frame that was selected passed the filter, or we've
1479 found the nearest displayed frame to that frame. Select it, make
1480 it the focus row, and make it visible. */
1481 packet_list_set_selected_row(selected_row);
1492 process_specified_packets(capture_file *cf, packet_range_t *range,
1493 const char *string1, const char *string2,
1494 gboolean (*callback)(capture_file *, frame_data *,
1495 union wtap_pseudo_header *, const guint8 *, void *),
1496 void *callback_args)
1501 union wtap_pseudo_header pseudo_header;
1502 guint8 pd[WTAP_MAX_PACKET_SIZE+1];
1503 psp_return_t ret = PSP_FINISHED;
1505 progdlg_t *progbar = NULL;
1508 gboolean progbar_stop_flag;
1509 GTimeVal progbar_start_time;
1510 gchar progbar_status_str[100];
1511 int progbar_nextstep;
1512 int progbar_quantum;
1513 range_process_e process_this;
1515 /* Update the progress bar when it gets to this value. */
1516 progbar_nextstep = 0;
1517 /* When we reach the value that triggers a progress bar update,
1518 bump that value by this amount. */
1519 progbar_quantum = cf->count/N_PROGBAR_UPDATES;
1520 /* Count of packets at which we've looked. */
1523 progbar_stop_flag = FALSE;
1524 g_get_current_time(&progbar_start_time);
1526 packet_range_process_init(range);
1528 /* Iterate through the list of packets, printing the packets that
1529 were selected by the current display filter. */
1530 for (fdata = cf->plist; fdata != NULL; fdata = fdata->next) {
1531 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
1532 when we update it, we have to run the GTK+ main loop to get it
1533 to repaint what's pending, and doing so may involve an "ioctl()"
1534 to see if there's any pending input from an X server, and doing
1535 that for every packet can be costly, especially on a big file. */
1536 if (progbar_count >= progbar_nextstep) {
1537 /* let's not divide by zero. I should never be started
1538 * with count == 0, so let's assert that
1540 g_assert(cf->count > 0);
1541 progbar_val = (gfloat) progbar_count / cf->count;
1543 if (progbar == NULL)
1544 /* Create the progress bar if necessary */
1545 progbar = delayed_create_progress_dlg(string1, string2,
1547 &progbar_start_time,
1550 if (progbar != NULL) {
1551 g_snprintf(progbar_status_str, sizeof(progbar_status_str),
1552 "%4u of %u packets", progbar_count, cf->count);
1553 update_progress_dlg(progbar, progbar_val, progbar_status_str);
1556 progbar_nextstep += progbar_quantum;
1559 if (progbar_stop_flag) {
1560 /* Well, the user decided to abort the operation. Just stop,
1561 and arrange to return TRUE to our caller, so they know it
1562 was stopped explicitly. */
1569 /* do we have to process this packet? */
1570 process_this = packet_range_process_packet(range, fdata);
1571 if (process_this == range_process_next) {
1572 /* this packet uninteresting, continue with next one */
1574 } else if (process_this == range_processing_finished) {
1575 /* all interesting packets processed, stop the loop */
1579 /* Get the packet */
1580 if (!wtap_seek_read(cf->wth, fdata->file_off, &pseudo_header,
1581 pd, fdata->cap_len, &err, &err_info)) {
1582 /* Attempt to get the packet failed. */
1583 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1584 cf_read_error_message(err, err_info), cf->filename);
1588 /* Process the packet */
1589 if (!callback(cf, fdata, &pseudo_header, pd, callback_args)) {
1590 /* Callback failed. We assume it reported the error appropriately. */
1596 /* We're done printing the packets; destroy the progress bar if
1598 if (progbar != NULL)
1599 destroy_progress_dlg(progbar);
1605 retap_packet(capture_file *cf _U_, frame_data *fdata,
1606 union wtap_pseudo_header *pseudo_header, const guint8 *pd,
1609 column_info *cinfo = argsp;
1610 epan_dissect_t *edt;
1612 /* If we have tap listeners, allocate a protocol tree root node, so that
1613 we'll construct a protocol tree against which a filter expression can
1615 edt = epan_dissect_new(num_tap_filters != 0, FALSE);
1616 tap_queue_init(edt);
1617 epan_dissect_run(edt, pseudo_header, pd, fdata, cinfo);
1618 tap_push_tapped_queue(edt);
1619 epan_dissect_free(edt);
1625 cf_retap_packets(capture_file *cf, gboolean do_columns)
1627 packet_range_t range;
1629 /* Reset the tap listeners. */
1630 reset_tap_listeners();
1632 /* Iterate through the list of packets, dissecting all packets and
1633 re-running the taps. */
1634 packet_range_init(&range);
1635 packet_range_process_init(&range);
1636 switch (process_specified_packets(cf, &range, "Refiltering statistics on",
1637 "all packets", retap_packet,
1638 do_columns ? &cf->cinfo : NULL)) {
1640 /* Completed successfully. */
1644 /* Well, the user decided to abort the refiltering.
1645 Return CF_READ_ABORTED so our caller knows they did that. */
1646 return CF_READ_ABORTED;
1649 /* Error while retapping. */
1650 return CF_READ_ERROR;
1653 g_assert_not_reached();
1658 print_args_t *print_args;
1659 gboolean print_header_line;
1660 char *header_line_buf;
1661 int header_line_buf_len;
1662 gboolean print_formfeed;
1663 gboolean print_separator;
1667 } print_callback_args_t;
1670 print_packet(capture_file *cf, frame_data *fdata,
1671 union wtap_pseudo_header *pseudo_header, const guint8 *pd,
1674 print_callback_args_t *args = argsp;
1675 epan_dissect_t *edt;
1681 gboolean proto_tree_needed;
1682 char bookmark_name[9+10+1]; /* "__frameNNNNNNNNNN__\0" */
1683 char bookmark_title[6+10+1]; /* "Frame NNNNNNNNNN__\0" */
1685 /* Create the protocol tree, and make it visible, if we're printing
1686 the dissection or the hex data.
1687 XXX - do we need it if we're just printing the hex data? */
1689 args->print_args->print_dissections != print_dissections_none || args->print_args->print_hex;
1690 edt = epan_dissect_new(proto_tree_needed, proto_tree_needed);
1692 /* Fill in the column information if we're printing the summary
1694 if (args->print_args->print_summary) {
1695 epan_dissect_run(edt, pseudo_header, pd, fdata, &cf->cinfo);
1696 epan_dissect_fill_in_columns(edt);
1698 epan_dissect_run(edt, pseudo_header, pd, fdata, NULL);
1700 if (args->print_formfeed) {
1701 if (!new_page(args->print_args->stream))
1704 if (args->print_separator) {
1705 if (!print_line(args->print_args->stream, 0, ""))
1711 * We generate bookmarks, if the output format supports them.
1712 * The name is "__frameN__".
1714 g_snprintf(bookmark_name, sizeof bookmark_name, "__frame%u__", fdata->num);
1716 if (args->print_args->print_summary) {
1717 if (args->print_header_line) {
1718 if (!print_line(args->print_args->stream, 0, args->header_line_buf))
1720 args->print_header_line = FALSE; /* we might not need to print any more */
1722 cp = &args->line_buf[0];
1724 for (i = 0; i < cf->cinfo.num_cols; i++) {
1725 /* Find the length of the string for this column. */
1726 column_len = strlen(cf->cinfo.col_data[i]);
1727 if (args->col_widths[i] > column_len)
1728 column_len = args->col_widths[i];
1730 /* Make sure there's room in the line buffer for the column; if not,
1731 double its length. */
1732 line_len += column_len + 1; /* "+1" for space */
1733 if (line_len > args->line_buf_len) {
1734 cp_off = cp - args->line_buf;
1735 args->line_buf_len = 2 * line_len;
1736 args->line_buf = g_realloc(args->line_buf, args->line_buf_len + 1);
1737 cp = args->line_buf + cp_off;
1740 /* Right-justify the packet number column. */
1741 if (cf->cinfo.col_fmt[i] == COL_NUMBER)
1742 sprintf(cp, "%*s", args->col_widths[i], cf->cinfo.col_data[i]);
1744 sprintf(cp, "%-*s", args->col_widths[i], cf->cinfo.col_data[i]);
1746 if (i != cf->cinfo.num_cols - 1)
1752 * Generate a bookmark, using the summary line as the title.
1754 if (!print_bookmark(args->print_args->stream, bookmark_name,
1758 if (!print_line(args->print_args->stream, 0, args->line_buf))
1762 * Generate a bookmark, using "Frame N" as the title, as we're not
1763 * printing the summary line.
1765 g_snprintf(bookmark_title, sizeof bookmark_title, "Frame %u", fdata->num);
1766 if (!print_bookmark(args->print_args->stream, bookmark_name,
1769 } /* if (print_summary) */
1771 if (args->print_args->print_dissections != print_dissections_none) {
1772 if (args->print_args->print_summary) {
1773 /* Separate the summary line from the tree with a blank line. */
1774 if (!print_line(args->print_args->stream, 0, ""))
1778 /* Print the information in that tree. */
1779 if (!proto_tree_print(args->print_args, edt, args->print_args->stream))
1782 /* Print a blank line if we print anything after this (aka more than one packet). */
1783 args->print_separator = TRUE;
1785 /* Print a header line if we print any more packet summaries */
1786 args->print_header_line = TRUE;
1789 if (args->print_args->print_hex) {
1790 /* Print the full packet data as hex. */
1791 if (!print_hex_data(args->print_args->stream, edt))
1794 /* Print a blank line if we print anything after this (aka more than one packet). */
1795 args->print_separator = TRUE;
1797 /* Print a header line if we print any more packet summaries */
1798 args->print_header_line = TRUE;
1799 } /* if (args->print_args->print_dissections != print_dissections_none) */
1801 epan_dissect_free(edt);
1803 /* do we want to have a formfeed between each packet from now on? */
1804 if(args->print_args->print_formfeed) {
1805 args->print_formfeed = TRUE;
1811 epan_dissect_free(edt);
1816 cf_print_packets(capture_file *cf, print_args_t *print_args)
1819 print_callback_args_t callback_args;
1827 callback_args.print_args = print_args;
1828 callback_args.print_header_line = TRUE;
1829 callback_args.header_line_buf = NULL;
1830 callback_args.header_line_buf_len = 256;
1831 callback_args.print_formfeed = FALSE;
1832 callback_args.print_separator = FALSE;
1833 callback_args.line_buf = NULL;
1834 callback_args.line_buf_len = 256;
1835 callback_args.col_widths = NULL;
1837 if (!print_preamble(print_args->stream, cf->filename)) {
1838 destroy_print_stream(print_args->stream);
1839 return CF_PRINT_WRITE_ERROR;
1842 if (print_args->print_summary) {
1843 /* We're printing packet summaries. Allocate the header line buffer
1844 and get the column widths. */
1845 callback_args.header_line_buf = g_malloc(callback_args.header_line_buf_len + 1);
1847 /* Find the widths for each of the columns - maximum of the
1848 width of the title and the width of the data - and construct
1849 a buffer with a line containing the column titles. */
1850 callback_args.col_widths = (gint *) g_malloc(sizeof(gint) * cf->cinfo.num_cols);
1851 cp = &callback_args.header_line_buf[0];
1853 for (i = 0; i < cf->cinfo.num_cols; i++) {
1854 /* Don't pad the last column. */
1855 if (i == cf->cinfo.num_cols - 1)
1856 callback_args.col_widths[i] = 0;
1858 callback_args.col_widths[i] = strlen(cf->cinfo.col_title[i]);
1859 data_width = get_column_char_width(get_column_format(i));
1860 if (data_width > callback_args.col_widths[i])
1861 callback_args.col_widths[i] = data_width;
1864 /* Find the length of the string for this column. */
1865 column_len = strlen(cf->cinfo.col_title[i]);
1866 if (callback_args.col_widths[i] > column_len)
1867 column_len = callback_args.col_widths[i];
1869 /* Make sure there's room in the line buffer for the column; if not,
1870 double its length. */
1871 line_len += column_len + 1; /* "+1" for space */
1872 if (line_len > callback_args.header_line_buf_len) {
1873 cp_off = cp - callback_args.header_line_buf;
1874 callback_args.header_line_buf_len = 2 * line_len;
1875 callback_args.header_line_buf = g_realloc(callback_args.header_line_buf,
1876 callback_args.header_line_buf_len + 1);
1877 cp = callback_args.header_line_buf + cp_off;
1880 /* Right-justify the packet number column. */
1881 /* if (cf->cinfo.col_fmt[i] == COL_NUMBER)
1882 sprintf(cp, "%*s", callback_args.col_widths[i], cf->cinfo.col_title[i]);
1884 sprintf(cp, "%-*s", callback_args.col_widths[i], cf->cinfo.col_title[i]);
1886 if (i != cf->cinfo.num_cols - 1)
1891 /* Now start out the main line buffer with the same length as the
1892 header line buffer. */
1893 callback_args.line_buf_len = callback_args.header_line_buf_len;
1894 callback_args.line_buf = g_malloc(callback_args.line_buf_len + 1);
1895 } /* if (print_summary) */
1897 /* Iterate through the list of packets, printing the packets we were
1899 ret = process_specified_packets(cf, &print_args->range, "Printing",
1900 "selected packets", print_packet,
1903 if (callback_args.header_line_buf != NULL)
1904 g_free(callback_args.header_line_buf);
1905 if (callback_args.line_buf != NULL)
1906 g_free(callback_args.line_buf);
1907 if (callback_args.col_widths != NULL)
1908 g_free(callback_args.col_widths);
1913 /* Completed successfully. */
1917 /* Well, the user decided to abort the printing.
1919 XXX - note that what got generated before they did that
1920 will get printed if we're piping to a print program; we'd
1921 have to write to a file and then hand that to the print
1922 program to make it actually not print anything. */
1926 /* Error while printing.
1928 XXX - note that what got generated before they did that
1929 will get printed if we're piping to a print program; we'd
1930 have to write to a file and then hand that to the print
1931 program to make it actually not print anything. */
1932 destroy_print_stream(print_args->stream);
1933 return CF_PRINT_WRITE_ERROR;
1936 if (!print_finale(print_args->stream)) {
1937 destroy_print_stream(print_args->stream);
1938 return CF_PRINT_WRITE_ERROR;
1941 if (!destroy_print_stream(print_args->stream))
1942 return CF_PRINT_WRITE_ERROR;
1948 write_pdml_packet(capture_file *cf _U_, frame_data *fdata,
1949 union wtap_pseudo_header *pseudo_header, const guint8 *pd,
1953 epan_dissect_t *edt;
1955 /* Create the protocol tree, but don't fill in the column information. */
1956 edt = epan_dissect_new(TRUE, TRUE);
1957 epan_dissect_run(edt, pseudo_header, pd, fdata, NULL);
1959 /* Write out the information in that tree. */
1960 proto_tree_write_pdml(edt, fh);
1962 epan_dissect_free(edt);
1968 cf_write_pdml_packets(capture_file *cf, print_args_t *print_args)
1973 fh = fopen(print_args->file, "w");
1975 return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
1977 write_pdml_preamble(fh);
1980 return CF_PRINT_WRITE_ERROR;
1983 /* Iterate through the list of packets, printing the packets we were
1985 ret = process_specified_packets(cf, &print_args->range, "Writing PDML",
1986 "selected packets", write_pdml_packet,
1992 /* Completed successfully. */
1996 /* Well, the user decided to abort the printing. */
2000 /* Error while printing. */
2002 return CF_PRINT_WRITE_ERROR;
2005 write_pdml_finale(fh);
2008 return CF_PRINT_WRITE_ERROR;
2011 /* XXX - check for an error */
2018 write_psml_packet(capture_file *cf, frame_data *fdata,
2019 union wtap_pseudo_header *pseudo_header, const guint8 *pd,
2023 epan_dissect_t *edt;
2025 /* Fill in the column information, but don't create the protocol tree. */
2026 edt = epan_dissect_new(FALSE, FALSE);
2027 epan_dissect_run(edt, pseudo_header, pd, fdata, &cf->cinfo);
2028 epan_dissect_fill_in_columns(edt);
2030 /* Write out the information in that tree. */
2031 proto_tree_write_psml(edt, fh);
2033 epan_dissect_free(edt);
2039 cf_write_psml_packets(capture_file *cf, print_args_t *print_args)
2044 fh = fopen(print_args->file, "w");
2046 return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
2048 write_psml_preamble(fh);
2051 return CF_PRINT_WRITE_ERROR;
2054 /* Iterate through the list of packets, printing the packets we were
2056 ret = process_specified_packets(cf, &print_args->range, "Writing PSML",
2057 "selected packets", write_psml_packet,
2063 /* Completed successfully. */
2067 /* Well, the user decided to abort the printing. */
2071 /* Error while printing. */
2073 return CF_PRINT_WRITE_ERROR;
2076 write_psml_finale(fh);
2079 return CF_PRINT_WRITE_ERROR;
2082 /* XXX - check for an error */
2089 write_csv_packet(capture_file *cf, frame_data *fdata,
2090 union wtap_pseudo_header *pseudo_header, const guint8 *pd,
2094 epan_dissect_t *edt;
2096 /* Fill in the column information, but don't create the protocol tree. */
2097 edt = epan_dissect_new(FALSE, FALSE);
2098 epan_dissect_run(edt, pseudo_header, pd, fdata, &cf->cinfo);
2099 epan_dissect_fill_in_columns(edt);
2101 /* Write out the information in that tree. */
2102 proto_tree_write_csv(edt, fh);
2104 epan_dissect_free(edt);
2110 cf_write_csv_packets(capture_file *cf, print_args_t *print_args)
2115 fh = fopen(print_args->file, "w");
2117 return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
2119 write_csv_preamble(fh);
2122 return CF_PRINT_WRITE_ERROR;
2125 /* Iterate through the list of packets, printing the packets we were
2127 ret = process_specified_packets(cf, &print_args->range, "Writing CSV",
2128 "selected packets", write_csv_packet,
2134 /* Completed successfully. */
2138 /* Well, the user decided to abort the printing. */
2142 /* Error while printing. */
2144 return CF_PRINT_WRITE_ERROR;
2147 write_csv_finale(fh);
2150 return CF_PRINT_WRITE_ERROR;
2153 /* XXX - check for an error */
2159 /* Scan through the packet list and change all columns that use the
2160 "command-line-specified" time stamp format to use the current
2161 value of that format. */
2163 cf_change_time_formats(capture_file *cf)
2166 progdlg_t *progbar = NULL;
2172 GTimeVal start_time;
2173 gchar status_str[100];
2174 int progbar_nextstep;
2175 int progbar_quantum;
2177 gboolean sorted_by_frame_column;
2180 /* adjust timestamp precision if auto is selected */
2181 cf_timestamp_auto_precision(cf);
2183 /* Are there any columns with time stamps in the "command-line-specified"
2186 XXX - we have to force the "column is writable" flag on, as it
2187 might be off from the last frame that was dissected. */
2188 col_set_writable(&cf->cinfo, TRUE);
2189 if (!check_col(&cf->cinfo, COL_CLS_TIME)) {
2190 /* No, there aren't any columns in that format, so we have no work
2194 first = cf->cinfo.col_first[COL_CLS_TIME];
2195 g_assert(first >= 0);
2196 last = cf->cinfo.col_last[COL_CLS_TIME];
2198 /* Freeze the packet list while we redo it, so we don't get any
2199 screen updates while it happens. */
2200 packet_list_freeze();
2202 /* Update the progress bar when it gets to this value. */
2203 progbar_nextstep = 0;
2204 /* When we reach the value that triggers a progress bar update,
2205 bump that value by this amount. */
2206 progbar_quantum = cf->count/N_PROGBAR_UPDATES;
2207 /* Count of packets at which we've looked. */
2210 /* If the rows are currently sorted by the frame column then we know
2211 * the row number of each packet: it's the row number of the previously
2212 * displayed packet + 1.
2214 * Otherwise, if the display is sorted by a different column then we have
2215 * to use the O(N) packet_list_find_row_from_data() (thus making the job
2216 * of changing the time display format O(N**2)).
2218 * (XXX - In fact it's still O(N**2) because gtk_clist_set_text() takes
2219 * the row number and walks that many elements down the clist to find
2220 * the appropriate element.)
2222 sorted_by_frame_column = FALSE;
2223 for (i = 0; i < cf->cinfo.num_cols; i++) {
2224 if (cf->cinfo.col_fmt[i] == COL_NUMBER)
2226 sorted_by_frame_column = (i == packet_list_get_sort_column());
2232 g_get_current_time(&start_time);
2234 /* Iterate through the list of packets, checking whether the packet
2235 is in a row of the summary list and, if so, whether there are
2236 any columns that show the time in the "command-line-specified"
2237 format and, if so, update that row. */
2238 for (fdata = cf->plist, row = -1; fdata != NULL; fdata = fdata->next) {
2239 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
2240 when we update it, we have to run the GTK+ main loop to get it
2241 to repaint what's pending, and doing so may involve an "ioctl()"
2242 to see if there's any pending input from an X server, and doing
2243 that for every packet can be costly, especially on a big file. */
2244 if (count >= progbar_nextstep) {
2245 /* let's not divide by zero. I should never be started
2246 * with count == 0, so let's assert that
2248 g_assert(cf->count > 0);
2250 prog_val = (gfloat) count / cf->count;
2252 if (progbar == NULL)
2253 /* Create the progress bar if necessary */
2254 progbar = delayed_create_progress_dlg("Changing", "time display",
2255 &stop_flag, &start_time, prog_val);
2257 if (progbar != NULL) {
2258 g_snprintf(status_str, sizeof(status_str),
2259 "%4u of %u packets", count, cf->count);
2260 update_progress_dlg(progbar, prog_val, status_str);
2263 progbar_nextstep += progbar_quantum;
2267 /* Well, the user decided to abort the redisplay. Just stop.
2269 XXX - this leaves the time field in the old format in
2270 frames we haven't yet processed. So it goes; should we
2271 simply not offer them the option of stopping? */
2277 /* Find what row this packet is in. */
2278 if (!sorted_by_frame_column) {
2279 /* This function is O(N), so we try to avoid using it... */
2280 row = packet_list_find_row_from_data(fdata);
2282 /* ...which we do by maintaining a count of packets that are
2283 being displayed (i.e., that have passed the display filter),
2284 and using the current value of that count as the row number
2285 (which is why we can only do it when the display is sorted
2286 by the frame number). */
2287 if (fdata->flags.passed_dfilter)
2294 /* This packet is in the summary list, on row "row". */
2296 for (i = first; i <= last; i++) {
2297 if (cf->cinfo.fmt_matx[i][COL_CLS_TIME]) {
2298 /* This is one of the columns that shows the time in
2299 "command-line-specified" format; update it. */
2300 cf->cinfo.col_buf[i][0] = '\0';
2301 col_set_cls_time(fdata, &cf->cinfo, i);
2302 packet_list_set_text(row, i, cf->cinfo.col_data[i]);
2308 /* We're done redisplaying the packets; destroy the progress bar if it
2310 if (progbar != NULL)
2311 destroy_progress_dlg(progbar);
2313 /* Set the column widths of those columns that show the time in
2314 "command-line-specified" format. */
2315 for (i = first; i <= last; i++) {
2316 if (cf->cinfo.fmt_matx[i][COL_CLS_TIME]) {
2317 packet_list_set_cls_time_width(i);
2321 /* Unfreeze the packet list. */
2329 gboolean frame_matched;
2333 cf_find_packet_protocol_tree(capture_file *cf, const char *string)
2337 mdata.string = string;
2338 mdata.string_len = strlen(string);
2339 return find_packet(cf, match_protocol_tree, &mdata);
2343 match_protocol_tree(capture_file *cf, frame_data *fdata, void *criterion)
2345 match_data *mdata = criterion;
2346 epan_dissect_t *edt;
2348 /* Construct the protocol tree, including the displayed text */
2349 edt = epan_dissect_new(TRUE, TRUE);
2350 /* We don't need the column information */
2351 epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, NULL);
2353 /* Iterate through all the nodes, seeing if they have text that matches. */
2355 mdata->frame_matched = FALSE;
2356 proto_tree_children_foreach(edt->tree, match_subtree_text, mdata);
2357 epan_dissect_free(edt);
2358 return mdata->frame_matched;
2362 match_subtree_text(proto_node *node, gpointer data)
2364 match_data *mdata = (match_data*) data;
2365 const gchar *string = mdata->string;
2366 size_t string_len = mdata->string_len;
2367 capture_file *cf = mdata->cf;
2368 field_info *fi = PITEM_FINFO(node);
2369 gchar label_str[ITEM_LABEL_LENGTH];
2376 if (mdata->frame_matched) {
2377 /* We already had a match; don't bother doing any more work. */
2381 /* Don't match invisible entries. */
2382 if (PROTO_ITEM_IS_HIDDEN(node))
2385 /* was a free format label produced? */
2387 label_ptr = fi->rep->representation;
2389 /* no, make a generic label */
2390 label_ptr = label_str;
2391 proto_item_fill_label(fi, label_str);
2394 /* Does that label match? */
2395 label_len = strlen(label_ptr);
2396 for (i = 0; i < label_len; i++) {
2397 c_char = label_ptr[i];
2399 c_char = toupper(c_char);
2400 if (c_char == string[c_match]) {
2402 if (c_match == string_len) {
2403 /* No need to look further; we have a match */
2404 mdata->frame_matched = TRUE;
2411 /* Recurse into the subtree, if it exists */
2412 if (node->first_child != NULL)
2413 proto_tree_children_foreach(node, match_subtree_text, mdata);
2417 cf_find_packet_summary_line(capture_file *cf, const char *string)
2421 mdata.string = string;
2422 mdata.string_len = strlen(string);
2423 return find_packet(cf, match_summary_line, &mdata);
2427 match_summary_line(capture_file *cf, frame_data *fdata, void *criterion)
2429 match_data *mdata = criterion;
2430 const gchar *string = mdata->string;
2431 size_t string_len = mdata->string_len;
2432 epan_dissect_t *edt;
2433 const char *info_column;
2434 size_t info_column_len;
2435 gboolean frame_matched = FALSE;
2441 /* Don't bother constructing the protocol tree */
2442 edt = epan_dissect_new(FALSE, FALSE);
2443 /* Get the column information */
2444 epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, &cf->cinfo);
2446 /* Find the Info column */
2447 for (colx = 0; colx < cf->cinfo.num_cols; colx++) {
2448 if (cf->cinfo.fmt_matx[colx][COL_INFO]) {
2449 /* Found it. See if we match. */
2450 info_column = edt->pi.cinfo->col_data[colx];
2451 info_column_len = strlen(info_column);
2452 for (i = 0; i < info_column_len; i++) {
2453 c_char = info_column[i];
2455 c_char = toupper(c_char);
2456 if (c_char == string[c_match]) {
2458 if (c_match == string_len) {
2459 frame_matched = TRUE;
2468 epan_dissect_free(edt);
2469 return frame_matched;
2475 } cbs_t; /* "Counted byte string" */
2478 cf_find_packet_data(capture_file *cf, const guint8 *string, size_t string_size)
2483 info.data_len = string_size;
2485 /* String or hex search? */
2487 /* String search - what type of string? */
2488 switch (cf->scs_type) {
2490 case SCS_ASCII_AND_UNICODE:
2491 return find_packet(cf, match_ascii_and_unicode, &info);
2494 return find_packet(cf, match_ascii, &info);
2497 return find_packet(cf, match_unicode, &info);
2500 g_assert_not_reached();
2504 return find_packet(cf, match_binary, &info);
2508 match_ascii_and_unicode(capture_file *cf, frame_data *fdata, void *criterion)
2510 cbs_t *info = criterion;
2511 const char *ascii_text = info->data;
2512 size_t textlen = info->data_len;
2513 gboolean frame_matched;
2519 frame_matched = FALSE;
2520 buf_len = fdata->pkt_len;
2521 for (i = 0; i < buf_len; i++) {
2524 c_char = toupper(c_char);
2526 if (c_char == ascii_text[c_match]) {
2528 if (c_match == textlen) {
2529 frame_matched = TRUE;
2536 return frame_matched;
2540 match_ascii(capture_file *cf, frame_data *fdata, void *criterion)
2542 cbs_t *info = criterion;
2543 const char *ascii_text = info->data;
2544 size_t textlen = info->data_len;
2545 gboolean frame_matched;
2551 frame_matched = FALSE;
2552 buf_len = fdata->pkt_len;
2553 for (i = 0; i < buf_len; i++) {
2556 c_char = toupper(c_char);
2557 if (c_char == ascii_text[c_match]) {
2559 if (c_match == textlen) {
2560 frame_matched = TRUE;
2566 return frame_matched;
2570 match_unicode(capture_file *cf, frame_data *fdata, void *criterion)
2572 cbs_t *info = criterion;
2573 const char *ascii_text = info->data;
2574 size_t textlen = info->data_len;
2575 gboolean frame_matched;
2581 frame_matched = FALSE;
2582 buf_len = fdata->pkt_len;
2583 for (i = 0; i < buf_len; i++) {
2586 c_char = toupper(c_char);
2587 if (c_char == ascii_text[c_match]) {
2590 if (c_match == textlen) {
2591 frame_matched = TRUE;
2597 return frame_matched;
2601 match_binary(capture_file *cf, frame_data *fdata, void *criterion)
2603 cbs_t *info = criterion;
2604 const guint8 *binary_data = info->data;
2605 size_t datalen = info->data_len;
2606 gboolean frame_matched;
2611 frame_matched = FALSE;
2612 buf_len = fdata->pkt_len;
2613 for (i = 0; i < buf_len; i++) {
2614 if (cf->pd[i] == binary_data[c_match]) {
2616 if (c_match == datalen) {
2617 frame_matched = TRUE;
2623 return frame_matched;
2627 cf_find_packet_dfilter(capture_file *cf, dfilter_t *sfcode)
2629 return find_packet(cf, match_dfilter, sfcode);
2633 match_dfilter(capture_file *cf, frame_data *fdata, void *criterion)
2635 dfilter_t *sfcode = criterion;
2636 epan_dissect_t *edt;
2637 gboolean frame_matched;
2639 edt = epan_dissect_new(TRUE, FALSE);
2640 epan_dissect_prime_dfilter(edt, sfcode);
2641 epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, NULL);
2642 frame_matched = dfilter_apply_edt(sfcode, edt);
2643 epan_dissect_free(edt);
2644 return frame_matched;
2648 find_packet(capture_file *cf,
2649 gboolean (*match_function)(capture_file *, frame_data *, void *),
2652 frame_data *start_fd;
2654 frame_data *new_fd = NULL;
2655 progdlg_t *progbar = NULL;
2662 GTimeVal start_time;
2663 gchar status_str[100];
2664 int progbar_nextstep;
2665 int progbar_quantum;
2667 start_fd = cf->current_frame;
2668 if (start_fd != NULL) {
2669 /* Iterate through the list of packets, starting at the packet we've
2670 picked, calling a routine to run the filter on the packet, see if
2671 it matches, and stop if so. */
2675 progbar_nextstep = 0;
2676 /* When we reach the value that triggers a progress bar update,
2677 bump that value by this amount. */
2678 progbar_quantum = cf->count/N_PROGBAR_UPDATES;
2681 g_get_current_time(&start_time);
2685 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
2686 when we update it, we have to run the GTK+ main loop to get it
2687 to repaint what's pending, and doing so may involve an "ioctl()"
2688 to see if there's any pending input from an X server, and doing
2689 that for every packet can be costly, especially on a big file. */
2690 if (count >= progbar_nextstep) {
2691 /* let's not divide by zero. I should never be started
2692 * with count == 0, so let's assert that
2694 g_assert(cf->count > 0);
2696 prog_val = (gfloat) count / cf->count;
2698 /* Create the progress bar if necessary */
2699 if (progbar == NULL)
2700 progbar = delayed_create_progress_dlg("Searching", cf->sfilter,
2701 &stop_flag, &start_time, prog_val);
2703 if (progbar != NULL) {
2704 g_snprintf(status_str, sizeof(status_str),
2705 "%4u of %u packets", count, cf->count);
2706 update_progress_dlg(progbar, prog_val, status_str);
2709 progbar_nextstep += progbar_quantum;
2713 /* Well, the user decided to abort the search. Go back to the
2714 frame where we started. */
2719 /* Go past the current frame. */
2720 if (cf->sbackward) {
2721 /* Go on to the previous frame. */
2722 fdata = fdata->prev;
2723 if (fdata == NULL) {
2725 * XXX - other apps have a bit more of a detailed message
2726 * for this, and instead of offering "OK" and "Cancel",
2727 * they offer things such as "Continue" and "Cancel";
2728 * we need an API for popping up alert boxes with
2729 * {Verb} and "Cancel".
2732 if (prefs.gui_find_wrap)
2734 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
2735 "%sBeginning of capture exceeded!%s\n\n"
2736 "Search is continued from the end of the capture.",
2737 simple_dialog_primary_start(), simple_dialog_primary_end());
2738 fdata = cf->plist_end; /* wrap around */
2742 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
2743 "%sBeginning of capture exceeded!%s\n\n"
2744 "Try searching forwards.",
2745 simple_dialog_primary_start(), simple_dialog_primary_end());
2746 fdata = start_fd; /* stay on previous packet */
2750 /* Go on to the next frame. */
2751 fdata = fdata->next;
2752 if (fdata == NULL) {
2753 if (prefs.gui_find_wrap)
2755 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
2756 "%sEnd of capture exceeded!%s\n\n"
2757 "Search is continued from the start of the capture.",
2758 simple_dialog_primary_start(), simple_dialog_primary_end());
2759 fdata = cf->plist; /* wrap around */
2763 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
2764 "%sEnd of capture exceeded!%s\n\n"
2765 "Try searching backwards.",
2766 simple_dialog_primary_start(), simple_dialog_primary_end());
2767 fdata = start_fd; /* stay on previous packet */
2774 /* Is this packet in the display? */
2775 if (fdata->flags.passed_dfilter) {
2776 /* Yes. Load its data. */
2777 if (!wtap_seek_read(cf->wth, fdata->file_off, &cf->pseudo_header,
2778 cf->pd, fdata->cap_len, &err, &err_info)) {
2779 /* Read error. Report the error, and go back to the frame
2780 where we started. */
2781 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
2782 cf_read_error_message(err, err_info), cf->filename);
2787 /* Does it match the search criterion? */
2788 if ((*match_function)(cf, fdata, criterion)) {
2790 break; /* found it! */
2794 if (fdata == start_fd) {
2795 /* We're back to the frame we were on originally, and that frame
2796 doesn't match the search filter. The search failed. */
2801 /* We're done scanning the packets; destroy the progress bar if it
2803 if (progbar != NULL)
2804 destroy_progress_dlg(progbar);
2807 if (new_fd != NULL) {
2808 /* We found a frame. Find what row it's in. */
2809 row = packet_list_find_row_from_data(new_fd);
2810 g_assert(row != -1);
2812 /* Select that row, make it the focus row, and make it visible. */
2813 packet_list_set_selected_row(row);
2814 return TRUE; /* success */
2816 return FALSE; /* failure */
2820 cf_goto_frame(capture_file *cf, guint fnumber)
2825 for (fdata = cf->plist; fdata != NULL && fdata->num < fnumber; fdata = fdata->next)
2828 if (fdata == NULL) {
2829 /* we didn't find a packet with that packet number */
2830 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
2831 "There is no packet with the packet number %u.", fnumber);
2832 return FALSE; /* we failed to go to that packet */
2834 if (!fdata->flags.passed_dfilter) {
2835 /* that packet currently isn't displayed */
2836 /* XXX - add it to the set of displayed packets? */
2837 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
2838 "The packet number %u isn't currently being displayed.", fnumber);
2839 return FALSE; /* we failed to go to that packet */
2842 /* We found that packet, and it's currently being displayed.
2843 Find what row it's in. */
2844 row = packet_list_find_row_from_data(fdata);
2845 g_assert(row != -1);
2847 /* Select that row, make it the focus row, and make it visible. */
2848 packet_list_set_selected_row(row);
2849 return TRUE; /* we got to that packet */
2853 cf_goto_top_frame(capture_file *cf)
2857 frame_data *lowest_fdata = NULL;
2859 for (fdata = cf->plist; fdata != NULL; fdata = fdata->next) {
2860 if (fdata->flags.passed_dfilter) {
2861 lowest_fdata = fdata;
2866 if (lowest_fdata == NULL) {
2870 /* We found that packet, and it's currently being displayed.
2871 Find what row it's in. */
2872 row = packet_list_find_row_from_data(lowest_fdata);
2873 g_assert(row != -1);
2875 /* Select that row, make it the focus row, and make it visible. */
2876 packet_list_set_selected_row(row);
2877 return TRUE; /* we got to that packet */
2881 cf_goto_bottom_frame(capture_file *cf)
2885 frame_data *highest_fdata = NULL;
2887 for (fdata = cf->plist; fdata != NULL; fdata = fdata->next) {
2888 if (fdata->flags.passed_dfilter) {
2889 highest_fdata = fdata;
2893 if (highest_fdata == NULL) {
2897 /* We found that packet, and it's currently being displayed.
2898 Find what row it's in. */
2899 row = packet_list_find_row_from_data(highest_fdata);
2900 g_assert(row != -1);
2902 /* Select that row, make it the focus row, and make it visible. */
2903 packet_list_set_selected_row(row);
2904 return TRUE; /* we got to that packet */
2908 * Go to frame specified by currently selected protocol tree item.
2911 cf_goto_framenum(capture_file *cf)
2913 header_field_info *hfinfo;
2916 if (cf->finfo_selected) {
2917 hfinfo = cf->finfo_selected->hfinfo;
2919 if (hfinfo->type == FT_FRAMENUM) {
2920 framenum = fvalue_get_integer(&cf->finfo_selected->value);
2922 return cf_goto_frame(cf, framenum);
2929 /* Select the packet on a given row. */
2931 cf_select_packet(capture_file *cf, int row)
2937 /* Get the frame data struct pointer for this frame */
2938 fdata = (frame_data *)packet_list_get_row_data(row);
2940 if (fdata == NULL) {
2941 /* XXX - if a GtkCList's selection mode is GTK_SELECTION_BROWSE, when
2942 the first entry is added to it by "real_insert_row()", that row
2943 is selected (see "real_insert_row()", in "gtk/gtkclist.c", in both
2944 our version and the vanilla GTK+ version).
2946 This means that a "select-row" signal is emitted; this causes
2947 "packet_list_select_cb()" to be called, which causes "cf_select_packet()"
2950 "cf_select_packet()" fetches, above, the data associated with the
2951 row that was selected; however, as "gtk_clist_append()", which
2952 called "real_insert_row()", hasn't yet returned, we haven't yet
2953 associated any data with that row, so we get back a null pointer.
2955 We can't assume that there's only one frame in the frame list,
2956 either, as we may be filtering the display.
2958 We therefore assume that, if "row" is 0, i.e. the first row
2959 is being selected, and "cf->first_displayed" equals
2960 "cf->last_displayed", i.e. there's only one frame being
2961 displayed, that frame is the frame we want.
2963 This means we have to set "cf->first_displayed" and
2964 "cf->last_displayed" before adding the row to the
2965 GtkCList; see the comment in "add_packet_to_packet_list()". */
2967 if (row == 0 && cf->first_displayed == cf->last_displayed)
2968 fdata = cf->first_displayed;
2971 /* Get the data in that frame. */
2972 if (!wtap_seek_read (cf->wth, fdata->file_off, &cf->pseudo_header,
2973 cf->pd, fdata->cap_len, &err, &err_info)) {
2974 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
2975 cf_read_error_message(err, err_info), cf->filename);
2979 /* Record that this frame is the current frame. */
2980 cf->current_frame = fdata;
2982 /* Create the logical protocol tree. */
2983 if (cf->edt != NULL) {
2984 epan_dissect_free(cf->edt);
2987 /* We don't need the columns here. */
2988 cf->edt = epan_dissect_new(TRUE, TRUE);
2989 epan_dissect_run(cf->edt, &cf->pseudo_header, cf->pd, cf->current_frame,
2992 cf_callback_invoke(cf_cb_packet_selected, cf);
2995 /* Unselect the selected packet, if any. */
2997 cf_unselect_packet(capture_file *cf)
2999 /* Destroy the epan_dissect_t for the unselected packet. */
3000 if (cf->edt != NULL) {
3001 epan_dissect_free(cf->edt);
3005 /* No packet is selected. */
3006 cf->current_frame = NULL;
3008 cf_callback_invoke(cf_cb_packet_unselected, cf);
3010 /* No protocol tree means no selected field. */
3011 cf_unselect_field(cf);
3014 /* Unset the selected protocol tree field, if any. */
3016 cf_unselect_field(capture_file *cf)
3018 cf->finfo_selected = NULL;
3020 cf_callback_invoke(cf_cb_field_unselected, cf);
3024 * Mark a particular frame.
3027 cf_mark_frame(capture_file *cf, frame_data *frame)
3029 if (! frame->flags.marked) {
3030 frame->flags.marked = TRUE;
3031 if (cf->count > cf->marked_count)
3037 * Unmark a particular frame.
3040 cf_unmark_frame(capture_file *cf, frame_data *frame)
3042 if (frame->flags.marked) {
3043 frame->flags.marked = FALSE;
3044 if (cf->marked_count > 0)
3052 } save_callback_args_t;
3055 * Save a capture to a file, in a particular format, saving either
3056 * all packets, all currently-displayed packets, or all marked packets.
3058 * Returns TRUE if it succeeds, FALSE otherwise; if it fails, it pops
3059 * up a message box for the failure.
3062 save_packet(capture_file *cf _U_, frame_data *fdata,
3063 union wtap_pseudo_header *pseudo_header, const guint8 *pd,
3066 save_callback_args_t *args = argsp;
3067 struct wtap_pkthdr hdr;
3070 /* init the wtap header for saving */
3071 hdr.ts = *(struct wtap_nstime *) &fdata->abs_ts;
3072 hdr.caplen = fdata->cap_len;
3073 hdr.len = fdata->pkt_len;
3074 hdr.pkt_encap = fdata->lnk_t;
3076 /* and save the packet */
3077 if (!wtap_dump(args->pdh, &hdr, pseudo_header, pd, &err)) {
3078 cf_write_failure_alert_box(args->fname, err);
3085 cf_save(capture_file *cf, const char *fname, packet_range_t *range, guint save_format, gboolean compressed)
3087 gchar *from_filename;
3091 save_callback_args_t callback_args;
3093 cf_callback_invoke(cf_cb_file_safe_started, (gpointer) fname);
3095 /* don't write over an existing file. */
3096 /* this should've been already checked by our caller, just to be sure... */
3097 if (file_exists(fname)) {
3098 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3099 "%sCapture file: \"%s\" already exists!%s\n\n"
3100 "Please choose a different filename.",
3101 simple_dialog_primary_start(), fname, simple_dialog_primary_end());
3105 packet_range_process_init(range);
3108 * if (!save_filtered && !save_marked && !save_manual_range &&
3109 * !save_marked_range && !save_curr && save_format == cf->cd_t) {
3112 if (packet_range_process_all(range) && save_format == cf->cd_t) {
3113 /* We're not filtering packets, and we're saving it in the format
3114 it's already in, so we can just move or copy the raw data. */
3116 if (cf->is_tempfile) {
3117 /* The file being saved is a temporary file from a live
3118 capture, so it doesn't need to stay around under that name;
3119 first, try renaming the capture buffer file to the new name. */
3121 if (rename(cf->filename, fname) == 0) {
3122 /* That succeeded - there's no need to copy the source file. */
3123 from_filename = NULL;
3126 if (errno == EXDEV) {
3127 /* They're on different file systems, so we have to copy the
3130 from_filename = cf->filename;
3132 /* The rename failed, but not because they're on different
3133 file systems - put up an error message. (Or should we
3134 just punt and try to copy? The only reason why I'd
3135 expect the rename to fail and the copy to succeed would
3136 be if we didn't have permission to remove the file from
3137 the temporary directory, and that might be fixable - but
3138 is it worth requiring the user to go off and fix it?) */
3139 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3140 file_rename_error_message(errno), fname);
3146 from_filename = cf->filename;
3149 /* It's a permanent file, so we should copy it, and not remove the
3152 from_filename = cf->filename;
3156 /* Copy the file, if we haven't moved it. */
3157 if (!copy_binary_file(from_filename, fname))
3161 /* Either we're filtering packets, or we're saving in a different
3162 format; we can't do that by copying or moving the capture file,
3163 we have to do it by writing the packets out in Wiretap. */
3164 pdh = wtap_dump_open(fname, save_format, cf->lnk_t, cf->snap,
3167 cf_open_failure_alert_box(fname, err, NULL, TRUE, save_format);
3171 /* XXX - we let the user save a subset of the packets.
3173 If we do that, should we make that file the current file? If so,
3174 it means we can no longer get at the other packets. What does
3177 /* Iterate through the list of packets, processing the packets we were
3180 XXX - we've already called "packet_range_process_init(range)", but
3181 "process_specified_packets()" will do it again. Fortunately,
3182 that's harmless in this case, as we haven't done anything to
3183 "range" since we initialized it. */
3184 callback_args.pdh = pdh;
3185 callback_args.fname = fname;
3186 switch (process_specified_packets(cf, range, "Saving",
3187 "selected packets", save_packet,
3191 /* Completed successfully. */
3195 /* The user decided to abort the saving.
3196 XXX - remove the output file? */
3200 /* Error while saving. */
3201 wtap_dump_close(pdh, &err);
3205 if (!wtap_dump_close(pdh, &err)) {
3206 cf_close_failure_alert_box(fname, err);
3211 cf_callback_invoke(cf_cb_file_safe_finished, NULL);
3213 if (packet_range_process_all(range)) {
3214 /* We saved the entire capture, not just some packets from it.
3215 Open and read the file we saved it to.
3217 XXX - this is somewhat of a waste; we already have the
3218 packets, all this gets us is updated file type information
3219 (which we could just stuff into "cf"), and having the new
3220 file be the one we have opened and from which we're reading
3221 the data, and it means we have to spend time opening and
3222 reading the file, which could be a significant amount of
3223 time if the file is large. */
3224 cf->user_saved = TRUE;
3226 if ((cf_open(cf, fname, FALSE, &err)) == CF_OK) {
3227 /* XXX - report errors if this fails?
3228 What should we return if it fails or is aborted? */
3229 switch (cf_read(cf)) {
3233 /* Just because we got an error, that doesn't mean we were unable
3234 to read any of the file; we handle what we could get from the
3238 case CF_READ_ABORTED:
3239 /* The user bailed out of re-reading the capture file; the
3240 capture file has been closed - just return (without
3241 changing any menu settings; "cf_close()" set them
3242 correctly for the "no capture file open" state). */
3245 cf_callback_invoke(cf_cb_file_safe_reload_finished, NULL);
3251 cf_callback_invoke(cf_cb_file_safe_failed, NULL);
3256 cf_open_failure_alert_box(const char *filename, int err, gchar *err_info,
3257 gboolean for_writing, int file_type)
3260 /* Wiretap error. */
3263 case WTAP_ERR_NOT_REGULAR_FILE:
3264 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3265 "The file \"%s\" is a \"special file\" or socket or other non-regular file.",
3269 case WTAP_ERR_RANDOM_OPEN_PIPE:
3270 /* Seen only when opening a capture file for reading. */
3271 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3272 "The file \"%s\" is a pipe or FIFO; Ethereal can't read pipe or FIFO files.",
3276 case WTAP_ERR_FILE_UNKNOWN_FORMAT:
3277 /* Seen only when opening a capture file for reading. */
3278 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3279 "The file \"%s\" isn't a capture file in a format Ethereal understands.",
3283 case WTAP_ERR_UNSUPPORTED:
3284 /* Seen only when opening a capture file for reading. */
3285 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3286 "The file \"%s\" isn't a capture file in a format Ethereal understands.\n"
3288 filename, err_info);
3292 case WTAP_ERR_CANT_WRITE_TO_PIPE:
3293 /* Seen only when opening a capture file for writing. */
3294 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3295 "The file \"%s\" is a pipe, and %s capture files can't be "
3296 "written to a pipe.",
3297 filename, wtap_file_type_string(file_type));
3300 case WTAP_ERR_UNSUPPORTED_FILE_TYPE:
3301 /* Seen only when opening a capture file for writing. */
3302 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3303 "Ethereal doesn't support writing capture files in that format.");
3306 case WTAP_ERR_UNSUPPORTED_ENCAP:
3308 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3309 "Ethereal can't save this capture in that format.");
3311 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3312 "The file \"%s\" is a capture for a network type that Ethereal doesn't support.\n"
3314 filename, err_info);
3319 case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED:
3321 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3322 "Ethereal can't save this capture in that format.");
3324 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3325 "The file \"%s\" is a capture for a network type that Ethereal doesn't support.",
3330 case WTAP_ERR_BAD_RECORD:
3331 /* Seen only when opening a capture file for reading. */
3332 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3333 "The file \"%s\" appears to be damaged or corrupt.\n"
3335 filename, err_info);
3339 case WTAP_ERR_CANT_OPEN:
3341 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3342 "The file \"%s\" could not be created for some unknown reason.",
3345 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3346 "The file \"%s\" could not be opened for some unknown reason.",
3351 case WTAP_ERR_SHORT_READ:
3352 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3353 "The file \"%s\" appears to have been cut short"
3354 " in the middle of a packet or other data.",
3358 case WTAP_ERR_SHORT_WRITE:
3359 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3360 "A full header couldn't be written to the file \"%s\".",
3364 case WTAP_ERR_COMPRESSION_NOT_SUPPORTED:
3365 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3366 "Gzip compression not supported by this file type.");
3370 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3371 "The file \"%s\" could not be %s: %s.",
3373 for_writing ? "created" : "opened",
3374 wtap_strerror(err));
3379 open_failure_alert_box(filename, err, for_writing);
3384 file_rename_error_message(int err)
3387 static char errmsg_errno[1024+1];
3392 errmsg = "The path to the file \"%s\" doesn't exist.";
3396 errmsg = "You don't have permission to move the capture file to \"%s\".";
3400 g_snprintf(errmsg_errno, sizeof(errmsg_errno),
3401 "The file \"%%s\" could not be moved: %s.",
3402 wtap_strerror(err));
3403 errmsg = errmsg_errno;
3410 cf_read_error_message(int err, const gchar *err_info)
3412 static char errmsg_errno[1024+1];
3416 case WTAP_ERR_UNSUPPORTED_ENCAP:
3417 g_snprintf(errmsg_errno, sizeof(errmsg_errno),
3418 "The file \"%%s\" has a packet with a network type that Ethereal doesn't support.\n(%s)",
3422 case WTAP_ERR_BAD_RECORD:
3423 g_snprintf(errmsg_errno, sizeof(errmsg_errno),
3424 "An error occurred while reading from the file \"%%s\": %s.\n(%s)",
3425 wtap_strerror(err), err_info);
3429 g_snprintf(errmsg_errno, sizeof(errmsg_errno),
3430 "An error occurred while reading from the file \"%%s\": %s.",
3431 wtap_strerror(err));
3434 return errmsg_errno;
3438 cf_write_failure_alert_box(const char *filename, int err)
3441 /* Wiretap error. */
3442 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3443 "An error occurred while writing to the file \"%s\": %s.",
3444 filename, wtap_strerror(err));
3447 write_failure_alert_box(filename, err);
3451 /* Check for write errors - if the file is being written to an NFS server,
3452 a write error may not show up until the file is closed, as NFS clients
3453 might not send writes to the server until the "write()" call finishes,
3454 so that the write may fail on the server but the "write()" may succeed. */
3456 cf_close_failure_alert_box(const char *filename, int err)
3459 /* Wiretap error. */
3462 case WTAP_ERR_CANT_CLOSE:
3463 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3464 "The file \"%s\" couldn't be closed for some unknown reason.",
3468 case WTAP_ERR_SHORT_WRITE:
3469 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3470 "Not all the packets could be written to the file \"%s\".",
3475 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3476 "An error occurred while closing the file \"%s\": %s.",
3477 filename, wtap_strerror(err));
3482 We assume that a close error from the OS is really a write error. */
3483 write_failure_alert_box(filename, err);
3487 /* Reload the current capture file. */
3489 cf_reload(capture_file *cf) {
3491 gboolean is_tempfile;
3494 /* If the file could be opened, "cf_open()" calls "cf_close()"
3495 to get rid of state for the old capture file before filling in state
3496 for the new capture file. "cf_close()" will remove the file if
3497 it's a temporary file; we don't want that to happen (for one thing,
3498 it'd prevent subsequent reopens from working). Remember whether it's
3499 a temporary file, mark it as not being a temporary file, and then
3500 reopen it as the type of file it was.
3502 Also, "cf_close()" will free "cf->filename", so we must make
3503 a copy of it first. */
3504 filename = g_strdup(cf->filename);
3505 is_tempfile = cf->is_tempfile;
3506 cf->is_tempfile = FALSE;
3507 if (cf_open(cf, filename, is_tempfile, &err) == CF_OK) {
3508 switch (cf_read(cf)) {
3512 /* Just because we got an error, that doesn't mean we were unable
3513 to read any of the file; we handle what we could get from the
3517 case CF_READ_ABORTED:
3518 /* The user bailed out of re-reading the capture file; the
3519 capture file has been closed - just free the capture file name
3520 string and return (without changing the last containing
3526 /* The open failed, so "cf->is_tempfile" wasn't set to "is_tempfile".
3527 Instead, the file was left open, so we should restore "cf->is_tempfile"
3530 XXX - change the menu? Presumably "cf_open()" will do that;
3531 make sure it does! */
3532 cf->is_tempfile = is_tempfile;
3534 /* "cf_open()" made a copy of the file name we handed it, so
3535 we should free up our copy. */
3539 /* Copies a file in binary mode, for those operating systems that care about
3541 * Returns TRUE on success, FALSE on failure. If a failure, it also
3542 * displays a simple dialog window with the error message.
3545 copy_binary_file(const char *from_filename, const char *to_filename)
3547 int from_fd, to_fd, nread, nwritten, err;
3550 /* Copy the raw bytes of the file. */
3551 from_fd = open(from_filename, O_RDONLY | O_BINARY);
3553 open_failure_alert_box(from_filename, errno, FALSE);
3557 /* Use open() instead of creat() so that we can pass the O_BINARY
3558 flag, which is relevant on Win32; it appears that "creat()"
3559 may open the file in text mode, not binary mode, but we want
3560 to copy the raw bytes of the file, so we need the output file
3561 to be open in binary mode. */
3562 to_fd = open(to_filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
3564 open_failure_alert_box(to_filename, errno, TRUE);
3569 while ((nread = read(from_fd, pd, sizeof pd)) > 0) {
3570 nwritten = write(to_fd, pd, nread);
3571 if (nwritten < nread) {
3575 err = WTAP_ERR_SHORT_WRITE;
3576 write_failure_alert_box(to_filename, err);
3584 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3585 "An error occurred while reading from the file \"%s\": %s.",
3586 from_filename, strerror(err));
3592 if (close(to_fd) < 0) {
3593 write_failure_alert_box(to_filename, errno);