6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@ethereal.com>
8 * Copyright 1998 Gerald Combs
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
50 #ifdef NEED_STRERROR_H
54 #include <epan/epan.h>
55 #include <epan/filesystem.h>
58 #include "color_filters.h"
59 #include <epan/column.h>
60 #include <epan/packet.h>
61 #include "packet-range.h"
67 #include "alert_box.h"
68 #include "simple_dialog.h"
69 #include "progress_dlg.h"
71 #include <epan/prefs.h>
72 #include <epan/dfilter/dfilter.h>
73 #include <epan/conversation.h>
74 #include <epan/epan_dissect.h>
76 #include "stat_menu.h"
77 #include "tap_dfilter_dlg.h"
78 #include <epan/dissectors/packet-data.h>
79 #include <epan/timestamp.h>
82 /* Win32 needs the O_BINARY flag for open() */
88 gboolean auto_scroll_live;
91 static nstime_t first_ts;
92 static nstime_t prev_ts;
93 static guint32 cum_bytes = 0;
95 static void cf_reset_state(capture_file *cf);
97 static void read_packet(capture_file *cf, long offset);
99 static void rescan_packets(capture_file *cf, const char *action, const char *action_item,
100 gboolean refilter, gboolean redissect);
102 static gboolean match_protocol_tree(capture_file *cf, frame_data *fdata,
104 static void match_subtree_text(proto_node *node, gpointer data);
105 static gboolean match_summary_line(capture_file *cf, frame_data *fdata,
107 static gboolean match_ascii_and_unicode(capture_file *cf, frame_data *fdata,
109 static gboolean match_ascii(capture_file *cf, frame_data *fdata,
111 static gboolean match_unicode(capture_file *cf, frame_data *fdata,
113 static gboolean match_binary(capture_file *cf, frame_data *fdata,
115 static gboolean match_dfilter(capture_file *cf, frame_data *fdata,
117 static gboolean find_packet(capture_file *cf,
118 gboolean (*match_function)(capture_file *, frame_data *, void *),
121 static void cf_open_failure_alert_box(const char *filename, int err,
122 gchar *err_info, gboolean for_writing,
124 static const char *file_rename_error_message(int err);
125 static void cf_write_failure_alert_box(const char *filename, int err);
126 static void cf_close_failure_alert_box(const char *filename, int err);
127 static gboolean copy_binary_file(const char *from_filename, const char *to_filename);
129 /* Update the progress bar this many times when reading a file. */
130 #define N_PROGBAR_UPDATES 100
132 /* Number of "frame_data" structures per memory chunk.
133 XXX - is this the right number? */
134 #define FRAME_DATA_CHUNK_SIZE 1024
137 /* one callback for now, we could have a list later */
138 static cf_callback_t cf_cb = NULL;
139 static gpointer cf_cb_user_data = NULL;
142 cf_callback_invoke(int event, gpointer data)
144 g_assert(cf_cb != NULL);
145 cf_cb(event, data, cf_cb_user_data);
150 cf_callback_add(cf_callback_t func, gpointer user_data)
152 /* More than one callback listener is currently not implemented,
153 but should be easy to do. */
154 g_assert(cf_cb == NULL);
156 cf_cb_user_data = user_data;
160 cf_callback_remove(cf_callback_t func _U_)
162 g_assert(cf_cb != NULL);
164 cf_cb_user_data = NULL;
168 cf_timestamp_auto_precision(capture_file *cf)
170 int prec = timestamp_get_precision();
173 /* don't try to get the file's precision if none is opened */
174 if(cf->state == FILE_CLOSED) {
178 /* if we are in auto mode, set precision of current file */
179 if(prec == TS_PREC_AUTO ||
180 prec == TS_PREC_AUTO_SEC ||
181 prec == TS_PREC_AUTO_DSEC ||
182 prec == TS_PREC_AUTO_CSEC ||
183 prec == TS_PREC_AUTO_MSEC ||
184 prec == TS_PREC_AUTO_USEC ||
185 prec == TS_PREC_AUTO_NSEC)
187 switch(wtap_file_tsprecision(cf->wth)) {
188 case(WTAP_FILE_TSPREC_SEC):
189 timestamp_set_precision(TS_PREC_AUTO_SEC);
191 case(WTAP_FILE_TSPREC_DSEC):
192 timestamp_set_precision(TS_PREC_AUTO_DSEC);
194 case(WTAP_FILE_TSPREC_CSEC):
195 timestamp_set_precision(TS_PREC_AUTO_CSEC);
197 case(WTAP_FILE_TSPREC_MSEC):
198 timestamp_set_precision(TS_PREC_AUTO_MSEC);
200 case(WTAP_FILE_TSPREC_USEC):
201 timestamp_set_precision(TS_PREC_AUTO_USEC);
203 case(WTAP_FILE_TSPREC_NSEC):
204 timestamp_set_precision(TS_PREC_AUTO_NSEC);
207 g_assert_not_reached();
214 cf_open(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
219 wth = wtap_open_offline(fname, err, &err_info, TRUE);
223 /* The open succeeded. Close whatever capture file we had open,
224 and fill in the information for this file. */
227 /* Initialize all data structures used for dissection. */
230 /* We're about to start reading the file. */
231 cf->state = FILE_READ_IN_PROGRESS;
236 /* Set the file name because we need it to set the follow stream filter.
237 XXX - is that still true? We need it for other reasons, though,
239 cf->filename = g_strdup(fname);
241 /* Indicate whether it's a permanent or temporary file. */
242 cf->is_tempfile = is_tempfile;
244 /* If it's a temporary capture buffer file, mark it as not saved. */
245 cf->user_saved = !is_tempfile;
247 cf->cd_t = wtap_file_type(cf->wth);
249 cf->displayed_count = 0;
250 cf->marked_count = 0;
251 cf->drops_known = FALSE;
253 cf->snap = wtap_snapshot_length(cf->wth);
255 /* Snapshot length not known. */
256 cf->has_snap = FALSE;
257 cf->snap = WTAP_MAX_PACKET_SIZE;
260 nstime_set_zero(&cf->elapsed_time);
261 nstime_set_zero(&first_ts);
262 nstime_set_zero(&prev_ts);
264 cf->plist_chunk = g_mem_chunk_new("frame_data_chunk",
266 FRAME_DATA_CHUNK_SIZE * sizeof(frame_data),
268 g_assert(cf->plist_chunk);
270 /* change the time formats now, as we might have a new precision */
271 cf_change_time_formats(cf);
273 fileset_file_opened(fname);
278 cf_open_failure_alert_box(fname, *err, err_info, FALSE, 0);
284 * Reset the state for the currently closed file, but don't do the
285 * UI callbacks; this is for use in "cf_open()", where we don't
286 * want the UI to go from "file open" to "file closed" back to
287 * "file open", we want it to go from "old file open" to "new file
288 * open and being read".
291 cf_reset_state(capture_file *cf)
293 /* Die if we're in the middle of reading a file. */
294 g_assert(cf->state != FILE_READ_IN_PROGRESS);
300 /* We have no file open... */
301 if (cf->filename != NULL) {
302 /* If it's a temporary file, remove it. */
304 unlink(cf->filename);
305 g_free(cf->filename);
308 /* ...which means we have nothing to save. */
309 cf->user_saved = FALSE;
311 if (cf->plist_chunk != NULL) {
312 g_mem_chunk_destroy(cf->plist_chunk);
313 cf->plist_chunk = NULL;
315 if (cf->rfcode != NULL) {
316 dfilter_free(cf->rfcode);
320 cf->plist_end = NULL;
321 cf_unselect_packet(cf); /* nothing to select */
322 cf->first_displayed = NULL;
323 cf->last_displayed = NULL;
325 /* No frame selected, no field in that frame selected. */
326 cf->current_frame = NULL;
327 cf->finfo_selected = NULL;
329 /* Clear the packet list. */
330 packet_list_freeze();
336 nstime_set_zero(&cf->elapsed_time);
338 reset_tap_listeners();
340 /* We have no file open. */
341 cf->state = FILE_CLOSED;
343 fileset_file_closed();
346 /* Reset everything to a pristine state */
348 cf_close(capture_file *cf)
350 /* do GUI things even if file is already closed,
351 * e.g. to cleanup things if a capture couldn't be started */
352 cf_callback_invoke(cf_cb_file_closing, cf);
354 /* close things, if not already closed before */
355 if(cf->state != FILE_CLOSED) {
359 cleanup_dissection();
362 cf_callback_invoke(cf_cb_file_closed, cf);
366 cf_read(capture_file *cf)
370 const gchar *name_ptr;
372 char errmsg_errno[1024+1];
373 gchar err_str[2048+1];
375 progdlg_t *progbar = NULL;
377 gint64 size, file_pos;
380 gchar status_str[100];
381 gint64 progbar_nextstep;
382 gint64 progbar_quantum;
386 reset_tap_listeners();
387 tap_dfilter_dlg_update();
389 cf_callback_invoke(cf_cb_file_read_start, cf);
391 name_ptr = get_basename(cf->filename);
393 /* Find the size of the file. */
394 size = wtap_file_size(cf->wth, NULL);
396 /* Update the progress bar when it gets to this value. */
397 progbar_nextstep = 0;
398 /* When we reach the value that triggers a progress bar update,
399 bump that value by this amount. */
401 progbar_quantum = size/N_PROGBAR_UPDATES;
405 packet_list_freeze();
408 g_get_current_time(&start_time);
410 while ((wtap_read(cf->wth, &err, &err_info, &data_offset))) {
412 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
413 when we update it, we have to run the GTK+ main loop to get it
414 to repaint what's pending, and doing so may involve an "ioctl()"
415 to see if there's any pending input from an X server, and doing
416 that for every packet can be costly, especially on a big file. */
417 if (data_offset >= progbar_nextstep) {
418 file_pos = wtap_read_so_far(cf->wth, NULL);
419 prog_val = (gfloat) file_pos / (gfloat) size;
420 if (prog_val > 1.0) {
421 /* The file probably grew while we were reading it.
422 Update file size, and try again. */
423 size = wtap_file_size(cf->wth, NULL);
425 prog_val = (gfloat) file_pos / (gfloat) size;
426 /* If it's still > 1, either "wtap_file_size()" failed (in which
427 case there's not much we can do about it), or the file
428 *shrank* (in which case there's not much we can do about
429 it); just clip the progress value at 1.0. */
433 if (progbar == NULL) {
434 /* Create the progress bar if necessary */
435 progbar = delayed_create_progress_dlg("Loading", name_ptr,
436 &stop_flag, &start_time, prog_val);
438 if (progbar != NULL) {
439 g_snprintf(status_str, sizeof(status_str),
440 "%" PRId64 "KB of %" PRId64 "KB",
441 file_pos / 1024, size / 1024);
442 update_progress_dlg(progbar, prog_val, status_str);
444 progbar_nextstep += progbar_quantum;
449 /* Well, the user decided to abort the read. Destroy the progress
450 bar, close the capture file, and return CF_READ_ABORTED so our caller
451 can do whatever is appropriate when that happens. */
452 destroy_progress_dlg(progbar);
453 cf->state = FILE_READ_ABORTED; /* so that we're allowed to close it */
454 packet_list_thaw(); /* undo our freeze */
456 return CF_READ_ABORTED;
458 read_packet(cf, data_offset);
461 /* We're done reading the file; destroy the progress bar if it was created. */
463 destroy_progress_dlg(progbar);
465 /* We're done reading sequentially through the file. */
466 cf->state = FILE_READ_DONE;
468 /* Close the sequential I/O side, to free up memory it requires. */
469 wtap_sequential_close(cf->wth);
471 /* Allow the protocol dissectors to free up memory that they
472 * don't need after the sequential run-through of the packets. */
473 postseq_cleanup_all_protocols();
475 /* Set the file encapsulation type now; we don't know what it is until
476 we've looked at all the packets, as we don't know until then whether
477 there's more than one type (and thus whether it's
478 WTAP_ENCAP_PER_PACKET). */
479 cf->lnk_t = wtap_file_encap(cf->wth);
481 cf->current_frame = cf->first_displayed;
484 cf_callback_invoke(cf_cb_file_read_finished, cf);
486 /* If we have any displayed packets to select, select the first of those
487 packets by making the first row the selected row. */
488 if (cf->first_displayed != NULL)
489 packet_list_select_row(0);
492 /* Put up a message box noting that the read failed somewhere along
493 the line. Don't throw out the stuff we managed to read, though,
497 case WTAP_ERR_UNSUPPORTED_ENCAP:
498 g_snprintf(errmsg_errno, sizeof(errmsg_errno),
499 "The capture file has a packet with a network type that Ethereal doesn't support.\n(%s)",
502 errmsg = errmsg_errno;
505 case WTAP_ERR_CANT_READ:
506 errmsg = "An attempt to read from the capture file failed for"
507 " some unknown reason.";
510 case WTAP_ERR_SHORT_READ:
511 errmsg = "The capture file appears to have been cut short"
512 " in the middle of a packet.";
515 case WTAP_ERR_BAD_RECORD:
516 g_snprintf(errmsg_errno, sizeof(errmsg_errno),
517 "The capture file appears to be damaged or corrupt.\n(%s)",
520 errmsg = errmsg_errno;
524 g_snprintf(errmsg_errno, sizeof(errmsg_errno),
525 "An error occurred while reading the"
526 " capture file: %s.", wtap_strerror(err));
527 errmsg = errmsg_errno;
530 g_snprintf(err_str, sizeof err_str, errmsg);
531 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, err_str);
532 return CF_READ_ERROR;
539 cf_start_tail(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
541 cf_status_t cf_status;
543 cf_status = cf_open(cf, fname, is_tempfile, err);
548 cf_continue_tail(capture_file *cf, int to_read, int *err)
550 long data_offset = 0;
555 packet_list_freeze();
557 /*g_log(NULL, G_LOG_LEVEL_MESSAGE, "cf_continue_tail: %u new: %u", cf->count, to_read);*/
559 while (to_read != 0 && (wtap_read(cf->wth, err, &err_info, &data_offset))) {
560 if (cf->state == FILE_READ_ABORTED) {
561 /* Well, the user decided to exit Ethereal. Break out of the
562 loop, and let the code below (which is called even if there
563 aren't any packets left to read) exit. */
566 read_packet(cf, data_offset);
570 /*g_log(NULL, G_LOG_LEVEL_MESSAGE, "cf_continue_tail: count %u state: %u err: %u",
571 cf->count, cf->state, *err);*/
573 /* XXX - this cheats and looks inside the packet list to find the final
575 if (auto_scroll_live && cf->plist_end != NULL)
576 packet_list_moveto_end();
580 if (cf->state == FILE_READ_ABORTED) {
581 /* Well, the user decided to exit Ethereal. Return CF_READ_ABORTED
582 so that our caller can kill off the capture child process;
583 this will cause an EOF on the pipe from the child, so
584 "cf_finish_tail()" will be called, and it will clean up
586 return CF_READ_ABORTED;
587 } else if (*err != 0) {
588 /* We got an error reading the capture file.
589 XXX - pop up a dialog box instead? */
590 g_warning("Error \"%s\" while reading: \"%s\"\n",
591 wtap_strerror(*err), cf->filename);
593 return CF_READ_ERROR;
599 cf_finish_tail(capture_file *cf, int *err)
604 if(cf->wth == NULL) {
606 return CF_READ_ERROR;
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);
623 if (cf->state == FILE_READ_ABORTED) {
624 /* Well, the user decided to abort the read. We're only called
625 when the child capture process closes the pipe to us (meaning
626 it's probably exited), so we can just close the capture
627 file; we return CF_READ_ABORTED so our caller can do whatever
628 is appropriate when that happens. */
630 return CF_READ_ABORTED;
633 if (auto_scroll_live && cf->plist_end != NULL)
634 /* XXX - this cheats and looks inside the packet list to find the final
636 packet_list_moveto_end();
638 /* We're done reading sequentially through the file. */
639 cf->state = FILE_READ_DONE;
641 /* We're done reading sequentially through the file; close the
642 sequential I/O side, to free up memory it requires. */
643 wtap_sequential_close(cf->wth);
645 /* Allow the protocol dissectors to free up memory that they
646 * don't need after the sequential run-through of the packets. */
647 postseq_cleanup_all_protocols();
649 /* Set the file encapsulation type now; we don't know what it is until
650 we've looked at all the packets, as we don't know until then whether
651 there's more than one type (and thus whether it's
652 WTAP_ENCAP_PER_PACKET). */
653 cf->lnk_t = wtap_file_encap(cf->wth);
656 /* We got an error reading the capture file.
657 XXX - pop up a dialog box? */
658 return CF_READ_ERROR;
663 #endif /* HAVE_LIBPCAP */
666 cf_get_display_name(capture_file *cf)
668 const gchar *displayname;
670 /* Return a name to use in displays */
671 if (!cf->is_tempfile) {
672 /* Get the last component of the file name, and use that. */
674 displayname = get_basename(cf->filename);
676 displayname="(No file)";
679 /* The file we read is a temporary file from a live capture;
680 we don't mention its name. */
681 displayname = "(Untitled)";
686 /* XXX - use a macro instead? */
688 cf_packet_count(capture_file *cf)
693 /* XXX - use a macro instead? */
695 cf_is_tempfile(capture_file *cf)
697 return cf->is_tempfile;
700 void cf_set_tempfile(capture_file *cf, gboolean is_tempfile)
702 cf->is_tempfile = is_tempfile;
706 /* XXX - use a macro instead? */
707 void cf_set_drops_known(capture_file *cf, gboolean drops_known)
709 cf->drops_known = drops_known;
712 /* XXX - use a macro instead? */
713 void cf_set_drops(capture_file *cf, guint32 drops)
718 /* XXX - use a macro instead? */
719 gboolean cf_get_drops_known(capture_file *cf)
721 return cf->drops_known;
724 /* XXX - use a macro instead? */
725 guint32 cf_get_drops(capture_file *cf)
730 void cf_set_rfcode(capture_file *cf, dfilter_t *rfcode)
736 add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
737 union wtap_pseudo_header *pseudo_header, const guchar *buf,
741 gboolean create_proto_tree = FALSE;
744 /* just add some value here until we know if it is being displayed or not */
745 fdata->cum_bytes = cum_bytes + fdata->pkt_len;
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 (nstime_is_zero(&first_ts)) {
751 first_ts = fdata->abs_ts;
753 /* if this frames is marked as a reference time frame, reset
754 firstsec and firstusec to this frame */
755 if(fdata->flags.ref_time){
756 first_ts = fdata->abs_ts;
759 /* If we don't have the time stamp of the previous displayed packet,
760 it's because this is the first displayed packet. Save the time
761 stamp of this packet as the time stamp of the previous displayed
763 if (nstime_is_zero(&prev_ts)) {
764 prev_ts = fdata->abs_ts;
767 /* Get the time elapsed between the first packet and this packet. */
768 nstime_delta(&fdata->rel_ts, &fdata->abs_ts, &first_ts);
770 /* If it's greater than the current elapsed time, set the elapsed time
771 to it (we check for "greater than" so as not to be confused by
772 time moving backwards). */
773 if ((gint32)cf->elapsed_time.secs < fdata->rel_ts.secs
774 || ((gint32)cf->elapsed_time.secs == fdata->rel_ts.secs && (gint32)cf->elapsed_time.nsecs < fdata->rel_ts.nsecs)) {
775 cf->elapsed_time = fdata->rel_ts;
778 /* Get the time elapsed between the previous displayed packet and
780 nstime_delta(&fdata->del_ts, &fdata->abs_ts, &prev_ts);
784 we have a display filter and are re-applying it;
786 we have a list of color filters;
788 we have tap listeners;
790 allocate a protocol tree root node, so that we'll construct
791 a protocol tree against which a filter expression can be
793 if ((cf->dfcode != NULL && refilter) || color_filters_used()
794 || num_tap_filters != 0)
795 create_proto_tree = TRUE;
797 /* Dissect the frame. */
798 edt = epan_dissect_new(create_proto_tree, FALSE);
800 if (cf->dfcode != NULL && refilter) {
801 epan_dissect_prime_dfilter(edt, cf->dfcode);
803 if (color_filters_used()) {
804 color_filters_prime_edt(edt);
807 epan_dissect_run(edt, pseudo_header, buf, fdata, &cf->cinfo);
808 tap_push_tapped_queue(edt);
810 /* If we have a display filter, apply it if we're refiltering, otherwise
811 leave the "passed_dfilter" flag alone.
813 If we don't have a display filter, set "passed_dfilter" to 1. */
814 if (cf->dfcode != NULL) {
816 fdata->flags.passed_dfilter = dfilter_apply_edt(cf->dfcode, edt) ? 1 : 0;
819 fdata->flags.passed_dfilter = 1;
821 if( (fdata->flags.passed_dfilter)
822 || (edt->pi.fd->flags.ref_time) ){
823 /* This frame either passed the display filter list or is marked as
824 a time reference frame. All time reference frames are displayed
825 even if they dont pass the display filter */
826 /* if this was a TIME REF frame we should reset the cul bytes field */
827 if(edt->pi.fd->flags.ref_time){
828 cum_bytes = fdata->pkt_len;
829 fdata->cum_bytes = cum_bytes;
832 /* increase cum_bytes with this packets length */
833 cum_bytes += fdata->pkt_len;
835 epan_dissect_fill_in_columns(edt);
837 /* If we haven't yet seen the first frame, this is it.
839 XXX - we must do this before we add the row to the display,
840 as, if the display's GtkCList's selection mode is
841 GTK_SELECTION_BROWSE, when the first entry is added to it,
842 "cf_select_packet()" will be called, and it will fetch the row
843 data for the 0th row, and will get a null pointer rather than
844 "fdata", as "gtk_clist_append()" won't yet have returned and
845 thus "gtk_clist_set_row_data()" won't yet have been called.
847 We thus need to leave behind bread crumbs so that
848 "cf_select_packet()" can find this frame. See the comment
849 in "cf_select_packet()". */
850 if (cf->first_displayed == NULL)
851 cf->first_displayed = fdata;
853 /* This is the last frame we've seen so far. */
854 cf->last_displayed = fdata;
856 row = packet_list_append(cf->cinfo.col_data, fdata);
858 /* colorize packet: if packet is marked, use preferences,
859 otherwise try to apply color filters */
860 if (fdata->flags.marked) {
861 fdata->color_filter = NULL;
862 packet_list_set_colors(row, &prefs.gui_marked_fg, &prefs.gui_marked_bg);
864 fdata->color_filter = color_filters_colorize_packet(row, edt);
867 /* Set the time of the previous displayed frame to the time of this
869 prev_ts = fdata->abs_ts;
871 cf->displayed_count++;
873 /* This frame didn't pass the display filter, so it's not being added
874 to the clist, and thus has no row. */
877 epan_dissect_free(edt);
882 read_packet(capture_file *cf, long offset)
884 const struct wtap_pkthdr *phdr = wtap_phdr(cf->wth);
885 union wtap_pseudo_header *pseudo_header = wtap_pseudoheader(cf->wth);
886 const guchar *buf = wtap_buf_ptr(cf->wth);
889 frame_data *plist_end;
892 /* Allocate the next list entry, and add it to the list. */
893 fdata = g_mem_chunk_alloc(cf->plist_chunk);
899 fdata->pkt_len = phdr->len;
900 fdata->cap_len = phdr->caplen;
901 fdata->file_off = offset;
902 fdata->lnk_t = phdr->pkt_encap;
903 fdata->flags.encoding = CHAR_ASCII;
904 fdata->flags.visited = 0;
905 fdata->flags.marked = 0;
906 fdata->flags.ref_time = 0;
908 fdata->abs_ts = *((nstime_t *) &phdr->ts);
912 edt = epan_dissect_new(TRUE, FALSE);
913 epan_dissect_prime_dfilter(edt, cf->rfcode);
914 epan_dissect_run(edt, pseudo_header, buf, fdata, NULL);
915 passed = dfilter_apply_edt(cf->rfcode, edt);
916 epan_dissect_free(edt);
919 plist_end = cf->plist_end;
920 fdata->prev = plist_end;
921 if (plist_end != NULL)
922 plist_end->next = fdata;
925 cf->plist_end = fdata;
928 cf->f_datalen = offset + phdr->caplen;
929 fdata->num = cf->count;
930 add_packet_to_packet_list(fdata, cf, pseudo_header, buf, TRUE);
932 /* XXX - if we didn't have read filters, or if we could avoid
933 allocating the "frame_data" structure until we knew whether
934 the frame passed the read filter, we could use a G_ALLOC_ONLY
937 ...but, at least in one test I did, where I just made the chunk
938 a G_ALLOC_ONLY chunk and read in a huge capture file, it didn't
939 seem to save a noticeable amount of time or space. */
940 g_mem_chunk_free(cf->plist_chunk, fdata);
945 cf_merge_files(char **out_filenamep, int in_file_count,
946 char *const *in_filenames, int file_type, gboolean do_append)
948 merge_in_file_t *in_files;
954 int open_err, read_err, write_err, close_err;
958 char errmsg_errno[1024+1];
959 gchar err_str[2048+1];
961 gboolean got_read_error = FALSE, got_write_error = FALSE;
963 progdlg_t *progbar = NULL;
965 gint64 f_len, file_pos;
968 gchar status_str[100];
969 gint64 progbar_nextstep;
970 gint64 progbar_quantum;
972 /* open the input files */
973 if (!merge_open_in_files(in_file_count, in_filenames, &in_files,
974 &open_err, &err_info, &err_fileno)) {
976 cf_open_failure_alert_box(in_filenames[err_fileno], open_err, err_info,
981 if (*out_filenamep != NULL) {
982 out_filename = *out_filenamep;
983 out_fd = open(out_filename, O_CREAT|O_TRUNC|O_BINARY, 0600);
987 out_fd = create_tempfile(tmpname, sizeof tmpname, "ether");
990 out_filename = g_strdup(tmpname);
991 *out_filenamep = out_filename;
995 merge_close_in_files(in_file_count, in_files);
997 cf_open_failure_alert_box(out_filename, open_err, NULL, TRUE, file_type);
1001 pdh = wtap_dump_fdopen(out_fd, file_type,
1002 merge_select_frame_type(in_file_count, in_files),
1003 merge_max_snapshot_length(in_file_count, in_files),
1004 FALSE /* compressed */, &open_err);
1007 merge_close_in_files(in_file_count, in_files);
1009 cf_open_failure_alert_box(out_filename, open_err, err_info, TRUE,
1014 /* Get the sum of the sizes of all the files. */
1016 for (i = 0; i < in_file_count; i++)
1017 f_len += in_files[i].size;
1019 /* Update the progress bar when it gets to this value. */
1020 progbar_nextstep = 0;
1021 /* When we reach the value that triggers a progress bar update,
1022 bump that value by this amount. */
1023 progbar_quantum = f_len/N_PROGBAR_UPDATES;
1026 g_get_current_time(&start_time);
1028 /* do the merge (or append) */
1031 wth = merge_append_read_packet(in_file_count, in_files, &read_err,
1034 wth = merge_read_packet(in_file_count, in_files, &read_err,
1038 got_read_error = TRUE;
1042 /* Get the sum of the data offsets in all of the files. */
1044 for (i = 0; i < in_file_count; i++)
1045 data_offset += in_files[i].data_offset;
1047 if (data_offset >= progbar_nextstep) {
1048 /* Get the sum of the seek positions in all of the files. */
1050 for (i = 0; i < in_file_count; i++)
1051 file_pos += wtap_read_so_far(in_files[i].wth, NULL);
1052 prog_val = (gfloat) file_pos / (gfloat) f_len;
1053 if (prog_val > 1.0) {
1054 /* Some file probably grew while we were reading it.
1055 That "shouldn't happen", so we'll just clip the progress
1059 if (progbar == NULL) {
1060 /* Create the progress bar if necessary */
1061 progbar = delayed_create_progress_dlg("Merging", "files",
1062 &stop_flag, &start_time, prog_val);
1064 if (progbar != NULL) {
1065 g_snprintf(status_str, sizeof(status_str),
1066 "%" PRId64 "KB of %" PRId64 "KB",
1067 file_pos / 1024, f_len / 1024);
1068 update_progress_dlg(progbar, prog_val, status_str);
1070 progbar_nextstep += progbar_quantum;
1073 if (!wtap_dump(pdh, wtap_phdr(wth), wtap_pseudoheader(wth),
1074 wtap_buf_ptr(wth), &write_err)) {
1075 got_write_error = TRUE;
1080 /* We're done merging the files; destroy the progress bar if it was created. */
1081 if (progbar != NULL)
1082 destroy_progress_dlg(progbar);
1084 merge_close_in_files(in_file_count, in_files);
1085 if (!got_read_error && !got_write_error) {
1086 if (!wtap_dump_close(pdh, &write_err))
1087 got_write_error = TRUE;
1089 wtap_dump_close(pdh, &close_err);
1091 if (got_read_error) {
1093 * Find the file on which we got the error, and report the error.
1095 for (i = 0; i < in_file_count; i++) {
1096 if (in_files[i].state == GOT_ERROR) {
1097 /* Put up a message box noting that a read failed somewhere along
1101 case WTAP_ERR_UNSUPPORTED_ENCAP:
1102 g_snprintf(errmsg_errno, sizeof(errmsg_errno),
1103 "The capture file %%s has a packet with a network type that Ethereal doesn't support.\n(%s)",
1106 errmsg = errmsg_errno;
1109 case WTAP_ERR_CANT_READ:
1110 errmsg = "An attempt to read from the capture file %s failed for"
1111 " some unknown reason.";
1114 case WTAP_ERR_SHORT_READ:
1115 errmsg = "The capture file %s appears to have been cut short"
1116 " in the middle of a packet.";
1119 case WTAP_ERR_BAD_RECORD:
1120 g_snprintf(errmsg_errno, sizeof(errmsg_errno),
1121 "The capture file %%s appears to be damaged or corrupt.\n(%s)",
1124 errmsg = errmsg_errno;
1128 g_snprintf(errmsg_errno, sizeof(errmsg_errno),
1129 "An error occurred while reading the"
1130 " capture file %%s: %s.", wtap_strerror(read_err));
1131 errmsg = errmsg_errno;
1134 g_snprintf(err_str, sizeof err_str, errmsg, in_files[i].filename);
1135 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, err_str);
1140 if (got_write_error) {
1141 /* Put up an alert box for the write error. */
1142 cf_write_failure_alert_box(out_filename, write_err);
1145 return (!got_read_error && !got_write_error) ? CF_OK : CF_ERROR;
1149 cf_filter_packets(capture_file *cf, gchar *dftext, gboolean force)
1152 const char *filter_new = dftext ? dftext : "";
1153 const char *filter_old = cf->dfilter ? cf->dfilter : "";
1155 /* if new filter equals old one, do nothing unless told to do so */
1156 if (!force && strcmp(filter_new, filter_old) == 0) {
1160 if (dftext == NULL) {
1161 /* The new filter is an empty filter (i.e., display all packets). */
1165 * We have a filter; make a copy of it (as we'll be saving it),
1166 * and try to compile it.
1168 dftext = g_strdup(dftext);
1169 if (!dfilter_compile(dftext, &dfcode)) {
1170 /* The attempt failed; report an error. */
1171 gchar *safe_dftext = simple_dialog_format_message(dftext);
1172 gchar *safe_dfilter_error_msg = simple_dialog_format_message(
1174 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1177 "The following display filter isn't a valid display filter:\n%s\n"
1178 "See the help for a description of the display filter syntax.",
1179 simple_dialog_primary_start(), safe_dfilter_error_msg,
1180 simple_dialog_primary_end(), safe_dftext);
1181 g_free(safe_dfilter_error_msg);
1182 g_free(safe_dftext);
1188 if (dfcode == NULL) {
1189 /* Yes - free the filter text, and set it to null. */
1195 /* We have a valid filter. Replace the current filter. */
1196 if (cf->dfilter != NULL)
1197 g_free(cf->dfilter);
1198 cf->dfilter = dftext;
1199 if (cf->dfcode != NULL)
1200 dfilter_free(cf->dfcode);
1201 cf->dfcode = dfcode;
1203 /* Now rescan the packet list, applying the new filter, but not
1204 throwing away information constructed on a previous pass. */
1205 if (dftext == NULL) {
1206 rescan_packets(cf, "Resetting", "Filter", TRUE, FALSE);
1208 rescan_packets(cf, "Filtering", dftext, TRUE, FALSE);
1214 cf_colorize_packets(capture_file *cf)
1216 rescan_packets(cf, "Colorizing", "all packets", FALSE, FALSE);
1220 cf_reftime_packets(capture_file *cf)
1222 rescan_packets(cf, "Updating Reftime", "all packets", FALSE, FALSE);
1226 cf_redissect_packets(capture_file *cf)
1228 rescan_packets(cf, "Reprocessing", "all packets", TRUE, TRUE);
1231 /* Rescan the list of packets, reconstructing the CList.
1233 "action" describes why we're doing this; it's used in the progress
1236 "action_item" describes what we're doing; it's used in the progress
1239 "refilter" is TRUE if we need to re-evaluate the filter expression.
1241 "redissect" is TRUE if we need to make the dissectors reconstruct
1242 any state information they have (because a preference that affects
1243 some dissector has changed, meaning some dissector might construct
1244 its state differently from the way it was constructed the last time). */
1246 rescan_packets(capture_file *cf, const char *action, const char *action_item,
1247 gboolean refilter, gboolean redissect)
1250 progdlg_t *progbar = NULL;
1255 frame_data *selected_frame, *preceding_frame, *following_frame, *prev_frame;
1256 int selected_row, prev_row, preceding_row, following_row;
1257 gboolean selected_frame_seen;
1260 GTimeVal start_time;
1261 gchar status_str[100];
1262 int progbar_nextstep;
1263 int progbar_quantum;
1266 reset_tap_listeners();
1267 /* Which frame, if any, is the currently selected frame?
1268 XXX - should the selected frame or the focus frame be the "current"
1269 frame, that frame being the one from which "Find Frame" searches
1271 selected_frame = cf->current_frame;
1273 /* We don't yet know what row that frame will be on, if any, after we
1274 rebuild the clist, however. */
1278 /* We need to re-initialize all the state information that protocols
1279 keep, because some preference that controls a dissector has changed,
1280 which might cause the state information to be constructed differently
1281 by that dissector. */
1283 /* Initialize all data structures used for dissection. */
1287 /* Freeze the packet list while we redo it, so we don't get any
1288 screen updates while it happens. */
1289 packet_list_freeze();
1292 packet_list_clear();
1294 /* We don't yet know which will be the first and last frames displayed. */
1295 cf->first_displayed = NULL;
1296 cf->last_displayed = NULL;
1298 /* We currently don't display any packets */
1299 cf->displayed_count = 0;
1301 /* Iterate through the list of frames. Call a routine for each frame
1302 to check whether it should be displayed and, if so, add it to
1303 the display list. */
1304 nstime_set_zero(&first_ts);
1305 nstime_set_zero(&prev_ts);
1307 /* Update the progress bar when it gets to this value. */
1308 progbar_nextstep = 0;
1309 /* When we reach the value that triggers a progress bar update,
1310 bump that value by this amount. */
1311 progbar_quantum = cf->count/N_PROGBAR_UPDATES;
1312 /* Count of packets at which we've looked. */
1316 g_get_current_time(&start_time);
1318 row = -1; /* no previous row yet */
1323 preceding_frame = NULL;
1325 following_frame = NULL;
1327 selected_frame_seen = FALSE;
1329 for (fdata = cf->plist; fdata != NULL; fdata = fdata->next) {
1330 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
1331 when we update it, we have to run the GTK+ main loop to get it
1332 to repaint what's pending, and doing so may involve an "ioctl()"
1333 to see if there's any pending input from an X server, and doing
1334 that for every packet can be costly, especially on a big file. */
1335 if (count >= progbar_nextstep) {
1336 /* let's not divide by zero. I should never be started
1337 * with count == 0, so let's assert that
1339 g_assert(cf->count > 0);
1340 prog_val = (gfloat) count / cf->count;
1342 if (progbar == NULL)
1343 /* Create the progress bar if necessary */
1344 progbar = delayed_create_progress_dlg(action, action_item, &stop_flag,
1345 &start_time, prog_val);
1347 if (progbar != NULL) {
1348 g_snprintf(status_str, sizeof(status_str),
1349 "%4u of %u frames", count, cf->count);
1350 update_progress_dlg(progbar, prog_val, status_str);
1353 progbar_nextstep += progbar_quantum;
1357 /* Well, the user decided to abort the filtering. Just stop.
1359 XXX - go back to the previous filter? Users probably just
1360 want not to wait for a filtering operation to finish;
1361 unless we cancel by having no filter, reverting to the
1362 previous filter will probably be even more expensive than
1363 continuing the filtering, as it involves going back to the
1364 beginning and filtering, and even with no filter we currently
1365 have to re-generate the entire clist, which is also expensive.
1367 I'm not sure what Network Monitor does, but it doesn't appear
1368 to give you an unfiltered display if you cancel. */
1375 /* Since all state for the frame was destroyed, mark the frame
1376 * as not visited, free the GSList referring to the state
1377 * data (the per-frame data itself was freed by
1378 * "init_dissection()"), and null out the GSList pointer. */
1379 fdata->flags.visited = 0;
1381 g_slist_free(fdata->pfd);
1386 if (!wtap_seek_read (cf->wth, fdata->file_off, &cf->pseudo_header,
1387 cf->pd, fdata->cap_len, &err, &err_info)) {
1388 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1389 cf_read_error_message(err, err_info), cf->filename);
1393 /* If the previous frame is displayed, and we haven't yet seen the
1394 selected frame, remember that frame - it's the closest one we've
1395 yet seen before the selected frame. */
1396 if (prev_row != -1 && !selected_frame_seen) {
1397 preceding_row = prev_row;
1398 preceding_frame = prev_frame;
1400 row = add_packet_to_packet_list(fdata, cf, &cf->pseudo_header, cf->pd,
1403 /* If this frame is displayed, and this is the first frame we've
1404 seen displayed after the selected frame, remember this frame -
1405 it's the closest one we've yet seen at or after the selected
1407 if (row != -1 && selected_frame_seen && following_row == -1) {
1408 following_row = row;
1409 following_frame = fdata;
1411 if (fdata == selected_frame) {
1413 selected_frame_seen = TRUE;
1416 /* Remember this row/frame - it'll be the previous row/frame
1417 on the next pass through the loop. */
1423 /* Clear out what remains of the visited flags and per-frame data
1426 XXX - that may cause various forms of bogosity when dissecting
1427 these frames, as they won't have been seen by this sequential
1428 pass, but the only alternative I see is to keep scanning them
1429 even though the user requested that the scan stop, and that
1430 would leave the user stuck with an Ethereal grinding on
1431 until it finishes. Should we just stick them with that? */
1432 for (; fdata != NULL; fdata = fdata->next) {
1433 fdata->flags.visited = 0;
1435 g_slist_free(fdata->pfd);
1441 /* We're done filtering the packets; destroy the progress bar if it
1443 if (progbar != NULL)
1444 destroy_progress_dlg(progbar);
1446 /* Unfreeze the packet list. */
1449 if (selected_row == -1) {
1450 /* The selected frame didn't pass the filter. */
1451 if (selected_frame == NULL) {
1452 /* That's because there *was* no selected frame. Make the first
1453 displayed frame the current frame. */
1456 /* Find the nearest displayed frame to the selected frame (whether
1457 it's before or after that frame) and make that the current frame.
1458 If the next and previous displayed frames are equidistant from the
1459 selected frame, choose the next one. */
1460 g_assert(following_frame == NULL ||
1461 following_frame->num >= selected_frame->num);
1462 g_assert(preceding_frame == NULL ||
1463 preceding_frame->num <= selected_frame->num);
1464 if (following_frame == NULL) {
1465 /* No frame after the selected frame passed the filter, so we
1466 have to select the last displayed frame before the selected
1468 selected_row = preceding_row;
1469 } else if (preceding_frame == NULL) {
1470 /* No frame before the selected frame passed the filter, so we
1471 have to select the first displayed frame after the selected
1473 selected_row = following_row;
1475 /* Choose the closer of the last displayed frame before the
1476 selected frame and the first displayed frame after the
1477 selected frame; in case of a tie, choose the first displayed
1478 frame after the selected frame. */
1479 if (following_frame->num - selected_frame->num <=
1480 selected_frame->num - preceding_frame->num) {
1481 selected_row = following_row;
1483 /* The previous frame is closer to the selected frame than the
1485 selected_row = preceding_row;
1491 if (selected_row == -1) {
1492 /* There are no frames displayed at all. */
1493 cf_unselect_packet(cf);
1495 /* Either the frame that was selected passed the filter, or we've
1496 found the nearest displayed frame to that frame. Select it, make
1497 it the focus row, and make it visible. */
1498 packet_list_set_selected_row(selected_row);
1509 process_specified_packets(capture_file *cf, packet_range_t *range,
1510 const char *string1, const char *string2,
1511 gboolean (*callback)(capture_file *, frame_data *,
1512 union wtap_pseudo_header *, const guint8 *, void *),
1513 void *callback_args)
1518 union wtap_pseudo_header pseudo_header;
1519 guint8 pd[WTAP_MAX_PACKET_SIZE+1];
1520 psp_return_t ret = PSP_FINISHED;
1522 progdlg_t *progbar = NULL;
1525 gboolean progbar_stop_flag;
1526 GTimeVal progbar_start_time;
1527 gchar progbar_status_str[100];
1528 int progbar_nextstep;
1529 int progbar_quantum;
1530 range_process_e process_this;
1532 /* Update the progress bar when it gets to this value. */
1533 progbar_nextstep = 0;
1534 /* When we reach the value that triggers a progress bar update,
1535 bump that value by this amount. */
1536 progbar_quantum = cf->count/N_PROGBAR_UPDATES;
1537 /* Count of packets at which we've looked. */
1540 progbar_stop_flag = FALSE;
1541 g_get_current_time(&progbar_start_time);
1543 packet_range_process_init(range);
1545 /* Iterate through the list of packets, printing the packets that
1546 were selected by the current display filter. */
1547 for (fdata = cf->plist; fdata != NULL; fdata = fdata->next) {
1548 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
1549 when we update it, we have to run the GTK+ main loop to get it
1550 to repaint what's pending, and doing so may involve an "ioctl()"
1551 to see if there's any pending input from an X server, and doing
1552 that for every packet can be costly, especially on a big file. */
1553 if (progbar_count >= progbar_nextstep) {
1554 /* let's not divide by zero. I should never be started
1555 * with count == 0, so let's assert that
1557 g_assert(cf->count > 0);
1558 progbar_val = (gfloat) progbar_count / cf->count;
1560 if (progbar == NULL)
1561 /* Create the progress bar if necessary */
1562 progbar = delayed_create_progress_dlg(string1, string2,
1564 &progbar_start_time,
1567 if (progbar != NULL) {
1568 g_snprintf(progbar_status_str, sizeof(progbar_status_str),
1569 "%4u of %u packets", progbar_count, cf->count);
1570 update_progress_dlg(progbar, progbar_val, progbar_status_str);
1573 progbar_nextstep += progbar_quantum;
1576 if (progbar_stop_flag) {
1577 /* Well, the user decided to abort the operation. Just stop,
1578 and arrange to return TRUE to our caller, so they know it
1579 was stopped explicitly. */
1586 /* do we have to process this packet? */
1587 process_this = packet_range_process_packet(range, fdata);
1588 if (process_this == range_process_next) {
1589 /* this packet uninteresting, continue with next one */
1591 } else if (process_this == range_processing_finished) {
1592 /* all interesting packets processed, stop the loop */
1596 /* Get the packet */
1597 if (!wtap_seek_read(cf->wth, fdata->file_off, &pseudo_header,
1598 pd, fdata->cap_len, &err, &err_info)) {
1599 /* Attempt to get the packet failed. */
1600 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1601 cf_read_error_message(err, err_info), cf->filename);
1605 /* Process the packet */
1606 if (!callback(cf, fdata, &pseudo_header, pd, callback_args)) {
1607 /* Callback failed. We assume it reported the error appropriately. */
1613 /* We're done printing the packets; destroy the progress bar if
1615 if (progbar != NULL)
1616 destroy_progress_dlg(progbar);
1622 retap_packet(capture_file *cf _U_, frame_data *fdata,
1623 union wtap_pseudo_header *pseudo_header, const guint8 *pd,
1626 column_info *cinfo = argsp;
1627 epan_dissect_t *edt;
1629 /* If we have tap listeners, allocate a protocol tree root node, so that
1630 we'll construct a protocol tree against which a filter expression can
1632 edt = epan_dissect_new(num_tap_filters != 0, FALSE);
1633 tap_queue_init(edt);
1634 epan_dissect_run(edt, pseudo_header, pd, fdata, cinfo);
1635 tap_push_tapped_queue(edt);
1636 epan_dissect_free(edt);
1642 cf_retap_packets(capture_file *cf, gboolean do_columns)
1644 packet_range_t range;
1646 /* Reset the tap listeners. */
1647 reset_tap_listeners();
1649 /* Iterate through the list of packets, dissecting all packets and
1650 re-running the taps. */
1651 packet_range_init(&range);
1652 packet_range_process_init(&range);
1653 switch (process_specified_packets(cf, &range, "Refiltering statistics on",
1654 "all packets", retap_packet,
1655 do_columns ? &cf->cinfo : NULL)) {
1657 /* Completed successfully. */
1661 /* Well, the user decided to abort the refiltering.
1662 Return CF_READ_ABORTED so our caller knows they did that. */
1663 return CF_READ_ABORTED;
1666 /* Error while retapping. */
1667 return CF_READ_ERROR;
1670 g_assert_not_reached();
1675 print_args_t *print_args;
1676 gboolean print_header_line;
1677 char *header_line_buf;
1678 int header_line_buf_len;
1679 gboolean print_formfeed;
1680 gboolean print_separator;
1684 } print_callback_args_t;
1687 print_packet(capture_file *cf, frame_data *fdata,
1688 union wtap_pseudo_header *pseudo_header, const guint8 *pd,
1691 print_callback_args_t *args = argsp;
1692 epan_dissect_t *edt;
1698 gboolean proto_tree_needed;
1699 char bookmark_name[9+10+1]; /* "__frameNNNNNNNNNN__\0" */
1700 char bookmark_title[6+10+1]; /* "Frame NNNNNNNNNN__\0" */
1702 /* Create the protocol tree, and make it visible, if we're printing
1703 the dissection or the hex data.
1704 XXX - do we need it if we're just printing the hex data? */
1706 args->print_args->print_dissections != print_dissections_none || args->print_args->print_hex;
1707 edt = epan_dissect_new(proto_tree_needed, proto_tree_needed);
1709 /* Fill in the column information if we're printing the summary
1711 if (args->print_args->print_summary) {
1712 epan_dissect_run(edt, pseudo_header, pd, fdata, &cf->cinfo);
1713 epan_dissect_fill_in_columns(edt);
1715 epan_dissect_run(edt, pseudo_header, pd, fdata, NULL);
1717 if (args->print_formfeed) {
1718 if (!new_page(args->print_args->stream))
1721 if (args->print_separator) {
1722 if (!print_line(args->print_args->stream, 0, ""))
1728 * We generate bookmarks, if the output format supports them.
1729 * The name is "__frameN__".
1731 g_snprintf(bookmark_name, sizeof bookmark_name, "__frame%u__", fdata->num);
1733 if (args->print_args->print_summary) {
1734 if (args->print_header_line) {
1735 if (!print_line(args->print_args->stream, 0, args->header_line_buf))
1737 args->print_header_line = FALSE; /* we might not need to print any more */
1739 cp = &args->line_buf[0];
1741 for (i = 0; i < cf->cinfo.num_cols; i++) {
1742 /* Find the length of the string for this column. */
1743 column_len = strlen(cf->cinfo.col_data[i]);
1744 if (args->col_widths[i] > column_len)
1745 column_len = args->col_widths[i];
1747 /* Make sure there's room in the line buffer for the column; if not,
1748 double its length. */
1749 line_len += column_len + 1; /* "+1" for space */
1750 if (line_len > args->line_buf_len) {
1751 cp_off = cp - args->line_buf;
1752 args->line_buf_len = 2 * line_len;
1753 args->line_buf = g_realloc(args->line_buf, args->line_buf_len + 1);
1754 cp = args->line_buf + cp_off;
1757 /* Right-justify the packet number column. */
1758 if (cf->cinfo.col_fmt[i] == COL_NUMBER)
1759 sprintf(cp, "%*s", args->col_widths[i], cf->cinfo.col_data[i]);
1761 sprintf(cp, "%-*s", args->col_widths[i], cf->cinfo.col_data[i]);
1763 if (i != cf->cinfo.num_cols - 1)
1769 * Generate a bookmark, using the summary line as the title.
1771 if (!print_bookmark(args->print_args->stream, bookmark_name,
1775 if (!print_line(args->print_args->stream, 0, args->line_buf))
1779 * Generate a bookmark, using "Frame N" as the title, as we're not
1780 * printing the summary line.
1782 g_snprintf(bookmark_title, sizeof bookmark_title, "Frame %u", fdata->num);
1783 if (!print_bookmark(args->print_args->stream, bookmark_name,
1786 } /* if (print_summary) */
1788 if (args->print_args->print_dissections != print_dissections_none) {
1789 if (args->print_args->print_summary) {
1790 /* Separate the summary line from the tree with a blank line. */
1791 if (!print_line(args->print_args->stream, 0, ""))
1795 /* Print the information in that tree. */
1796 if (!proto_tree_print(args->print_args, edt, args->print_args->stream))
1799 /* Print a blank line if we print anything after this (aka more than one packet). */
1800 args->print_separator = TRUE;
1802 /* Print a header line if we print any more packet summaries */
1803 args->print_header_line = TRUE;
1806 if (args->print_args->print_hex) {
1807 /* Print the full packet data as hex. */
1808 if (!print_hex_data(args->print_args->stream, edt))
1811 /* Print a blank line if we print anything after this (aka more than one packet). */
1812 args->print_separator = TRUE;
1814 /* Print a header line if we print any more packet summaries */
1815 args->print_header_line = TRUE;
1816 } /* if (args->print_args->print_dissections != print_dissections_none) */
1818 epan_dissect_free(edt);
1820 /* do we want to have a formfeed between each packet from now on? */
1821 if(args->print_args->print_formfeed) {
1822 args->print_formfeed = TRUE;
1828 epan_dissect_free(edt);
1833 cf_print_packets(capture_file *cf, print_args_t *print_args)
1836 print_callback_args_t callback_args;
1844 callback_args.print_args = print_args;
1845 callback_args.print_header_line = TRUE;
1846 callback_args.header_line_buf = NULL;
1847 callback_args.header_line_buf_len = 256;
1848 callback_args.print_formfeed = FALSE;
1849 callback_args.print_separator = FALSE;
1850 callback_args.line_buf = NULL;
1851 callback_args.line_buf_len = 256;
1852 callback_args.col_widths = NULL;
1854 if (!print_preamble(print_args->stream, cf->filename)) {
1855 destroy_print_stream(print_args->stream);
1856 return CF_PRINT_WRITE_ERROR;
1859 if (print_args->print_summary) {
1860 /* We're printing packet summaries. Allocate the header line buffer
1861 and get the column widths. */
1862 callback_args.header_line_buf = g_malloc(callback_args.header_line_buf_len + 1);
1864 /* Find the widths for each of the columns - maximum of the
1865 width of the title and the width of the data - and construct
1866 a buffer with a line containing the column titles. */
1867 callback_args.col_widths = (gint *) g_malloc(sizeof(gint) * cf->cinfo.num_cols);
1868 cp = &callback_args.header_line_buf[0];
1870 for (i = 0; i < cf->cinfo.num_cols; i++) {
1871 /* Don't pad the last column. */
1872 if (i == cf->cinfo.num_cols - 1)
1873 callback_args.col_widths[i] = 0;
1875 callback_args.col_widths[i] = strlen(cf->cinfo.col_title[i]);
1876 data_width = get_column_char_width(get_column_format(i));
1877 if (data_width > callback_args.col_widths[i])
1878 callback_args.col_widths[i] = data_width;
1881 /* Find the length of the string for this column. */
1882 column_len = strlen(cf->cinfo.col_title[i]);
1883 if (callback_args.col_widths[i] > column_len)
1884 column_len = callback_args.col_widths[i];
1886 /* Make sure there's room in the line buffer for the column; if not,
1887 double its length. */
1888 line_len += column_len + 1; /* "+1" for space */
1889 if (line_len > callback_args.header_line_buf_len) {
1890 cp_off = cp - callback_args.header_line_buf;
1891 callback_args.header_line_buf_len = 2 * line_len;
1892 callback_args.header_line_buf = g_realloc(callback_args.header_line_buf,
1893 callback_args.header_line_buf_len + 1);
1894 cp = callback_args.header_line_buf + cp_off;
1897 /* Right-justify the packet number column. */
1898 /* if (cf->cinfo.col_fmt[i] == COL_NUMBER)
1899 sprintf(cp, "%*s", callback_args.col_widths[i], cf->cinfo.col_title[i]);
1901 sprintf(cp, "%-*s", callback_args.col_widths[i], cf->cinfo.col_title[i]);
1903 if (i != cf->cinfo.num_cols - 1)
1908 /* Now start out the main line buffer with the same length as the
1909 header line buffer. */
1910 callback_args.line_buf_len = callback_args.header_line_buf_len;
1911 callback_args.line_buf = g_malloc(callback_args.line_buf_len + 1);
1912 } /* if (print_summary) */
1914 /* Iterate through the list of packets, printing the packets we were
1916 ret = process_specified_packets(cf, &print_args->range, "Printing",
1917 "selected packets", print_packet,
1920 if (callback_args.header_line_buf != NULL)
1921 g_free(callback_args.header_line_buf);
1922 if (callback_args.line_buf != NULL)
1923 g_free(callback_args.line_buf);
1924 if (callback_args.col_widths != NULL)
1925 g_free(callback_args.col_widths);
1930 /* Completed successfully. */
1934 /* Well, the user decided to abort the printing.
1936 XXX - note that what got generated before they did that
1937 will get printed if we're piping to a print program; we'd
1938 have to write to a file and then hand that to the print
1939 program to make it actually not print anything. */
1943 /* Error while printing.
1945 XXX - note that what got generated before they did that
1946 will get printed if we're piping to a print program; we'd
1947 have to write to a file and then hand that to the print
1948 program to make it actually not print anything. */
1949 destroy_print_stream(print_args->stream);
1950 return CF_PRINT_WRITE_ERROR;
1953 if (!print_finale(print_args->stream)) {
1954 destroy_print_stream(print_args->stream);
1955 return CF_PRINT_WRITE_ERROR;
1958 if (!destroy_print_stream(print_args->stream))
1959 return CF_PRINT_WRITE_ERROR;
1965 write_pdml_packet(capture_file *cf _U_, frame_data *fdata,
1966 union wtap_pseudo_header *pseudo_header, const guint8 *pd,
1970 epan_dissect_t *edt;
1972 /* Create the protocol tree, but don't fill in the column information. */
1973 edt = epan_dissect_new(TRUE, TRUE);
1974 epan_dissect_run(edt, pseudo_header, pd, fdata, NULL);
1976 /* Write out the information in that tree. */
1977 proto_tree_write_pdml(edt, fh);
1979 epan_dissect_free(edt);
1985 cf_write_pdml_packets(capture_file *cf, print_args_t *print_args)
1990 fh = fopen(print_args->file, "w");
1992 return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
1994 write_pdml_preamble(fh);
1997 return CF_PRINT_WRITE_ERROR;
2000 /* Iterate through the list of packets, printing the packets we were
2002 ret = process_specified_packets(cf, &print_args->range, "Writing PDML",
2003 "selected packets", write_pdml_packet,
2009 /* Completed successfully. */
2013 /* Well, the user decided to abort the printing. */
2017 /* Error while printing. */
2019 return CF_PRINT_WRITE_ERROR;
2022 write_pdml_finale(fh);
2025 return CF_PRINT_WRITE_ERROR;
2028 /* XXX - check for an error */
2035 write_psml_packet(capture_file *cf, frame_data *fdata,
2036 union wtap_pseudo_header *pseudo_header, const guint8 *pd,
2040 epan_dissect_t *edt;
2042 /* Fill in the column information, but don't create the protocol tree. */
2043 edt = epan_dissect_new(FALSE, FALSE);
2044 epan_dissect_run(edt, pseudo_header, pd, fdata, &cf->cinfo);
2045 epan_dissect_fill_in_columns(edt);
2047 /* Write out the information in that tree. */
2048 proto_tree_write_psml(edt, fh);
2050 epan_dissect_free(edt);
2056 cf_write_psml_packets(capture_file *cf, print_args_t *print_args)
2061 fh = fopen(print_args->file, "w");
2063 return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
2065 write_psml_preamble(fh);
2068 return CF_PRINT_WRITE_ERROR;
2071 /* Iterate through the list of packets, printing the packets we were
2073 ret = process_specified_packets(cf, &print_args->range, "Writing PSML",
2074 "selected packets", write_psml_packet,
2080 /* Completed successfully. */
2084 /* Well, the user decided to abort the printing. */
2088 /* Error while printing. */
2090 return CF_PRINT_WRITE_ERROR;
2093 write_psml_finale(fh);
2096 return CF_PRINT_WRITE_ERROR;
2099 /* XXX - check for an error */
2106 write_csv_packet(capture_file *cf, frame_data *fdata,
2107 union wtap_pseudo_header *pseudo_header, const guint8 *pd,
2111 epan_dissect_t *edt;
2113 /* Fill in the column information, but don't create the protocol tree. */
2114 edt = epan_dissect_new(FALSE, FALSE);
2115 epan_dissect_run(edt, pseudo_header, pd, fdata, &cf->cinfo);
2116 epan_dissect_fill_in_columns(edt);
2118 /* Write out the information in that tree. */
2119 proto_tree_write_csv(edt, fh);
2121 epan_dissect_free(edt);
2127 cf_write_csv_packets(capture_file *cf, print_args_t *print_args)
2132 fh = fopen(print_args->file, "w");
2134 return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
2136 write_csv_preamble(fh);
2139 return CF_PRINT_WRITE_ERROR;
2142 /* Iterate through the list of packets, printing the packets we were
2144 ret = process_specified_packets(cf, &print_args->range, "Writing CSV",
2145 "selected packets", write_csv_packet,
2151 /* Completed successfully. */
2155 /* Well, the user decided to abort the printing. */
2159 /* Error while printing. */
2161 return CF_PRINT_WRITE_ERROR;
2164 write_csv_finale(fh);
2167 return CF_PRINT_WRITE_ERROR;
2170 /* XXX - check for an error */
2176 /* Scan through the packet list and change all columns that use the
2177 "command-line-specified" time stamp format to use the current
2178 value of that format. */
2180 cf_change_time_formats(capture_file *cf)
2183 progdlg_t *progbar = NULL;
2189 GTimeVal start_time;
2190 gchar status_str[100];
2191 int progbar_nextstep;
2192 int progbar_quantum;
2194 gboolean sorted_by_frame_column;
2197 /* adjust timestamp precision if auto is selected */
2198 cf_timestamp_auto_precision(cf);
2200 /* Are there any columns with time stamps in the "command-line-specified"
2203 XXX - we have to force the "column is writable" flag on, as it
2204 might be off from the last frame that was dissected. */
2205 col_set_writable(&cf->cinfo, TRUE);
2206 if (!check_col(&cf->cinfo, COL_CLS_TIME)) {
2207 /* No, there aren't any columns in that format, so we have no work
2211 first = cf->cinfo.col_first[COL_CLS_TIME];
2212 g_assert(first >= 0);
2213 last = cf->cinfo.col_last[COL_CLS_TIME];
2215 /* Freeze the packet list while we redo it, so we don't get any
2216 screen updates while it happens. */
2217 packet_list_freeze();
2219 /* Update the progress bar when it gets to this value. */
2220 progbar_nextstep = 0;
2221 /* When we reach the value that triggers a progress bar update,
2222 bump that value by this amount. */
2223 progbar_quantum = cf->count/N_PROGBAR_UPDATES;
2224 /* Count of packets at which we've looked. */
2227 /* If the rows are currently sorted by the frame column then we know
2228 * the row number of each packet: it's the row number of the previously
2229 * displayed packet + 1.
2231 * Otherwise, if the display is sorted by a different column then we have
2232 * to use the O(N) packet_list_find_row_from_data() (thus making the job
2233 * of changing the time display format O(N**2)).
2235 * (XXX - In fact it's still O(N**2) because gtk_clist_set_text() takes
2236 * the row number and walks that many elements down the clist to find
2237 * the appropriate element.)
2239 sorted_by_frame_column = FALSE;
2240 for (i = 0; i < cf->cinfo.num_cols; i++) {
2241 if (cf->cinfo.col_fmt[i] == COL_NUMBER)
2243 sorted_by_frame_column = (i == packet_list_get_sort_column());
2249 g_get_current_time(&start_time);
2251 /* Iterate through the list of packets, checking whether the packet
2252 is in a row of the summary list and, if so, whether there are
2253 any columns that show the time in the "command-line-specified"
2254 format and, if so, update that row. */
2255 for (fdata = cf->plist, row = -1; fdata != NULL; fdata = fdata->next) {
2256 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
2257 when we update it, we have to run the GTK+ main loop to get it
2258 to repaint what's pending, and doing so may involve an "ioctl()"
2259 to see if there's any pending input from an X server, and doing
2260 that for every packet can be costly, especially on a big file. */
2261 if (count >= progbar_nextstep) {
2262 /* let's not divide by zero. I should never be started
2263 * with count == 0, so let's assert that
2265 g_assert(cf->count > 0);
2267 prog_val = (gfloat) count / cf->count;
2269 if (progbar == NULL)
2270 /* Create the progress bar if necessary */
2271 progbar = delayed_create_progress_dlg("Changing", "time display",
2272 &stop_flag, &start_time, prog_val);
2274 if (progbar != NULL) {
2275 g_snprintf(status_str, sizeof(status_str),
2276 "%4u of %u packets", count, cf->count);
2277 update_progress_dlg(progbar, prog_val, status_str);
2280 progbar_nextstep += progbar_quantum;
2284 /* Well, the user decided to abort the redisplay. Just stop.
2286 XXX - this leaves the time field in the old format in
2287 frames we haven't yet processed. So it goes; should we
2288 simply not offer them the option of stopping? */
2294 /* Find what row this packet is in. */
2295 if (!sorted_by_frame_column) {
2296 /* This function is O(N), so we try to avoid using it... */
2297 row = packet_list_find_row_from_data(fdata);
2299 /* ...which we do by maintaining a count of packets that are
2300 being displayed (i.e., that have passed the display filter),
2301 and using the current value of that count as the row number
2302 (which is why we can only do it when the display is sorted
2303 by the frame number). */
2304 if (fdata->flags.passed_dfilter)
2311 /* This packet is in the summary list, on row "row". */
2313 for (i = first; i <= last; i++) {
2314 if (cf->cinfo.fmt_matx[i][COL_CLS_TIME]) {
2315 /* This is one of the columns that shows the time in
2316 "command-line-specified" format; update it. */
2317 cf->cinfo.col_buf[i][0] = '\0';
2318 col_set_cls_time(fdata, &cf->cinfo, i);
2319 packet_list_set_text(row, i, cf->cinfo.col_data[i]);
2325 /* We're done redisplaying the packets; destroy the progress bar if it
2327 if (progbar != NULL)
2328 destroy_progress_dlg(progbar);
2330 /* Set the column widths of those columns that show the time in
2331 "command-line-specified" format. */
2332 for (i = first; i <= last; i++) {
2333 if (cf->cinfo.fmt_matx[i][COL_CLS_TIME]) {
2334 packet_list_set_cls_time_width(i);
2338 /* Unfreeze the packet list. */
2346 gboolean frame_matched;
2350 cf_find_packet_protocol_tree(capture_file *cf, const char *string)
2354 mdata.string = string;
2355 mdata.string_len = strlen(string);
2356 return find_packet(cf, match_protocol_tree, &mdata);
2360 match_protocol_tree(capture_file *cf, frame_data *fdata, void *criterion)
2362 match_data *mdata = criterion;
2363 epan_dissect_t *edt;
2365 /* Construct the protocol tree, including the displayed text */
2366 edt = epan_dissect_new(TRUE, TRUE);
2367 /* We don't need the column information */
2368 epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, NULL);
2370 /* Iterate through all the nodes, seeing if they have text that matches. */
2372 mdata->frame_matched = FALSE;
2373 proto_tree_children_foreach(edt->tree, match_subtree_text, mdata);
2374 epan_dissect_free(edt);
2375 return mdata->frame_matched;
2379 match_subtree_text(proto_node *node, gpointer data)
2381 match_data *mdata = (match_data*) data;
2382 const gchar *string = mdata->string;
2383 size_t string_len = mdata->string_len;
2384 capture_file *cf = mdata->cf;
2385 field_info *fi = PITEM_FINFO(node);
2386 gchar label_str[ITEM_LABEL_LENGTH];
2393 if (mdata->frame_matched) {
2394 /* We already had a match; don't bother doing any more work. */
2398 /* Don't match invisible entries. */
2399 if (PROTO_ITEM_IS_HIDDEN(node))
2402 /* was a free format label produced? */
2404 label_ptr = fi->rep->representation;
2406 /* no, make a generic label */
2407 label_ptr = label_str;
2408 proto_item_fill_label(fi, label_str);
2411 /* Does that label match? */
2412 label_len = strlen(label_ptr);
2413 for (i = 0; i < label_len; i++) {
2414 c_char = label_ptr[i];
2416 c_char = toupper(c_char);
2417 if (c_char == string[c_match]) {
2419 if (c_match == string_len) {
2420 /* No need to look further; we have a match */
2421 mdata->frame_matched = TRUE;
2428 /* Recurse into the subtree, if it exists */
2429 if (node->first_child != NULL)
2430 proto_tree_children_foreach(node, match_subtree_text, mdata);
2434 cf_find_packet_summary_line(capture_file *cf, const char *string)
2438 mdata.string = string;
2439 mdata.string_len = strlen(string);
2440 return find_packet(cf, match_summary_line, &mdata);
2444 match_summary_line(capture_file *cf, frame_data *fdata, void *criterion)
2446 match_data *mdata = criterion;
2447 const gchar *string = mdata->string;
2448 size_t string_len = mdata->string_len;
2449 epan_dissect_t *edt;
2450 const char *info_column;
2451 size_t info_column_len;
2452 gboolean frame_matched = FALSE;
2458 /* Don't bother constructing the protocol tree */
2459 edt = epan_dissect_new(FALSE, FALSE);
2460 /* Get the column information */
2461 epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, &cf->cinfo);
2463 /* Find the Info column */
2464 for (colx = 0; colx < cf->cinfo.num_cols; colx++) {
2465 if (cf->cinfo.fmt_matx[colx][COL_INFO]) {
2466 /* Found it. See if we match. */
2467 info_column = edt->pi.cinfo->col_data[colx];
2468 info_column_len = strlen(info_column);
2469 for (i = 0; i < info_column_len; i++) {
2470 c_char = info_column[i];
2472 c_char = toupper(c_char);
2473 if (c_char == string[c_match]) {
2475 if (c_match == string_len) {
2476 frame_matched = TRUE;
2485 epan_dissect_free(edt);
2486 return frame_matched;
2492 } cbs_t; /* "Counted byte string" */
2495 cf_find_packet_data(capture_file *cf, const guint8 *string, size_t string_size)
2500 info.data_len = string_size;
2502 /* String or hex search? */
2504 /* String search - what type of string? */
2505 switch (cf->scs_type) {
2507 case SCS_ASCII_AND_UNICODE:
2508 return find_packet(cf, match_ascii_and_unicode, &info);
2511 return find_packet(cf, match_ascii, &info);
2514 return find_packet(cf, match_unicode, &info);
2517 g_assert_not_reached();
2521 return find_packet(cf, match_binary, &info);
2525 match_ascii_and_unicode(capture_file *cf, frame_data *fdata, void *criterion)
2527 cbs_t *info = criterion;
2528 const char *ascii_text = info->data;
2529 size_t textlen = info->data_len;
2530 gboolean frame_matched;
2536 frame_matched = FALSE;
2537 buf_len = fdata->pkt_len;
2538 for (i = 0; i < buf_len; i++) {
2541 c_char = toupper(c_char);
2543 if (c_char == ascii_text[c_match]) {
2545 if (c_match == textlen) {
2546 frame_matched = TRUE;
2553 return frame_matched;
2557 match_ascii(capture_file *cf, frame_data *fdata, void *criterion)
2559 cbs_t *info = criterion;
2560 const char *ascii_text = info->data;
2561 size_t textlen = info->data_len;
2562 gboolean frame_matched;
2568 frame_matched = FALSE;
2569 buf_len = fdata->pkt_len;
2570 for (i = 0; i < buf_len; i++) {
2573 c_char = toupper(c_char);
2574 if (c_char == ascii_text[c_match]) {
2576 if (c_match == textlen) {
2577 frame_matched = TRUE;
2583 return frame_matched;
2587 match_unicode(capture_file *cf, frame_data *fdata, void *criterion)
2589 cbs_t *info = criterion;
2590 const char *ascii_text = info->data;
2591 size_t textlen = info->data_len;
2592 gboolean frame_matched;
2598 frame_matched = FALSE;
2599 buf_len = fdata->pkt_len;
2600 for (i = 0; i < buf_len; i++) {
2603 c_char = toupper(c_char);
2604 if (c_char == ascii_text[c_match]) {
2607 if (c_match == textlen) {
2608 frame_matched = TRUE;
2614 return frame_matched;
2618 match_binary(capture_file *cf, frame_data *fdata, void *criterion)
2620 cbs_t *info = criterion;
2621 const guint8 *binary_data = info->data;
2622 size_t datalen = info->data_len;
2623 gboolean frame_matched;
2628 frame_matched = FALSE;
2629 buf_len = fdata->pkt_len;
2630 for (i = 0; i < buf_len; i++) {
2631 if (cf->pd[i] == binary_data[c_match]) {
2633 if (c_match == datalen) {
2634 frame_matched = TRUE;
2640 return frame_matched;
2644 cf_find_packet_dfilter(capture_file *cf, dfilter_t *sfcode)
2646 return find_packet(cf, match_dfilter, sfcode);
2650 match_dfilter(capture_file *cf, frame_data *fdata, void *criterion)
2652 dfilter_t *sfcode = criterion;
2653 epan_dissect_t *edt;
2654 gboolean frame_matched;
2656 edt = epan_dissect_new(TRUE, FALSE);
2657 epan_dissect_prime_dfilter(edt, sfcode);
2658 epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, NULL);
2659 frame_matched = dfilter_apply_edt(sfcode, edt);
2660 epan_dissect_free(edt);
2661 return frame_matched;
2665 find_packet(capture_file *cf,
2666 gboolean (*match_function)(capture_file *, frame_data *, void *),
2669 frame_data *start_fd;
2671 frame_data *new_fd = NULL;
2672 progdlg_t *progbar = NULL;
2679 GTimeVal start_time;
2680 gchar status_str[100];
2681 int progbar_nextstep;
2682 int progbar_quantum;
2684 start_fd = cf->current_frame;
2685 if (start_fd != NULL) {
2686 /* Iterate through the list of packets, starting at the packet we've
2687 picked, calling a routine to run the filter on the packet, see if
2688 it matches, and stop if so. */
2692 progbar_nextstep = 0;
2693 /* When we reach the value that triggers a progress bar update,
2694 bump that value by this amount. */
2695 progbar_quantum = cf->count/N_PROGBAR_UPDATES;
2698 g_get_current_time(&start_time);
2702 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
2703 when we update it, we have to run the GTK+ main loop to get it
2704 to repaint what's pending, and doing so may involve an "ioctl()"
2705 to see if there's any pending input from an X server, and doing
2706 that for every packet can be costly, especially on a big file. */
2707 if (count >= progbar_nextstep) {
2708 /* let's not divide by zero. I should never be started
2709 * with count == 0, so let's assert that
2711 g_assert(cf->count > 0);
2713 prog_val = (gfloat) count / cf->count;
2715 /* Create the progress bar if necessary */
2716 if (progbar == NULL)
2717 progbar = delayed_create_progress_dlg("Searching", cf->sfilter,
2718 &stop_flag, &start_time, prog_val);
2720 if (progbar != NULL) {
2721 g_snprintf(status_str, sizeof(status_str),
2722 "%4u of %u packets", count, cf->count);
2723 update_progress_dlg(progbar, prog_val, status_str);
2726 progbar_nextstep += progbar_quantum;
2730 /* Well, the user decided to abort the search. Go back to the
2731 frame where we started. */
2736 /* Go past the current frame. */
2737 if (cf->sbackward) {
2738 /* Go on to the previous frame. */
2739 fdata = fdata->prev;
2740 if (fdata == NULL) {
2742 * XXX - other apps have a bit more of a detailed message
2743 * for this, and instead of offering "OK" and "Cancel",
2744 * they offer things such as "Continue" and "Cancel";
2745 * we need an API for popping up alert boxes with
2746 * {Verb} and "Cancel".
2749 if (prefs.gui_find_wrap)
2751 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
2752 "%sBeginning of capture exceeded!%s\n\n"
2753 "Search is continued from the end of the capture.",
2754 simple_dialog_primary_start(), simple_dialog_primary_end());
2755 fdata = cf->plist_end; /* wrap around */
2759 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
2760 "%sBeginning of capture exceeded!%s\n\n"
2761 "Try searching forwards.",
2762 simple_dialog_primary_start(), simple_dialog_primary_end());
2763 fdata = start_fd; /* stay on previous packet */
2767 /* Go on to the next frame. */
2768 fdata = fdata->next;
2769 if (fdata == NULL) {
2770 if (prefs.gui_find_wrap)
2772 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
2773 "%sEnd of capture exceeded!%s\n\n"
2774 "Search is continued from the start of the capture.",
2775 simple_dialog_primary_start(), simple_dialog_primary_end());
2776 fdata = cf->plist; /* wrap around */
2780 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
2781 "%sEnd of capture exceeded!%s\n\n"
2782 "Try searching backwards.",
2783 simple_dialog_primary_start(), simple_dialog_primary_end());
2784 fdata = start_fd; /* stay on previous packet */
2791 /* Is this packet in the display? */
2792 if (fdata->flags.passed_dfilter) {
2793 /* Yes. Load its data. */
2794 if (!wtap_seek_read(cf->wth, fdata->file_off, &cf->pseudo_header,
2795 cf->pd, fdata->cap_len, &err, &err_info)) {
2796 /* Read error. Report the error, and go back to the frame
2797 where we started. */
2798 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
2799 cf_read_error_message(err, err_info), cf->filename);
2804 /* Does it match the search criterion? */
2805 if ((*match_function)(cf, fdata, criterion)) {
2807 break; /* found it! */
2811 if (fdata == start_fd) {
2812 /* We're back to the frame we were on originally, and that frame
2813 doesn't match the search filter. The search failed. */
2818 /* We're done scanning the packets; destroy the progress bar if it
2820 if (progbar != NULL)
2821 destroy_progress_dlg(progbar);
2824 if (new_fd != NULL) {
2825 /* We found a frame. Find what row it's in. */
2826 row = packet_list_find_row_from_data(new_fd);
2827 g_assert(row != -1);
2829 /* Select that row, make it the focus row, and make it visible. */
2830 packet_list_set_selected_row(row);
2831 return TRUE; /* success */
2833 return FALSE; /* failure */
2837 cf_goto_frame(capture_file *cf, guint fnumber)
2842 for (fdata = cf->plist; fdata != NULL && fdata->num < fnumber; fdata = fdata->next)
2845 if (fdata == NULL) {
2846 /* we didn't find a packet with that packet number */
2847 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
2848 "There is no packet with the packet number %u.", fnumber);
2849 return FALSE; /* we failed to go to that packet */
2851 if (!fdata->flags.passed_dfilter) {
2852 /* that packet currently isn't displayed */
2853 /* XXX - add it to the set of displayed packets? */
2854 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
2855 "The packet number %u isn't currently being displayed.", fnumber);
2856 return FALSE; /* we failed to go to that packet */
2859 /* We found that packet, and it's currently being displayed.
2860 Find what row it's in. */
2861 row = packet_list_find_row_from_data(fdata);
2862 g_assert(row != -1);
2864 /* Select that row, make it the focus row, and make it visible. */
2865 packet_list_set_selected_row(row);
2866 return TRUE; /* we got to that packet */
2870 cf_goto_top_frame(capture_file *cf)
2874 frame_data *lowest_fdata = NULL;
2876 for (fdata = cf->plist; fdata != NULL; fdata = fdata->next) {
2877 if (fdata->flags.passed_dfilter) {
2878 lowest_fdata = fdata;
2883 if (lowest_fdata == NULL) {
2887 /* We found that packet, and it's currently being displayed.
2888 Find what row it's in. */
2889 row = packet_list_find_row_from_data(lowest_fdata);
2890 g_assert(row != -1);
2892 /* Select that row, make it the focus row, and make it visible. */
2893 packet_list_set_selected_row(row);
2894 return TRUE; /* we got to that packet */
2898 cf_goto_bottom_frame(capture_file *cf)
2902 frame_data *highest_fdata = NULL;
2904 for (fdata = cf->plist; fdata != NULL; fdata = fdata->next) {
2905 if (fdata->flags.passed_dfilter) {
2906 highest_fdata = fdata;
2910 if (highest_fdata == NULL) {
2914 /* We found that packet, and it's currently being displayed.
2915 Find what row it's in. */
2916 row = packet_list_find_row_from_data(highest_fdata);
2917 g_assert(row != -1);
2919 /* Select that row, make it the focus row, and make it visible. */
2920 packet_list_set_selected_row(row);
2921 return TRUE; /* we got to that packet */
2925 * Go to frame specified by currently selected protocol tree item.
2928 cf_goto_framenum(capture_file *cf)
2930 header_field_info *hfinfo;
2933 if (cf->finfo_selected) {
2934 hfinfo = cf->finfo_selected->hfinfo;
2936 if (hfinfo->type == FT_FRAMENUM) {
2937 framenum = fvalue_get_integer(&cf->finfo_selected->value);
2939 return cf_goto_frame(cf, framenum);
2946 /* Select the packet on a given row. */
2948 cf_select_packet(capture_file *cf, int row)
2954 /* Get the frame data struct pointer for this frame */
2955 fdata = (frame_data *)packet_list_get_row_data(row);
2957 if (fdata == NULL) {
2958 /* XXX - if a GtkCList's selection mode is GTK_SELECTION_BROWSE, when
2959 the first entry is added to it by "real_insert_row()", that row
2960 is selected (see "real_insert_row()", in "gtk/gtkclist.c", in both
2961 our version and the vanilla GTK+ version).
2963 This means that a "select-row" signal is emitted; this causes
2964 "packet_list_select_cb()" to be called, which causes "cf_select_packet()"
2967 "cf_select_packet()" fetches, above, the data associated with the
2968 row that was selected; however, as "gtk_clist_append()", which
2969 called "real_insert_row()", hasn't yet returned, we haven't yet
2970 associated any data with that row, so we get back a null pointer.
2972 We can't assume that there's only one frame in the frame list,
2973 either, as we may be filtering the display.
2975 We therefore assume that, if "row" is 0, i.e. the first row
2976 is being selected, and "cf->first_displayed" equals
2977 "cf->last_displayed", i.e. there's only one frame being
2978 displayed, that frame is the frame we want.
2980 This means we have to set "cf->first_displayed" and
2981 "cf->last_displayed" before adding the row to the
2982 GtkCList; see the comment in "add_packet_to_packet_list()". */
2984 if (row == 0 && cf->first_displayed == cf->last_displayed)
2985 fdata = cf->first_displayed;
2988 /* Get the data in that frame. */
2989 if (!wtap_seek_read (cf->wth, fdata->file_off, &cf->pseudo_header,
2990 cf->pd, fdata->cap_len, &err, &err_info)) {
2991 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
2992 cf_read_error_message(err, err_info), cf->filename);
2996 /* Record that this frame is the current frame. */
2997 cf->current_frame = fdata;
2999 /* Create the logical protocol tree. */
3000 if (cf->edt != NULL) {
3001 epan_dissect_free(cf->edt);
3004 /* We don't need the columns here. */
3005 cf->edt = epan_dissect_new(TRUE, TRUE);
3006 epan_dissect_run(cf->edt, &cf->pseudo_header, cf->pd, cf->current_frame,
3009 cf_callback_invoke(cf_cb_packet_selected, cf);
3012 /* Unselect the selected packet, if any. */
3014 cf_unselect_packet(capture_file *cf)
3016 /* Destroy the epan_dissect_t for the unselected packet. */
3017 if (cf->edt != NULL) {
3018 epan_dissect_free(cf->edt);
3022 /* No packet is selected. */
3023 cf->current_frame = NULL;
3025 cf_callback_invoke(cf_cb_packet_unselected, cf);
3027 /* No protocol tree means no selected field. */
3028 cf_unselect_field(cf);
3031 /* Unset the selected protocol tree field, if any. */
3033 cf_unselect_field(capture_file *cf)
3035 cf->finfo_selected = NULL;
3037 cf_callback_invoke(cf_cb_field_unselected, cf);
3041 * Mark a particular frame.
3044 cf_mark_frame(capture_file *cf, frame_data *frame)
3046 if (! frame->flags.marked) {
3047 frame->flags.marked = TRUE;
3048 if (cf->count > cf->marked_count)
3054 * Unmark a particular frame.
3057 cf_unmark_frame(capture_file *cf, frame_data *frame)
3059 if (frame->flags.marked) {
3060 frame->flags.marked = FALSE;
3061 if (cf->marked_count > 0)
3069 } save_callback_args_t;
3072 * Save a capture to a file, in a particular format, saving either
3073 * all packets, all currently-displayed packets, or all marked packets.
3075 * Returns TRUE if it succeeds, FALSE otherwise; if it fails, it pops
3076 * up a message box for the failure.
3079 save_packet(capture_file *cf _U_, frame_data *fdata,
3080 union wtap_pseudo_header *pseudo_header, const guint8 *pd,
3083 save_callback_args_t *args = argsp;
3084 struct wtap_pkthdr hdr;
3087 /* init the wtap header for saving */
3088 hdr.ts = *(struct wtap_nstime *) &fdata->abs_ts;
3089 hdr.caplen = fdata->cap_len;
3090 hdr.len = fdata->pkt_len;
3091 hdr.pkt_encap = fdata->lnk_t;
3093 /* and save the packet */
3094 if (!wtap_dump(args->pdh, &hdr, pseudo_header, pd, &err)) {
3095 cf_write_failure_alert_box(args->fname, err);
3102 cf_save(capture_file *cf, const char *fname, packet_range_t *range, guint save_format, gboolean compressed)
3104 gchar *from_filename;
3108 save_callback_args_t callback_args;
3110 cf_callback_invoke(cf_cb_file_safe_started, (gpointer) fname);
3112 /* don't write over an existing file. */
3113 /* this should've been already checked by our caller, just to be sure... */
3114 if (file_exists(fname)) {
3115 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3116 "%sCapture file: \"%s\" already exists!%s\n\n"
3117 "Please choose a different filename.",
3118 simple_dialog_primary_start(), fname, simple_dialog_primary_end());
3122 packet_range_process_init(range);
3125 if (packet_range_process_all(range) && save_format == cf->cd_t) {
3126 /* We're not filtering packets, and we're saving it in the format
3127 it's already in, so we can just move or copy the raw data. */
3129 if (cf->is_tempfile) {
3130 /* The file being saved is a temporary file from a live
3131 capture, so it doesn't need to stay around under that name;
3132 first, try renaming the capture buffer file to the new name. */
3134 if (rename(cf->filename, fname) == 0) {
3135 /* That succeeded - there's no need to copy the source file. */
3136 from_filename = NULL;
3139 if (errno == EXDEV) {
3140 /* They're on different file systems, so we have to copy the
3143 from_filename = cf->filename;
3145 /* The rename failed, but not because they're on different
3146 file systems - put up an error message. (Or should we
3147 just punt and try to copy? The only reason why I'd
3148 expect the rename to fail and the copy to succeed would
3149 be if we didn't have permission to remove the file from
3150 the temporary directory, and that might be fixable - but
3151 is it worth requiring the user to go off and fix it?) */
3152 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3153 file_rename_error_message(errno), fname);
3159 from_filename = cf->filename;
3162 /* It's a permanent file, so we should copy it, and not remove the
3165 from_filename = cf->filename;
3169 /* Copy the file, if we haven't moved it. */
3170 if (!copy_binary_file(from_filename, fname))
3174 /* Either we're filtering packets, or we're saving in a different
3175 format; we can't do that by copying or moving the capture file,
3176 we have to do it by writing the packets out in Wiretap. */
3177 pdh = wtap_dump_open(fname, save_format, cf->lnk_t, cf->snap,
3180 cf_open_failure_alert_box(fname, err, NULL, TRUE, save_format);
3184 /* XXX - we let the user save a subset of the packets.
3186 If we do that, should we make that file the current file? If so,
3187 it means we can no longer get at the other packets. What does
3190 /* Iterate through the list of packets, processing the packets we were
3193 XXX - we've already called "packet_range_process_init(range)", but
3194 "process_specified_packets()" will do it again. Fortunately,
3195 that's harmless in this case, as we haven't done anything to
3196 "range" since we initialized it. */
3197 callback_args.pdh = pdh;
3198 callback_args.fname = fname;
3199 switch (process_specified_packets(cf, range, "Saving",
3200 "selected packets", save_packet,
3204 /* Completed successfully. */
3208 /* The user decided to abort the saving.
3209 XXX - remove the output file? */
3213 /* Error while saving. */
3214 wtap_dump_close(pdh, &err);
3218 if (!wtap_dump_close(pdh, &err)) {
3219 cf_close_failure_alert_box(fname, err);
3224 cf_callback_invoke(cf_cb_file_safe_finished, NULL);
3226 if (packet_range_process_all(range)) {
3227 /* We saved the entire capture, not just some packets from it.
3228 Open and read the file we saved it to.
3230 XXX - this is somewhat of a waste; we already have the
3231 packets, all this gets us is updated file type information
3232 (which we could just stuff into "cf"), and having the new
3233 file be the one we have opened and from which we're reading
3234 the data, and it means we have to spend time opening and
3235 reading the file, which could be a significant amount of
3236 time if the file is large. */
3237 cf->user_saved = TRUE;
3239 if ((cf_open(cf, fname, FALSE, &err)) == CF_OK) {
3240 /* XXX - report errors if this fails?
3241 What should we return if it fails or is aborted? */
3242 switch (cf_read(cf)) {
3246 /* Just because we got an error, that doesn't mean we were unable
3247 to read any of the file; we handle what we could get from the
3251 case CF_READ_ABORTED:
3252 /* The user bailed out of re-reading the capture file; the
3253 capture file has been closed - just return (without
3254 changing any menu settings; "cf_close()" set them
3255 correctly for the "no capture file open" state). */
3258 cf_callback_invoke(cf_cb_file_safe_reload_finished, NULL);
3264 cf_callback_invoke(cf_cb_file_safe_failed, NULL);
3269 cf_open_failure_alert_box(const char *filename, int err, gchar *err_info,
3270 gboolean for_writing, int file_type)
3273 /* Wiretap error. */
3276 case WTAP_ERR_NOT_REGULAR_FILE:
3277 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3278 "The file \"%s\" is a \"special file\" or socket or other non-regular file.",
3282 case WTAP_ERR_RANDOM_OPEN_PIPE:
3283 /* Seen only when opening a capture file for reading. */
3284 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3285 "The file \"%s\" is a pipe or FIFO; Ethereal can't read pipe or FIFO files.",
3289 case WTAP_ERR_FILE_UNKNOWN_FORMAT:
3290 /* Seen only when opening a capture file for reading. */
3291 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3292 "The file \"%s\" isn't a capture file in a format Ethereal understands.",
3296 case WTAP_ERR_UNSUPPORTED:
3297 /* Seen only when opening a capture file for reading. */
3298 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3299 "The file \"%s\" isn't a capture file in a format Ethereal understands.\n"
3301 filename, err_info);
3305 case WTAP_ERR_CANT_WRITE_TO_PIPE:
3306 /* Seen only when opening a capture file for writing. */
3307 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3308 "The file \"%s\" is a pipe, and %s capture files can't be "
3309 "written to a pipe.",
3310 filename, wtap_file_type_string(file_type));
3313 case WTAP_ERR_UNSUPPORTED_FILE_TYPE:
3314 /* Seen only when opening a capture file for writing. */
3315 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3316 "Ethereal doesn't support writing capture files in that format.");
3319 case WTAP_ERR_UNSUPPORTED_ENCAP:
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.\n"
3327 filename, err_info);
3332 case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED:
3334 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3335 "Ethereal can't save this capture in that format.");
3337 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3338 "The file \"%s\" is a capture for a network type that Ethereal doesn't support.",
3343 case WTAP_ERR_BAD_RECORD:
3344 /* Seen only when opening a capture file for reading. */
3345 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3346 "The file \"%s\" appears to be damaged or corrupt.\n"
3348 filename, err_info);
3352 case WTAP_ERR_CANT_OPEN:
3354 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3355 "The file \"%s\" could not be created for some unknown reason.",
3358 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3359 "The file \"%s\" could not be opened for some unknown reason.",
3364 case WTAP_ERR_SHORT_READ:
3365 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3366 "The file \"%s\" appears to have been cut short"
3367 " in the middle of a packet or other data.",
3371 case WTAP_ERR_SHORT_WRITE:
3372 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3373 "A full header couldn't be written to the file \"%s\".",
3377 case WTAP_ERR_COMPRESSION_NOT_SUPPORTED:
3378 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3379 "Gzip compression not supported by this file type.");
3383 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3384 "The file \"%s\" could not be %s: %s.",
3386 for_writing ? "created" : "opened",
3387 wtap_strerror(err));
3392 open_failure_alert_box(filename, err, for_writing);
3397 file_rename_error_message(int err)
3400 static char errmsg_errno[1024+1];
3405 errmsg = "The path to the file \"%s\" doesn't exist.";
3409 errmsg = "You don't have permission to move the capture file to \"%s\".";
3413 g_snprintf(errmsg_errno, sizeof(errmsg_errno),
3414 "The file \"%%s\" could not be moved: %s.",
3415 wtap_strerror(err));
3416 errmsg = errmsg_errno;
3423 cf_read_error_message(int err, const gchar *err_info)
3425 static char errmsg_errno[1024+1];
3429 case WTAP_ERR_UNSUPPORTED_ENCAP:
3430 g_snprintf(errmsg_errno, sizeof(errmsg_errno),
3431 "The file \"%%s\" has a packet with a network type that Ethereal doesn't support.\n(%s)",
3435 case WTAP_ERR_BAD_RECORD:
3436 g_snprintf(errmsg_errno, sizeof(errmsg_errno),
3437 "An error occurred while reading from the file \"%%s\": %s.\n(%s)",
3438 wtap_strerror(err), err_info);
3442 g_snprintf(errmsg_errno, sizeof(errmsg_errno),
3443 "An error occurred while reading from the file \"%%s\": %s.",
3444 wtap_strerror(err));
3447 return errmsg_errno;
3451 cf_write_failure_alert_box(const char *filename, int err)
3454 /* Wiretap error. */
3455 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3456 "An error occurred while writing to the file \"%s\": %s.",
3457 filename, wtap_strerror(err));
3460 write_failure_alert_box(filename, err);
3464 /* Check for write errors - if the file is being written to an NFS server,
3465 a write error may not show up until the file is closed, as NFS clients
3466 might not send writes to the server until the "write()" call finishes,
3467 so that the write may fail on the server but the "write()" may succeed. */
3469 cf_close_failure_alert_box(const char *filename, int err)
3472 /* Wiretap error. */
3475 case WTAP_ERR_CANT_CLOSE:
3476 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3477 "The file \"%s\" couldn't be closed for some unknown reason.",
3481 case WTAP_ERR_SHORT_WRITE:
3482 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3483 "Not all the packets could be written to the file \"%s\".",
3488 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3489 "An error occurred while closing the file \"%s\": %s.",
3490 filename, wtap_strerror(err));
3495 We assume that a close error from the OS is really a write error. */
3496 write_failure_alert_box(filename, err);
3500 /* Reload the current capture file. */
3502 cf_reload(capture_file *cf) {
3504 gboolean is_tempfile;
3507 /* If the file could be opened, "cf_open()" calls "cf_close()"
3508 to get rid of state for the old capture file before filling in state
3509 for the new capture file. "cf_close()" will remove the file if
3510 it's a temporary file; we don't want that to happen (for one thing,
3511 it'd prevent subsequent reopens from working). Remember whether it's
3512 a temporary file, mark it as not being a temporary file, and then
3513 reopen it as the type of file it was.
3515 Also, "cf_close()" will free "cf->filename", so we must make
3516 a copy of it first. */
3517 filename = g_strdup(cf->filename);
3518 is_tempfile = cf->is_tempfile;
3519 cf->is_tempfile = FALSE;
3520 if (cf_open(cf, filename, is_tempfile, &err) == CF_OK) {
3521 switch (cf_read(cf)) {
3525 /* Just because we got an error, that doesn't mean we were unable
3526 to read any of the file; we handle what we could get from the
3530 case CF_READ_ABORTED:
3531 /* The user bailed out of re-reading the capture file; the
3532 capture file has been closed - just free the capture file name
3533 string and return (without changing the last containing
3539 /* The open failed, so "cf->is_tempfile" wasn't set to "is_tempfile".
3540 Instead, the file was left open, so we should restore "cf->is_tempfile"
3543 XXX - change the menu? Presumably "cf_open()" will do that;
3544 make sure it does! */
3545 cf->is_tempfile = is_tempfile;
3547 /* "cf_open()" made a copy of the file name we handed it, so
3548 we should free up our copy. */
3552 /* Copies a file in binary mode, for those operating systems that care about
3554 * Returns TRUE on success, FALSE on failure. If a failure, it also
3555 * displays a simple dialog window with the error message.
3558 copy_binary_file(const char *from_filename, const char *to_filename)
3560 int from_fd, to_fd, nread, nwritten, err;
3563 /* Copy the raw bytes of the file. */
3564 from_fd = open(from_filename, O_RDONLY | O_BINARY);
3566 open_failure_alert_box(from_filename, errno, FALSE);
3570 /* Use open() instead of creat() so that we can pass the O_BINARY
3571 flag, which is relevant on Win32; it appears that "creat()"
3572 may open the file in text mode, not binary mode, but we want
3573 to copy the raw bytes of the file, so we need the output file
3574 to be open in binary mode. */
3575 to_fd = open(to_filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
3577 open_failure_alert_box(to_filename, errno, TRUE);
3582 while ((nread = read(from_fd, pd, sizeof pd)) > 0) {
3583 nwritten = write(to_fd, pd, nread);
3584 if (nwritten < nread) {
3588 err = WTAP_ERR_SHORT_WRITE;
3589 write_failure_alert_box(to_filename, err);
3597 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3598 "An error occurred while reading from the file \"%s\": %s.",
3599 from_filename, strerror(err));
3605 if (close(to_fd) < 0) {
3606 write_failure_alert_box(to_filename, errno);