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.
46 #ifdef HAVE_SYS_STAT_H
54 #ifdef NEED_SNPRINTF_H
55 # include "snprintf.h"
58 #ifdef NEED_STRERROR_H
62 #include <epan/epan.h>
63 #include <epan/filesystem.h>
66 #include "color_filters.h"
67 #include <epan/column.h>
68 #include <epan/packet.h>
69 #include "packet-range.h"
74 #include "alert_box.h"
75 #include "simple_dialog.h"
76 #include "progress_dlg.h"
78 #include <epan/prefs.h>
79 #include <epan/dfilter/dfilter.h>
80 #include <epan/conversation.h>
81 #include <epan/epan_dissect.h>
83 #include "tap_dfilter_dlg.h"
84 #include <epan/dissectors/packet-data.h>
86 /* Win32 needs the O_BINARY flag for open() */
92 gboolean auto_scroll_live;
95 static guint32 firstsec, firstusec;
96 static guint32 prevsec, prevusec;
97 static guint32 cum_bytes = 0;
99 static void cf_reset_state(capture_file *cf);
101 static void read_packet(capture_file *cf, long offset);
103 static void rescan_packets(capture_file *cf, const char *action, const char *action_item,
104 gboolean refilter, gboolean redissect);
106 static gboolean match_protocol_tree(capture_file *cf, frame_data *fdata,
108 static void match_subtree_text(proto_node *node, gpointer data);
109 static gboolean match_summary_line(capture_file *cf, frame_data *fdata,
111 static gboolean match_ascii_and_unicode(capture_file *cf, frame_data *fdata,
113 static gboolean match_ascii(capture_file *cf, frame_data *fdata,
115 static gboolean match_unicode(capture_file *cf, frame_data *fdata,
117 static gboolean match_binary(capture_file *cf, frame_data *fdata,
119 static gboolean match_dfilter(capture_file *cf, frame_data *fdata,
121 static gboolean find_packet(capture_file *cf,
122 gboolean (*match_function)(capture_file *, frame_data *, void *),
125 static void cf_open_failure_alert_box(const char *filename, int err,
126 gchar *err_info, gboolean for_writing,
128 static char *file_rename_error_message(int err);
129 static void cf_write_failure_alert_box(const char *filename, int err);
130 static void cf_close_failure_alert_box(const char *filename, int err);
131 static gboolean copy_binary_file(const char *from_filename, const char *to_filename);
133 /* Update the progress bar this many times when reading a file. */
134 #define N_PROGBAR_UPDATES 100
136 /* Number of "frame_data" structures per memory chunk.
137 XXX - is this the right number? */
138 #define FRAME_DATA_CHUNK_SIZE 1024
141 /* one callback for now, we could have a list later */
142 static cf_callback_t cf_cb = NULL;
143 static gpointer cf_cb_user_data = NULL;
146 cf_callback_invoke(int event, gpointer data)
148 g_assert(cf_cb != NULL);
149 cf_cb(event, data, cf_cb_user_data);
154 cf_callback_add(cf_callback_t func, gpointer user_data)
156 /* More than one callback listener is currently not implemented,
157 but should be easy to do. */
158 g_assert(cf_cb == NULL);
160 cf_cb_user_data = user_data;
164 cf_callback_remove(cf_callback_t func _U_)
166 g_assert(cf_cb != NULL);
168 cf_cb_user_data = NULL;
173 cf_open(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
180 wth = wtap_open_offline(fname, err, &err_info, TRUE);
184 /* Find the size of the file. */
186 if (fstat(fd, &cf_stat) < 0) {
192 /* The open succeeded. Close whatever capture file we had open,
193 and fill in the information for this file. */
196 /* Initialize all data structures used for dissection. */
199 /* We're about to start reading the file. */
200 cf->state = FILE_READ_IN_PROGRESS;
204 cf->f_len = cf_stat.st_size;
206 /* Set the file name because we need it to set the follow stream filter.
207 XXX - is that still true? We need it for other reasons, though,
209 cf->filename = g_strdup(fname);
211 /* Indicate whether it's a permanent or temporary file. */
212 cf->is_tempfile = is_tempfile;
214 /* If it's a temporary capture buffer file, mark it as not saved. */
215 cf->user_saved = !is_tempfile;
217 cf->cd_t = wtap_file_type(cf->wth);
219 cf->displayed_count = 0;
220 cf->marked_count = 0;
221 cf->drops_known = FALSE;
225 cf->snap = wtap_snapshot_length(cf->wth);
227 /* Snapshot length not known. */
228 cf->has_snap = FALSE;
229 cf->snap = WTAP_MAX_PACKET_SIZE;
232 firstsec = 0, firstusec = 0;
233 prevsec = 0, prevusec = 0;
235 cf->plist_chunk = g_mem_chunk_new("frame_data_chunk",
237 FRAME_DATA_CHUNK_SIZE * sizeof(frame_data),
239 g_assert(cf->plist_chunk);
244 cf_open_failure_alert_box(fname, *err, err_info, FALSE, 0);
249 * Reset the state for the currently closed file, but don't do the
250 * UI callbacks; this is for use in "cf_open()", where we don't
251 * want the UI to go from "file open" to "file closed" back to
252 * "file open", we want it to go from "old file open" to "new file
253 * open and being read".
256 cf_reset_state(capture_file *cf)
258 /* Die if we're in the middle of reading a file. */
259 g_assert(cf->state != FILE_READ_IN_PROGRESS);
265 /* We have no file open... */
266 if (cf->filename != NULL) {
267 /* If it's a temporary file, remove it. */
269 unlink(cf->filename);
270 g_free(cf->filename);
273 /* ...which means we have nothing to save. */
274 cf->user_saved = FALSE;
276 if (cf->plist_chunk != NULL) {
277 g_mem_chunk_destroy(cf->plist_chunk);
278 cf->plist_chunk = NULL;
280 if (cf->rfcode != NULL) {
281 dfilter_free(cf->rfcode);
285 cf->plist_end = NULL;
286 cf_unselect_packet(cf); /* nothing to select */
287 cf->first_displayed = NULL;
288 cf->last_displayed = NULL;
290 /* No frame selected, no field in that frame selected. */
291 cf->current_frame = NULL;
292 cf->finfo_selected = NULL;
294 /* Clear the packet list. */
295 packet_list_freeze();
304 reset_tap_listeners();
306 /* We have no file open. */
307 cf->state = FILE_CLOSED;
310 /* Reset everything to a pristine state */
312 cf_close(capture_file *cf)
316 cleanup_dissection();
318 cf_callback_invoke(cf_cb_file_closed, cf);
322 cf_read(capture_file *cf)
326 const gchar *name_ptr;
327 gchar *load_msg, *load_fmt = "%s";
329 char errmsg_errno[1024+1];
330 gchar err_str[2048+1];
332 progdlg_t *progbar = NULL;
335 * XXX - should be "off_t", but Wiretap would need more work to handle
336 * the full size of "off_t" on platforms where it's more than a "long"
344 gchar status_str[100];
345 int progbar_nextstep;
350 reset_tap_listeners();
351 tap_dfilter_dlg_update();
353 cf_callback_invoke(cf_cb_file_read_start, cf);
355 name_ptr = get_basename(cf->filename);
356 load_msg = g_strdup_printf(load_fmt, name_ptr);
358 /* Update the progress bar when it gets to this value. */
359 progbar_nextstep = 0;
360 /* When we reach the value that triggers a progress bar update,
361 bump that value by this amount. */
362 progbar_quantum = cf->f_len/N_PROGBAR_UPDATES;
364 packet_list_freeze();
367 g_get_current_time(&start_time);
369 while ((wtap_read(cf->wth, &err, &err_info, &data_offset))) {
370 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
371 when we update it, we have to run the GTK+ main loop to get it
372 to repaint what's pending, and doing so may involve an "ioctl()"
373 to see if there's any pending input from an X server, and doing
374 that for every packet can be costly, especially on a big file. */
375 if (data_offset >= progbar_nextstep) {
376 file_pos = lseek(cf->filed, 0, SEEK_CUR);
377 prog_val = (gfloat) file_pos / (gfloat) cf->f_len;
378 if (prog_val > 1.0) {
379 /* The file probably grew while we were reading it.
380 Update "cf->f_len", and try again. */
381 fd = wtap_fd(cf->wth);
382 if (fstat(fd, &cf_stat) >= 0) {
383 cf->f_len = cf_stat.st_size;
384 prog_val = (gfloat) file_pos / (gfloat) cf->f_len;
386 /* If it's still > 1, either the "fstat()" failed (in which
387 case there's not much we can do about it), or the file
388 *shrank* (in which case there's not much we can do about
389 it); just clip the progress value at 1.0. */
393 if (progbar == NULL) {
394 /* Create the progress bar if necessary */
395 progbar = delayed_create_progress_dlg("Loading", load_msg,
396 &stop_flag, &start_time, prog_val);
400 if (progbar != NULL) {
401 g_snprintf(status_str, sizeof(status_str),
402 "%luKB of %luKB", file_pos / 1024, cf->f_len / 1024);
403 update_progress_dlg(progbar, prog_val, status_str);
405 progbar_nextstep += progbar_quantum;
409 /* Well, the user decided to abort the read. Destroy the progress
410 bar, close the capture file, and return CF_READ_ABORTED so our caller
411 can do whatever is appropriate when that happens. */
412 destroy_progress_dlg(progbar);
413 cf->state = FILE_READ_ABORTED; /* so that we're allowed to close it */
414 packet_list_thaw(); /* undo our freeze */
416 return CF_READ_ABORTED;
418 read_packet(cf, data_offset);
421 /* We're done reading the file; destroy the progress bar if it was created. */
425 destroy_progress_dlg(progbar);
427 /* We're done reading sequentially through the file. */
428 cf->state = FILE_READ_DONE;
430 /* Close the sequential I/O side, to free up memory it requires. */
431 wtap_sequential_close(cf->wth);
433 /* Allow the protocol dissectors to free up memory that they
434 * don't need after the sequential run-through of the packets. */
435 postseq_cleanup_all_protocols();
437 /* Set the file encapsulation type now; we don't know what it is until
438 we've looked at all the packets, as we don't know until then whether
439 there's more than one type (and thus whether it's
440 WTAP_ENCAP_PER_PACKET). */
441 cf->lnk_t = wtap_file_encap(cf->wth);
443 cf->current_frame = cf->first_displayed;
446 cf_callback_invoke(cf_cb_file_read_finished, cf);
448 /* If we have any displayed packets to select, select the first of those
449 packets by making the first row the selected row. */
450 if (cf->first_displayed != NULL)
451 packet_list_select_row(0);
454 /* Put up a message box noting that the read failed somewhere along
455 the line. Don't throw out the stuff we managed to read, though,
459 case WTAP_ERR_UNSUPPORTED_ENCAP:
460 snprintf(errmsg_errno, sizeof(errmsg_errno),
461 "The capture file has a packet with a network type that Ethereal doesn't support.\n(%s)",
464 errmsg = errmsg_errno;
467 case WTAP_ERR_CANT_READ:
468 errmsg = "An attempt to read from the capture file failed for"
469 " some unknown reason.";
472 case WTAP_ERR_SHORT_READ:
473 errmsg = "The capture file appears to have been cut short"
474 " in the middle of a packet.";
477 case WTAP_ERR_BAD_RECORD:
478 snprintf(errmsg_errno, sizeof(errmsg_errno),
479 "The capture file appears to be damaged or corrupt.\n(%s)",
482 errmsg = errmsg_errno;
486 snprintf(errmsg_errno, sizeof(errmsg_errno),
487 "An error occurred while reading the"
488 " capture file: %s.", wtap_strerror(err));
489 errmsg = errmsg_errno;
492 snprintf(err_str, sizeof err_str, errmsg);
493 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, err_str);
494 return CF_READ_ERROR;
501 cf_start_tail(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
503 cf_status_t cf_status;
505 cf_status = cf_open(cf, fname, is_tempfile, err);
506 if (cf_status == CF_OK) {
507 cf_callback_invoke(cf_cb_live_capture_started, cf);
513 cf_continue_tail(capture_file *cf, int to_read, int *err)
515 long data_offset = 0;
520 packet_list_freeze();
522 while (to_read != 0 && (wtap_read(cf->wth, err, &err_info, &data_offset))) {
523 if (cf->state == FILE_READ_ABORTED) {
524 /* Well, the user decided to exit Ethereal. Break out of the
525 loop, and let the code below (which is called even if there
526 aren't any packets left to read) exit. */
529 read_packet(cf, data_offset);
535 /* XXX - this cheats and looks inside the packet list to find the final
537 if (auto_scroll_live && cf->plist_end != NULL)
538 packet_list_moveto_end();
540 if (cf->state == FILE_READ_ABORTED) {
541 /* Well, the user decided to exit Ethereal. Return CF_READ_ABORTED
542 so that our caller can kill off the capture child process;
543 this will cause an EOF on the pipe from the child, so
544 "cf_finish_tail()" will be called, and it will clean up
546 return CF_READ_ABORTED;
547 } else if (*err != 0) {
548 /* We got an error reading the capture file.
549 XXX - pop up a dialog box? */
550 return CF_READ_ERROR;
556 cf_finish_tail(capture_file *cf, int *err)
563 packet_list_freeze();
565 while ((wtap_read(cf->wth, err, &err_info, &data_offset))) {
566 if (cf->state == FILE_READ_ABORTED) {
567 /* Well, the user decided to abort the read. Break out of the
568 loop, and let the code below (which is called even if there
569 aren't any packets left to read) exit. */
572 read_packet(cf, data_offset);
575 if (cf->state == FILE_READ_ABORTED) {
576 /* Well, the user decided to abort the read. We're only called
577 when the child capture process closes the pipe to us (meaning
578 it's probably exited), so we can just close the capture
579 file; we return CF_READ_ABORTED so our caller can do whatever
580 is appropriate when that happens. */
582 return CF_READ_ABORTED;
586 if (auto_scroll_live && cf->plist_end != NULL)
587 /* XXX - this cheats and looks inside the packet list to find the final
589 packet_list_moveto_end();
591 /* We're done reading sequentially through the file. */
592 cf->state = FILE_READ_DONE;
594 /* we have to update the f_len field */
595 /* Find the size of the file. */
596 fd = wtap_fd(cf->wth);
597 if (fstat(fd, &cf_stat) >= 0) {
598 cf->f_len = cf_stat.st_size;
601 /* We're done reading sequentially through the file; close the
602 sequential I/O side, to free up memory it requires. */
603 wtap_sequential_close(cf->wth);
605 /* Allow the protocol dissectors to free up memory that they
606 * don't need after the sequential run-through of the packets. */
607 postseq_cleanup_all_protocols();
609 /* Set the file encapsulation type now; we don't know what it is until
610 we've looked at all the packets, as we don't know until then whether
611 there's more than one type (and thus whether it's
612 WTAP_ENCAP_PER_PACKET). */
613 cf->lnk_t = wtap_file_encap(cf->wth);
615 cf_callback_invoke(cf_cb_live_capture_finished, cf);
618 /* We got an error reading the capture file.
619 XXX - pop up a dialog box? */
620 return CF_READ_ERROR;
625 #endif /* HAVE_LIBPCAP */
628 cf_get_display_name(capture_file *cf)
630 const gchar *displayname;
632 /* Return a name to use in displays */
633 if (!cf->is_tempfile) {
634 /* Get the last component of the file name, and use that. */
636 displayname = get_basename(cf->filename);
638 displayname="(No file)";
641 /* The file we read is a temporary file from a live capture;
642 we don't mention its name. */
643 displayname = "(Untitled)";
648 /* XXX - use a macro instead? */
650 cf_packet_count(capture_file *cf)
655 /* XXX - use a macro instead? */
657 cf_is_tempfile(capture_file *cf)
659 return cf->is_tempfile;
662 /* XXX - use a macro instead? */
663 void cf_set_drops_known(capture_file *cf, gboolean drops_known)
665 cf->drops_known = drops_known;
668 /* XXX - use a macro instead? */
669 void cf_set_drops(capture_file *cf, guint32 drops)
674 /* XXX - use a macro instead? */
675 gboolean cf_get_drops_known(capture_file *cf)
677 return cf->drops_known;
680 /* XXX - use a macro instead? */
681 guint32 cf_get_drops(capture_file *cf)
686 void cf_set_rfcode(capture_file *cf, dfilter_t *rfcode)
692 color_filter_t *colorf;
694 } apply_color_filter_args;
697 * If no color filter has been applied, apply this one.
698 * (The "if no color filter has been applied" is to handle the case where
699 * more than one color filter matches the packet.)
702 apply_color_filter(gpointer filter_arg, gpointer argp)
704 color_filter_t *colorf = filter_arg;
705 apply_color_filter_args *args = argp;
707 if (colorf->c_colorfilter != NULL && args->colorf == NULL) {
708 if (dfilter_apply_edt(colorf->c_colorfilter, args->edt))
709 args->colorf = colorf;
714 add_packet_to_packet_list(frame_data *fdata, capture_file *cf,
715 union wtap_pseudo_header *pseudo_header, const guchar *buf,
718 apply_color_filter_args args;
720 gboolean create_proto_tree = FALSE;
723 /* just add some value here until we know if it is being displayed or not */
724 fdata->cum_bytes = cum_bytes + fdata->pkt_len;
726 /* We don't yet have a color filter to apply. */
729 /* If we don't have the time stamp of the first packet in the
730 capture, it's because this is the first packet. Save the time
731 stamp of this packet as the time stamp of the first packet. */
732 if (!firstsec && !firstusec) {
733 firstsec = fdata->abs_secs;
734 firstusec = fdata->abs_usecs;
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 firstsec = fdata->abs_secs;
740 firstusec = fdata->abs_usecs;
743 /* If we don't have the time stamp of the previous displayed packet,
744 it's because this is the first displayed packet. Save the time
745 stamp of this packet as the time stamp of the previous displayed
747 if (!prevsec && !prevusec) {
748 prevsec = fdata->abs_secs;
749 prevusec = fdata->abs_usecs;
752 /* Get the time elapsed between the first packet and this packet. */
753 compute_timestamp_diff(&fdata->rel_secs, &fdata->rel_usecs,
754 fdata->abs_secs, fdata->abs_usecs, firstsec, firstusec);
756 /* If it's greater than the current elapsed time, set the elapsed time
757 to it (we check for "greater than" so as not to be confused by
758 time moving backwards). */
759 if ((gint32)cf->esec < fdata->rel_secs
760 || ((gint32)cf->esec == fdata->rel_secs && (gint32)cf->eusec < fdata->rel_usecs)) {
761 cf->esec = fdata->rel_secs;
762 cf->eusec = fdata->rel_usecs;
765 /* Get the time elapsed between the previous displayed packet and
767 compute_timestamp_diff(&fdata->del_secs, &fdata->del_usecs,
768 fdata->abs_secs, fdata->abs_usecs, prevsec, prevusec);
772 we have a display filter and are re-applying it;
774 we have a list of color filters;
776 we have tap listeners;
778 allocate a protocol tree root node, so that we'll construct
779 a protocol tree against which a filter expression can be
781 if ((cf->dfcode != NULL && refilter) || filter_list != NULL
782 || num_tap_filters != 0)
783 create_proto_tree = TRUE;
785 /* Dissect the frame. */
786 edt = epan_dissect_new(create_proto_tree, FALSE);
788 if (cf->dfcode != NULL && refilter) {
789 epan_dissect_prime_dfilter(edt, cf->dfcode);
792 filter_list_prime_edt(edt);
795 epan_dissect_run(edt, pseudo_header, buf, fdata, &cf->cinfo);
796 tap_push_tapped_queue(edt);
798 /* If we have a display filter, apply it if we're refiltering, otherwise
799 leave the "passed_dfilter" flag alone.
801 If we don't have a display filter, set "passed_dfilter" to 1. */
802 if (cf->dfcode != NULL) {
804 fdata->flags.passed_dfilter = dfilter_apply_edt(cf->dfcode, edt) ? 1 : 0;
807 fdata->flags.passed_dfilter = 1;
809 /* If we have color filters, and the frame is to be displayed, apply
810 the color filters. */
811 if (fdata->flags.passed_dfilter) {
812 if (filter_list != NULL) {
814 g_slist_foreach(filter_list, apply_color_filter, &args);
819 if( (fdata->flags.passed_dfilter)
820 || (edt->pi.fd->flags.ref_time) ){
821 /* This frame either passed the display filter list or is marked as
822 a time reference frame. All time reference frames are displayed
823 even if they dont pass the display filter */
824 /* if this was a TIME REF frame we should reset the cul bytes field */
825 if(edt->pi.fd->flags.ref_time){
826 cum_bytes = fdata->pkt_len;
827 fdata->cum_bytes = cum_bytes;
830 /* increase cum_bytes with this packets length */
831 cum_bytes += fdata->pkt_len;
833 epan_dissect_fill_in_columns(edt);
835 /* If we haven't yet seen the first frame, this is it.
837 XXX - we must do this before we add the row to the display,
838 as, if the display's GtkCList's selection mode is
839 GTK_SELECTION_BROWSE, when the first entry is added to it,
840 "cf_select_packet()" will be called, and it will fetch the row
841 data for the 0th row, and will get a null pointer rather than
842 "fdata", as "gtk_clist_append()" won't yet have returned and
843 thus "gtk_clist_set_row_data()" won't yet have been called.
845 We thus need to leave behind bread crumbs so that
846 "cf_select_packet()" can find this frame. See the comment
847 in "cf_select_packet()". */
848 if (cf->first_displayed == NULL)
849 cf->first_displayed = fdata;
851 /* This is the last frame we've seen so far. */
852 cf->last_displayed = fdata;
854 row = packet_list_append(cf->cinfo.col_data, fdata);
856 /* If the packet matches a color filter,
857 * store matching color_filter_t object in frame data. */
858 if (filter_list != NULL && (args.colorf != NULL)) {
859 /* add the matching colorfilter to the frame data */
860 fdata->color_filter = args.colorf;
861 /* If packet is marked, use colors from preferences */
862 if (fdata->flags.marked) {
863 packet_list_set_colors(row, &prefs.gui_marked_fg, &prefs.gui_marked_bg);
864 } else /* if (filter_list != NULL && (args.colorf != NULL)) */ {
865 packet_list_set_colors(row, &(args.colorf->fg_color),
866 &(args.colorf->bg_color));
869 /* No color filter match */
870 fdata->color_filter = NULL;
871 if (fdata->flags.marked) {
872 packet_list_set_colors(row, &prefs.gui_marked_fg, &prefs.gui_marked_bg);
876 /* Set the time of the previous displayed frame to the time of this
878 prevsec = fdata->abs_secs;
879 prevusec = fdata->abs_usecs;
881 cf->displayed_count++;
883 /* This frame didn't pass the display filter, so it's not being added
884 to the clist, and thus has no row. */
887 epan_dissect_free(edt);
892 read_packet(capture_file *cf, long offset)
894 const struct wtap_pkthdr *phdr = wtap_phdr(cf->wth);
895 union wtap_pseudo_header *pseudo_header = wtap_pseudoheader(cf->wth);
896 const guchar *buf = wtap_buf_ptr(cf->wth);
899 frame_data *plist_end;
902 /* Allocate the next list entry, and add it to the list. */
903 fdata = g_mem_chunk_alloc(cf->plist_chunk);
908 fdata->pkt_len = phdr->len;
909 fdata->cap_len = phdr->caplen;
910 fdata->file_off = offset;
911 fdata->lnk_t = phdr->pkt_encap;
912 fdata->abs_secs = phdr->ts.tv_sec;
913 fdata->abs_usecs = phdr->ts.tv_usec;
914 fdata->flags.encoding = CHAR_ASCII;
915 fdata->flags.visited = 0;
916 fdata->flags.marked = 0;
917 fdata->flags.ref_time = 0;
921 edt = epan_dissect_new(TRUE, FALSE);
922 epan_dissect_prime_dfilter(edt, cf->rfcode);
923 epan_dissect_run(edt, pseudo_header, buf, fdata, NULL);
924 passed = dfilter_apply_edt(cf->rfcode, edt);
925 epan_dissect_free(edt);
928 plist_end = cf->plist_end;
929 fdata->prev = plist_end;
930 if (plist_end != NULL)
931 plist_end->next = fdata;
934 cf->plist_end = fdata;
937 fdata->num = cf->count;
938 add_packet_to_packet_list(fdata, cf, pseudo_header, buf, TRUE);
940 /* XXX - if we didn't have read filters, or if we could avoid
941 allocating the "frame_data" structure until we knew whether
942 the frame passed the read filter, we could use a G_ALLOC_ONLY
945 ...but, at least in one test I did, where I just made the chunk
946 a G_ALLOC_ONLY chunk and read in a huge capture file, it didn't
947 seem to save a noticeable amount of time or space. */
948 g_mem_chunk_free(cf->plist_chunk, fdata);
953 cf_merge_files(char **out_filenamep, int in_file_count,
954 char *const *in_filenames, int file_type, gboolean do_append)
956 merge_in_file_t *in_files;
962 int open_err, read_err, write_err, close_err;
966 char errmsg_errno[1024+1];
967 gchar err_str[2048+1];
969 gboolean got_read_error = FALSE, got_write_error = FALSE;
971 progdlg_t *progbar = NULL;
974 * XXX - should be "off_t", but Wiretap would need more work to handle
975 * the full size of "off_t" on platforms where it's more than a "long"
978 long f_len, file_pos;
981 gchar status_str[100];
982 int progbar_nextstep;
985 /* open the input files */
986 if (!merge_open_in_files(in_file_count, in_filenames, &in_files,
987 &open_err, &err_info, &err_fileno)) {
989 cf_open_failure_alert_box(in_filenames[err_fileno], open_err, err_info,
994 if (*out_filenamep != NULL) {
995 out_filename = *out_filenamep;
996 out_fd = open(out_filename, O_CREAT|O_TRUNC|O_BINARY, 0600);
1000 out_fd = create_tempfile(tmpname, sizeof tmpname, "ether");
1003 out_filename = g_strdup(tmpname);
1004 *out_filenamep = out_filename;
1008 merge_close_in_files(in_file_count, in_files);
1010 cf_open_failure_alert_box(out_filename, open_err, NULL, TRUE, file_type);
1014 pdh = wtap_dump_fdopen(out_fd, file_type,
1015 merge_select_frame_type(in_file_count, in_files),
1016 merge_max_snapshot_length(in_file_count, in_files), &open_err);
1019 merge_close_in_files(in_file_count, in_files);
1021 cf_open_failure_alert_box(out_filename, open_err, err_info, TRUE,
1026 /* Get the sum of the sizes of all the files. */
1028 for (i = 0; i < in_file_count; i++)
1029 f_len += in_files[i].size;
1031 /* Update the progress bar when it gets to this value. */
1032 progbar_nextstep = 0;
1033 /* When we reach the value that triggers a progress bar update,
1034 bump that value by this amount. */
1035 progbar_quantum = f_len/N_PROGBAR_UPDATES;
1038 g_get_current_time(&start_time);
1040 /* do the merge (or append) */
1043 wth = merge_append_read_packet(in_file_count, in_files, &read_err,
1046 wth = merge_read_packet(in_file_count, in_files, &read_err,
1050 got_read_error = TRUE;
1054 /* Get the sum of the data offsets in all of the files. */
1056 for (i = 0; i < in_file_count; i++)
1057 data_offset += in_files[i].data_offset;
1059 if (data_offset >= progbar_nextstep) {
1060 /* Get the sum of the seek positions in all of the files. */
1062 for (i = 0; i < in_file_count; i++)
1063 file_pos += lseek(wtap_fd(in_files[i].wth), 0, SEEK_CUR);
1064 prog_val = (gfloat) file_pos / (gfloat) f_len;
1065 if (prog_val > 1.0) {
1066 /* Some file probably grew while we were reading it.
1067 That "shouldn't happen", so we'll just clip the progress
1071 if (progbar == NULL) {
1072 /* Create the progress bar if necessary */
1073 progbar = delayed_create_progress_dlg("Merging", "files",
1074 &stop_flag, &start_time, prog_val);
1076 if (progbar != NULL) {
1077 g_snprintf(status_str, sizeof(status_str),
1078 "%luKB of %luKB", file_pos / 1024, f_len / 1024);
1079 update_progress_dlg(progbar, prog_val, status_str);
1081 progbar_nextstep += progbar_quantum;
1084 if (!wtap_dump(pdh, wtap_phdr(wth), wtap_pseudoheader(wth),
1085 wtap_buf_ptr(wth), &write_err)) {
1086 got_write_error = TRUE;
1091 /* We're done merging the files; destroy the progress bar if it was created. */
1092 if (progbar != NULL)
1093 destroy_progress_dlg(progbar);
1095 merge_close_in_files(in_file_count, in_files);
1096 if (!got_read_error && !got_write_error) {
1097 if (!wtap_dump_close(pdh, &write_err))
1098 got_write_error = TRUE;
1100 wtap_dump_close(pdh, &close_err);
1102 if (got_read_error) {
1104 * Find the file on which we got the error, and report the error.
1106 for (i = 0; i < in_file_count; i++) {
1107 if (in_files[i].state == GOT_ERROR) {
1108 /* Put up a message box noting that a read failed somewhere along
1112 case WTAP_ERR_UNSUPPORTED_ENCAP:
1113 snprintf(errmsg_errno, sizeof(errmsg_errno),
1114 "The capture file %%s has a packet with a network type that Ethereal doesn't support.\n(%s)",
1117 errmsg = errmsg_errno;
1120 case WTAP_ERR_CANT_READ:
1121 errmsg = "An attempt to read from the capture file %s failed for"
1122 " some unknown reason.";
1125 case WTAP_ERR_SHORT_READ:
1126 errmsg = "The capture file %s appears to have been cut short"
1127 " in the middle of a packet.";
1130 case WTAP_ERR_BAD_RECORD:
1131 snprintf(errmsg_errno, sizeof(errmsg_errno),
1132 "The capture file %%s appears to be damaged or corrupt.\n(%s)",
1135 errmsg = errmsg_errno;
1139 snprintf(errmsg_errno, sizeof(errmsg_errno),
1140 "An error occurred while reading the"
1141 " capture file %%s: %s.", wtap_strerror(read_err));
1142 errmsg = errmsg_errno;
1145 snprintf(err_str, sizeof err_str, errmsg, in_files[i].filename);
1146 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, err_str);
1151 if (got_write_error) {
1152 /* Put up an alert box for the write error. */
1153 cf_write_failure_alert_box(out_filename, write_err);
1156 return (!got_read_error && !got_write_error) ? CF_OK : CF_ERROR;
1160 cf_filter_packets(capture_file *cf, gchar *dftext, gboolean force)
1163 char *filter_new = dftext ? dftext : "";
1164 char *filter_old = cf->dfilter ? cf->dfilter : "";
1166 /* if new filter equals old one, do nothing unless told to do so */
1167 if (!force && strcmp(filter_new, filter_old) == 0) {
1171 if (dftext == NULL) {
1172 /* The new filter is an empty filter (i.e., display all packets). */
1176 * We have a filter; make a copy of it (as we'll be saving it),
1177 * and try to compile it.
1179 dftext = g_strdup(dftext);
1180 if (!dfilter_compile(dftext, &dfcode)) {
1181 /* The attempt failed; report an error. */
1182 gchar *safe_dftext = simple_dialog_format_message(dftext);
1183 gchar *safe_dfilter_error_msg = simple_dialog_format_message(
1185 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1188 "The following display filter isn't a valid display filter:\n%s\n"
1189 "See the help for a description of the display filter syntax.",
1190 simple_dialog_primary_start(), safe_dfilter_error_msg,
1191 simple_dialog_primary_end(), safe_dftext);
1192 g_free(safe_dfilter_error_msg);
1193 g_free(safe_dftext);
1199 if (dfcode == NULL) {
1200 /* Yes - free the filter text, and set it to null. */
1206 /* We have a valid filter. Replace the current filter. */
1207 if (cf->dfilter != NULL)
1208 g_free(cf->dfilter);
1209 cf->dfilter = dftext;
1210 if (cf->dfcode != NULL)
1211 dfilter_free(cf->dfcode);
1212 cf->dfcode = dfcode;
1214 /* Now rescan the packet list, applying the new filter, but not
1215 throwing away information constructed on a previous pass. */
1216 if (dftext == NULL) {
1217 rescan_packets(cf, "Resetting", "Filter", TRUE, FALSE);
1219 rescan_packets(cf, "Filtering", dftext, TRUE, FALSE);
1225 cf_colorize_packets(capture_file *cf)
1227 rescan_packets(cf, "Colorizing", "all packets", FALSE, FALSE);
1231 cf_reftime_packets(capture_file *cf)
1233 rescan_packets(cf, "Updating Reftime", "all packets", FALSE, FALSE);
1237 cf_redissect_packets(capture_file *cf)
1239 rescan_packets(cf, "Reprocessing", "all packets", TRUE, TRUE);
1242 /* Rescan the list of packets, reconstructing the CList.
1244 "action" describes why we're doing this; it's used in the progress
1247 "action_item" describes what we're doing; it's used in the progress
1250 "refilter" is TRUE if we need to re-evaluate the filter expression.
1252 "redissect" is TRUE if we need to make the dissectors reconstruct
1253 any state information they have (because a preference that affects
1254 some dissector has changed, meaning some dissector might construct
1255 its state differently from the way it was constructed the last time). */
1257 rescan_packets(capture_file *cf, const char *action, const char *action_item,
1258 gboolean refilter, gboolean redissect)
1261 progdlg_t *progbar = NULL;
1266 frame_data *selected_frame, *preceding_frame, *following_frame, *prev_frame;
1267 int selected_row, prev_row, preceding_row, following_row;
1268 gboolean selected_frame_seen;
1271 GTimeVal start_time;
1272 gchar status_str[100];
1273 int progbar_nextstep;
1274 int progbar_quantum;
1277 reset_tap_listeners();
1278 /* Which frame, if any, is the currently selected frame?
1279 XXX - should the selected frame or the focus frame be the "current"
1280 frame, that frame being the one from which "Find Frame" searches
1282 selected_frame = cf->current_frame;
1284 /* We don't yet know what row that frame will be on, if any, after we
1285 rebuild the clist, however. */
1289 /* We need to re-initialize all the state information that protocols
1290 keep, because some preference that controls a dissector has changed,
1291 which might cause the state information to be constructed differently
1292 by that dissector. */
1294 /* Initialize all data structures used for dissection. */
1298 /* Freeze the packet list while we redo it, so we don't get any
1299 screen updates while it happens. */
1300 packet_list_freeze();
1303 packet_list_clear();
1305 /* We don't yet know which will be the first and last frames displayed. */
1306 cf->first_displayed = NULL;
1307 cf->last_displayed = NULL;
1309 /* We currently don't display any packets */
1310 cf->displayed_count = 0;
1312 /* Iterate through the list of frames. Call a routine for each frame
1313 to check whether it should be displayed and, if so, add it to
1314 the display list. */
1320 /* Update the progress bar when it gets to this value. */
1321 progbar_nextstep = 0;
1322 /* When we reach the value that triggers a progress bar update,
1323 bump that value by this amount. */
1324 progbar_quantum = cf->count/N_PROGBAR_UPDATES;
1325 /* Count of packets at which we've looked. */
1329 g_get_current_time(&start_time);
1331 row = -1; /* no previous row yet */
1336 preceding_frame = NULL;
1338 following_frame = NULL;
1340 selected_frame_seen = FALSE;
1342 for (fdata = cf->plist; fdata != NULL; fdata = fdata->next) {
1343 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
1344 when we update it, we have to run the GTK+ main loop to get it
1345 to repaint what's pending, and doing so may involve an "ioctl()"
1346 to see if there's any pending input from an X server, and doing
1347 that for every packet can be costly, especially on a big file. */
1348 if (count >= progbar_nextstep) {
1349 /* let's not divide by zero. I should never be started
1350 * with count == 0, so let's assert that
1352 g_assert(cf->count > 0);
1353 prog_val = (gfloat) count / cf->count;
1355 if (progbar == NULL)
1356 /* Create the progress bar if necessary */
1357 progbar = delayed_create_progress_dlg(action, action_item, &stop_flag,
1358 &start_time, prog_val);
1360 if (progbar != NULL) {
1361 g_snprintf(status_str, sizeof(status_str),
1362 "%4u of %u frames", count, cf->count);
1363 update_progress_dlg(progbar, prog_val, status_str);
1366 progbar_nextstep += progbar_quantum;
1370 /* Well, the user decided to abort the filtering. Just stop.
1372 XXX - go back to the previous filter? Users probably just
1373 want not to wait for a filtering operation to finish;
1374 unless we cancel by having no filter, reverting to the
1375 previous filter will probably be even more expensive than
1376 continuing the filtering, as it involves going back to the
1377 beginning and filtering, and even with no filter we currently
1378 have to re-generate the entire clist, which is also expensive.
1380 I'm not sure what Network Monitor does, but it doesn't appear
1381 to give you an unfiltered display if you cancel. */
1388 /* Since all state for the frame was destroyed, mark the frame
1389 * as not visited, free the GSList referring to the state
1390 * data (the per-frame data itself was freed by
1391 * "init_dissection()"), and null out the GSList pointer. */
1392 fdata->flags.visited = 0;
1394 g_slist_free(fdata->pfd);
1399 if (!wtap_seek_read (cf->wth, fdata->file_off, &cf->pseudo_header,
1400 cf->pd, fdata->cap_len, &err, &err_info)) {
1401 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1402 cf_read_error_message(err, err_info), cf->filename);
1406 /* If the previous frame is displayed, and we haven't yet seen the
1407 selected frame, remember that frame - it's the closest one we've
1408 yet seen before the selected frame. */
1409 if (prev_row != -1 && !selected_frame_seen) {
1410 preceding_row = prev_row;
1411 preceding_frame = prev_frame;
1413 row = add_packet_to_packet_list(fdata, cf, &cf->pseudo_header, cf->pd,
1416 /* If this frame is displayed, and this is the first frame we've
1417 seen displayed after the selected frame, remember this frame -
1418 it's the closest one we've yet seen at or after the selected
1420 if (row != -1 && selected_frame_seen && following_row == -1) {
1421 following_row = row;
1422 following_frame = fdata;
1424 if (fdata == selected_frame) {
1426 selected_frame_seen = TRUE;
1429 /* Remember this row/frame - it'll be the previous row/frame
1430 on the next pass through the loop. */
1436 /* Clear out what remains of the visited flags and per-frame data
1439 XXX - that may cause various forms of bogosity when dissecting
1440 these frames, as they won't have been seen by this sequential
1441 pass, but the only alternative I see is to keep scanning them
1442 even though the user requested that the scan stop, and that
1443 would leave the user stuck with an Ethereal grinding on
1444 until it finishes. Should we just stick them with that? */
1445 for (; fdata != NULL; fdata = fdata->next) {
1446 fdata->flags.visited = 0;
1448 g_slist_free(fdata->pfd);
1454 /* We're done filtering the packets; destroy the progress bar if it
1456 if (progbar != NULL)
1457 destroy_progress_dlg(progbar);
1459 /* Unfreeze the packet list. */
1462 if (selected_row == -1) {
1463 /* The selected frame didn't pass the filter. */
1464 if (selected_frame == NULL) {
1465 /* That's because there *was* no selected frame. Make the first
1466 displayed frame the current frame. */
1469 /* Find the nearest displayed frame to the selected frame (whether
1470 it's before or after that frame) and make that the current frame.
1471 If the next and previous displayed frames are equidistant from the
1472 selected frame, choose the next one. */
1473 g_assert(following_frame == NULL ||
1474 following_frame->num >= selected_frame->num);
1475 g_assert(preceding_frame == NULL ||
1476 preceding_frame->num <= selected_frame->num);
1477 if (following_frame == NULL) {
1478 /* No frame after the selected frame passed the filter, so we
1479 have to select the last displayed frame before the selected
1481 selected_row = preceding_row;
1482 } else if (preceding_frame == NULL) {
1483 /* No frame before the selected frame passed the filter, so we
1484 have to select the first displayed frame after the selected
1486 selected_row = following_row;
1488 /* Choose the closer of the last displayed frame before the
1489 selected frame and the first displayed frame after the
1490 selected frame; in case of a tie, choose the first displayed
1491 frame after the selected frame. */
1492 if (following_frame->num - selected_frame->num <=
1493 selected_frame->num - preceding_frame->num) {
1494 selected_row = following_row;
1496 /* The previous frame is closer to the selected frame than the
1498 selected_row = preceding_row;
1504 if (selected_row == -1) {
1505 /* There are no frames displayed at all. */
1506 cf_unselect_packet(cf);
1508 /* Either the frame that was selected passed the filter, or we've
1509 found the nearest displayed frame to that frame. Select it, make
1510 it the focus row, and make it visible. */
1511 packet_list_set_selected_row(selected_row);
1522 process_specified_packets(capture_file *cf, packet_range_t *range,
1523 const char *string1, const char *string2,
1524 gboolean (*callback)(capture_file *, frame_data *,
1525 union wtap_pseudo_header *, const guint8 *, void *),
1526 void *callback_args)
1531 union wtap_pseudo_header pseudo_header;
1532 guint8 pd[WTAP_MAX_PACKET_SIZE+1];
1533 psp_return_t ret = PSP_FINISHED;
1535 progdlg_t *progbar = NULL;
1538 gboolean progbar_stop_flag;
1539 GTimeVal progbar_start_time;
1540 gchar progbar_status_str[100];
1541 int progbar_nextstep;
1542 int progbar_quantum;
1543 range_process_e process_this;
1545 /* Update the progress bar when it gets to this value. */
1546 progbar_nextstep = 0;
1547 /* When we reach the value that triggers a progress bar update,
1548 bump that value by this amount. */
1549 progbar_quantum = cf->count/N_PROGBAR_UPDATES;
1550 /* Count of packets at which we've looked. */
1553 progbar_stop_flag = FALSE;
1554 g_get_current_time(&progbar_start_time);
1556 packet_range_process_init(range);
1558 /* Iterate through the list of packets, printing the packets that
1559 were selected by the current display filter. */
1560 for (fdata = cf->plist; fdata != NULL; fdata = fdata->next) {
1561 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
1562 when we update it, we have to run the GTK+ main loop to get it
1563 to repaint what's pending, and doing so may involve an "ioctl()"
1564 to see if there's any pending input from an X server, and doing
1565 that for every packet can be costly, especially on a big file. */
1566 if (progbar_count >= progbar_nextstep) {
1567 /* let's not divide by zero. I should never be started
1568 * with count == 0, so let's assert that
1570 g_assert(cf->count > 0);
1571 progbar_val = (gfloat) progbar_count / cf->count;
1573 if (progbar == NULL)
1574 /* Create the progress bar if necessary */
1575 progbar = delayed_create_progress_dlg(string1, string2,
1577 &progbar_start_time,
1580 if (progbar != NULL) {
1581 g_snprintf(progbar_status_str, sizeof(progbar_status_str),
1582 "%4u of %u packets", progbar_count, cf->count);
1583 update_progress_dlg(progbar, progbar_val, progbar_status_str);
1586 progbar_nextstep += progbar_quantum;
1589 if (progbar_stop_flag) {
1590 /* Well, the user decided to abort the operation. Just stop,
1591 and arrange to return TRUE to our caller, so they know it
1592 was stopped explicitly. */
1599 /* do we have to process this packet? */
1600 process_this = packet_range_process_packet(range, fdata);
1601 if (process_this == range_process_next) {
1602 /* this packet uninteresting, continue with next one */
1604 } else if (process_this == range_processing_finished) {
1605 /* all interesting packets processed, stop the loop */
1609 /* Get the packet */
1610 if (!wtap_seek_read(cf->wth, fdata->file_off, &pseudo_header,
1611 pd, fdata->cap_len, &err, &err_info)) {
1612 /* Attempt to get the packet failed. */
1613 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1614 cf_read_error_message(err, err_info), cf->filename);
1618 /* Process the packet */
1619 if (!callback(cf, fdata, &pseudo_header, pd, callback_args)) {
1620 /* Callback failed. We assume it reported the error appropriately. */
1626 /* We're done printing the packets; destroy the progress bar if
1628 if (progbar != NULL)
1629 destroy_progress_dlg(progbar);
1635 retap_packet(capture_file *cf _U_, frame_data *fdata,
1636 union wtap_pseudo_header *pseudo_header, const guint8 *pd,
1639 epan_dissect_t *edt;
1641 /* If we have tap listeners, allocate a protocol tree root node, so that
1642 we'll construct a protocol tree against which a filter expression can
1644 edt = epan_dissect_new(num_tap_filters != 0, FALSE);
1645 tap_queue_init(edt);
1646 epan_dissect_run(edt, pseudo_header, pd, fdata, NULL);
1647 tap_push_tapped_queue(edt);
1648 epan_dissect_free(edt);
1654 cf_retap_packets(capture_file *cf)
1656 packet_range_t range;
1658 /* Reset the tap listeners. */
1659 reset_tap_listeners();
1661 /* Iterate through the list of packets, dissecting all packets and
1662 re-running the taps. */
1663 packet_range_init(&range);
1664 packet_range_process_init(&range);
1665 switch (process_specified_packets(cf, &range, "Refiltering statistics on",
1666 "all packets", retap_packet,
1669 /* Completed successfully. */
1673 /* Well, the user decided to abort the refiltering.
1674 Return CF_READ_ABORTED so our caller knows they did that. */
1675 return CF_READ_ABORTED;
1678 /* Error while retapping. */
1679 return CF_READ_ERROR;
1682 g_assert_not_reached();
1687 print_args_t *print_args;
1688 gboolean print_header_line;
1689 char *header_line_buf;
1690 int header_line_buf_len;
1691 gboolean print_formfeed;
1692 gboolean print_separator;
1696 } print_callback_args_t;
1699 print_packet(capture_file *cf, frame_data *fdata,
1700 union wtap_pseudo_header *pseudo_header, const guint8 *pd,
1703 print_callback_args_t *args = argsp;
1704 epan_dissect_t *edt;
1710 gboolean proto_tree_needed;
1711 char bookmark_name[9+10+1]; /* "__frameNNNNNNNNNN__\0" */
1712 char bookmark_title[6+10+1]; /* "Frame NNNNNNNNNN__\0" */
1714 /* Create the protocol tree, and make it visible, if we're printing
1715 the dissection or the hex data.
1716 XXX - do we need it if we're just printing the hex data? */
1718 args->print_args->print_dissections != print_dissections_none || args->print_args->print_hex;
1719 edt = epan_dissect_new(proto_tree_needed, proto_tree_needed);
1721 /* Fill in the column information if we're printing the summary
1723 if (args->print_args->print_summary) {
1724 epan_dissect_run(edt, pseudo_header, pd, fdata, &cf->cinfo);
1725 epan_dissect_fill_in_columns(edt);
1727 epan_dissect_run(edt, pseudo_header, pd, fdata, NULL);
1729 if (args->print_formfeed) {
1730 if (!new_page(args->print_args->stream))
1733 if (args->print_separator) {
1734 if (!print_line(args->print_args->stream, 0, ""))
1740 * We generate bookmarks, if the output format supports them.
1741 * The name is "__frameN__".
1743 sprintf(bookmark_name, "__frame%u__", fdata->num);
1745 if (args->print_args->print_summary) {
1746 if (args->print_header_line) {
1747 if (!print_line(args->print_args->stream, 0, args->header_line_buf))
1749 args->print_header_line = FALSE; /* we might not need to print any more */
1751 cp = &args->line_buf[0];
1753 for (i = 0; i < cf->cinfo.num_cols; i++) {
1754 /* Find the length of the string for this column. */
1755 column_len = strlen(cf->cinfo.col_data[i]);
1756 if (args->col_widths[i] > column_len)
1757 column_len = args->col_widths[i];
1759 /* Make sure there's room in the line buffer for the column; if not,
1760 double its length. */
1761 line_len += column_len + 1; /* "+1" for space */
1762 if (line_len > args->line_buf_len) {
1763 cp_off = cp - args->line_buf;
1764 args->line_buf_len = 2 * line_len;
1765 args->line_buf = g_realloc(args->line_buf, args->line_buf_len + 1);
1766 cp = args->line_buf + cp_off;
1769 /* Right-justify the packet number column. */
1770 if (cf->cinfo.col_fmt[i] == COL_NUMBER)
1771 sprintf(cp, "%*s", args->col_widths[i], cf->cinfo.col_data[i]);
1773 sprintf(cp, "%-*s", args->col_widths[i], cf->cinfo.col_data[i]);
1775 if (i != cf->cinfo.num_cols - 1)
1781 * Generate a bookmark, using the summary line as the title.
1783 if (!print_bookmark(args->print_args->stream, bookmark_name,
1787 if (!print_line(args->print_args->stream, 0, args->line_buf))
1791 * Generate a bookmark, using "Frame N" as the title, as we're not
1792 * printing the summary line.
1794 sprintf(bookmark_title, "Frame %u", fdata->num);
1795 if (!print_bookmark(args->print_args->stream, bookmark_name,
1798 } /* if (print_summary) */
1800 if (args->print_args->print_dissections != print_dissections_none) {
1801 if (args->print_args->print_summary) {
1802 /* Separate the summary line from the tree with a blank line. */
1803 if (!print_line(args->print_args->stream, 0, ""))
1807 /* Print the information in that tree. */
1808 if (!proto_tree_print(args->print_args, edt, args->print_args->stream))
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;
1818 if (args->print_args->print_hex) {
1819 /* Print the full packet data as hex. */
1820 if (!print_hex_data(args->print_args->stream, edt))
1823 /* Print a blank line if we print anything after this (aka more than one packet). */
1824 args->print_separator = TRUE;
1826 /* Print a header line if we print any more packet summaries */
1827 args->print_header_line = TRUE;
1828 } /* if (args->print_args->print_dissections != print_dissections_none) */
1830 epan_dissect_free(edt);
1832 /* do we want to have a formfeed between each packet from now on? */
1833 if(args->print_args->print_formfeed) {
1834 args->print_formfeed = TRUE;
1840 epan_dissect_free(edt);
1845 cf_print_packets(capture_file *cf, print_args_t *print_args)
1848 print_callback_args_t callback_args;
1856 callback_args.print_args = print_args;
1857 callback_args.print_header_line = TRUE;
1858 callback_args.header_line_buf = NULL;
1859 callback_args.header_line_buf_len = 256;
1860 callback_args.print_formfeed = FALSE;
1861 callback_args.print_separator = FALSE;
1862 callback_args.line_buf = NULL;
1863 callback_args.line_buf_len = 256;
1864 callback_args.col_widths = NULL;
1866 if (!print_preamble(print_args->stream, cf->filename)) {
1867 destroy_print_stream(print_args->stream);
1868 return CF_PRINT_WRITE_ERROR;
1871 if (print_args->print_summary) {
1872 /* We're printing packet summaries. Allocate the header line buffer
1873 and get the column widths. */
1874 callback_args.header_line_buf = g_malloc(callback_args.header_line_buf_len + 1);
1876 /* Find the widths for each of the columns - maximum of the
1877 width of the title and the width of the data - and construct
1878 a buffer with a line containing the column titles. */
1879 callback_args.col_widths = (gint *) g_malloc(sizeof(gint) * cf->cinfo.num_cols);
1880 cp = &callback_args.header_line_buf[0];
1882 for (i = 0; i < cf->cinfo.num_cols; i++) {
1883 /* Don't pad the last column. */
1884 if (i == cf->cinfo.num_cols - 1)
1885 callback_args.col_widths[i] = 0;
1887 callback_args.col_widths[i] = strlen(cf->cinfo.col_title[i]);
1888 data_width = get_column_char_width(get_column_format(i));
1889 if (data_width > callback_args.col_widths[i])
1890 callback_args.col_widths[i] = data_width;
1893 /* Find the length of the string for this column. */
1894 column_len = strlen(cf->cinfo.col_title[i]);
1895 if (callback_args.col_widths[i] > column_len)
1896 column_len = callback_args.col_widths[i];
1898 /* Make sure there's room in the line buffer for the column; if not,
1899 double its length. */
1900 line_len += column_len + 1; /* "+1" for space */
1901 if (line_len > callback_args.header_line_buf_len) {
1902 cp_off = cp - callback_args.header_line_buf;
1903 callback_args.header_line_buf_len = 2 * line_len;
1904 callback_args.header_line_buf = g_realloc(callback_args.header_line_buf,
1905 callback_args.header_line_buf_len + 1);
1906 cp = callback_args.header_line_buf + cp_off;
1909 /* Right-justify the packet number column. */
1910 /* if (cf->cinfo.col_fmt[i] == COL_NUMBER)
1911 sprintf(cp, "%*s", callback_args.col_widths[i], cf->cinfo.col_title[i]);
1913 sprintf(cp, "%-*s", callback_args.col_widths[i], cf->cinfo.col_title[i]);
1915 if (i != cf->cinfo.num_cols - 1)
1920 /* Now start out the main line buffer with the same length as the
1921 header line buffer. */
1922 callback_args.line_buf_len = callback_args.header_line_buf_len;
1923 callback_args.line_buf = g_malloc(callback_args.line_buf_len + 1);
1924 } /* if (print_summary) */
1926 /* Iterate through the list of packets, printing the packets we were
1928 ret = process_specified_packets(cf, &print_args->range, "Printing",
1929 "selected packets", print_packet,
1932 if (callback_args.header_line_buf != NULL)
1933 g_free(callback_args.header_line_buf);
1934 if (callback_args.line_buf != NULL)
1935 g_free(callback_args.line_buf);
1936 if (callback_args.col_widths != NULL)
1937 g_free(callback_args.col_widths);
1942 /* Completed successfully. */
1946 /* Well, the user decided to abort the printing.
1948 XXX - note that what got generated before they did that
1949 will get printed if we're piping to a print program; we'd
1950 have to write to a file and then hand that to the print
1951 program to make it actually not print anything. */
1955 /* Error while printing.
1957 XXX - note that what got generated before they did that
1958 will get printed if we're piping to a print program; we'd
1959 have to write to a file and then hand that to the print
1960 program to make it actually not print anything. */
1961 destroy_print_stream(print_args->stream);
1962 return CF_PRINT_WRITE_ERROR;
1965 if (!print_finale(print_args->stream)) {
1966 destroy_print_stream(print_args->stream);
1967 return CF_PRINT_WRITE_ERROR;
1970 if (!destroy_print_stream(print_args->stream))
1971 return CF_PRINT_WRITE_ERROR;
1977 write_pdml_packet(capture_file *cf _U_, frame_data *fdata,
1978 union wtap_pseudo_header *pseudo_header, const guint8 *pd,
1982 epan_dissect_t *edt;
1984 /* Create the protocol tree, but don't fill in the column information. */
1985 edt = epan_dissect_new(TRUE, TRUE);
1986 epan_dissect_run(edt, pseudo_header, pd, fdata, NULL);
1988 /* Write out the information in that tree. */
1989 proto_tree_write_pdml(edt, fh);
1991 epan_dissect_free(edt);
1997 cf_write_pdml_packets(capture_file *cf, print_args_t *print_args)
2002 fh = fopen(print_args->file, "w");
2004 return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
2006 write_pdml_preamble(fh);
2009 return CF_PRINT_WRITE_ERROR;
2012 /* Iterate through the list of packets, printing the packets we were
2014 ret = process_specified_packets(cf, &print_args->range, "Writing PDML",
2015 "selected packets", write_pdml_packet,
2021 /* Completed successfully. */
2025 /* Well, the user decided to abort the printing. */
2029 /* Error while printing. */
2031 return CF_PRINT_WRITE_ERROR;
2034 write_pdml_finale(fh);
2037 return CF_PRINT_WRITE_ERROR;
2040 /* XXX - check for an error */
2047 write_psml_packet(capture_file *cf, frame_data *fdata,
2048 union wtap_pseudo_header *pseudo_header, const guint8 *pd,
2052 epan_dissect_t *edt;
2054 /* Fill in the column information, but don't create the protocol tree. */
2055 edt = epan_dissect_new(FALSE, FALSE);
2056 epan_dissect_run(edt, pseudo_header, pd, fdata, &cf->cinfo);
2057 epan_dissect_fill_in_columns(edt);
2059 /* Write out the information in that tree. */
2060 proto_tree_write_psml(edt, fh);
2062 epan_dissect_free(edt);
2068 cf_write_psml_packets(capture_file *cf, print_args_t *print_args)
2073 fh = fopen(print_args->file, "w");
2075 return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
2077 write_psml_preamble(fh);
2080 return CF_PRINT_WRITE_ERROR;
2083 /* Iterate through the list of packets, printing the packets we were
2085 ret = process_specified_packets(cf, &print_args->range, "Writing PSML",
2086 "selected packets", write_psml_packet,
2092 /* Completed successfully. */
2096 /* Well, the user decided to abort the printing. */
2100 /* Error while printing. */
2102 return CF_PRINT_WRITE_ERROR;
2105 write_psml_finale(fh);
2108 return CF_PRINT_WRITE_ERROR;
2111 /* XXX - check for an error */
2118 write_csv_packet(capture_file *cf, frame_data *fdata,
2119 union wtap_pseudo_header *pseudo_header, const guint8 *pd,
2123 epan_dissect_t *edt;
2125 /* Fill in the column information, but don't create the protocol tree. */
2126 edt = epan_dissect_new(FALSE, FALSE);
2127 epan_dissect_run(edt, pseudo_header, pd, fdata, &cf->cinfo);
2128 epan_dissect_fill_in_columns(edt);
2130 /* Write out the information in that tree. */
2131 proto_tree_write_csv(edt, fh);
2133 epan_dissect_free(edt);
2139 cf_write_csv_packets(capture_file *cf, print_args_t *print_args)
2144 fh = fopen(print_args->file, "w");
2146 return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */
2148 write_csv_preamble(fh);
2151 return CF_PRINT_WRITE_ERROR;
2154 /* Iterate through the list of packets, printing the packets we were
2156 ret = process_specified_packets(cf, &print_args->range, "Writing CSV",
2157 "selected packets", write_csv_packet,
2163 /* Completed successfully. */
2167 /* Well, the user decided to abort the printing. */
2171 /* Error while printing. */
2173 return CF_PRINT_WRITE_ERROR;
2176 write_csv_finale(fh);
2179 return CF_PRINT_WRITE_ERROR;
2182 /* XXX - check for an error */
2188 /* Scan through the packet list and change all columns that use the
2189 "command-line-specified" time stamp format to use the current
2190 value of that format. */
2192 cf_change_time_formats(capture_file *cf)
2195 progdlg_t *progbar = NULL;
2201 GTimeVal start_time;
2202 gchar status_str[100];
2203 int progbar_nextstep;
2204 int progbar_quantum;
2206 gboolean sorted_by_frame_column;
2208 /* Are there any columns with time stamps in the "command-line-specified"
2211 XXX - we have to force the "column is writable" flag on, as it
2212 might be off from the last frame that was dissected. */
2213 col_set_writable(&cf->cinfo, TRUE);
2214 if (!check_col(&cf->cinfo, COL_CLS_TIME)) {
2215 /* No, there aren't any columns in that format, so we have no work
2219 first = cf->cinfo.col_first[COL_CLS_TIME];
2220 g_assert(first >= 0);
2221 last = cf->cinfo.col_last[COL_CLS_TIME];
2223 /* Freeze the packet list while we redo it, so we don't get any
2224 screen updates while it happens. */
2225 packet_list_freeze();
2227 /* Update the progress bar when it gets to this value. */
2228 progbar_nextstep = 0;
2229 /* When we reach the value that triggers a progress bar update,
2230 bump that value by this amount. */
2231 progbar_quantum = cf->count/N_PROGBAR_UPDATES;
2232 /* Count of packets at which we've looked. */
2235 /* If the rows are currently sorted by the frame column then we know
2236 * the row number of each packet: it's the row number of the previously
2237 * displayed packet + 1.
2239 * Otherwise, if the display is sorted by a different column then we have
2240 * to use the O(N) packet_list_find_row_from_data() (thus making the job
2241 * of changing the time display format O(N**2)).
2243 * (XXX - In fact it's still O(N**2) because gtk_clist_set_text() takes
2244 * the row number and walks that many elements down the clist to find
2245 * the appropriate element.)
2247 sorted_by_frame_column = FALSE;
2248 for (i = 0; i < cf->cinfo.num_cols; i++) {
2249 if (cf->cinfo.col_fmt[i] == COL_NUMBER)
2251 sorted_by_frame_column = (i == packet_list_get_sort_column());
2257 g_get_current_time(&start_time);
2259 /* Iterate through the list of packets, checking whether the packet
2260 is in a row of the summary list and, if so, whether there are
2261 any columns that show the time in the "command-line-specified"
2262 format and, if so, update that row. */
2263 for (fdata = cf->plist, row = -1; fdata != NULL; fdata = fdata->next) {
2264 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
2265 when we update it, we have to run the GTK+ main loop to get it
2266 to repaint what's pending, and doing so may involve an "ioctl()"
2267 to see if there's any pending input from an X server, and doing
2268 that for every packet can be costly, especially on a big file. */
2269 if (count >= progbar_nextstep) {
2270 /* let's not divide by zero. I should never be started
2271 * with count == 0, so let's assert that
2273 g_assert(cf->count > 0);
2275 prog_val = (gfloat) count / cf->count;
2277 if (progbar == NULL)
2278 /* Create the progress bar if necessary */
2279 progbar = delayed_create_progress_dlg("Changing", "time display",
2280 &stop_flag, &start_time, prog_val);
2282 if (progbar != NULL) {
2283 g_snprintf(status_str, sizeof(status_str),
2284 "%4u of %u packets", count, cf->count);
2285 update_progress_dlg(progbar, prog_val, status_str);
2288 progbar_nextstep += progbar_quantum;
2292 /* Well, the user decided to abort the redisplay. Just stop.
2294 XXX - this leaves the time field in the old format in
2295 frames we haven't yet processed. So it goes; should we
2296 simply not offer them the option of stopping? */
2302 /* Find what row this packet is in. */
2303 if (!sorted_by_frame_column) {
2304 /* This function is O(N), so we try to avoid using it... */
2305 row = packet_list_find_row_from_data(fdata);
2307 /* ...which we do by maintaining a count of packets that are
2308 being displayed (i.e., that have passed the display filter),
2309 and using the current value of that count as the row number
2310 (which is why we can only do it when the display is sorted
2311 by the frame number). */
2312 if (fdata->flags.passed_dfilter)
2319 /* This packet is in the summary list, on row "row". */
2321 for (i = first; i <= last; i++) {
2322 if (cf->cinfo.fmt_matx[i][COL_CLS_TIME]) {
2323 /* This is one of the columns that shows the time in
2324 "command-line-specified" format; update it. */
2325 cf->cinfo.col_buf[i][0] = '\0';
2326 col_set_cls_time(fdata, &cf->cinfo, i);
2327 packet_list_set_text(row, i, cf->cinfo.col_data[i]);
2333 /* We're done redisplaying the packets; destroy the progress bar if it
2335 if (progbar != NULL)
2336 destroy_progress_dlg(progbar);
2338 /* Set the column widths of those columns that show the time in
2339 "command-line-specified" format. */
2340 for (i = first; i <= last; i++) {
2341 if (cf->cinfo.fmt_matx[i][COL_CLS_TIME]) {
2342 packet_list_set_cls_time_width(i);
2346 /* Unfreeze the packet list. */
2354 gboolean frame_matched;
2358 cf_find_packet_protocol_tree(capture_file *cf, const char *string)
2362 mdata.string = string;
2363 mdata.string_len = strlen(string);
2364 return find_packet(cf, match_protocol_tree, &mdata);
2368 match_protocol_tree(capture_file *cf, frame_data *fdata, void *criterion)
2370 match_data *mdata = criterion;
2371 epan_dissect_t *edt;
2373 /* Construct the protocol tree, including the displayed text */
2374 edt = epan_dissect_new(TRUE, TRUE);
2375 /* We don't need the column information */
2376 epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, NULL);
2378 /* Iterate through all the nodes, seeing if they have text that matches. */
2380 mdata->frame_matched = FALSE;
2381 proto_tree_children_foreach(edt->tree, match_subtree_text, mdata);
2382 epan_dissect_free(edt);
2383 return mdata->frame_matched;
2387 match_subtree_text(proto_node *node, gpointer data)
2389 match_data *mdata = (match_data*) data;
2390 const gchar *string = mdata->string;
2391 size_t string_len = mdata->string_len;
2392 capture_file *cf = mdata->cf;
2393 field_info *fi = PITEM_FINFO(node);
2394 gchar label_str[ITEM_LABEL_LENGTH];
2401 if (mdata->frame_matched) {
2402 /* We already had a match; don't bother doing any more work. */
2406 /* Don't match invisible entries. */
2407 if (PROTO_ITEM_IS_HIDDEN(node))
2410 /* was a free format label produced? */
2412 label_ptr = fi->rep->representation;
2414 /* no, make a generic label */
2415 label_ptr = label_str;
2416 proto_item_fill_label(fi, label_str);
2419 /* Does that label match? */
2420 label_len = strlen(label_ptr);
2421 for (i = 0; i < label_len; i++) {
2422 c_char = label_ptr[i];
2424 c_char = toupper(c_char);
2425 if (c_char == string[c_match]) {
2427 if (c_match == string_len) {
2428 /* No need to look further; we have a match */
2429 mdata->frame_matched = TRUE;
2436 /* Recurse into the subtree, if it exists */
2437 if (node->first_child != NULL)
2438 proto_tree_children_foreach(node, match_subtree_text, mdata);
2442 cf_find_packet_summary_line(capture_file *cf, const char *string)
2446 mdata.string = string;
2447 mdata.string_len = strlen(string);
2448 return find_packet(cf, match_summary_line, &mdata);
2452 match_summary_line(capture_file *cf, frame_data *fdata, void *criterion)
2454 match_data *mdata = criterion;
2455 const gchar *string = mdata->string;
2456 size_t string_len = mdata->string_len;
2457 epan_dissect_t *edt;
2458 const char *info_column;
2459 size_t info_column_len;
2460 gboolean frame_matched = FALSE;
2466 /* Don't bother constructing the protocol tree */
2467 edt = epan_dissect_new(FALSE, FALSE);
2468 /* Get the column information */
2469 epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, &cf->cinfo);
2471 /* Find the Info column */
2472 for (colx = 0; colx < cf->cinfo.num_cols; colx++) {
2473 if (cf->cinfo.fmt_matx[colx][COL_INFO]) {
2474 /* Found it. See if we match. */
2475 info_column = edt->pi.cinfo->col_data[colx];
2476 info_column_len = strlen(info_column);
2477 for (i = 0; i < info_column_len; i++) {
2478 c_char = info_column[i];
2480 c_char = toupper(c_char);
2481 if (c_char == string[c_match]) {
2483 if (c_match == string_len) {
2484 frame_matched = TRUE;
2493 epan_dissect_free(edt);
2494 return frame_matched;
2500 } cbs_t; /* "Counted byte string" */
2503 cf_find_packet_data(capture_file *cf, const guint8 *string, size_t string_size)
2508 info.data_len = string_size;
2510 /* String or hex search? */
2512 /* String search - what type of string? */
2513 switch (cf->scs_type) {
2515 case SCS_ASCII_AND_UNICODE:
2516 return find_packet(cf, match_ascii_and_unicode, &info);
2519 return find_packet(cf, match_ascii, &info);
2522 return find_packet(cf, match_unicode, &info);
2525 g_assert_not_reached();
2529 return find_packet(cf, match_binary, &info);
2533 match_ascii_and_unicode(capture_file *cf, frame_data *fdata, void *criterion)
2535 cbs_t *info = criterion;
2536 const char *ascii_text = info->data;
2537 size_t textlen = info->data_len;
2538 gboolean frame_matched;
2544 frame_matched = FALSE;
2545 buf_len = fdata->pkt_len;
2546 for (i = 0; i < buf_len; i++) {
2549 c_char = toupper(c_char);
2551 if (c_char == ascii_text[c_match]) {
2553 if (c_match == textlen) {
2554 frame_matched = TRUE;
2561 return frame_matched;
2565 match_ascii(capture_file *cf, frame_data *fdata, void *criterion)
2567 cbs_t *info = criterion;
2568 const char *ascii_text = info->data;
2569 size_t textlen = info->data_len;
2570 gboolean frame_matched;
2576 frame_matched = FALSE;
2577 buf_len = fdata->pkt_len;
2578 for (i = 0; i < buf_len; i++) {
2581 c_char = toupper(c_char);
2582 if (c_char == ascii_text[c_match]) {
2584 if (c_match == textlen) {
2585 frame_matched = TRUE;
2591 return frame_matched;
2595 match_unicode(capture_file *cf, frame_data *fdata, void *criterion)
2597 cbs_t *info = criterion;
2598 const char *ascii_text = info->data;
2599 size_t textlen = info->data_len;
2600 gboolean frame_matched;
2606 frame_matched = FALSE;
2607 buf_len = fdata->pkt_len;
2608 for (i = 0; i < buf_len; i++) {
2611 c_char = toupper(c_char);
2612 if (c_char == ascii_text[c_match]) {
2615 if (c_match == textlen) {
2616 frame_matched = TRUE;
2622 return frame_matched;
2626 match_binary(capture_file *cf, frame_data *fdata, void *criterion)
2628 cbs_t *info = criterion;
2629 const guint8 *binary_data = info->data;
2630 size_t datalen = info->data_len;
2631 gboolean frame_matched;
2636 frame_matched = FALSE;
2637 buf_len = fdata->pkt_len;
2638 for (i = 0; i < buf_len; i++) {
2639 if (cf->pd[i] == binary_data[c_match]) {
2641 if (c_match == datalen) {
2642 frame_matched = TRUE;
2648 return frame_matched;
2652 cf_find_packet_dfilter(capture_file *cf, dfilter_t *sfcode)
2654 return find_packet(cf, match_dfilter, sfcode);
2658 match_dfilter(capture_file *cf, frame_data *fdata, void *criterion)
2660 dfilter_t *sfcode = criterion;
2661 epan_dissect_t *edt;
2662 gboolean frame_matched;
2664 edt = epan_dissect_new(TRUE, FALSE);
2665 epan_dissect_prime_dfilter(edt, sfcode);
2666 epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, NULL);
2667 frame_matched = dfilter_apply_edt(sfcode, edt);
2668 epan_dissect_free(edt);
2669 return frame_matched;
2673 find_packet(capture_file *cf,
2674 gboolean (*match_function)(capture_file *, frame_data *, void *),
2677 frame_data *start_fd;
2679 frame_data *new_fd = NULL;
2680 progdlg_t *progbar = NULL;
2687 GTimeVal start_time;
2688 gchar status_str[100];
2689 int progbar_nextstep;
2690 int progbar_quantum;
2692 start_fd = cf->current_frame;
2693 if (start_fd != NULL) {
2694 /* Iterate through the list of packets, starting at the packet we've
2695 picked, calling a routine to run the filter on the packet, see if
2696 it matches, and stop if so. */
2700 progbar_nextstep = 0;
2701 /* When we reach the value that triggers a progress bar update,
2702 bump that value by this amount. */
2703 progbar_quantum = cf->count/N_PROGBAR_UPDATES;
2706 g_get_current_time(&start_time);
2710 /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
2711 when we update it, we have to run the GTK+ main loop to get it
2712 to repaint what's pending, and doing so may involve an "ioctl()"
2713 to see if there's any pending input from an X server, and doing
2714 that for every packet can be costly, especially on a big file. */
2715 if (count >= progbar_nextstep) {
2716 /* let's not divide by zero. I should never be started
2717 * with count == 0, so let's assert that
2719 g_assert(cf->count > 0);
2721 prog_val = (gfloat) count / cf->count;
2723 /* Create the progress bar if necessary */
2724 if (progbar == NULL)
2725 progbar = delayed_create_progress_dlg("Searching", cf->sfilter,
2726 &stop_flag, &start_time, prog_val);
2728 if (progbar != NULL) {
2729 g_snprintf(status_str, sizeof(status_str),
2730 "%4u of %u packets", count, cf->count);
2731 update_progress_dlg(progbar, prog_val, status_str);
2734 progbar_nextstep += progbar_quantum;
2738 /* Well, the user decided to abort the search. Go back to the
2739 frame where we started. */
2744 /* Go past the current frame. */
2745 if (cf->sbackward) {
2746 /* Go on to the previous frame. */
2747 fdata = fdata->prev;
2748 if (fdata == NULL) {
2750 * XXX - other apps have a bit more of a detailed message
2751 * for this, and instead of offering "OK" and "Cancel",
2752 * they offer things such as "Continue" and "Cancel";
2753 * we need an API for popping up alert boxes with
2754 * {Verb} and "Cancel".
2757 if (prefs.gui_find_wrap)
2759 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
2760 "%sBeginning of capture exceeded!%s\n\n"
2761 "Search is continued from the end of the capture.",
2762 simple_dialog_primary_start(), simple_dialog_primary_end());
2763 fdata = cf->plist_end; /* wrap around */
2767 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
2768 "%sBeginning of capture exceeded!%s\n\n"
2769 "Try searching forwards.",
2770 simple_dialog_primary_start(), simple_dialog_primary_end());
2771 fdata = start_fd; /* stay on previous packet */
2775 /* Go on to the next frame. */
2776 fdata = fdata->next;
2777 if (fdata == NULL) {
2778 if (prefs.gui_find_wrap)
2780 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
2781 "%sEnd of capture exceeded!%s\n\n"
2782 "Search is continued from the start of the capture.",
2783 simple_dialog_primary_start(), simple_dialog_primary_end());
2784 fdata = cf->plist; /* wrap around */
2788 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
2789 "%sEnd of capture exceeded!%s\n\n"
2790 "Try searching backwards.",
2791 simple_dialog_primary_start(), simple_dialog_primary_end());
2792 fdata = start_fd; /* stay on previous packet */
2799 /* Is this packet in the display? */
2800 if (fdata->flags.passed_dfilter) {
2801 /* Yes. Load its data. */
2802 if (!wtap_seek_read(cf->wth, fdata->file_off, &cf->pseudo_header,
2803 cf->pd, fdata->cap_len, &err, &err_info)) {
2804 /* Read error. Report the error, and go back to the frame
2805 where we started. */
2806 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
2807 cf_read_error_message(err, err_info), cf->filename);
2812 /* Does it match the search criterion? */
2813 if ((*match_function)(cf, fdata, criterion)) {
2815 break; /* found it! */
2819 if (fdata == start_fd) {
2820 /* We're back to the frame we were on originally, and that frame
2821 doesn't match the search filter. The search failed. */
2826 /* We're done scanning the packets; destroy the progress bar if it
2828 if (progbar != NULL)
2829 destroy_progress_dlg(progbar);
2832 if (new_fd != NULL) {
2833 /* We found a frame. Find what row it's in. */
2834 row = packet_list_find_row_from_data(new_fd);
2835 g_assert(row != -1);
2837 /* Select that row, make it the focus row, and make it visible. */
2838 packet_list_set_selected_row(row);
2839 return TRUE; /* success */
2841 return FALSE; /* failure */
2845 cf_goto_frame(capture_file *cf, guint fnumber)
2850 for (fdata = cf->plist; fdata != NULL && fdata->num < fnumber; fdata = fdata->next)
2853 if (fdata == NULL) {
2854 /* we didn't find a packet with that packet number */
2855 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
2856 "There is no packet with that packet number.");
2857 return FALSE; /* we failed to go to that packet */
2859 if (!fdata->flags.passed_dfilter) {
2860 /* that packet currently isn't displayed */
2861 /* XXX - add it to the set of displayed packets? */
2862 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
2863 "That packet isn't currently being displayed.");
2864 return FALSE; /* we failed to go to that packet */
2867 /* We found that packet, and it's currently being displayed.
2868 Find what row it's in. */
2869 row = packet_list_find_row_from_data(fdata);
2870 g_assert(row != -1);
2872 /* Select that row, make it the focus row, and make it visible. */
2873 packet_list_set_selected_row(row);
2874 return TRUE; /* we got to that packet */
2878 cf_goto_top_frame(capture_file *cf)
2882 frame_data *lowest_fdata = NULL;
2884 for (fdata = cf->plist; fdata != NULL; fdata = fdata->next) {
2885 if (fdata->flags.passed_dfilter) {
2886 lowest_fdata = fdata;
2891 if (lowest_fdata == NULL) {
2895 /* We found that packet, and it's currently being displayed.
2896 Find what row it's in. */
2897 row = packet_list_find_row_from_data(lowest_fdata);
2898 g_assert(row != -1);
2900 /* Select that row, make it the focus row, and make it visible. */
2901 packet_list_set_selected_row(row);
2902 return TRUE; /* we got to that packet */
2906 cf_goto_bottom_frame(capture_file *cf)
2910 frame_data *highest_fdata = NULL;
2912 for (fdata = cf->plist; fdata != NULL; fdata = fdata->next) {
2913 if (fdata->flags.passed_dfilter) {
2914 highest_fdata = fdata;
2918 if (highest_fdata == NULL) {
2922 /* We found that packet, and it's currently being displayed.
2923 Find what row it's in. */
2924 row = packet_list_find_row_from_data(highest_fdata);
2925 g_assert(row != -1);
2927 /* Select that row, make it the focus row, and make it visible. */
2928 packet_list_set_selected_row(row);
2929 return TRUE; /* we got to that packet */
2933 * Go to frame specified by currently selected protocol tree item.
2936 cf_goto_framenum(capture_file *cf)
2938 header_field_info *hfinfo;
2941 if (cf->finfo_selected) {
2942 hfinfo = cf->finfo_selected->hfinfo;
2944 if (hfinfo->type == FT_FRAMENUM) {
2945 framenum = fvalue_get_integer(&cf->finfo_selected->value);
2947 return cf_goto_frame(cf, framenum);
2954 /* Select the packet on a given row. */
2956 cf_select_packet(capture_file *cf, int row)
2962 /* Get the frame data struct pointer for this frame */
2963 fdata = (frame_data *)packet_list_get_row_data(row);
2965 if (fdata == NULL) {
2966 /* XXX - if a GtkCList's selection mode is GTK_SELECTION_BROWSE, when
2967 the first entry is added to it by "real_insert_row()", that row
2968 is selected (see "real_insert_row()", in "gtk/gtkclist.c", in both
2969 our version and the vanilla GTK+ version).
2971 This means that a "select-row" signal is emitted; this causes
2972 "packet_list_select_cb()" to be called, which causes "cf_select_packet()"
2975 "cf_select_packet()" fetches, above, the data associated with the
2976 row that was selected; however, as "gtk_clist_append()", which
2977 called "real_insert_row()", hasn't yet returned, we haven't yet
2978 associated any data with that row, so we get back a null pointer.
2980 We can't assume that there's only one frame in the frame list,
2981 either, as we may be filtering the display.
2983 We therefore assume that, if "row" is 0, i.e. the first row
2984 is being selected, and "cf->first_displayed" equals
2985 "cf->last_displayed", i.e. there's only one frame being
2986 displayed, that frame is the frame we want.
2988 This means we have to set "cf->first_displayed" and
2989 "cf->last_displayed" before adding the row to the
2990 GtkCList; see the comment in "add_packet_to_packet_list()". */
2992 if (row == 0 && cf->first_displayed == cf->last_displayed)
2993 fdata = cf->first_displayed;
2996 /* Get the data in that frame. */
2997 if (!wtap_seek_read (cf->wth, fdata->file_off, &cf->pseudo_header,
2998 cf->pd, fdata->cap_len, &err, &err_info)) {
2999 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3000 cf_read_error_message(err, err_info), cf->filename);
3004 /* Record that this frame is the current frame. */
3005 cf->current_frame = fdata;
3007 /* Create the logical protocol tree. */
3008 if (cf->edt != NULL) {
3009 epan_dissect_free(cf->edt);
3012 /* We don't need the columns here. */
3013 cf->edt = epan_dissect_new(TRUE, TRUE);
3014 epan_dissect_run(cf->edt, &cf->pseudo_header, cf->pd, cf->current_frame,
3017 cf_callback_invoke(cf_cb_packet_selected, cf);
3020 /* Unselect the selected packet, if any. */
3022 cf_unselect_packet(capture_file *cf)
3024 /* Destroy the epan_dissect_t for the unselected packet. */
3025 if (cf->edt != NULL) {
3026 epan_dissect_free(cf->edt);
3030 /* No packet is selected. */
3031 cf->current_frame = NULL;
3033 cf_callback_invoke(cf_cb_packet_unselected, cf);
3035 /* No protocol tree means no selected field. */
3036 cf_unselect_field(cf);
3039 /* Unset the selected protocol tree field, if any. */
3041 cf_unselect_field(capture_file *cf)
3043 cf->finfo_selected = NULL;
3045 cf_callback_invoke(cf_cb_field_unselected, cf);
3049 * Mark a particular frame.
3052 cf_mark_frame(capture_file *cf, frame_data *frame)
3054 if (! frame->flags.marked) {
3055 frame->flags.marked = TRUE;
3056 if (cf->count > cf->marked_count)
3062 * Unmark a particular frame.
3065 cf_unmark_frame(capture_file *cf, frame_data *frame)
3067 if (frame->flags.marked) {
3068 frame->flags.marked = FALSE;
3069 if (cf->marked_count > 0)
3077 } save_callback_args_t;
3080 * Save a capture to a file, in a particular format, saving either
3081 * all packets, all currently-displayed packets, or all marked packets.
3083 * Returns TRUE if it succeeds, FALSE otherwise; if it fails, it pops
3084 * up a message box for the failure.
3087 save_packet(capture_file *cf _U_, frame_data *fdata,
3088 union wtap_pseudo_header *pseudo_header, const guint8 *pd,
3091 save_callback_args_t *args = argsp;
3092 struct wtap_pkthdr hdr;
3095 /* init the wtap header for saving */
3096 hdr.ts.tv_sec = fdata->abs_secs;
3097 hdr.ts.tv_usec = fdata->abs_usecs;
3098 hdr.caplen = fdata->cap_len;
3099 hdr.len = fdata->pkt_len;
3100 hdr.pkt_encap = fdata->lnk_t;
3102 /* and save the packet */
3103 if (!wtap_dump(args->pdh, &hdr, pseudo_header, pd, &err)) {
3104 cf_write_failure_alert_box(args->fname, err);
3111 cf_save(capture_file *cf, const char *fname, packet_range_t *range, guint save_format)
3113 gchar *from_filename;
3117 struct stat infile, outfile;
3118 save_callback_args_t callback_args;
3120 cf_callback_invoke(cf_cb_file_safe_started, (gpointer) fname);
3123 * Check that the from file is not the same as to file
3124 * We do it here so we catch all cases ...
3125 * Unfortunately, the file requester gives us an absolute file
3126 * name and the read file name may be relative (if supplied on
3127 * the command line). From Joerg Mayer.
3129 * This is a bit tricky on win32. The st_ino field is documented as:
3130 * "The inode, and therefore st_ino, has no meaning in the FAT, ..."
3131 * but it *is* set to zero if stat() returns without an error,
3132 * so this is working, but maybe not quite the way expected. ULFL
3134 infile.st_ino = 1; /* These prevent us from getting equality */
3135 outfile.st_ino = 2; /* If one or other of the files is not accessible */
3136 stat(cf->filename, &infile);
3137 stat(fname, &outfile);
3138 if (infile.st_ino == outfile.st_ino) {
3139 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3140 "%sCapture file: \"%s\" already exists!%s\n\n"
3141 "Please choose a different filename.",
3142 simple_dialog_primary_start(), fname, simple_dialog_primary_end());
3146 packet_range_process_init(range);
3149 * if (!save_filtered && !save_marked && !save_manual_range &&
3150 * !save_marked_range && !save_curr && save_format == cf->cd_t) {
3153 if (packet_range_process_all(range) && save_format == cf->cd_t) {
3154 /* We're not filtering packets, and we're saving it in the format
3155 it's already in, so we can just move or copy the raw data. */
3157 if (cf->is_tempfile) {
3158 /* The file being saved is a temporary file from a live
3159 capture, so it doesn't need to stay around under that name;
3160 first, try renaming the capture buffer file to the new name. */
3162 if (rename(cf->filename, fname) == 0) {
3163 /* That succeeded - there's no need to copy the source file. */
3164 from_filename = NULL;
3167 if (errno == EXDEV) {
3168 /* They're on different file systems, so we have to copy the
3171 from_filename = cf->filename;
3173 /* The rename failed, but not because they're on different
3174 file systems - put up an error message. (Or should we
3175 just punt and try to copy? The only reason why I'd
3176 expect the rename to fail and the copy to succeed would
3177 be if we didn't have permission to remove the file from
3178 the temporary directory, and that might be fixable - but
3179 is it worth requiring the user to go off and fix it?) */
3180 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3181 file_rename_error_message(errno), fname);
3187 from_filename = cf->filename;
3190 /* It's a permanent file, so we should copy it, and not remove the
3193 from_filename = cf->filename;
3197 /* Copy the file, if we haven't moved it. */
3198 if (!copy_binary_file(from_filename, fname))
3202 /* Either we're filtering packets, or we're saving in a different
3203 format; we can't do that by copying or moving the capture file,
3204 we have to do it by writing the packets out in Wiretap. */
3205 pdh = wtap_dump_open(fname, save_format, cf->lnk_t, cf->snap, &err);
3207 cf_open_failure_alert_box(fname, err, NULL, TRUE, save_format);
3211 /* XXX - we let the user save a subset of the packets.
3213 If we do that, should we make that file the current file? If so,
3214 it means we can no longer get at the other packets. What does
3217 /* Iterate through the list of packets, processing the packets we were
3220 XXX - we've already called "packet_range_process_init(range)", but
3221 "process_specified_packets()" will do it again. Fortunately,
3222 that's harmless in this case, as we haven't done anything to
3223 "range" since we initialized it. */
3224 callback_args.pdh = pdh;
3225 callback_args.fname = fname;
3226 switch (process_specified_packets(cf, range, "Saving",
3227 "selected packets", save_packet,
3231 /* Completed successfully. */
3235 /* The user decided to abort the saving.
3236 XXX - remove the output file? */
3240 /* Error while saving. */
3241 wtap_dump_close(pdh, &err);
3245 if (!wtap_dump_close(pdh, &err)) {
3246 cf_close_failure_alert_box(fname, err);
3251 cf_callback_invoke(cf_cb_file_safe_finished, NULL);
3253 if (packet_range_process_all(range)) {
3254 /* We saved the entire capture, not just some packets from it.
3255 Open and read the file we saved it to.
3257 XXX - this is somewhat of a waste; we already have the
3258 packets, all this gets us is updated file type information
3259 (which we could just stuff into "cf"), and having the new
3260 file be the one we have opened and from which we're reading
3261 the data, and it means we have to spend time opening and
3262 reading the file, which could be a significant amount of
3263 time if the file is large. */
3264 cf->user_saved = TRUE;
3266 if ((cf_open(cf, fname, FALSE, &err)) == CF_OK) {
3267 /* XXX - report errors if this fails?
3268 What should we return if it fails or is aborted? */
3269 switch (cf_read(cf)) {
3273 /* Just because we got an error, that doesn't mean we were unable
3274 to read any of the file; we handle what we could get from the
3278 case CF_READ_ABORTED:
3279 /* The user bailed out of re-reading the capture file; the
3280 capture file has been closed - just return (without
3281 changing any menu settings; "cf_close()" set them
3282 correctly for the "no capture file open" state). */
3285 cf_callback_invoke(cf_cb_file_safe_reload_finished, NULL);
3291 cf_callback_invoke(cf_cb_file_safe_failed, NULL);
3296 cf_open_failure_alert_box(const char *filename, int err, gchar *err_info,
3297 gboolean for_writing, int file_type)
3300 /* Wiretap error. */
3303 case WTAP_ERR_NOT_REGULAR_FILE:
3304 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3305 "The file \"%s\" is a \"special file\" or socket or other non-regular file.",
3309 case WTAP_ERR_RANDOM_OPEN_PIPE:
3310 /* Seen only when opening a capture file for reading. */
3311 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3312 "The file \"%s\" is a pipe or FIFO; Ethereal can't read pipe or FIFO files.",
3316 case WTAP_ERR_FILE_UNKNOWN_FORMAT:
3317 /* Seen only when opening a capture file for reading. */
3318 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3319 "The file \"%s\" isn't a capture file in a format Ethereal understands.",
3323 case WTAP_ERR_UNSUPPORTED:
3324 /* Seen only when opening a capture file for reading. */
3325 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3326 "The file \"%s\" isn't a capture file in a format Ethereal understands.\n"
3328 filename, err_info);
3332 case WTAP_ERR_CANT_WRITE_TO_PIPE:
3333 /* Seen only when opening a capture file for writing. */
3334 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3335 "The file \"%s\" is a pipe, and %s capture files can't be "
3336 "written to a pipe.",
3337 filename, wtap_file_type_string(file_type));
3340 case WTAP_ERR_UNSUPPORTED_FILE_TYPE:
3341 /* Seen only when opening a capture file for writing. */
3342 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3343 "Ethereal doesn't support writing capture files in that format.");
3346 case WTAP_ERR_UNSUPPORTED_ENCAP:
3348 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3349 "Ethereal can't save this capture in that format.");
3351 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3352 "The file \"%s\" is a capture for a network type that Ethereal doesn't support.\n"
3354 filename, err_info);
3359 case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED:
3361 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3362 "Ethereal can't save this capture in that format.");
3364 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3365 "The file \"%s\" is a capture for a network type that Ethereal doesn't support.",
3370 case WTAP_ERR_BAD_RECORD:
3371 /* Seen only when opening a capture file for reading. */
3372 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3373 "The file \"%s\" appears to be damaged or corrupt.\n"
3375 filename, err_info);
3379 case WTAP_ERR_CANT_OPEN:
3381 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3382 "The file \"%s\" could not be created for some unknown reason.",
3385 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3386 "The file \"%s\" could not be opened for some unknown reason.",
3391 case WTAP_ERR_SHORT_READ:
3392 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3393 "The file \"%s\" appears to have been cut short"
3394 " in the middle of a packet or other data.",
3398 case WTAP_ERR_SHORT_WRITE:
3399 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3400 "A full header couldn't be written to the file \"%s\".",
3405 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3406 "The file \"%s\" could not be %s: %s.",
3408 for_writing ? "created" : "opened",
3409 wtap_strerror(err));
3414 open_failure_alert_box(filename, err, for_writing);
3419 file_rename_error_message(int err)
3422 static char errmsg_errno[1024+1];
3427 errmsg = "The path to the file \"%s\" doesn't exist.";
3431 errmsg = "You don't have permission to move the capture file to \"%s\".";
3435 snprintf(errmsg_errno, sizeof(errmsg_errno),
3436 "The file \"%%s\" could not be moved: %s.",
3437 wtap_strerror(err));
3438 errmsg = errmsg_errno;
3445 cf_read_error_message(int err, const gchar *err_info)
3447 static char errmsg_errno[1024+1];
3451 case WTAP_ERR_UNSUPPORTED_ENCAP:
3452 snprintf(errmsg_errno, sizeof(errmsg_errno),
3453 "The file \"%%s\" has a packet with a network type that Ethereal doesn't support.\n(%s)",
3457 case WTAP_ERR_BAD_RECORD:
3458 snprintf(errmsg_errno, sizeof(errmsg_errno),
3459 "An error occurred while reading from the file \"%%s\": %s.\n(%s)",
3460 wtap_strerror(err), err_info);
3464 snprintf(errmsg_errno, sizeof(errmsg_errno),
3465 "An error occurred while reading from the file \"%%s\": %s.",
3466 wtap_strerror(err));
3469 return errmsg_errno;
3473 cf_write_failure_alert_box(const char *filename, int err)
3476 /* Wiretap error. */
3477 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3478 "An error occurred while writing to the file \"%s\": %s.",
3479 filename, wtap_strerror(err));
3482 write_failure_alert_box(filename, err);
3486 /* Check for write errors - if the file is being written to an NFS server,
3487 a write error may not show up until the file is closed, as NFS clients
3488 might not send writes to the server until the "write()" call finishes,
3489 so that the write may fail on the server but the "write()" may succeed. */
3491 cf_close_failure_alert_box(const char *filename, int err)
3494 /* Wiretap error. */
3497 case WTAP_ERR_CANT_CLOSE:
3498 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3499 "The file \"%s\" couldn't be closed for some unknown reason.",
3503 case WTAP_ERR_SHORT_WRITE:
3504 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3505 "Not all the packets could be written to the file \"%s\".",
3510 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3511 "An error occurred while closing the file \"%s\": %s.",
3512 filename, wtap_strerror(err));
3517 We assume that a close error from the OS is really a write error. */
3518 write_failure_alert_box(filename, err);
3522 /* Reload the current capture file. */
3524 cf_reload(capture_file *cf) {
3526 gboolean is_tempfile;
3529 /* If the file could be opened, "cf_open()" calls "cf_close()"
3530 to get rid of state for the old capture file before filling in state
3531 for the new capture file. "cf_close()" will remove the file if
3532 it's a temporary file; we don't want that to happen (for one thing,
3533 it'd prevent subsequent reopens from working). Remember whether it's
3534 a temporary file, mark it as not being a temporary file, and then
3535 reopen it as the type of file it was.
3537 Also, "cf_close()" will free "cf->filename", so we must make
3538 a copy of it first. */
3539 filename = g_strdup(cf->filename);
3540 is_tempfile = cf->is_tempfile;
3541 cf->is_tempfile = FALSE;
3542 if (cf_open(cf, filename, is_tempfile, &err) == CF_OK) {
3543 switch (cf_read(cf)) {
3547 /* Just because we got an error, that doesn't mean we were unable
3548 to read any of the file; we handle what we could get from the
3552 case CF_READ_ABORTED:
3553 /* The user bailed out of re-reading the capture file; the
3554 capture file has been closed - just free the capture file name
3555 string and return (without changing the last containing
3561 /* The open failed, so "cf->is_tempfile" wasn't set to "is_tempfile".
3562 Instead, the file was left open, so we should restore "cf->is_tempfile"
3565 XXX - change the menu? Presumably "cf_open()" will do that;
3566 make sure it does! */
3567 cf->is_tempfile = is_tempfile;
3569 /* "cf_open()" made a copy of the file name we handed it, so
3570 we should free up our copy. */
3574 /* Copies a file in binary mode, for those operating systems that care about
3576 * Returns TRUE on success, FALSE on failure. If a failure, it also
3577 * displays a simple dialog window with the error message.
3580 copy_binary_file(const char *from_filename, const char *to_filename)
3582 int from_fd, to_fd, nread, nwritten, err;
3585 /* Copy the raw bytes of the file. */
3586 from_fd = open(from_filename, O_RDONLY | O_BINARY);
3588 open_failure_alert_box(from_filename, errno, FALSE);
3592 /* Use open() instead of creat() so that we can pass the O_BINARY
3593 flag, which is relevant on Win32; it appears that "creat()"
3594 may open the file in text mode, not binary mode, but we want
3595 to copy the raw bytes of the file, so we need the output file
3596 to be open in binary mode. */
3597 to_fd = open(to_filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
3599 open_failure_alert_box(to_filename, errno, TRUE);
3604 while ((nread = read(from_fd, pd, sizeof pd)) > 0) {
3605 nwritten = write(to_fd, pd, nread);
3606 if (nwritten < nread) {
3610 err = WTAP_ERR_SHORT_WRITE;
3611 write_failure_alert_box(to_filename, err);
3619 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3620 "An error occurred while reading from the file \"%s\": %s.",
3621 from_filename, strerror(err));
3627 if (close(to_fd) < 0) {
3628 write_failure_alert_box(to_filename, errno);