nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* file.c |
2 | * File I/O routines |
||
3 | * |
||
4 | * Wireshark - Network traffic analyzer |
||
5 | * By Gerald Combs <gerald@wireshark.org> |
||
6 | * Copyright 1998 Gerald Combs |
||
7 | * |
||
8 | * This program is free software; you can redistribute it and/or |
||
9 | * modify it under the terms of the GNU General Public License |
||
10 | * as published by the Free Software Foundation; either version 2 |
||
11 | * of the License, or (at your option) any later version. |
||
12 | * |
||
13 | * This program is distributed in the hope that it will be useful, |
||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
16 | * GNU General Public License for more details. |
||
17 | * |
||
18 | * You should have received a copy of the GNU General Public License |
||
19 | * along with this program; if not, write to the Free Software |
||
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
||
21 | */ |
||
22 | |||
23 | #include <config.h> |
||
24 | |||
25 | #include <time.h> |
||
26 | |||
27 | #include <stdlib.h> |
||
28 | #include <stdio.h> |
||
29 | #include <string.h> |
||
30 | #include <ctype.h> |
||
31 | #include <errno.h> |
||
32 | |||
33 | #include <wsutil/tempfile.h> |
||
34 | #include <wsutil/file_util.h> |
||
35 | #include <wsutil/filesystem.h> |
||
36 | #include <ws_version_info.h> |
||
37 | |||
38 | #include <wiretap/merge.h> |
||
39 | |||
40 | #include <epan/exceptions.h> |
||
41 | #include <epan/epan-int.h> |
||
42 | #include <epan/epan.h> |
||
43 | #include <epan/column.h> |
||
44 | #include <epan/packet.h> |
||
45 | #include <epan/column-utils.h> |
||
46 | #include <epan/expert.h> |
||
47 | #include <epan/prefs.h> |
||
48 | #include <epan/dfilter/dfilter.h> |
||
49 | #include <epan/epan_dissect.h> |
||
50 | #include <epan/tap.h> |
||
51 | #include <epan/dissectors/packet-ber.h> |
||
52 | #include <epan/timestamp.h> |
||
53 | #include <epan/dfilter/dfilter-macro.h> |
||
54 | #include <epan/strutil.h> |
||
55 | #include <epan/addr_resolv.h> |
||
56 | #include <epan/color_filters.h> |
||
57 | |||
58 | #include "cfile.h" |
||
59 | #include "file.h" |
||
60 | #include "fileset.h" |
||
61 | #include "frame_tvbuff.h" |
||
62 | |||
63 | #include "ui/alert_box.h" |
||
64 | #include "ui/simple_dialog.h" |
||
65 | #include "ui/main_statusbar.h" |
||
66 | #include "ui/progress_dlg.h" |
||
67 | #include "ui/ui_util.h" |
||
68 | |||
69 | /* Needed for addrinfo */ |
||
70 | #ifdef HAVE_SYS_TYPES_H |
||
71 | # include <sys/types.h> |
||
72 | #endif |
||
73 | |||
74 | #ifdef HAVE_SYS_SOCKET_H |
||
75 | #include <sys/socket.h> |
||
76 | #endif |
||
77 | |||
78 | #ifdef HAVE_NETINET_IN_H |
||
79 | # include <netinet/in.h> |
||
80 | #endif |
||
81 | |||
82 | #ifdef HAVE_NETDB_H |
||
83 | # include <netdb.h> |
||
84 | #endif |
||
85 | |||
86 | #ifdef HAVE_WINSOCK2_H |
||
87 | # include <winsock2.h> |
||
88 | #endif |
||
89 | |||
90 | #ifdef _WIN32 |
||
91 | # include <ws2tcpip.h> |
||
92 | #endif |
||
93 | |||
94 | #ifdef HAVE_LIBPCAP |
||
95 | gboolean auto_scroll_live; /* GTK+ only? */ |
||
96 | #endif |
||
97 | |||
98 | static int read_packet(capture_file *cf, dfilter_t *dfcode, epan_dissect_t *edt, |
||
99 | column_info *cinfo, gint64 offset); |
||
100 | |||
101 | static void rescan_packets(capture_file *cf, const char *action, const char *action_item, gboolean redissect); |
||
102 | |||
103 | typedef enum { |
||
104 | MR_NOTMATCHED, |
||
105 | MR_MATCHED, |
||
106 | MR_ERROR |
||
107 | } match_result; |
||
108 | static match_result match_protocol_tree(capture_file *cf, frame_data *fdata, |
||
109 | void *criterion); |
||
110 | static void match_subtree_text(proto_node *node, gpointer data); |
||
111 | static match_result match_summary_line(capture_file *cf, frame_data *fdata, |
||
112 | void *criterion); |
||
113 | static match_result match_narrow_and_wide(capture_file *cf, frame_data *fdata, |
||
114 | void *criterion); |
||
115 | static match_result match_narrow(capture_file *cf, frame_data *fdata, |
||
116 | void *criterion); |
||
117 | static match_result match_wide(capture_file *cf, frame_data *fdata, |
||
118 | void *criterion); |
||
119 | static match_result match_binary(capture_file *cf, frame_data *fdata, |
||
120 | void *criterion); |
||
121 | static match_result match_regex(capture_file *cf, frame_data *fdata, |
||
122 | void *criterion); |
||
123 | static match_result match_dfilter(capture_file *cf, frame_data *fdata, |
||
124 | void *criterion); |
||
125 | static match_result match_marked(capture_file *cf, frame_data *fdata, |
||
126 | void *criterion); |
||
127 | static match_result match_time_reference(capture_file *cf, frame_data *fdata, |
||
128 | void *criterion); |
||
129 | static gboolean find_packet(capture_file *cf, |
||
130 | match_result (*match_function)(capture_file *, frame_data *, void *), |
||
131 | void *criterion, search_direction dir); |
||
132 | |||
133 | static const char *cf_get_user_packet_comment(capture_file *cf, const frame_data *fd); |
||
134 | |||
135 | static void cf_open_failure_alert_box(const char *filename, int err, |
||
136 | gchar *err_info, gboolean for_writing, |
||
137 | int file_type); |
||
138 | static void cf_rename_failure_alert_box(const char *filename, int err); |
||
139 | static void cf_close_failure_alert_box(const char *filename, int err); |
||
140 | static void ref_time_packets(capture_file *cf); |
||
141 | |||
142 | /* Seconds spent processing packets between pushing UI updates. */ |
||
143 | #define PROGBAR_UPDATE_INTERVAL 0.150 |
||
144 | |||
145 | /* Show the progress bar after this many seconds. */ |
||
146 | #define PROGBAR_SHOW_DELAY 0.5 |
||
147 | |||
148 | /* |
||
149 | * We could probably use g_signal_...() instead of the callbacks below but that |
||
150 | * would require linking our CLI programs to libgobject and creating an object |
||
151 | * instance for the signals. |
||
152 | */ |
||
153 | typedef struct { |
||
154 | cf_callback_t cb_fct; |
||
155 | gpointer user_data; |
||
156 | } cf_callback_data_t; |
||
157 | |||
158 | static GList *cf_callbacks = NULL; |
||
159 | |||
160 | static void |
||
161 | cf_callback_invoke(int event, gpointer data) |
||
162 | { |
||
163 | cf_callback_data_t *cb; |
||
164 | GList *cb_item = cf_callbacks; |
||
165 | |||
166 | /* there should be at least one interested */ |
||
167 | g_assert(cb_item != NULL); |
||
168 | |||
169 | while (cb_item != NULL) { |
||
170 | cb = (cf_callback_data_t *)cb_item->data; |
||
171 | cb->cb_fct(event, data, cb->user_data); |
||
172 | cb_item = g_list_next(cb_item); |
||
173 | } |
||
174 | } |
||
175 | |||
176 | |||
177 | void |
||
178 | cf_callback_add(cf_callback_t func, gpointer user_data) |
||
179 | { |
||
180 | cf_callback_data_t *cb; |
||
181 | |||
182 | cb = g_new(cf_callback_data_t,1); |
||
183 | cb->cb_fct = func; |
||
184 | cb->user_data = user_data; |
||
185 | |||
186 | cf_callbacks = g_list_prepend(cf_callbacks, cb); |
||
187 | } |
||
188 | |||
189 | void |
||
190 | cf_callback_remove(cf_callback_t func, gpointer user_data) |
||
191 | { |
||
192 | cf_callback_data_t *cb; |
||
193 | GList *cb_item = cf_callbacks; |
||
194 | |||
195 | while (cb_item != NULL) { |
||
196 | cb = (cf_callback_data_t *)cb_item->data; |
||
197 | if (cb->cb_fct == func && cb->user_data == user_data) { |
||
198 | cf_callbacks = g_list_remove(cf_callbacks, cb); |
||
199 | g_free(cb); |
||
200 | return; |
||
201 | } |
||
202 | cb_item = g_list_next(cb_item); |
||
203 | } |
||
204 | |||
205 | g_assert_not_reached(); |
||
206 | } |
||
207 | |||
208 | void |
||
209 | cf_timestamp_auto_precision(capture_file *cf) |
||
210 | { |
||
211 | int i; |
||
212 | |||
213 | /* don't try to get the file's precision if none is opened */ |
||
214 | if (cf->state == FILE_CLOSED) { |
||
215 | return; |
||
216 | } |
||
217 | |||
218 | /* Set the column widths of those columns that show the time in |
||
219 | "command-line-specified" format. */ |
||
220 | for (i = 0; i < cf->cinfo.num_cols; i++) { |
||
221 | if (col_has_time_fmt(&cf->cinfo, i)) { |
||
222 | packet_list_resize_column(i); |
||
223 | } |
||
224 | } |
||
225 | } |
||
226 | |||
227 | gulong |
||
228 | cf_get_computed_elapsed(capture_file *cf) |
||
229 | { |
||
230 | return cf->computed_elapsed; |
||
231 | } |
||
232 | |||
233 | /* |
||
234 | * GLIB_CHECK_VERSION(2,28,0) adds g_get_real_time which could minimize or |
||
235 | * replace this |
||
236 | */ |
||
237 | static void compute_elapsed(capture_file *cf, GTimeVal *start_time) |
||
238 | { |
||
239 | gdouble delta_time; |
||
240 | GTimeVal time_now; |
||
241 | |||
242 | g_get_current_time(&time_now); |
||
243 | |||
244 | delta_time = (time_now.tv_sec - start_time->tv_sec) * 1e6 + |
||
245 | time_now.tv_usec - start_time->tv_usec; |
||
246 | |||
247 | cf->computed_elapsed = (gulong) (delta_time / 1000); /* ms */ |
||
248 | } |
||
249 | |||
250 | static const nstime_t * |
||
251 | ws_get_frame_ts(void *data, guint32 frame_num) |
||
252 | { |
||
253 | capture_file *cf = (capture_file *) data; |
||
254 | |||
255 | if (cf->prev_dis && cf->prev_dis->num == frame_num) |
||
256 | return &cf->prev_dis->abs_ts; |
||
257 | |||
258 | if (cf->prev_cap && cf->prev_cap->num == frame_num) |
||
259 | return &cf->prev_cap->abs_ts; |
||
260 | |||
261 | if (cf->frames) { |
||
262 | frame_data *fd = frame_data_sequence_find(cf->frames, frame_num); |
||
263 | |||
264 | return (fd) ? &fd->abs_ts : NULL; |
||
265 | } |
||
266 | |||
267 | return NULL; |
||
268 | } |
||
269 | |||
270 | static const char * |
||
271 | ws_get_user_comment(void *data, const frame_data *fd) |
||
272 | { |
||
273 | capture_file *cf = (capture_file *) data; |
||
274 | |||
275 | return cf_get_user_packet_comment(cf, fd); |
||
276 | } |
||
277 | |||
278 | static epan_t * |
||
279 | ws_epan_new(capture_file *cf) |
||
280 | { |
||
281 | epan_t *epan = epan_new(); |
||
282 | |||
283 | epan->data = cf; |
||
284 | epan->get_frame_ts = ws_get_frame_ts; |
||
285 | epan->get_interface_name = cap_file_get_interface_name; |
||
286 | epan->get_user_comment = ws_get_user_comment; |
||
287 | |||
288 | return epan; |
||
289 | } |
||
290 | |||
291 | cf_status_t |
||
292 | cf_open(capture_file *cf, const char *fname, unsigned int type, gboolean is_tempfile, int *err) |
||
293 | { |
||
294 | wtap *wth; |
||
295 | gchar *err_info; |
||
296 | |||
297 | wth = wtap_open_offline(fname, type, err, &err_info, TRUE); |
||
298 | if (wth == NULL) |
||
299 | goto fail; |
||
300 | |||
301 | /* The open succeeded. Close whatever capture file we had open, |
||
302 | and fill in the information for this file. */ |
||
303 | cf_close(cf); |
||
304 | |||
305 | /* Initialize the packet header. */ |
||
306 | wtap_phdr_init(&cf->phdr); |
||
307 | |||
308 | /* XXX - we really want to initialize this after we've read all |
||
309 | the packets, so we know how much we'll ultimately need. */ |
||
310 | ws_buffer_init(&cf->buf, 1500); |
||
311 | |||
312 | /* Create new epan session for dissection. |
||
313 | * (The old one was freed in cf_close().) |
||
314 | */ |
||
315 | cf->epan = ws_epan_new(cf); |
||
316 | |||
317 | /* We're about to start reading the file. */ |
||
318 | cf->state = FILE_READ_IN_PROGRESS; |
||
319 | |||
320 | cf->wth = wth; |
||
321 | cf->f_datalen = 0; |
||
322 | |||
323 | /* Set the file name because we need it to set the follow stream filter. |
||
324 | XXX - is that still true? We need it for other reasons, though, |
||
325 | in any case. */ |
||
326 | cf->filename = g_strdup(fname); |
||
327 | |||
328 | /* Indicate whether it's a permanent or temporary file. */ |
||
329 | cf->is_tempfile = is_tempfile; |
||
330 | |||
331 | /* No user changes yet. */ |
||
332 | cf->unsaved_changes = FALSE; |
||
333 | |||
334 | cf->computed_elapsed = 0; |
||
335 | |||
336 | cf->cd_t = wtap_file_type_subtype(cf->wth); |
||
337 | cf->open_type = type; |
||
338 | cf->linktypes = g_array_sized_new(FALSE, FALSE, (guint) sizeof(int), 1); |
||
339 | cf->count = 0; |
||
340 | cf->packet_comment_count = 0; |
||
341 | cf->displayed_count = 0; |
||
342 | cf->marked_count = 0; |
||
343 | cf->ignored_count = 0; |
||
344 | cf->ref_time_count = 0; |
||
345 | cf->drops_known = FALSE; |
||
346 | cf->drops = 0; |
||
347 | cf->snap = wtap_snapshot_length(cf->wth); |
||
348 | if (cf->snap == 0) { |
||
349 | /* Snapshot length not known. */ |
||
350 | cf->has_snap = FALSE; |
||
351 | cf->snap = WTAP_MAX_PACKET_SIZE; |
||
352 | } else |
||
353 | cf->has_snap = TRUE; |
||
354 | |||
355 | /* Allocate a frame_data_sequence for the frames in this file */ |
||
356 | cf->frames = new_frame_data_sequence(); |
||
357 | |||
358 | nstime_set_zero(&cf->elapsed_time); |
||
359 | cf->ref = NULL; |
||
360 | cf->prev_dis = NULL; |
||
361 | cf->prev_cap = NULL; |
||
362 | cf->cum_bytes = 0; |
||
363 | |||
364 | packet_list_queue_draw(); |
||
365 | cf_callback_invoke(cf_cb_file_opened, cf); |
||
366 | |||
367 | if (cf->cd_t == WTAP_FILE_TYPE_SUBTYPE_BER) { |
||
368 | /* tell the BER dissector the file name */ |
||
369 | ber_set_filename(cf->filename); |
||
370 | } |
||
371 | |||
372 | wtap_set_cb_new_ipv4(cf->wth, add_ipv4_name); |
||
373 | wtap_set_cb_new_ipv6(cf->wth, (wtap_new_ipv6_callback_t) add_ipv6_name); |
||
374 | |||
375 | return CF_OK; |
||
376 | |||
377 | fail: |
||
378 | cf_open_failure_alert_box(fname, *err, err_info, FALSE, 0); |
||
379 | return CF_ERROR; |
||
380 | } |
||
381 | |||
382 | /* |
||
383 | * Add an encapsulation type to cf->linktypes. |
||
384 | */ |
||
385 | static void |
||
386 | cf_add_encapsulation_type(capture_file *cf, int encap) |
||
387 | { |
||
388 | guint i; |
||
389 | |||
390 | for (i = 0; i < cf->linktypes->len; i++) { |
||
391 | if (g_array_index(cf->linktypes, gint, i) == encap) |
||
392 | return; /* it's already there */ |
||
393 | } |
||
394 | /* It's not already there - add it. */ |
||
395 | g_array_append_val(cf->linktypes, encap); |
||
396 | } |
||
397 | |||
398 | /* Reset everything to a pristine state */ |
||
399 | void |
||
400 | cf_close(capture_file *cf) |
||
401 | { |
||
402 | cf->stop_flag = FALSE; |
||
403 | if (cf->state == FILE_CLOSED) |
||
404 | return; /* Nothing to do */ |
||
405 | |||
406 | /* Die if we're in the middle of reading a file. */ |
||
407 | g_assert(cf->state != FILE_READ_IN_PROGRESS); |
||
408 | |||
409 | cf_callback_invoke(cf_cb_file_closing, cf); |
||
410 | |||
411 | /* close things, if not already closed before */ |
||
412 | color_filters_cleanup(); |
||
413 | |||
414 | if (cf->wth) { |
||
415 | wtap_close(cf->wth); |
||
416 | cf->wth = NULL; |
||
417 | } |
||
418 | /* We have no file open... */ |
||
419 | if (cf->filename != NULL) { |
||
420 | /* If it's a temporary file, remove it. */ |
||
421 | if (cf->is_tempfile) |
||
422 | ws_unlink(cf->filename); |
||
423 | g_free(cf->filename); |
||
424 | cf->filename = NULL; |
||
425 | } |
||
426 | /* ...which means we have no changes to that file to save. */ |
||
427 | cf->unsaved_changes = FALSE; |
||
428 | |||
429 | /* no open_routine type */ |
||
430 | cf->open_type = WTAP_TYPE_AUTO; |
||
431 | |||
432 | /* Clean up the packet header. */ |
||
433 | wtap_phdr_cleanup(&cf->phdr); |
||
434 | |||
435 | /* Free up the packet buffer. */ |
||
436 | ws_buffer_free(&cf->buf); |
||
437 | |||
438 | dfilter_free(cf->rfcode); |
||
439 | cf->rfcode = NULL; |
||
440 | if (cf->frames != NULL) { |
||
441 | free_frame_data_sequence(cf->frames); |
||
442 | cf->frames = NULL; |
||
443 | } |
||
444 | #ifdef WANT_PACKET_EDITOR |
||
445 | if (cf->edited_frames) { |
||
446 | g_tree_destroy(cf->edited_frames); |
||
447 | cf->edited_frames = NULL; |
||
448 | } |
||
449 | #endif |
||
450 | if (cf->frames_user_comments) { |
||
451 | g_tree_destroy(cf->frames_user_comments); |
||
452 | cf->frames_user_comments = NULL; |
||
453 | } |
||
454 | cf_unselect_packet(cf); /* nothing to select */ |
||
455 | cf->first_displayed = 0; |
||
456 | cf->last_displayed = 0; |
||
457 | |||
458 | /* No frames, no frame selected, no field in that frame selected. */ |
||
459 | cf->count = 0; |
||
460 | cf->current_frame = 0; |
||
461 | cf->current_row = 0; |
||
462 | cf->finfo_selected = NULL; |
||
463 | |||
464 | /* No frame link-layer types, either. */ |
||
465 | if (cf->linktypes != NULL) { |
||
466 | g_array_free(cf->linktypes, TRUE); |
||
467 | cf->linktypes = NULL; |
||
468 | } |
||
469 | |||
470 | /* Clear the packet list. */ |
||
471 | packet_list_freeze(); |
||
472 | packet_list_clear(); |
||
473 | packet_list_thaw(); |
||
474 | |||
475 | cf->f_datalen = 0; |
||
476 | nstime_set_zero(&cf->elapsed_time); |
||
477 | |||
478 | reset_tap_listeners(); |
||
479 | |||
480 | epan_free(cf->epan); |
||
481 | cf->epan = NULL; |
||
482 | |||
483 | /* We have no file open. */ |
||
484 | cf->state = FILE_CLOSED; |
||
485 | |||
486 | cf_callback_invoke(cf_cb_file_closed, cf); |
||
487 | } |
||
488 | |||
489 | /* |
||
490 | * TRUE if the progress dialog doesn't exist and it looks like we'll |
||
491 | * take > 2s to load, FALSE otherwise. |
||
492 | */ |
||
493 | static inline gboolean |
||
494 | progress_is_slow(progdlg_t *progdlg, GTimer *prog_timer, gint64 size, gint64 pos) |
||
495 | { |
||
496 | double elapsed; |
||
497 | |||
498 | if (progdlg) return FALSE; |
||
499 | elapsed = g_timer_elapsed(prog_timer, NULL); |
||
500 | if ((elapsed / 2 > PROGBAR_SHOW_DELAY && (size / pos) > 2) /* It looks like we're going to be slow. */ |
||
501 | || elapsed > PROGBAR_SHOW_DELAY) { /* We are indeed slow. */ |
||
502 | return TRUE; |
||
503 | } |
||
504 | return FALSE; |
||
505 | } |
||
506 | |||
507 | static float |
||
508 | calc_progbar_val(capture_file *cf, gint64 size, gint64 file_pos, gchar *status_str, gulong status_size) |
||
509 | { |
||
510 | float progbar_val; |
||
511 | |||
512 | progbar_val = (gfloat) file_pos / (gfloat) size; |
||
513 | if (progbar_val > 1.0) { |
||
514 | |||
515 | /* The file probably grew while we were reading it. |
||
516 | * Update file size, and try again. |
||
517 | */ |
||
518 | size = wtap_file_size(cf->wth, NULL); |
||
519 | |||
520 | if (size >= 0) |
||
521 | progbar_val = (gfloat) file_pos / (gfloat) size; |
||
522 | |||
523 | /* If it's still > 1, either "wtap_file_size()" failed (in which |
||
524 | * case there's not much we can do about it), or the file |
||
525 | * *shrank* (in which case there's not much we can do about |
||
526 | * it); just clip the progress value at 1.0. |
||
527 | */ |
||
528 | if (progbar_val > 1.0f) |
||
529 | progbar_val = 1.0f; |
||
530 | } |
||
531 | |||
532 | g_snprintf(status_str, status_size, |
||
533 | "%" G_GINT64_MODIFIER "dKB of %" G_GINT64_MODIFIER "dKB", |
||
534 | file_pos / 1024, size / 1024); |
||
535 | |||
536 | return progbar_val; |
||
537 | } |
||
538 | |||
539 | cf_read_status_t |
||
540 | cf_read(capture_file *cf, gboolean reloading) |
||
541 | { |
||
542 | int err = 0; |
||
543 | gchar *err_info = NULL; |
||
544 | gchar *name_ptr; |
||
545 | progdlg_t *volatile progbar = NULL; |
||
546 | GTimer *prog_timer = g_timer_new(); |
||
547 | GTimeVal start_time; |
||
548 | epan_dissect_t edt; |
||
549 | dfilter_t *dfcode; |
||
550 | volatile gboolean create_proto_tree; |
||
551 | guint tap_flags; |
||
552 | gboolean compiled; |
||
553 | |||
554 | /* Compile the current display filter. |
||
555 | * We assume this will not fail since cf->dfilter is only set in |
||
556 | * cf_filter IFF the filter was valid. |
||
557 | */ |
||
558 | compiled = dfilter_compile(cf->dfilter, &dfcode, NULL); |
||
559 | g_assert(!cf->dfilter || (compiled && dfcode)); |
||
560 | |||
561 | /* Get the union of the flags for all tap listeners. */ |
||
562 | tap_flags = union_of_tap_listener_flags(); |
||
563 | create_proto_tree = |
||
564 | (dfcode != NULL || have_filtering_tap_listeners() || (tap_flags & TL_REQUIRES_PROTO_TREE)); |
||
565 | |||
566 | reset_tap_listeners(); |
||
567 | |||
568 | name_ptr = g_filename_display_basename(cf->filename); |
||
569 | |||
570 | if (reloading) |
||
571 | cf_callback_invoke(cf_cb_file_reload_started, cf); |
||
572 | else |
||
573 | cf_callback_invoke(cf_cb_file_read_started, cf); |
||
574 | |||
575 | /* Record whether the file is compressed. |
||
576 | XXX - do we know this at open time? */ |
||
577 | cf->iscompressed = wtap_iscompressed(cf->wth); |
||
578 | |||
579 | /* The packet list window will be empty until the file is completly loaded */ |
||
580 | packet_list_freeze(); |
||
581 | |||
582 | cf->stop_flag = FALSE; |
||
583 | g_get_current_time(&start_time); |
||
584 | |||
585 | epan_dissect_init(&edt, cf->epan, create_proto_tree, FALSE); |
||
586 | |||
587 | TRY { |
||
588 | int count = 0; |
||
589 | |||
590 | gint64 size; |
||
591 | gint64 file_pos; |
||
592 | gint64 data_offset; |
||
593 | |||
594 | float progbar_val; |
||
595 | gchar status_str[100]; |
||
596 | |||
597 | column_info *cinfo; |
||
598 | |||
599 | cinfo = (tap_flags & TL_REQUIRES_COLUMNS) ? &cf->cinfo : NULL; |
||
600 | |||
601 | /* Find the size of the file. */ |
||
602 | size = wtap_file_size(cf->wth, NULL); |
||
603 | |||
604 | g_timer_start(prog_timer); |
||
605 | |||
606 | while ((wtap_read(cf->wth, &err, &err_info, &data_offset))) { |
||
607 | if (size >= 0) { |
||
608 | count++; |
||
609 | file_pos = wtap_read_so_far(cf->wth); |
||
610 | |||
611 | /* Create the progress bar if necessary. */ |
||
612 | if (progress_is_slow(progbar, prog_timer, size, file_pos)) { |
||
613 | progbar_val = calc_progbar_val(cf, size, file_pos, status_str, sizeof(status_str)); |
||
614 | if (reloading) |
||
615 | progbar = delayed_create_progress_dlg(cf->window, "Reloading", name_ptr, |
||
616 | TRUE, &cf->stop_flag, &start_time, progbar_val); |
||
617 | else |
||
618 | progbar = delayed_create_progress_dlg(cf->window, "Loading", name_ptr, |
||
619 | TRUE, &cf->stop_flag, &start_time, progbar_val); |
||
620 | } |
||
621 | |||
622 | /* |
||
623 | * Update the progress bar, but do it only after |
||
624 | * PROGBAR_UPDATE_INTERVAL has elapsed. Calling update_progress_dlg |
||
625 | * and packets_bar_update will likely trigger UI paint events, which |
||
626 | * might take a while depending on the platform and display. Reset |
||
627 | * our timer *after* painting. |
||
628 | */ |
||
629 | if (progbar && g_timer_elapsed(prog_timer, NULL) > PROGBAR_UPDATE_INTERVAL) { |
||
630 | progbar_val = calc_progbar_val(cf, size, file_pos, status_str, sizeof(status_str)); |
||
631 | /* update the packet bar content on the first run or frequently on very large files */ |
||
632 | update_progress_dlg(progbar, progbar_val, status_str); |
||
633 | packets_bar_update(); |
||
634 | g_timer_start(prog_timer); |
||
635 | } |
||
636 | } |
||
637 | |||
638 | if (cf->stop_flag) { |
||
639 | /* Well, the user decided to abort the read. He/She will be warned and |
||
640 | it might be enough for him/her to work with the already loaded |
||
641 | packets. |
||
642 | This is especially true for very large capture files, where you don't |
||
643 | want to wait loading the whole file (which may last minutes or even |
||
644 | hours even on fast machines) just to see that it was the wrong file. */ |
||
645 | break; |
||
646 | } |
||
647 | read_packet(cf, dfcode, &edt, cinfo, data_offset); |
||
648 | } |
||
649 | } |
||
650 | CATCH(OutOfMemoryError) { |
||
651 | simple_message_box(ESD_TYPE_ERROR, NULL, |
||
652 | "More information and workarounds can be found at\n" |
||
653 | "https://wiki.wireshark.org/KnownBugs/OutOfMemory", |
||
654 | "Sorry, but Wireshark has run out of memory and has to terminate now."); |
||
655 | #if 0 |
||
656 | /* Could we close the current capture and free up memory from that? */ |
||
657 | #else |
||
658 | /* we have to terminate, as we cannot recover from the memory error */ |
||
659 | exit(1); |
||
660 | #endif |
||
661 | } |
||
662 | ENDTRY; |
||
663 | |||
664 | /* Free the display name */ |
||
665 | g_free(name_ptr); |
||
666 | |||
667 | /* Cleanup and release all dfilter resources */ |
||
668 | if (dfcode != NULL) { |
||
669 | dfilter_free(dfcode); |
||
670 | } |
||
671 | |||
672 | epan_dissect_cleanup(&edt); |
||
673 | |||
674 | /* We're done reading the file; destroy the progress bar if it was created. */ |
||
675 | if (progbar != NULL) |
||
676 | destroy_progress_dlg(progbar); |
||
677 | g_timer_destroy(prog_timer); |
||
678 | |||
679 | /* We're done reading sequentially through the file. */ |
||
680 | cf->state = FILE_READ_DONE; |
||
681 | |||
682 | /* Close the sequential I/O side, to free up memory it requires. */ |
||
683 | wtap_sequential_close(cf->wth); |
||
684 | |||
685 | /* Allow the protocol dissectors to free up memory that they |
||
686 | * don't need after the sequential run-through of the packets. */ |
||
687 | postseq_cleanup_all_protocols(); |
||
688 | |||
689 | /* compute the time it took to load the file */ |
||
690 | compute_elapsed(cf, &start_time); |
||
691 | |||
692 | /* Set the file encapsulation type now; we don't know what it is until |
||
693 | we've looked at all the packets, as we don't know until then whether |
||
694 | there's more than one type (and thus whether it's |
||
695 | WTAP_ENCAP_PER_PACKET). */ |
||
696 | cf->lnk_t = wtap_file_encap(cf->wth); |
||
697 | |||
698 | cf->current_frame = frame_data_sequence_find(cf->frames, cf->first_displayed); |
||
699 | cf->current_row = 0; |
||
700 | |||
701 | packet_list_thaw(); |
||
702 | if (reloading) |
||
703 | cf_callback_invoke(cf_cb_file_reload_finished, cf); |
||
704 | else |
||
705 | cf_callback_invoke(cf_cb_file_read_finished, cf); |
||
706 | |||
707 | /* If we have any displayed packets to select, select the first of those |
||
708 | packets by making the first row the selected row. */ |
||
709 | if (cf->first_displayed != 0) { |
||
710 | packet_list_select_first_row(); |
||
711 | } |
||
712 | |||
713 | if (cf->stop_flag) { |
||
714 | simple_message_box(ESD_TYPE_WARN, NULL, |
||
715 | "The remaining packets in the file were discarded.\n" |
||
716 | "\n" |
||
717 | "As a lot of packets from the original file will be missing,\n" |
||
718 | "remember to be careful when saving the current content to a file.\n", |
||
719 | "File loading was cancelled."); |
||
720 | return CF_READ_ERROR; |
||
721 | } |
||
722 | |||
723 | if (err != 0) { |
||
724 | /* Put up a message box noting that the read failed somewhere along |
||
725 | the line. Don't throw out the stuff we managed to read, though, |
||
726 | if any. */ |
||
727 | switch (err) { |
||
728 | |||
729 | case WTAP_ERR_UNSUPPORTED: |
||
730 | simple_error_message_box( |
||
731 | "The capture file contains record data that Wireshark doesn't support.\n(%s)", |
||
732 | err_info != NULL ? err_info : "no information supplied"); |
||
733 | g_free(err_info); |
||
734 | break; |
||
735 | |||
736 | case WTAP_ERR_SHORT_READ: |
||
737 | simple_error_message_box( |
||
738 | "The capture file appears to have been cut short" |
||
739 | " in the middle of a packet."); |
||
740 | break; |
||
741 | |||
742 | case WTAP_ERR_BAD_FILE: |
||
743 | simple_error_message_box( |
||
744 | "The capture file appears to be damaged or corrupt.\n(%s)", |
||
745 | err_info != NULL ? err_info : "no information supplied"); |
||
746 | g_free(err_info); |
||
747 | break; |
||
748 | |||
749 | case WTAP_ERR_DECOMPRESS: |
||
750 | simple_error_message_box( |
||
751 | "The compressed capture file appears to be damaged or corrupt.\n(%s)", |
||
752 | err_info != NULL ? err_info : "no information supplied"); |
||
753 | g_free(err_info); |
||
754 | break; |
||
755 | |||
756 | default: |
||
757 | simple_error_message_box( |
||
758 | "An error occurred while reading the" |
||
759 | " capture file: %s.", wtap_strerror(err)); |
||
760 | break; |
||
761 | } |
||
762 | return CF_READ_ERROR; |
||
763 | } else |
||
764 | return CF_READ_OK; |
||
765 | } |
||
766 | |||
767 | #ifdef HAVE_LIBPCAP |
||
768 | cf_read_status_t |
||
769 | cf_continue_tail(capture_file *cf, volatile int to_read, int *err) |
||
770 | { |
||
771 | gchar *err_info; |
||
772 | volatile int newly_displayed_packets = 0; |
||
773 | dfilter_t *dfcode; |
||
774 | epan_dissect_t edt; |
||
775 | gboolean create_proto_tree; |
||
776 | guint tap_flags; |
||
777 | gboolean compiled; |
||
778 | |||
779 | /* Compile the current display filter. |
||
780 | * We assume this will not fail since cf->dfilter is only set in |
||
781 | * cf_filter IFF the filter was valid. |
||
782 | */ |
||
783 | compiled = dfilter_compile(cf->dfilter, &dfcode, NULL); |
||
784 | g_assert(!cf->dfilter || (compiled && dfcode)); |
||
785 | |||
786 | /* Get the union of the flags for all tap listeners. */ |
||
787 | tap_flags = union_of_tap_listener_flags(); |
||
788 | create_proto_tree = |
||
789 | (dfcode != NULL || have_filtering_tap_listeners() || (tap_flags & TL_REQUIRES_PROTO_TREE)); |
||
790 | |||
791 | *err = 0; |
||
792 | |||
793 | packet_list_check_end(); |
||
794 | /* Don't freeze/thaw the list when doing live capture */ |
||
795 | /*packet_list_freeze();*/ |
||
796 | |||
797 | /*g_log(NULL, G_LOG_LEVEL_MESSAGE, "cf_continue_tail: %u new: %u", cf->count, to_read);*/ |
||
798 | |||
799 | epan_dissect_init(&edt, cf->epan, create_proto_tree, FALSE); |
||
800 | |||
801 | TRY { |
||
802 | gint64 data_offset = 0; |
||
803 | column_info *cinfo; |
||
804 | |||
805 | cinfo = (tap_flags & TL_REQUIRES_COLUMNS) ? &cf->cinfo : NULL; |
||
806 | |||
807 | while (to_read != 0) { |
||
808 | wtap_cleareof(cf->wth); |
||
809 | if (!wtap_read(cf->wth, err, &err_info, &data_offset)) { |
||
810 | break; |
||
811 | } |
||
812 | if (cf->state == FILE_READ_ABORTED) { |
||
813 | /* Well, the user decided to exit Wireshark. Break out of the |
||
814 | loop, and let the code below (which is called even if there |
||
815 | aren't any packets left to read) exit. */ |
||
816 | break; |
||
817 | } |
||
818 | if (read_packet(cf, dfcode, &edt, (column_info *) cinfo, data_offset) != -1) { |
||
819 | newly_displayed_packets++; |
||
820 | } |
||
821 | to_read--; |
||
822 | } |
||
823 | } |
||
824 | CATCH(OutOfMemoryError) { |
||
825 | simple_message_box(ESD_TYPE_ERROR, NULL, |
||
826 | "More information and workarounds can be found at\n" |
||
827 | "https://wiki.wireshark.org/KnownBugs/OutOfMemory", |
||
828 | "Sorry, but Wireshark has run out of memory and has to terminate now."); |
||
829 | #if 0 |
||
830 | /* Could we close the current capture and free up memory from that? */ |
||
831 | return CF_READ_ABORTED; |
||
832 | #else |
||
833 | /* we have to terminate, as we cannot recover from the memory error */ |
||
834 | exit(1); |
||
835 | #endif |
||
836 | } |
||
837 | ENDTRY; |
||
838 | |||
839 | /* Update the file encapsulation; it might have changed based on the |
||
840 | packets we've read. */ |
||
841 | cf->lnk_t = wtap_file_encap(cf->wth); |
||
842 | |||
843 | /* Cleanup and release all dfilter resources */ |
||
844 | if (dfcode != NULL) { |
||
845 | dfilter_free(dfcode); |
||
846 | } |
||
847 | |||
848 | epan_dissect_cleanup(&edt); |
||
849 | |||
850 | /*g_log(NULL, G_LOG_LEVEL_MESSAGE, "cf_continue_tail: count %u state: %u err: %u", |
||
851 | cf->count, cf->state, *err);*/ |
||
852 | |||
853 | /* Don't freeze/thaw the list when doing live capture */ |
||
854 | /*packet_list_thaw();*/ |
||
855 | /* With the new packet list the first packet |
||
856 | * isn't automatically selected. |
||
857 | */ |
||
858 | if (!cf->current_frame) |
||
859 | packet_list_select_first_row(); |
||
860 | |||
861 | /* moving to the end of the packet list - if the user requested so and |
||
862 | we have some new packets. */ |
||
863 | if (newly_displayed_packets && auto_scroll_live && cf->count != 0) |
||
864 | packet_list_moveto_end(); |
||
865 | |||
866 | if (cf->state == FILE_READ_ABORTED) { |
||
867 | /* Well, the user decided to exit Wireshark. Return CF_READ_ABORTED |
||
868 | so that our caller can kill off the capture child process; |
||
869 | this will cause an EOF on the pipe from the child, so |
||
870 | "cf_finish_tail()" will be called, and it will clean up |
||
871 | and exit. */ |
||
872 | return CF_READ_ABORTED; |
||
873 | } else if (*err != 0) { |
||
874 | /* We got an error reading the capture file. |
||
875 | XXX - pop up a dialog box instead? */ |
||
876 | if (err_info != NULL) { |
||
877 | g_warning("Error \"%s\" while reading \"%s\" (\"%s\")", |
||
878 | wtap_strerror(*err), cf->filename, err_info); |
||
879 | g_free(err_info); |
||
880 | } else { |
||
881 | g_warning("Error \"%s\" while reading \"%s\"", |
||
882 | wtap_strerror(*err), cf->filename); |
||
883 | } |
||
884 | return CF_READ_ERROR; |
||
885 | } else |
||
886 | return CF_READ_OK; |
||
887 | } |
||
888 | |||
889 | void |
||
890 | cf_fake_continue_tail(capture_file *cf) { |
||
891 | cf->state = FILE_READ_DONE; |
||
892 | } |
||
893 | |||
894 | cf_read_status_t |
||
895 | cf_finish_tail(capture_file *cf, int *err) |
||
896 | { |
||
897 | gchar *err_info; |
||
898 | gint64 data_offset; |
||
899 | dfilter_t *dfcode; |
||
900 | column_info *cinfo; |
||
901 | epan_dissect_t edt; |
||
902 | gboolean create_proto_tree; |
||
903 | guint tap_flags; |
||
904 | gboolean compiled; |
||
905 | |||
906 | /* Compile the current display filter. |
||
907 | * We assume this will not fail since cf->dfilter is only set in |
||
908 | * cf_filter IFF the filter was valid. |
||
909 | */ |
||
910 | compiled = dfilter_compile(cf->dfilter, &dfcode, NULL); |
||
911 | g_assert(!cf->dfilter || (compiled && dfcode)); |
||
912 | |||
913 | /* Get the union of the flags for all tap listeners. */ |
||
914 | tap_flags = union_of_tap_listener_flags(); |
||
915 | cinfo = (tap_flags & TL_REQUIRES_COLUMNS) ? &cf->cinfo : NULL; |
||
916 | create_proto_tree = |
||
917 | (dfcode != NULL || have_filtering_tap_listeners() || (tap_flags & TL_REQUIRES_PROTO_TREE)); |
||
918 | |||
919 | if (cf->wth == NULL) { |
||
920 | cf_close(cf); |
||
921 | return CF_READ_ERROR; |
||
922 | } |
||
923 | |||
924 | packet_list_check_end(); |
||
925 | /* Don't freeze/thaw the list when doing live capture */ |
||
926 | /*packet_list_freeze();*/ |
||
927 | |||
928 | epan_dissect_init(&edt, cf->epan, create_proto_tree, FALSE); |
||
929 | |||
930 | while ((wtap_read(cf->wth, err, &err_info, &data_offset))) { |
||
931 | if (cf->state == FILE_READ_ABORTED) { |
||
932 | /* Well, the user decided to abort the read. Break out of the |
||
933 | loop, and let the code below (which is called even if there |
||
934 | aren't any packets left to read) exit. */ |
||
935 | break; |
||
936 | } |
||
937 | read_packet(cf, dfcode, &edt, cinfo, data_offset); |
||
938 | } |
||
939 | |||
940 | /* Cleanup and release all dfilter resources */ |
||
941 | if (dfcode != NULL) { |
||
942 | dfilter_free(dfcode); |
||
943 | } |
||
944 | |||
945 | epan_dissect_cleanup(&edt); |
||
946 | |||
947 | /* Don't freeze/thaw the list when doing live capture */ |
||
948 | /*packet_list_thaw();*/ |
||
949 | |||
950 | if (cf->state == FILE_READ_ABORTED) { |
||
951 | /* Well, the user decided to abort the read. We're only called |
||
952 | when the child capture process closes the pipe to us (meaning |
||
953 | it's probably exited), so we can just close the capture |
||
954 | file; we return CF_READ_ABORTED so our caller can do whatever |
||
955 | is appropriate when that happens. */ |
||
956 | cf_close(cf); |
||
957 | return CF_READ_ABORTED; |
||
958 | } |
||
959 | |||
960 | if (auto_scroll_live && cf->count != 0) |
||
961 | packet_list_moveto_end(); |
||
962 | |||
963 | /* We're done reading sequentially through the file. */ |
||
964 | cf->state = FILE_READ_DONE; |
||
965 | |||
966 | /* We're done reading sequentially through the file; close the |
||
967 | sequential I/O side, to free up memory it requires. */ |
||
968 | wtap_sequential_close(cf->wth); |
||
969 | |||
970 | /* Allow the protocol dissectors to free up memory that they |
||
971 | * don't need after the sequential run-through of the packets. */ |
||
972 | postseq_cleanup_all_protocols(); |
||
973 | |||
974 | /* Update the file encapsulation; it might have changed based on the |
||
975 | packets we've read. */ |
||
976 | cf->lnk_t = wtap_file_encap(cf->wth); |
||
977 | |||
978 | /* Update the details in the file-set dialog, as the capture file |
||
979 | * has likely grown since we first stat-ed it */ |
||
980 | fileset_update_file(cf->filename); |
||
981 | |||
982 | if (*err != 0) { |
||
983 | /* We got an error reading the capture file. |
||
984 | XXX - pop up a dialog box? */ |
||
985 | if (err_info != NULL) { |
||
986 | g_warning("Error \"%s\" while reading \"%s\" (\"%s\")", |
||
987 | wtap_strerror(*err), cf->filename, err_info); |
||
988 | g_free(err_info); |
||
989 | } else { |
||
990 | g_warning("Error \"%s\" while reading \"%s\"", |
||
991 | wtap_strerror(*err), cf->filename); |
||
992 | } |
||
993 | return CF_READ_ERROR; |
||
994 | } else { |
||
995 | return CF_READ_OK; |
||
996 | } |
||
997 | } |
||
998 | #endif /* HAVE_LIBPCAP */ |
||
999 | |||
1000 | gchar * |
||
1001 | cf_get_display_name(capture_file *cf) |
||
1002 | { |
||
1003 | gchar *displayname; |
||
1004 | |||
1005 | /* Return a name to use in displays */ |
||
1006 | if (!cf->is_tempfile) { |
||
1007 | /* Get the last component of the file name, and use that. */ |
||
1008 | if (cf->filename) { |
||
1009 | displayname = g_filename_display_basename(cf->filename); |
||
1010 | } else { |
||
1011 | displayname=g_strdup("(No file)"); |
||
1012 | } |
||
1013 | } else { |
||
1014 | /* The file we read is a temporary file from a live capture or |
||
1015 | a merge operation; we don't mention its name, but, if it's |
||
1016 | from a capture, give the source of the capture. */ |
||
1017 | if (cf->source) { |
||
1018 | displayname = g_strdup(cf->source); |
||
1019 | } else { |
||
1020 | displayname = g_strdup("(Untitled)"); |
||
1021 | } |
||
1022 | } |
||
1023 | return displayname; |
||
1024 | } |
||
1025 | |||
1026 | void cf_set_tempfile_source(capture_file *cf, gchar *source) { |
||
1027 | if (cf->source) { |
||
1028 | g_free(cf->source); |
||
1029 | } |
||
1030 | |||
1031 | if (source) { |
||
1032 | cf->source = g_strdup(source); |
||
1033 | } else { |
||
1034 | cf->source = g_strdup(""); |
||
1035 | } |
||
1036 | } |
||
1037 | |||
1038 | const gchar *cf_get_tempfile_source(capture_file *cf) { |
||
1039 | if (!cf->source) { |
||
1040 | return ""; |
||
1041 | } |
||
1042 | |||
1043 | return cf->source; |
||
1044 | } |
||
1045 | |||
1046 | /* XXX - use a macro instead? */ |
||
1047 | int |
||
1048 | cf_get_packet_count(capture_file *cf) |
||
1049 | { |
||
1050 | return cf->count; |
||
1051 | } |
||
1052 | |||
1053 | /* XXX - use a macro instead? */ |
||
1054 | gboolean |
||
1055 | cf_is_tempfile(capture_file *cf) |
||
1056 | { |
||
1057 | return cf->is_tempfile; |
||
1058 | } |
||
1059 | |||
1060 | void cf_set_tempfile(capture_file *cf, gboolean is_tempfile) |
||
1061 | { |
||
1062 | cf->is_tempfile = is_tempfile; |
||
1063 | } |
||
1064 | |||
1065 | |||
1066 | /* XXX - use a macro instead? */ |
||
1067 | void cf_set_drops_known(capture_file *cf, gboolean drops_known) |
||
1068 | { |
||
1069 | cf->drops_known = drops_known; |
||
1070 | } |
||
1071 | |||
1072 | /* XXX - use a macro instead? */ |
||
1073 | void cf_set_drops(capture_file *cf, guint32 drops) |
||
1074 | { |
||
1075 | cf->drops = drops; |
||
1076 | } |
||
1077 | |||
1078 | /* XXX - use a macro instead? */ |
||
1079 | gboolean cf_get_drops_known(capture_file *cf) |
||
1080 | { |
||
1081 | return cf->drops_known; |
||
1082 | } |
||
1083 | |||
1084 | /* XXX - use a macro instead? */ |
||
1085 | guint32 cf_get_drops(capture_file *cf) |
||
1086 | { |
||
1087 | return cf->drops; |
||
1088 | } |
||
1089 | |||
1090 | void cf_set_rfcode(capture_file *cf, dfilter_t *rfcode) |
||
1091 | { |
||
1092 | cf->rfcode = rfcode; |
||
1093 | } |
||
1094 | |||
1095 | static int |
||
1096 | add_packet_to_packet_list(frame_data *fdata, capture_file *cf, |
||
1097 | epan_dissect_t *edt, dfilter_t *dfcode, column_info *cinfo, |
||
1098 | struct wtap_pkthdr *phdr, const guint8 *buf, gboolean add_to_packet_list) |
||
1099 | { |
||
1100 | gint row = -1; |
||
1101 | |||
1102 | frame_data_set_before_dissect(fdata, &cf->elapsed_time, |
||
1103 | &cf->ref, cf->prev_dis); |
||
1104 | cf->prev_cap = fdata; |
||
1105 | |||
1106 | if (dfcode != NULL) { |
||
1107 | epan_dissect_prime_dfilter(edt, dfcode); |
||
1108 | } |
||
1109 | #if 0 |
||
1110 | /* Prepare coloring rules, this ensures that display filter rules containing |
||
1111 | * frame.color_rule references are still processed. |
||
1112 | * TODO: actually detect that situation or maybe apply other optimizations? */ |
||
1113 | if (edt->tree && color_filters_used()) { |
||
1114 | color_filters_prime_edt(edt); |
||
1115 | fdata->flags.need_colorize = 1; |
||
1116 | } |
||
1117 | #endif |
||
1118 | |||
1119 | /* Dissect the frame. */ |
||
1120 | epan_dissect_run_with_taps(edt, cf->cd_t, phdr, frame_tvbuff_new(fdata, buf), fdata, cinfo); |
||
1121 | |||
1122 | /* If we don't have a display filter, set "passed_dfilter" to 1. */ |
||
1123 | if (dfcode != NULL) { |
||
1124 | fdata->flags.passed_dfilter = dfilter_apply_edt(dfcode, edt) ? 1 : 0; |
||
1125 | |||
1126 | if (fdata->flags.passed_dfilter) { |
||
1127 | /* This frame passed the display filter but it may depend on other |
||
1128 | * (potentially not displayed) frames. Find those frames and mark them |
||
1129 | * as depended upon. |
||
1130 | */ |
||
1131 | g_slist_foreach(edt->pi.dependent_frames, find_and_mark_frame_depended_upon, cf->frames); |
||
1132 | } |
||
1133 | } else |
||
1134 | fdata->flags.passed_dfilter = 1; |
||
1135 | |||
1136 | if (fdata->flags.passed_dfilter || fdata->flags.ref_time) |
||
1137 | cf->displayed_count++; |
||
1138 | |||
1139 | if (add_to_packet_list) { |
||
1140 | /* We fill the needed columns from new_packet_list */ |
||
1141 | row = packet_list_append(cinfo, fdata); |
||
1142 | } |
||
1143 | |||
1144 | if (fdata->flags.passed_dfilter || fdata->flags.ref_time) |
||
1145 | { |
||
1146 | frame_data_set_after_dissect(fdata, &cf->cum_bytes); |
||
1147 | cf->prev_dis = fdata; |
||
1148 | |||
1149 | /* If we haven't yet seen the first frame, this is it. |
||
1150 | |||
1151 | XXX - we must do this before we add the row to the display, |
||
1152 | as, if the display's GtkCList's selection mode is |
||
1153 | GTK_SELECTION_BROWSE, when the first entry is added to it, |
||
1154 | "cf_select_packet()" will be called, and it will fetch the row |
||
1155 | data for the 0th row, and will get a null pointer rather than |
||
1156 | "fdata", as "gtk_clist_append()" won't yet have returned and |
||
1157 | thus "gtk_clist_set_row_data()" won't yet have been called. |
||
1158 | |||
1159 | We thus need to leave behind bread crumbs so that |
||
1160 | "cf_select_packet()" can find this frame. See the comment |
||
1161 | in "cf_select_packet()". */ |
||
1162 | if (cf->first_displayed == 0) |
||
1163 | cf->first_displayed = fdata->num; |
||
1164 | |||
1165 | /* This is the last frame we've seen so far. */ |
||
1166 | cf->last_displayed = fdata->num; |
||
1167 | } |
||
1168 | |||
1169 | epan_dissect_reset(edt); |
||
1170 | return row; |
||
1171 | } |
||
1172 | |||
1173 | /* read in a new packet */ |
||
1174 | /* returns the row of the new packet in the packet list or -1 if not displayed */ |
||
1175 | static int |
||
1176 | read_packet(capture_file *cf, dfilter_t *dfcode, epan_dissect_t *edt, |
||
1177 | column_info *cinfo, gint64 offset) |
||
1178 | { |
||
1179 | struct wtap_pkthdr *phdr = wtap_phdr(cf->wth); |
||
1180 | const guint8 *buf = wtap_buf_ptr(cf->wth); |
||
1181 | frame_data fdlocal; |
||
1182 | guint32 framenum; |
||
1183 | frame_data *fdata; |
||
1184 | gboolean passed; |
||
1185 | int row = -1; |
||
1186 | |||
1187 | /* Add this packet's link-layer encapsulation type to cf->linktypes, if |
||
1188 | it's not already there. |
||
1189 | XXX - yes, this is O(N), so if every packet had a different |
||
1190 | link-layer encapsulation type, it'd be O(N^2) to read the file, but |
||
1191 | there are probably going to be a small number of encapsulation types |
||
1192 | in a file. */ |
||
1193 | cf_add_encapsulation_type(cf, phdr->pkt_encap); |
||
1194 | |||
1195 | /* The frame number of this packet is one more than the count of |
||
1196 | frames in the file so far. */ |
||
1197 | framenum = cf->count + 1; |
||
1198 | |||
1199 | frame_data_init(&fdlocal, framenum, phdr, offset, cf->cum_bytes); |
||
1200 | |||
1201 | passed = TRUE; |
||
1202 | if (cf->rfcode) { |
||
1203 | epan_dissect_t rf_edt; |
||
1204 | |||
1205 | epan_dissect_init(&rf_edt, cf->epan, TRUE, FALSE); |
||
1206 | epan_dissect_prime_dfilter(&rf_edt, cf->rfcode); |
||
1207 | epan_dissect_run(&rf_edt, cf->cd_t, phdr, frame_tvbuff_new(&fdlocal, buf), &fdlocal, NULL); |
||
1208 | passed = dfilter_apply_edt(cf->rfcode, &rf_edt); |
||
1209 | epan_dissect_cleanup(&rf_edt); |
||
1210 | } |
||
1211 | |||
1212 | if (passed) { |
||
1213 | /* This does a shallow copy of fdlocal, which is good enough. */ |
||
1214 | fdata = frame_data_sequence_add(cf->frames, &fdlocal); |
||
1215 | |||
1216 | cf->count++; |
||
1217 | if (phdr->opt_comment != NULL) |
||
1218 | cf->packet_comment_count++; |
||
1219 | cf->f_datalen = offset + fdlocal.cap_len; |
||
1220 | |||
1221 | if (!cf->redissecting) { |
||
1222 | row = add_packet_to_packet_list(fdata, cf, edt, dfcode, |
||
1223 | cinfo, phdr, buf, TRUE); |
||
1224 | } |
||
1225 | } |
||
1226 | |||
1227 | return row; |
||
1228 | } |
||
1229 | |||
1230 | |||
1231 | typedef struct _callback_data_t { |
||
1232 | gint64 f_len; |
||
1233 | GTimeVal start_time; |
||
1234 | progdlg_t *progbar; |
||
1235 | GTimer *prog_timer; |
||
1236 | gboolean stop_flag; |
||
1237 | } callback_data_t; |
||
1238 | |||
1239 | |||
1240 | static gboolean |
||
1241 | merge_callback(merge_event event, int num _U_, |
||
1242 | const merge_in_file_t in_files[], const guint in_file_count, |
||
1243 | void *data) |
||
1244 | { |
||
1245 | guint i; |
||
1246 | callback_data_t *cb_data = (callback_data_t*) data; |
||
1247 | |||
1248 | g_assert(cb_data != NULL); |
||
1249 | |||
1250 | switch (event) { |
||
1251 | |||
1252 | case MERGE_EVENT_INPUT_FILES_OPENED: |
||
1253 | /* do nothing */ |
||
1254 | break; |
||
1255 | |||
1256 | case MERGE_EVENT_FRAME_TYPE_SELECTED: |
||
1257 | /* do nothing */ |
||
1258 | break; |
||
1259 | |||
1260 | case MERGE_EVENT_READY_TO_MERGE: |
||
1261 | /* Get the sum of the sizes of all the files. */ |
||
1262 | for (i = 0; i < in_file_count; i++) |
||
1263 | cb_data->f_len += in_files[i].size; |
||
1264 | |||
1265 | cb_data->prog_timer = g_timer_new(); |
||
1266 | g_timer_start(cb_data->prog_timer); |
||
1267 | |||
1268 | g_get_current_time(&cb_data->start_time); |
||
1269 | break; |
||
1270 | |||
1271 | case MERGE_EVENT_PACKET_WAS_READ: |
||
1272 | { |
||
1273 | gint64 data_offset = 0; |
||
1274 | |||
1275 | /* Get the sum of the data offsets in all of the files. */ |
||
1276 | data_offset = 0; |
||
1277 | for (i = 0; i < in_file_count; i++) |
||
1278 | data_offset += in_files[i].data_offset; |
||
1279 | |||
1280 | /* Create the progress bar if necessary. |
||
1281 | We check on every iteration of the loop, so that it takes no |
||
1282 | longer than the standard time to create it (otherwise, for a |
||
1283 | large file, we might take considerably longer than that standard |
||
1284 | time in order to get to the next progress bar step). */ |
||
1285 | if (cb_data->progbar == NULL) { |
||
1286 | cb_data->progbar = delayed_create_progress_dlg(NULL, "Merging", "files", |
||
1287 | FALSE, &cb_data->stop_flag, &cb_data->start_time, 0.0f); |
||
1288 | } |
||
1289 | |||
1290 | /* |
||
1291 | * Update the progress bar, but do it only after |
||
1292 | * PROGBAR_UPDATE_INTERVAL has elapsed. Calling update_progress_dlg |
||
1293 | * and packets_bar_update will likely trigger UI paint events, which |
||
1294 | * might take a while depending on the platform and display. Reset |
||
1295 | * our timer *after* painting. |
||
1296 | */ |
||
1297 | if (g_timer_elapsed(cb_data->prog_timer, NULL) > PROGBAR_UPDATE_INTERVAL) { |
||
1298 | float progbar_val; |
||
1299 | gint64 file_pos = 0; |
||
1300 | /* Get the sum of the seek positions in all of the files. */ |
||
1301 | for (i = 0; i < in_file_count; i++) |
||
1302 | file_pos += wtap_read_so_far(in_files[i].wth); |
||
1303 | |||
1304 | progbar_val = (gfloat) file_pos / (gfloat) cb_data->f_len; |
||
1305 | if (progbar_val > 1.0f) { |
||
1306 | /* Some file probably grew while we were reading it. |
||
1307 | That "shouldn't happen", so we'll just clip the progress |
||
1308 | value at 1.0. */ |
||
1309 | progbar_val = 1.0f; |
||
1310 | } |
||
1311 | |||
1312 | if (cb_data->progbar != NULL) { |
||
1313 | gchar status_str[100]; |
||
1314 | g_snprintf(status_str, sizeof(status_str), |
||
1315 | "%" G_GINT64_MODIFIER "dKB of %" G_GINT64_MODIFIER "dKB", |
||
1316 | file_pos / 1024, cb_data->f_len / 1024); |
||
1317 | update_progress_dlg(cb_data->progbar, progbar_val, status_str); |
||
1318 | } |
||
1319 | g_timer_start(cb_data->prog_timer); |
||
1320 | } |
||
1321 | } |
||
1322 | break; |
||
1323 | |||
1324 | case MERGE_EVENT_DONE: |
||
1325 | /* We're done merging the files; destroy the progress bar if it was created. */ |
||
1326 | if (cb_data->progbar != NULL) |
||
1327 | destroy_progress_dlg(cb_data->progbar); |
||
1328 | g_timer_destroy(cb_data->prog_timer); |
||
1329 | break; |
||
1330 | } |
||
1331 | |||
1332 | return cb_data->stop_flag; |
||
1333 | } |
||
1334 | |||
1335 | |||
1336 | |||
1337 | cf_status_t |
||
1338 | cf_merge_files(char **out_filenamep, int in_file_count, |
||
1339 | char *const *in_filenames, int file_type, gboolean do_append) |
||
1340 | { |
||
1341 | char *out_filename; |
||
1342 | char *tmpname; |
||
1343 | int out_fd; |
||
1344 | int err = 0; |
||
1345 | gchar *err_info = NULL; |
||
1346 | guint err_fileno; |
||
1347 | merge_result status; |
||
1348 | merge_progress_callback_t cb; |
||
1349 | |||
1350 | |||
1351 | if (*out_filenamep != NULL) { |
||
1352 | out_filename = *out_filenamep; |
||
1353 | out_fd = ws_open(out_filename, O_CREAT|O_TRUNC|O_BINARY, 0600); |
||
1354 | if (out_fd == -1) |
||
1355 | err = errno; |
||
1356 | } else { |
||
1357 | out_fd = create_tempfile(&tmpname, "wireshark", NULL); |
||
1358 | if (out_fd == -1) |
||
1359 | err = errno; |
||
1360 | out_filename = g_strdup(tmpname); |
||
1361 | *out_filenamep = out_filename; |
||
1362 | } |
||
1363 | if (out_fd == -1) { |
||
1364 | cf_open_failure_alert_box(out_filename, err, NULL, TRUE, file_type); |
||
1365 | return CF_ERROR; |
||
1366 | } |
||
1367 | |||
1368 | /* prepare our callback routine */ |
||
1369 | cb.callback_func = merge_callback; |
||
1370 | cb.data = g_malloc0(sizeof(callback_data_t)); |
||
1371 | |||
1372 | /* merge the files */ |
||
1373 | status = merge_files(out_fd, out_filename, file_type, |
||
1374 | (const char *const *) in_filenames, in_file_count, |
||
1375 | do_append, IDB_MERGE_MODE_ALL_SAME, 0 /* snaplen */, |
||
1376 | "Wireshark", &cb, &err, &err_info, &err_fileno); |
||
1377 | |||
1378 | g_free(cb.data); |
||
1379 | |||
1380 | switch (status) { |
||
1381 | case MERGE_OK: |
||
1382 | break; |
||
1383 | |||
1384 | case MERGE_USER_ABORTED: |
||
1385 | /* this isn't really an error, though we will return CF_ERROR later */ |
||
1386 | break; |
||
1387 | |||
1388 | case MERGE_ERR_CANT_OPEN_INFILE: |
||
1389 | cf_open_failure_alert_box(in_filenames[err_fileno], err, err_info, |
||
1390 | FALSE, 0); |
||
1391 | ws_close(out_fd); |
||
1392 | break; |
||
1393 | |||
1394 | case MERGE_ERR_CANT_OPEN_OUTFILE: |
||
1395 | cf_open_failure_alert_box(out_filename, err, err_info, TRUE, |
||
1396 | file_type); |
||
1397 | ws_close(out_fd); |
||
1398 | break; |
||
1399 | |||
1400 | case MERGE_ERR_CANT_READ_INFILE: /* fall through */ |
||
1401 | case MERGE_ERR_BAD_PHDR_INTERFACE_ID: |
||
1402 | case MERGE_ERR_CANT_WRITE_OUTFILE: |
||
1403 | case MERGE_ERR_CANT_CLOSE_OUTFILE: |
||
1404 | default: |
||
1405 | simple_error_message_box("%s", err_info ? err_info : "unknown error"); |
||
1406 | break; |
||
1407 | } |
||
1408 | |||
1409 | g_free(err_info); |
||
1410 | /* for general case, no need to close out_fd: file handle associated to this file |
||
1411 | descriptor was already closed by the call to wtap_dump_close() in merge_files() */ |
||
1412 | |||
1413 | if (status != MERGE_OK) { |
||
1414 | /* Callers aren't expected to treat an error or an explicit abort |
||
1415 | differently - we put up error dialogs ourselves, so they don't |
||
1416 | have to. */ |
||
1417 | return CF_ERROR; |
||
1418 | } else |
||
1419 | return CF_OK; |
||
1420 | } |
||
1421 | |||
1422 | cf_status_t |
||
1423 | cf_filter_packets(capture_file *cf, gchar *dftext, gboolean force) |
||
1424 | { |
||
1425 | const char *filter_new = dftext ? dftext : ""; |
||
1426 | const char *filter_old = cf->dfilter ? cf->dfilter : ""; |
||
1427 | dfilter_t *dfcode; |
||
1428 | gchar *err_msg; |
||
1429 | GTimeVal start_time; |
||
1430 | |||
1431 | /* if new filter equals old one, do nothing unless told to do so */ |
||
1432 | if (!force && strcmp(filter_new, filter_old) == 0) { |
||
1433 | return CF_OK; |
||
1434 | } |
||
1435 | |||
1436 | dfcode=NULL; |
||
1437 | |||
1438 | if (dftext == NULL) { |
||
1439 | /* The new filter is an empty filter (i.e., display all packets). |
||
1440 | * so leave dfcode==NULL |
||
1441 | */ |
||
1442 | } else { |
||
1443 | /* |
||
1444 | * We have a filter; make a copy of it (as we'll be saving it), |
||
1445 | * and try to compile it. |
||
1446 | */ |
||
1447 | dftext = g_strdup(dftext); |
||
1448 | if (!dfilter_compile(dftext, &dfcode, &err_msg)) { |
||
1449 | /* The attempt failed; report an error. */ |
||
1450 | simple_message_box(ESD_TYPE_ERROR, NULL, |
||
1451 | "See the help for a description of the display filter syntax.", |
||
1452 | "\"%s\" isn't a valid display filter: %s", |
||
1453 | dftext, err_msg); |
||
1454 | g_free(err_msg); |
||
1455 | g_free(dftext); |
||
1456 | return CF_ERROR; |
||
1457 | } |
||
1458 | |||
1459 | /* Was it empty? */ |
||
1460 | if (dfcode == NULL) { |
||
1461 | /* Yes - free the filter text, and set it to null. */ |
||
1462 | g_free(dftext); |
||
1463 | dftext = NULL; |
||
1464 | } |
||
1465 | } |
||
1466 | |||
1467 | /* We have a valid filter. Replace the current filter. */ |
||
1468 | g_free(cf->dfilter); |
||
1469 | cf->dfilter = dftext; |
||
1470 | g_get_current_time(&start_time); |
||
1471 | |||
1472 | |||
1473 | /* Now rescan the packet list, applying the new filter, but not |
||
1474 | throwing away information constructed on a previous pass. */ |
||
1475 | if (cf->state != FILE_CLOSED) { |
||
1476 | if (dftext == NULL) { |
||
1477 | rescan_packets(cf, "Resetting", "Filter", FALSE); |
||
1478 | } else { |
||
1479 | rescan_packets(cf, "Filtering", dftext, FALSE); |
||
1480 | } |
||
1481 | } |
||
1482 | |||
1483 | /* Cleanup and release all dfilter resources */ |
||
1484 | dfilter_free(dfcode); |
||
1485 | |||
1486 | return CF_OK; |
||
1487 | } |
||
1488 | |||
1489 | void |
||
1490 | cf_reftime_packets(capture_file *cf) |
||
1491 | { |
||
1492 | ref_time_packets(cf); |
||
1493 | } |
||
1494 | |||
1495 | void |
||
1496 | cf_redissect_packets(capture_file *cf) |
||
1497 | { |
||
1498 | if (cf->state != FILE_CLOSED) { |
||
1499 | rescan_packets(cf, "Reprocessing", "all packets", TRUE); |
||
1500 | } |
||
1501 | } |
||
1502 | |||
1503 | gboolean |
||
1504 | cf_read_record_r(capture_file *cf, const frame_data *fdata, |
||
1505 | struct wtap_pkthdr *phdr, Buffer *buf) |
||
1506 | { |
||
1507 | int err; |
||
1508 | gchar *err_info; |
||
1509 | gchar *display_basename; |
||
1510 | |||
1511 | #ifdef WANT_PACKET_EDITOR |
||
1512 | /* if fdata->file_off == -1 it means packet was edited, and we must find data inside edited_frames tree */ |
||
1513 | if (G_UNLIKELY(fdata->file_off == -1)) { |
||
1514 | const modified_frame_data *frame = (const modified_frame_data *) g_tree_lookup(cf->edited_frames, GINT_TO_POINTER(fdata->num)); |
||
1515 | |||
1516 | if (!frame) { |
||
1517 | simple_error_message_box("fdata->file_off == -1, but can't find modified frame."); |
||
1518 | return FALSE; |
||
1519 | } |
||
1520 | |||
1521 | *phdr = frame->phdr; |
||
1522 | ws_buffer_assure_space(buf, frame->phdr.caplen); |
||
1523 | memcpy(ws_buffer_start_ptr(buf), frame->pd, frame->phdr.caplen); |
||
1524 | return TRUE; |
||
1525 | } |
||
1526 | #endif |
||
1527 | |||
1528 | if (!wtap_seek_read(cf->wth, fdata->file_off, phdr, buf, &err, &err_info)) { |
||
1529 | display_basename = g_filename_display_basename(cf->filename); |
||
1530 | switch (err) { |
||
1531 | |||
1532 | case WTAP_ERR_BAD_FILE: |
||
1533 | simple_error_message_box("An error occurred while reading from the file \"%s\": %s.\n(%s)", |
||
1534 | display_basename, wtap_strerror(err), |
||
1535 | err_info != NULL ? err_info : "no information supplied"); |
||
1536 | g_free(err_info); |
||
1537 | break; |
||
1538 | |||
1539 | default: |
||
1540 | simple_error_message_box( |
||
1541 | "An error occurred while reading from the file \"%s\": %s.", |
||
1542 | display_basename, wtap_strerror(err)); |
||
1543 | break; |
||
1544 | } |
||
1545 | g_free(display_basename); |
||
1546 | return FALSE; |
||
1547 | } |
||
1548 | return TRUE; |
||
1549 | } |
||
1550 | |||
1551 | gboolean |
||
1552 | cf_read_record(capture_file *cf, frame_data *fdata) |
||
1553 | { |
||
1554 | return cf_read_record_r(cf, fdata, &cf->phdr, &cf->buf); |
||
1555 | } |
||
1556 | |||
1557 | /* Rescan the list of packets, reconstructing the CList. |
||
1558 | |||
1559 | "action" describes why we're doing this; it's used in the progress |
||
1560 | dialog box. |
||
1561 | |||
1562 | "action_item" describes what we're doing; it's used in the progress |
||
1563 | dialog box. |
||
1564 | |||
1565 | "redissect" is TRUE if we need to make the dissectors reconstruct |
||
1566 | any state information they have (because a preference that affects |
||
1567 | some dissector has changed, meaning some dissector might construct |
||
1568 | its state differently from the way it was constructed the last time). */ |
||
1569 | static void |
||
1570 | rescan_packets(capture_file *cf, const char *action, const char *action_item, gboolean redissect) |
||
1571 | { |
||
1572 | /* Rescan packets new packet list */ |
||
1573 | guint32 framenum; |
||
1574 | frame_data *fdata; |
||
1575 | progdlg_t *progbar = NULL; |
||
1576 | GTimer *prog_timer = g_timer_new(); |
||
1577 | int count; |
||
1578 | frame_data *selected_frame, *preceding_frame, *following_frame, *prev_frame; |
||
1579 | int selected_frame_num, preceding_frame_num, following_frame_num, prev_frame_num; |
||
1580 | gboolean selected_frame_seen; |
||
1581 | float progbar_val; |
||
1582 | GTimeVal start_time; |
||
1583 | gchar status_str[100]; |
||
1584 | epan_dissect_t edt; |
||
1585 | dfilter_t *dfcode; |
||
1586 | column_info *cinfo; |
||
1587 | gboolean create_proto_tree; |
||
1588 | guint tap_flags; |
||
1589 | gboolean add_to_packet_list = FALSE; |
||
1590 | gboolean compiled; |
||
1591 | guint32 frames_count; |
||
1592 | |||
1593 | /* Compile the current display filter. |
||
1594 | * We assume this will not fail since cf->dfilter is only set in |
||
1595 | * cf_filter IFF the filter was valid. |
||
1596 | */ |
||
1597 | compiled = dfilter_compile(cf->dfilter, &dfcode, NULL); |
||
1598 | g_assert(!cf->dfilter || (compiled && dfcode)); |
||
1599 | |||
1600 | /* Get the union of the flags for all tap listeners. */ |
||
1601 | tap_flags = union_of_tap_listener_flags(); |
||
1602 | cinfo = (tap_flags & TL_REQUIRES_COLUMNS) ? &cf->cinfo : NULL; |
||
1603 | create_proto_tree = |
||
1604 | (dfcode != NULL || have_filtering_tap_listeners() || (tap_flags & TL_REQUIRES_PROTO_TREE)); |
||
1605 | |||
1606 | reset_tap_listeners(); |
||
1607 | /* Which frame, if any, is the currently selected frame? |
||
1608 | XXX - should the selected frame or the focus frame be the "current" |
||
1609 | frame, that frame being the one from which "Find Frame" searches |
||
1610 | start? */ |
||
1611 | selected_frame = cf->current_frame; |
||
1612 | |||
1613 | /* Mark frame num as not found */ |
||
1614 | selected_frame_num = -1; |
||
1615 | |||
1616 | /* Freeze the packet list while we redo it, so we don't get any |
||
1617 | screen updates while it happens. */ |
||
1618 | packet_list_freeze(); |
||
1619 | |||
1620 | if (redissect) { |
||
1621 | /* We need to re-initialize all the state information that protocols |
||
1622 | keep, because some preference that controls a dissector has changed, |
||
1623 | which might cause the state information to be constructed differently |
||
1624 | by that dissector. */ |
||
1625 | |||
1626 | /* We might receive new packets while redissecting, and we don't |
||
1627 | want to dissect those before their time. */ |
||
1628 | cf->redissecting = TRUE; |
||
1629 | |||
1630 | /* 'reset' dissection session */ |
||
1631 | epan_free(cf->epan); |
||
1632 | if (cf->edt && cf->edt->pi.fd) { |
||
1633 | /* All pointers in "per frame proto data" for the currently selected |
||
1634 | packet are allocated in wmem_file_scope() and deallocated in epan_free(). |
||
1635 | Free them here to avoid unintended usage in packet_list_clear(). */ |
||
1636 | frame_data_destroy(cf->edt->pi.fd); |
||
1637 | } |
||
1638 | cf->epan = ws_epan_new(cf); |
||
1639 | cf->cinfo.epan = cf->epan; |
||
1640 | |||
1641 | /* A new Lua tap listener may be registered in lua_prime_all_fields() |
||
1642 | called via epan_new() / init_dissection() when reloading Lua plugins. */ |
||
1643 | if (!create_proto_tree && have_filtering_tap_listeners()) { |
||
1644 | create_proto_tree = TRUE; |
||
1645 | } |
||
1646 | |||
1647 | /* We need to redissect the packets so we have to discard our old |
||
1648 | * packet list store. */ |
||
1649 | packet_list_clear(); |
||
1650 | add_to_packet_list = TRUE; |
||
1651 | } |
||
1652 | |||
1653 | /* We don't yet know which will be the first and last frames displayed. */ |
||
1654 | cf->first_displayed = 0; |
||
1655 | cf->last_displayed = 0; |
||
1656 | |||
1657 | /* We currently don't display any packets */ |
||
1658 | cf->displayed_count = 0; |
||
1659 | |||
1660 | /* Iterate through the list of frames. Call a routine for each frame |
||
1661 | to check whether it should be displayed and, if so, add it to |
||
1662 | the display list. */ |
||
1663 | cf->ref = NULL; |
||
1664 | cf->prev_dis = NULL; |
||
1665 | cf->prev_cap = NULL; |
||
1666 | cf->cum_bytes = 0; |
||
1667 | |||
1668 | cf_callback_invoke(cf_cb_file_rescan_started, cf); |
||
1669 | |||
1670 | g_timer_start(prog_timer); |
||
1671 | /* Count of packets at which we've looked. */ |
||
1672 | count = 0; |
||
1673 | /* Progress so far. */ |
||
1674 | progbar_val = 0.0f; |
||
1675 | |||
1676 | cf->stop_flag = FALSE; |
||
1677 | g_get_current_time(&start_time); |
||
1678 | |||
1679 | /* no previous row yet */ |
||
1680 | prev_frame_num = -1; |
||
1681 | prev_frame = NULL; |
||
1682 | |||
1683 | preceding_frame_num = -1; |
||
1684 | preceding_frame = NULL; |
||
1685 | following_frame_num = -1; |
||
1686 | following_frame = NULL; |
||
1687 | |||
1688 | selected_frame_seen = FALSE; |
||
1689 | |||
1690 | frames_count = cf->count; |
||
1691 | |||
1692 | epan_dissect_init(&edt, cf->epan, create_proto_tree, FALSE); |
||
1693 | |||
1694 | for (framenum = 1; framenum <= frames_count; framenum++) { |
||
1695 | fdata = frame_data_sequence_find(cf->frames, framenum); |
||
1696 | |||
1697 | /* Create the progress bar if necessary. |
||
1698 | We check on every iteration of the loop, so that it takes no |
||
1699 | longer than the standard time to create it (otherwise, for a |
||
1700 | large file, we might take considerably longer than that standard |
||
1701 | time in order to get to the next progress bar step). */ |
||
1702 | if (progbar == NULL) |
||
1703 | progbar = delayed_create_progress_dlg(cf->window, action, action_item, TRUE, |
||
1704 | &cf->stop_flag, |
||
1705 | &start_time, |
||
1706 | progbar_val); |
||
1707 | |||
1708 | /* |
||
1709 | * Update the progress bar, but do it only after PROGBAR_UPDATE_INTERVAL |
||
1710 | * has elapsed. Calling update_progress_dlg and packets_bar_update will |
||
1711 | * likely trigger UI paint events, which might take a while depending on |
||
1712 | * the platform and display. Reset our timer *after* painting. |
||
1713 | */ |
||
1714 | if (g_timer_elapsed(prog_timer, NULL) > PROGBAR_UPDATE_INTERVAL) { |
||
1715 | /* let's not divide by zero. I should never be started |
||
1716 | * with count == 0, so let's assert that |
||
1717 | */ |
||
1718 | g_assert(cf->count > 0); |
||
1719 | progbar_val = (gfloat) count / frames_count; |
||
1720 | |||
1721 | if (progbar != NULL) { |
||
1722 | g_snprintf(status_str, sizeof(status_str), |
||
1723 | "%4u of %u frames", count, frames_count); |
||
1724 | update_progress_dlg(progbar, progbar_val, status_str); |
||
1725 | } |
||
1726 | |||
1727 | g_timer_start(prog_timer); |
||
1728 | } |
||
1729 | |||
1730 | if (cf->stop_flag) { |
||
1731 | /* Well, the user decided to abort the filtering. Just stop. |
||
1732 | |||
1733 | XXX - go back to the previous filter? Users probably just |
||
1734 | want not to wait for a filtering operation to finish; |
||
1735 | unless we cancel by having no filter, reverting to the |
||
1736 | previous filter will probably be even more expensive than |
||
1737 | continuing the filtering, as it involves going back to the |
||
1738 | beginning and filtering, and even with no filter we currently |
||
1739 | have to re-generate the entire clist, which is also expensive. |
||
1740 | |||
1741 | I'm not sure what Network Monitor does, but it doesn't appear |
||
1742 | to give you an unfiltered display if you cancel. */ |
||
1743 | break; |
||
1744 | } |
||
1745 | |||
1746 | count++; |
||
1747 | |||
1748 | if (redissect) { |
||
1749 | /* Since all state for the frame was destroyed, mark the frame |
||
1750 | * as not visited, free the GSList referring to the state |
||
1751 | * data (the per-frame data itself was freed by |
||
1752 | * "init_dissection()"), and null out the GSList pointer. */ |
||
1753 | frame_data_reset(fdata); |
||
1754 | frames_count = cf->count; |
||
1755 | } |
||
1756 | |||
1757 | /* Frame dependencies from the previous dissection/filtering are no longer valid. */ |
||
1758 | fdata->flags.dependent_of_displayed = 0; |
||
1759 | |||
1760 | if (!cf_read_record(cf, fdata)) |
||
1761 | break; /* error reading the frame */ |
||
1762 | |||
1763 | /* If the previous frame is displayed, and we haven't yet seen the |
||
1764 | selected frame, remember that frame - it's the closest one we've |
||
1765 | yet seen before the selected frame. */ |
||
1766 | if (prev_frame_num != -1 && !selected_frame_seen && prev_frame->flags.passed_dfilter) { |
||
1767 | preceding_frame_num = prev_frame_num; |
||
1768 | preceding_frame = prev_frame; |
||
1769 | } |
||
1770 | |||
1771 | add_packet_to_packet_list(fdata, cf, &edt, dfcode, |
||
1772 | cinfo, &cf->phdr, |
||
1773 | ws_buffer_start_ptr(&cf->buf), |
||
1774 | add_to_packet_list); |
||
1775 | |||
1776 | /* If this frame is displayed, and this is the first frame we've |
||
1777 | seen displayed after the selected frame, remember this frame - |
||
1778 | it's the closest one we've yet seen at or after the selected |
||
1779 | frame. */ |
||
1780 | if (fdata->flags.passed_dfilter && selected_frame_seen && following_frame_num == -1) { |
||
1781 | following_frame_num = fdata->num; |
||
1782 | following_frame = fdata; |
||
1783 | } |
||
1784 | if (fdata == selected_frame) { |
||
1785 | selected_frame_seen = TRUE; |
||
1786 | if (fdata->flags.passed_dfilter) |
||
1787 | selected_frame_num = fdata->num; |
||
1788 | } |
||
1789 | |||
1790 | /* Remember this frame - it'll be the previous frame |
||
1791 | on the next pass through the loop. */ |
||
1792 | prev_frame_num = fdata->num; |
||
1793 | prev_frame = fdata; |
||
1794 | } |
||
1795 | |||
1796 | epan_dissect_cleanup(&edt); |
||
1797 | |||
1798 | /* We are done redissecting the packet list. */ |
||
1799 | cf->redissecting = FALSE; |
||
1800 | |||
1801 | if (redissect) { |
||
1802 | frames_count = cf->count; |
||
1803 | /* Clear out what remains of the visited flags and per-frame data |
||
1804 | pointers. |
||
1805 | |||
1806 | XXX - that may cause various forms of bogosity when dissecting |
||
1807 | these frames, as they won't have been seen by this sequential |
||
1808 | pass, but the only alternative I see is to keep scanning them |
||
1809 | even though the user requested that the scan stop, and that |
||
1810 | would leave the user stuck with an Wireshark grinding on |
||
1811 | until it finishes. Should we just stick them with that? */ |
||
1812 | for (; framenum <= frames_count; framenum++) { |
||
1813 | fdata = frame_data_sequence_find(cf->frames, framenum); |
||
1814 | frame_data_reset(fdata); |
||
1815 | } |
||
1816 | } |
||
1817 | |||
1818 | /* We're done filtering the packets; destroy the progress bar if it |
||
1819 | was created. */ |
||
1820 | if (progbar != NULL) |
||
1821 | destroy_progress_dlg(progbar); |
||
1822 | g_timer_destroy(prog_timer); |
||
1823 | |||
1824 | /* Unfreeze the packet list. */ |
||
1825 | if (!add_to_packet_list) |
||
1826 | packet_list_recreate_visible_rows(); |
||
1827 | |||
1828 | /* Compute the time it took to filter the file */ |
||
1829 | compute_elapsed(cf, &start_time); |
||
1830 | |||
1831 | packet_list_thaw(); |
||
1832 | |||
1833 | cf_callback_invoke(cf_cb_file_rescan_finished, cf); |
||
1834 | |||
1835 | if (selected_frame_num == -1) { |
||
1836 | /* The selected frame didn't pass the filter. */ |
||
1837 | if (selected_frame == NULL) { |
||
1838 | /* That's because there *was* no selected frame. Make the first |
||
1839 | displayed frame the current frame. */ |
||
1840 | selected_frame_num = 0; |
||
1841 | } else { |
||
1842 | /* Find the nearest displayed frame to the selected frame (whether |
||
1843 | it's before or after that frame) and make that the current frame. |
||
1844 | If the next and previous displayed frames are equidistant from the |
||
1845 | selected frame, choose the next one. */ |
||
1846 | g_assert(following_frame == NULL || |
||
1847 | following_frame->num >= selected_frame->num); |
||
1848 | g_assert(preceding_frame == NULL || |
||
1849 | preceding_frame->num <= selected_frame->num); |
||
1850 | if (following_frame == NULL) { |
||
1851 | /* No frame after the selected frame passed the filter, so we |
||
1852 | have to select the last displayed frame before the selected |
||
1853 | frame. */ |
||
1854 | selected_frame_num = preceding_frame_num; |
||
1855 | selected_frame = preceding_frame; |
||
1856 | } else if (preceding_frame == NULL) { |
||
1857 | /* No frame before the selected frame passed the filter, so we |
||
1858 | have to select the first displayed frame after the selected |
||
1859 | frame. */ |
||
1860 | selected_frame_num = following_frame_num; |
||
1861 | selected_frame = following_frame; |
||
1862 | } else { |
||
1863 | /* Frames before and after the selected frame passed the filter, so |
||
1864 | we'll select the previous frame */ |
||
1865 | selected_frame_num = preceding_frame_num; |
||
1866 | selected_frame = preceding_frame; |
||
1867 | } |
||
1868 | } |
||
1869 | } |
||
1870 | |||
1871 | if (selected_frame_num == -1) { |
||
1872 | /* There are no frames displayed at all. */ |
||
1873 | cf_unselect_packet(cf); |
||
1874 | } else { |
||
1875 | /* Either the frame that was selected passed the filter, or we've |
||
1876 | found the nearest displayed frame to that frame. Select it, make |
||
1877 | it the focus row, and make it visible. */ |
||
1878 | /* Set to invalid to force update of packet list and packet details */ |
||
1879 | cf->current_row = -1; |
||
1880 | if (selected_frame_num == 0) { |
||
1881 | packet_list_select_first_row(); |
||
1882 | }else{ |
||
1883 | if (!packet_list_select_row_from_data(selected_frame)) { |
||
1884 | /* We didn't find a row corresponding to this frame. |
||
1885 | This means that the frame isn't being displayed currently, |
||
1886 | so we can't select it. */ |
||
1887 | simple_message_box(ESD_TYPE_INFO, NULL, |
||
1888 | "The capture file is probably not fully dissected.", |
||
1889 | "End of capture exceeded."); |
||
1890 | } |
||
1891 | } |
||
1892 | } |
||
1893 | |||
1894 | /* Cleanup and release all dfilter resources */ |
||
1895 | dfilter_free(dfcode); |
||
1896 | } |
||
1897 | |||
1898 | |||
1899 | /* |
||
1900 | * Scan through all frame data and recalculate the ref time |
||
1901 | * without rereading the file. |
||
1902 | * XXX - do we need a progres bar or is this fast enough? |
||
1903 | */ |
||
1904 | static void |
||
1905 | ref_time_packets(capture_file *cf) |
||
1906 | { |
||
1907 | guint32 framenum; |
||
1908 | frame_data *fdata; |
||
1909 | nstime_t rel_ts; |
||
1910 | |||
1911 | cf->ref = NULL; |
||
1912 | cf->prev_dis = NULL; |
||
1913 | cf->cum_bytes = 0; |
||
1914 | |||
1915 | for (framenum = 1; framenum <= cf->count; framenum++) { |
||
1916 | fdata = frame_data_sequence_find(cf->frames, framenum); |
||
1917 | |||
1918 | /* just add some value here until we know if it is being displayed or not */ |
||
1919 | fdata->cum_bytes = cf->cum_bytes + fdata->pkt_len; |
||
1920 | |||
1921 | /* |
||
1922 | *Timestamps |
||
1923 | */ |
||
1924 | |||
1925 | /* If we don't have the time stamp of the first packet in the |
||
1926 | capture, it's because this is the first packet. Save the time |
||
1927 | stamp of this packet as the time stamp of the first packet. */ |
||
1928 | if (cf->ref == NULL) |
||
1929 | cf->ref = fdata; |
||
1930 | /* if this frames is marked as a reference time frame, reset |
||
1931 | firstsec and firstusec to this frame */ |
||
1932 | if (fdata->flags.ref_time) |
||
1933 | cf->ref = fdata; |
||
1934 | |||
1935 | /* If we don't have the time stamp of the previous displayed packet, |
||
1936 | it's because this is the first displayed packet. Save the time |
||
1937 | stamp of this packet as the time stamp of the previous displayed |
||
1938 | packet. */ |
||
1939 | if (cf->prev_dis == NULL) { |
||
1940 | cf->prev_dis = fdata; |
||
1941 | } |
||
1942 | |||
1943 | /* Get the time elapsed between the first packet and this packet. */ |
||
1944 | fdata->frame_ref_num = (fdata != cf->ref) ? cf->ref->num : 0; |
||
1945 | nstime_delta(&rel_ts, &fdata->abs_ts, &cf->ref->abs_ts); |
||
1946 | |||
1947 | /* If it's greater than the current elapsed time, set the elapsed time |
||
1948 | to it (we check for "greater than" so as not to be confused by |
||
1949 | time moving backwards). */ |
||
1950 | if ((gint32)cf->elapsed_time.secs < rel_ts.secs |
||
1951 | || ((gint32)cf->elapsed_time.secs == rel_ts.secs && (gint32)cf->elapsed_time.nsecs < rel_ts.nsecs)) { |
||
1952 | cf->elapsed_time = rel_ts; |
||
1953 | } |
||
1954 | |||
1955 | /* If this frame is displayed, get the time elapsed between the |
||
1956 | previous displayed packet and this packet. */ |
||
1957 | if ( fdata->flags.passed_dfilter ) { |
||
1958 | fdata->prev_dis_num = cf->prev_dis->num; |
||
1959 | cf->prev_dis = fdata; |
||
1960 | } |
||
1961 | |||
1962 | /* |
||
1963 | * Byte counts |
||
1964 | */ |
||
1965 | if ( (fdata->flags.passed_dfilter) || (fdata->flags.ref_time) ) { |
||
1966 | /* This frame either passed the display filter list or is marked as |
||
1967 | a time reference frame. All time reference frames are displayed |
||
1968 | even if they don't pass the display filter */ |
||
1969 | if (fdata->flags.ref_time) { |
||
1970 | /* if this was a TIME REF frame we should reset the cum_bytes field */ |
||
1971 | cf->cum_bytes = fdata->pkt_len; |
||
1972 | fdata->cum_bytes = cf->cum_bytes; |
||
1973 | } else { |
||
1974 | /* increase cum_bytes with this packets length */ |
||
1975 | cf->cum_bytes += fdata->pkt_len; |
||
1976 | } |
||
1977 | } |
||
1978 | } |
||
1979 | } |
||
1980 | |||
1981 | typedef enum { |
||
1982 | PSP_FINISHED, |
||
1983 | PSP_STOPPED, |
||
1984 | PSP_FAILED |
||
1985 | } psp_return_t; |
||
1986 | |||
1987 | static psp_return_t |
||
1988 | process_specified_records(capture_file *cf, packet_range_t *range, |
||
1989 | const char *string1, const char *string2, gboolean terminate_is_stop, |
||
1990 | gboolean (*callback)(capture_file *, frame_data *, |
||
1991 | struct wtap_pkthdr *, const guint8 *, void *), |
||
1992 | void *callback_args, |
||
1993 | gboolean show_progress_bar) |
||
1994 | { |
||
1995 | guint32 framenum; |
||
1996 | frame_data *fdata; |
||
1997 | Buffer buf; |
||
1998 | psp_return_t ret = PSP_FINISHED; |
||
1999 | |||
2000 | progdlg_t *progbar = NULL; |
||
2001 | GTimer *prog_timer = g_timer_new(); |
||
2002 | int progbar_count; |
||
2003 | float progbar_val; |
||
2004 | GTimeVal progbar_start_time; |
||
2005 | gchar progbar_status_str[100]; |
||
2006 | range_process_e process_this; |
||
2007 | struct wtap_pkthdr phdr; |
||
2008 | |||
2009 | wtap_phdr_init(&phdr); |
||
2010 | ws_buffer_init(&buf, 1500); |
||
2011 | |||
2012 | g_timer_start(prog_timer); |
||
2013 | /* Count of packets at which we've looked. */ |
||
2014 | progbar_count = 0; |
||
2015 | /* Progress so far. */ |
||
2016 | progbar_val = 0.0f; |
||
2017 | |||
2018 | cf->stop_flag = FALSE; |
||
2019 | g_get_current_time(&progbar_start_time); |
||
2020 | |||
2021 | if (range != NULL) |
||
2022 | packet_range_process_init(range); |
||
2023 | |||
2024 | /* Iterate through all the packets, printing the packets that |
||
2025 | were selected by the current display filter. */ |
||
2026 | for (framenum = 1; framenum <= cf->count; framenum++) { |
||
2027 | fdata = frame_data_sequence_find(cf->frames, framenum); |
||
2028 | |||
2029 | /* Create the progress bar if necessary. |
||
2030 | We check on every iteration of the loop, so that it takes no |
||
2031 | longer than the standard time to create it (otherwise, for a |
||
2032 | large file, we might take considerably longer than that standard |
||
2033 | time in order to get to the next progress bar step). */ |
||
2034 | if (show_progress_bar && progbar == NULL) |
||
2035 | progbar = delayed_create_progress_dlg(cf->window, string1, string2, |
||
2036 | terminate_is_stop, |
||
2037 | &cf->stop_flag, |
||
2038 | &progbar_start_time, |
||
2039 | progbar_val); |
||
2040 | |||
2041 | /* |
||
2042 | * Update the progress bar, but do it only after PROGBAR_UPDATE_INTERVAL |
||
2043 | * has elapsed. Calling update_progress_dlg and packets_bar_update will |
||
2044 | * likely trigger UI paint events, which might take a while depending on |
||
2045 | * the platform and display. Reset our timer *after* painting. |
||
2046 | */ |
||
2047 | if (progbar && g_timer_elapsed(prog_timer, NULL) > PROGBAR_UPDATE_INTERVAL) { |
||
2048 | /* let's not divide by zero. I should never be started |
||
2049 | * with count == 0, so let's assert that |
||
2050 | */ |
||
2051 | g_assert(cf->count > 0); |
||
2052 | progbar_val = (gfloat) progbar_count / cf->count; |
||
2053 | |||
2054 | g_snprintf(progbar_status_str, sizeof(progbar_status_str), |
||
2055 | "%4u of %u packets", progbar_count, cf->count); |
||
2056 | update_progress_dlg(progbar, progbar_val, progbar_status_str); |
||
2057 | |||
2058 | g_timer_start(prog_timer); |
||
2059 | } |
||
2060 | |||
2061 | if (cf->stop_flag) { |
||
2062 | /* Well, the user decided to abort the operation. Just stop, |
||
2063 | and arrange to return PSP_STOPPED to our caller, so they know |
||
2064 | it was stopped explicitly. */ |
||
2065 | ret = PSP_STOPPED; |
||
2066 | break; |
||
2067 | } |
||
2068 | |||
2069 | progbar_count++; |
||
2070 | |||
2071 | if (range != NULL) { |
||
2072 | /* do we have to process this packet? */ |
||
2073 | process_this = packet_range_process_packet(range, fdata); |
||
2074 | if (process_this == range_process_next) { |
||
2075 | /* this packet uninteresting, continue with next one */ |
||
2076 | continue; |
||
2077 | } else if (process_this == range_processing_finished) { |
||
2078 | /* all interesting packets processed, stop the loop */ |
||
2079 | break; |
||
2080 | } |
||
2081 | } |
||
2082 | |||
2083 | /* Get the packet */ |
||
2084 | if (!cf_read_record_r(cf, fdata, &phdr, &buf)) { |
||
2085 | /* Attempt to get the packet failed. */ |
||
2086 | ret = PSP_FAILED; |
||
2087 | break; |
||
2088 | } |
||
2089 | /* Process the packet */ |
||
2090 | if (!callback(cf, fdata, &phdr, ws_buffer_start_ptr(&buf), callback_args)) { |
||
2091 | /* Callback failed. We assume it reported the error appropriately. */ |
||
2092 | ret = PSP_FAILED; |
||
2093 | break; |
||
2094 | } |
||
2095 | } |
||
2096 | |||
2097 | /* We're done printing the packets; destroy the progress bar if |
||
2098 | it was created. */ |
||
2099 | if (progbar != NULL) |
||
2100 | destroy_progress_dlg(progbar); |
||
2101 | g_timer_destroy(prog_timer); |
||
2102 | |||
2103 | wtap_phdr_cleanup(&phdr); |
||
2104 | ws_buffer_free(&buf); |
||
2105 | |||
2106 | return ret; |
||
2107 | } |
||
2108 | |||
2109 | typedef struct { |
||
2110 | epan_dissect_t edt; |
||
2111 | column_info *cinfo; |
||
2112 | } retap_callback_args_t; |
||
2113 | |||
2114 | static gboolean |
||
2115 | retap_packet(capture_file *cf, frame_data *fdata, |
||
2116 | struct wtap_pkthdr *phdr, const guint8 *pd, |
||
2117 | void *argsp) |
||
2118 | { |
||
2119 | retap_callback_args_t *args = (retap_callback_args_t *)argsp; |
||
2120 | |||
2121 | epan_dissect_run_with_taps(&args->edt, cf->cd_t, phdr, frame_tvbuff_new(fdata, pd), fdata, args->cinfo); |
||
2122 | epan_dissect_reset(&args->edt); |
||
2123 | |||
2124 | return TRUE; |
||
2125 | } |
||
2126 | |||
2127 | cf_read_status_t |
||
2128 | cf_retap_packets(capture_file *cf) |
||
2129 | { |
||
2130 | packet_range_t range; |
||
2131 | retap_callback_args_t callback_args; |
||
2132 | gboolean construct_protocol_tree; |
||
2133 | gboolean filtering_tap_listeners; |
||
2134 | guint tap_flags; |
||
2135 | psp_return_t ret; |
||
2136 | |||
2137 | /* Presumably the user closed the capture file. */ |
||
2138 | if (cf == NULL) { |
||
2139 | return CF_READ_ABORTED; |
||
2140 | } |
||
2141 | |||
2142 | cf_callback_invoke(cf_cb_file_retap_started, cf); |
||
2143 | |||
2144 | /* Do we have any tap listeners with filters? */ |
||
2145 | filtering_tap_listeners = have_filtering_tap_listeners(); |
||
2146 | |||
2147 | tap_flags = union_of_tap_listener_flags(); |
||
2148 | |||
2149 | /* If any tap listeners have filters, or require the protocol tree, |
||
2150 | construct the protocol tree. */ |
||
2151 | construct_protocol_tree = filtering_tap_listeners || |
||
2152 | (tap_flags & TL_REQUIRES_PROTO_TREE); |
||
2153 | |||
2154 | /* If any tap listeners require the columns, construct them. */ |
||
2155 | callback_args.cinfo = (tap_flags & TL_REQUIRES_COLUMNS) ? &cf->cinfo : NULL; |
||
2156 | |||
2157 | /* Reset the tap listeners. */ |
||
2158 | reset_tap_listeners(); |
||
2159 | |||
2160 | epan_dissect_init(&callback_args.edt, cf->epan, construct_protocol_tree, FALSE); |
||
2161 | |||
2162 | /* Iterate through the list of packets, dissecting all packets and |
||
2163 | re-running the taps. */ |
||
2164 | packet_range_init(&range, cf); |
||
2165 | packet_range_process_init(&range); |
||
2166 | |||
2167 | ret = process_specified_records(cf, &range, "Recalculating statistics on", |
||
2168 | "all packets", TRUE, retap_packet, |
||
2169 | &callback_args, TRUE); |
||
2170 | |||
2171 | epan_dissect_cleanup(&callback_args.edt); |
||
2172 | |||
2173 | cf_callback_invoke(cf_cb_file_retap_finished, cf); |
||
2174 | |||
2175 | switch (ret) { |
||
2176 | case PSP_FINISHED: |
||
2177 | /* Completed successfully. */ |
||
2178 | return CF_READ_OK; |
||
2179 | |||
2180 | case PSP_STOPPED: |
||
2181 | /* Well, the user decided to abort the refiltering. |
||
2182 | Return CF_READ_ABORTED so our caller knows they did that. */ |
||
2183 | return CF_READ_ABORTED; |
||
2184 | |||
2185 | case PSP_FAILED: |
||
2186 | /* Error while retapping. */ |
||
2187 | return CF_READ_ERROR; |
||
2188 | } |
||
2189 | |||
2190 | g_assert_not_reached(); |
||
2191 | return CF_READ_OK; |
||
2192 | } |
||
2193 | |||
2194 | typedef struct { |
||
2195 | print_args_t *print_args; |
||
2196 | gboolean print_header_line; |
||
2197 | char *header_line_buf; |
||
2198 | int header_line_buf_len; |
||
2199 | gboolean print_formfeed; |
||
2200 | gboolean print_separator; |
||
2201 | char *line_buf; |
||
2202 | int line_buf_len; |
||
2203 | gint *col_widths; |
||
2204 | int num_visible_cols; |
||
2205 | gint *visible_cols; |
||
2206 | epan_dissect_t edt; |
||
2207 | } print_callback_args_t; |
||
2208 | |||
2209 | static gboolean |
||
2210 | print_packet(capture_file *cf, frame_data *fdata, |
||
2211 | struct wtap_pkthdr *phdr, const guint8 *pd, |
||
2212 | void *argsp) |
||
2213 | { |
||
2214 | print_callback_args_t *args = (print_callback_args_t *)argsp; |
||
2215 | int i; |
||
2216 | char *cp; |
||
2217 | int line_len; |
||
2218 | int column_len; |
||
2219 | int cp_off; |
||
2220 | char bookmark_name[9+10+1]; /* "__frameNNNNNNNNNN__\0" */ |
||
2221 | char bookmark_title[6+10+1]; /* "Frame NNNNNNNNNN__\0" */ |
||
2222 | col_item_t* col_item; |
||
2223 | |||
2224 | /* Fill in the column information if we're printing the summary |
||
2225 | information. */ |
||
2226 | if (args->print_args->print_summary) { |
||
2227 | col_custom_prime_edt(&args->edt, &cf->cinfo); |
||
2228 | epan_dissect_run(&args->edt, cf->cd_t, phdr, frame_tvbuff_new(fdata, pd), fdata, &cf->cinfo); |
||
2229 | epan_dissect_fill_in_columns(&args->edt, FALSE, TRUE); |
||
2230 | } else |
||
2231 | epan_dissect_run(&args->edt, cf->cd_t, phdr, frame_tvbuff_new(fdata, pd), fdata, NULL); |
||
2232 | |||
2233 | if (args->print_formfeed) { |
||
2234 | if (!new_page(args->print_args->stream)) |
||
2235 | goto fail; |
||
2236 | } else { |
||
2237 | if (args->print_separator) { |
||
2238 | if (!print_line(args->print_args->stream, 0, "")) |
||
2239 | goto fail; |
||
2240 | } |
||
2241 | } |
||
2242 | |||
2243 | /* |
||
2244 | * We generate bookmarks, if the output format supports them. |
||
2245 | * The name is "__frameN__". |
||
2246 | */ |
||
2247 | g_snprintf(bookmark_name, sizeof bookmark_name, "__frame%u__", fdata->num); |
||
2248 | |||
2249 | if (args->print_args->print_summary) { |
||
2250 | if (!args->print_args->print_col_headings) |
||
2251 | args->print_header_line = FALSE; |
||
2252 | if (args->print_header_line) { |
||
2253 | if (!print_line(args->print_args->stream, 0, args->header_line_buf)) |
||
2254 | goto fail; |
||
2255 | args->print_header_line = FALSE; /* we might not need to print any more */ |
||
2256 | } |
||
2257 | cp = &args->line_buf[0]; |
||
2258 | line_len = 0; |
||
2259 | for (i = 0; i < args->num_visible_cols; i++) { |
||
2260 | col_item = &cf->cinfo.columns[args->visible_cols[i]]; |
||
2261 | /* Find the length of the string for this column. */ |
||
2262 | column_len = (int) strlen(col_item->col_data); |
||
2263 | if (args->col_widths[i] > column_len) |
||
2264 | column_len = args->col_widths[i]; |
||
2265 | |||
2266 | /* Make sure there's room in the line buffer for the column; if not, |
||
2267 | double its length. */ |
||
2268 | line_len += column_len + 1; /* "+1" for space */ |
||
2269 | if (line_len > args->line_buf_len) { |
||
2270 | cp_off = (int) (cp - args->line_buf); |
||
2271 | args->line_buf_len = 2 * line_len; |
||
2272 | args->line_buf = (char *)g_realloc(args->line_buf, args->line_buf_len + 1); |
||
2273 | cp = args->line_buf + cp_off; |
||
2274 | } |
||
2275 | |||
2276 | /* Right-justify the packet number column. */ |
||
2277 | if (col_item->col_fmt == COL_NUMBER) |
||
2278 | g_snprintf(cp, column_len+1, "%*s", args->col_widths[i], col_item->col_data); |
||
2279 | else |
||
2280 | g_snprintf(cp, column_len+1, "%-*s", args->col_widths[i], col_item->col_data); |
||
2281 | cp += column_len; |
||
2282 | if (i != args->num_visible_cols - 1) |
||
2283 | *cp++ = ' '; |
||
2284 | } |
||
2285 | *cp = '\0'; |
||
2286 | |||
2287 | /* |
||
2288 | * Generate a bookmark, using the summary line as the title. |
||
2289 | */ |
||
2290 | if (!print_bookmark(args->print_args->stream, bookmark_name, |
||
2291 | args->line_buf)) |
||
2292 | goto fail; |
||
2293 | |||
2294 | if (!print_line(args->print_args->stream, 0, args->line_buf)) |
||
2295 | goto fail; |
||
2296 | } else { |
||
2297 | /* |
||
2298 | * Generate a bookmark, using "Frame N" as the title, as we're not |
||
2299 | * printing the summary line. |
||
2300 | */ |
||
2301 | g_snprintf(bookmark_title, sizeof bookmark_title, "Frame %u", fdata->num); |
||
2302 | if (!print_bookmark(args->print_args->stream, bookmark_name, |
||
2303 | bookmark_title)) |
||
2304 | goto fail; |
||
2305 | } /* if (print_summary) */ |
||
2306 | |||
2307 | if (args->print_args->print_dissections != print_dissections_none) { |
||
2308 | if (args->print_args->print_summary) { |
||
2309 | /* Separate the summary line from the tree with a blank line. */ |
||
2310 | if (!print_line(args->print_args->stream, 0, "")) |
||
2311 | goto fail; |
||
2312 | } |
||
2313 | |||
2314 | /* Print the information in that tree. */ |
||
2315 | if (!proto_tree_print(args->print_args, &args->edt, NULL, args->print_args->stream)) |
||
2316 | goto fail; |
||
2317 | |||
2318 | /* Print a blank line if we print anything after this (aka more than one packet). */ |
||
2319 | args->print_separator = TRUE; |
||
2320 | |||
2321 | /* Print a header line if we print any more packet summaries */ |
||
2322 | if (args->print_args->print_col_headings) |
||
2323 | args->print_header_line = TRUE; |
||
2324 | } |
||
2325 | |||
2326 | if (args->print_args->print_hex) { |
||
2327 | if (args->print_args->print_summary || (args->print_args->print_dissections != print_dissections_none)) { |
||
2328 | if (!print_line(args->print_args->stream, 0, "")) |
||
2329 | goto fail; |
||
2330 | } |
||
2331 | /* Print the full packet data as hex. */ |
||
2332 | if (!print_hex_data(args->print_args->stream, &args->edt)) |
||
2333 | goto fail; |
||
2334 | |||
2335 | /* Print a blank line if we print anything after this (aka more than one packet). */ |
||
2336 | args->print_separator = TRUE; |
||
2337 | |||
2338 | /* Print a header line if we print any more packet summaries */ |
||
2339 | if (args->print_args->print_col_headings) |
||
2340 | args->print_header_line = TRUE; |
||
2341 | } /* if (args->print_args->print_dissections != print_dissections_none) */ |
||
2342 | |||
2343 | epan_dissect_reset(&args->edt); |
||
2344 | |||
2345 | /* do we want to have a formfeed between each packet from now on? */ |
||
2346 | if (args->print_args->print_formfeed) { |
||
2347 | args->print_formfeed = TRUE; |
||
2348 | } |
||
2349 | |||
2350 | return TRUE; |
||
2351 | |||
2352 | fail: |
||
2353 | epan_dissect_reset(&args->edt); |
||
2354 | return FALSE; |
||
2355 | } |
||
2356 | |||
2357 | cf_print_status_t |
||
2358 | cf_print_packets(capture_file *cf, print_args_t *print_args, |
||
2359 | gboolean show_progress_bar) |
||
2360 | { |
||
2361 | print_callback_args_t callback_args; |
||
2362 | gint data_width; |
||
2363 | char *cp; |
||
2364 | int i, cp_off, column_len, line_len; |
||
2365 | int num_visible_col = 0, last_visible_col = 0, visible_col_count; |
||
2366 | psp_return_t ret; |
||
2367 | GList *clp; |
||
2368 | fmt_data *cfmt; |
||
2369 | gboolean proto_tree_needed; |
||
2370 | |||
2371 | callback_args.print_args = print_args; |
||
2372 | callback_args.print_header_line = print_args->print_col_headings; |
||
2373 | callback_args.header_line_buf = NULL; |
||
2374 | callback_args.header_line_buf_len = 256; |
||
2375 | callback_args.print_formfeed = FALSE; |
||
2376 | callback_args.print_separator = FALSE; |
||
2377 | callback_args.line_buf = NULL; |
||
2378 | callback_args.line_buf_len = 256; |
||
2379 | callback_args.col_widths = NULL; |
||
2380 | callback_args.num_visible_cols = 0; |
||
2381 | callback_args.visible_cols = NULL; |
||
2382 | |||
2383 | if (!print_preamble(print_args->stream, cf->filename, get_ws_vcs_version_info())) { |
||
2384 | destroy_print_stream(print_args->stream); |
||
2385 | return CF_PRINT_WRITE_ERROR; |
||
2386 | } |
||
2387 | |||
2388 | if (print_args->print_summary) { |
||
2389 | /* We're printing packet summaries. Allocate the header line buffer |
||
2390 | and get the column widths. */ |
||
2391 | callback_args.header_line_buf = (char *)g_malloc(callback_args.header_line_buf_len + 1); |
||
2392 | |||
2393 | /* Find the number of visible columns and the last visible column */ |
||
2394 | for (i = 0; i < prefs.num_cols; i++) { |
||
2395 | |||
2396 | clp = g_list_nth(prefs.col_list, i); |
||
2397 | if (clp == NULL) /* Sanity check, Invalid column requested */ |
||
2398 | continue; |
||
2399 | |||
2400 | cfmt = (fmt_data *) clp->data; |
||
2401 | if (cfmt->visible) { |
||
2402 | num_visible_col++; |
||
2403 | last_visible_col = i; |
||
2404 | } |
||
2405 | } |
||
2406 | |||
2407 | /* Find the widths for each of the columns - maximum of the |
||
2408 | width of the title and the width of the data - and construct |
||
2409 | a buffer with a line containing the column titles. */ |
||
2410 | callback_args.num_visible_cols = num_visible_col; |
||
2411 | callback_args.col_widths = (gint *) g_malloc(sizeof(gint) * num_visible_col); |
||
2412 | callback_args.visible_cols = (gint *) g_malloc(sizeof(gint) * num_visible_col); |
||
2413 | cp = &callback_args.header_line_buf[0]; |
||
2414 | line_len = 0; |
||
2415 | visible_col_count = 0; |
||
2416 | for (i = 0; i < cf->cinfo.num_cols; i++) { |
||
2417 | |||
2418 | clp = g_list_nth(prefs.col_list, i); |
||
2419 | if (clp == NULL) /* Sanity check, Invalid column requested */ |
||
2420 | continue; |
||
2421 | |||
2422 | cfmt = (fmt_data *) clp->data; |
||
2423 | if (cfmt->visible == FALSE) |
||
2424 | continue; |
||
2425 | |||
2426 | /* Save the order of visible columns */ |
||
2427 | callback_args.visible_cols[visible_col_count] = i; |
||
2428 | |||
2429 | /* Don't pad the last column. */ |
||
2430 | if (i == last_visible_col) |
||
2431 | callback_args.col_widths[visible_col_count] = 0; |
||
2432 | else { |
||
2433 | callback_args.col_widths[visible_col_count] = (gint) strlen(cf->cinfo.columns[i].col_title); |
||
2434 | data_width = get_column_char_width(get_column_format(i)); |
||
2435 | if (data_width > callback_args.col_widths[visible_col_count]) |
||
2436 | callback_args.col_widths[visible_col_count] = data_width; |
||
2437 | } |
||
2438 | |||
2439 | /* Find the length of the string for this column. */ |
||
2440 | column_len = (int) strlen(cf->cinfo.columns[i].col_title); |
||
2441 | if (callback_args.col_widths[i] > column_len) |
||
2442 | column_len = callback_args.col_widths[visible_col_count]; |
||
2443 | |||
2444 | /* Make sure there's room in the line buffer for the column; if not, |
||
2445 | double its length. */ |
||
2446 | line_len += column_len + 1; /* "+1" for space */ |
||
2447 | if (line_len > callback_args.header_line_buf_len) { |
||
2448 | cp_off = (int) (cp - callback_args.header_line_buf); |
||
2449 | callback_args.header_line_buf_len = 2 * line_len; |
||
2450 | callback_args.header_line_buf = (char *)g_realloc(callback_args.header_line_buf, |
||
2451 | callback_args.header_line_buf_len + 1); |
||
2452 | cp = callback_args.header_line_buf + cp_off; |
||
2453 | } |
||
2454 | |||
2455 | /* Right-justify the packet number column. */ |
||
2456 | /* if (cf->cinfo.col_fmt[i] == COL_NUMBER) |
||
2457 | g_snprintf(cp, column_len+1, "%*s", callback_args.col_widths[visible_col_count], cf->cinfo.columns[i].col_title); |
||
2458 | else*/ |
||
2459 | g_snprintf(cp, column_len+1, "%-*s", callback_args.col_widths[visible_col_count], cf->cinfo.columns[i].col_title); |
||
2460 | cp += column_len; |
||
2461 | if (i != cf->cinfo.num_cols - 1) |
||
2462 | *cp++ = ' '; |
||
2463 | |||
2464 | visible_col_count++; |
||
2465 | } |
||
2466 | *cp = '\0'; |
||
2467 | |||
2468 | /* Now start out the main line buffer with the same length as the |
||
2469 | header line buffer. */ |
||
2470 | callback_args.line_buf_len = callback_args.header_line_buf_len; |
||
2471 | callback_args.line_buf = (char *)g_malloc(callback_args.line_buf_len + 1); |
||
2472 | } /* if (print_summary) */ |
||
2473 | |||
2474 | /* Create the protocol tree, and make it visible, if we're printing |
||
2475 | the dissection or the hex data. |
||
2476 | XXX - do we need it if we're just printing the hex data? */ |
||
2477 | proto_tree_needed = |
||
2478 | callback_args.print_args->print_dissections != print_dissections_none || |
||
2479 | callback_args.print_args->print_hex || |
||
2480 | have_custom_cols(&cf->cinfo) || have_field_extractors(); |
||
2481 | epan_dissect_init(&callback_args.edt, cf->epan, proto_tree_needed, proto_tree_needed); |
||
2482 | |||
2483 | /* Iterate through the list of packets, printing the packets we were |
||
2484 | told to print. */ |
||
2485 | ret = process_specified_records(cf, &print_args->range, "Printing", |
||
2486 | "selected packets", TRUE, print_packet, |
||
2487 | &callback_args, show_progress_bar); |
||
2488 | epan_dissect_cleanup(&callback_args.edt); |
||
2489 | g_free(callback_args.header_line_buf); |
||
2490 | g_free(callback_args.line_buf); |
||
2491 | g_free(callback_args.col_widths); |
||
2492 | g_free(callback_args.visible_cols); |
||
2493 | |||
2494 | switch (ret) { |
||
2495 | |||
2496 | case PSP_FINISHED: |
||
2497 | /* Completed successfully. */ |
||
2498 | break; |
||
2499 | |||
2500 | case PSP_STOPPED: |
||
2501 | /* Well, the user decided to abort the printing. |
||
2502 | |||
2503 | XXX - note that what got generated before they did that |
||
2504 | will get printed if we're piping to a print program; we'd |
||
2505 | have to write to a file and then hand that to the print |
||
2506 | program to make it actually not print anything. */ |
||
2507 | break; |
||
2508 | |||
2509 | case PSP_FAILED: |
||
2510 | /* Error while printing. |
||
2511 | |||
2512 | XXX - note that what got generated before they did that |
||
2513 | will get printed if we're piping to a print program; we'd |
||
2514 | have to write to a file and then hand that to the print |
||
2515 | program to make it actually not print anything. */ |
||
2516 | destroy_print_stream(print_args->stream); |
||
2517 | return CF_PRINT_WRITE_ERROR; |
||
2518 | } |
||
2519 | |||
2520 | if (!print_finale(print_args->stream)) { |
||
2521 | destroy_print_stream(print_args->stream); |
||
2522 | return CF_PRINT_WRITE_ERROR; |
||
2523 | } |
||
2524 | |||
2525 | if (!destroy_print_stream(print_args->stream)) |
||
2526 | return CF_PRINT_WRITE_ERROR; |
||
2527 | |||
2528 | return CF_PRINT_OK; |
||
2529 | } |
||
2530 | |||
2531 | typedef struct { |
||
2532 | FILE *fh; |
||
2533 | epan_dissect_t edt; |
||
2534 | print_args_t *print_args; |
||
2535 | } write_packet_callback_args_t; |
||
2536 | |||
2537 | static gboolean |
||
2538 | write_pdml_packet(capture_file *cf, frame_data *fdata, |
||
2539 | struct wtap_pkthdr *phdr, const guint8 *pd, |
||
2540 | void *argsp) |
||
2541 | { |
||
2542 | write_packet_callback_args_t *args = (write_packet_callback_args_t *)argsp; |
||
2543 | |||
2544 | /* Create the protocol tree, but don't fill in the column information. */ |
||
2545 | epan_dissect_run(&args->edt, cf->cd_t, phdr, frame_tvbuff_new(fdata, pd), fdata, NULL); |
||
2546 | |||
2547 | /* Write out the information in that tree. */ |
||
2548 | write_pdml_proto_tree(NULL, NULL, &args->edt, args->fh); |
||
2549 | |||
2550 | epan_dissect_reset(&args->edt); |
||
2551 | |||
2552 | return !ferror(args->fh); |
||
2553 | } |
||
2554 | |||
2555 | cf_print_status_t |
||
2556 | cf_write_pdml_packets(capture_file *cf, print_args_t *print_args) |
||
2557 | { |
||
2558 | write_packet_callback_args_t callback_args; |
||
2559 | FILE *fh; |
||
2560 | psp_return_t ret; |
||
2561 | |||
2562 | fh = ws_fopen(print_args->file, "w"); |
||
2563 | if (fh == NULL) |
||
2564 | return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */ |
||
2565 | |||
2566 | write_pdml_preamble(fh, cf->filename); |
||
2567 | if (ferror(fh)) { |
||
2568 | fclose(fh); |
||
2569 | return CF_PRINT_WRITE_ERROR; |
||
2570 | } |
||
2571 | |||
2572 | callback_args.fh = fh; |
||
2573 | callback_args.print_args = print_args; |
||
2574 | epan_dissect_init(&callback_args.edt, cf->epan, TRUE, TRUE); |
||
2575 | |||
2576 | /* Iterate through the list of packets, printing the packets we were |
||
2577 | told to print. */ |
||
2578 | ret = process_specified_records(cf, &print_args->range, "Writing PDML", |
||
2579 | "selected packets", TRUE, |
||
2580 | write_pdml_packet, &callback_args, TRUE); |
||
2581 | |||
2582 | epan_dissect_cleanup(&callback_args.edt); |
||
2583 | |||
2584 | switch (ret) { |
||
2585 | |||
2586 | case PSP_FINISHED: |
||
2587 | /* Completed successfully. */ |
||
2588 | break; |
||
2589 | |||
2590 | case PSP_STOPPED: |
||
2591 | /* Well, the user decided to abort the printing. */ |
||
2592 | break; |
||
2593 | |||
2594 | case PSP_FAILED: |
||
2595 | /* Error while printing. */ |
||
2596 | fclose(fh); |
||
2597 | return CF_PRINT_WRITE_ERROR; |
||
2598 | } |
||
2599 | |||
2600 | write_pdml_finale(fh); |
||
2601 | if (ferror(fh)) { |
||
2602 | fclose(fh); |
||
2603 | return CF_PRINT_WRITE_ERROR; |
||
2604 | } |
||
2605 | |||
2606 | /* XXX - check for an error */ |
||
2607 | fclose(fh); |
||
2608 | |||
2609 | return CF_PRINT_OK; |
||
2610 | } |
||
2611 | |||
2612 | static gboolean |
||
2613 | write_psml_packet(capture_file *cf, frame_data *fdata, |
||
2614 | struct wtap_pkthdr *phdr, const guint8 *pd, |
||
2615 | void *argsp) |
||
2616 | { |
||
2617 | write_packet_callback_args_t *args = (write_packet_callback_args_t *)argsp; |
||
2618 | |||
2619 | /* Fill in the column information */ |
||
2620 | col_custom_prime_edt(&args->edt, &cf->cinfo); |
||
2621 | epan_dissect_run(&args->edt, cf->cd_t, phdr, frame_tvbuff_new(fdata, pd), fdata, &cf->cinfo); |
||
2622 | epan_dissect_fill_in_columns(&args->edt, FALSE, TRUE); |
||
2623 | |||
2624 | /* Write out the column information. */ |
||
2625 | write_psml_columns(&args->edt, args->fh); |
||
2626 | |||
2627 | epan_dissect_reset(&args->edt); |
||
2628 | |||
2629 | return !ferror(args->fh); |
||
2630 | } |
||
2631 | |||
2632 | cf_print_status_t |
||
2633 | cf_write_psml_packets(capture_file *cf, print_args_t *print_args) |
||
2634 | { |
||
2635 | write_packet_callback_args_t callback_args; |
||
2636 | FILE *fh; |
||
2637 | psp_return_t ret; |
||
2638 | |||
2639 | gboolean proto_tree_needed; |
||
2640 | |||
2641 | fh = ws_fopen(print_args->file, "w"); |
||
2642 | if (fh == NULL) |
||
2643 | return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */ |
||
2644 | |||
2645 | write_psml_preamble(&cf->cinfo, fh); |
||
2646 | if (ferror(fh)) { |
||
2647 | fclose(fh); |
||
2648 | return CF_PRINT_WRITE_ERROR; |
||
2649 | } |
||
2650 | |||
2651 | callback_args.fh = fh; |
||
2652 | callback_args.print_args = print_args; |
||
2653 | |||
2654 | /* Fill in the column information, only create the protocol tree |
||
2655 | if having custom columns or field extractors. */ |
||
2656 | proto_tree_needed = have_custom_cols(&cf->cinfo) || have_field_extractors(); |
||
2657 | epan_dissect_init(&callback_args.edt, cf->epan, proto_tree_needed, proto_tree_needed); |
||
2658 | |||
2659 | /* Iterate through the list of packets, printing the packets we were |
||
2660 | told to print. */ |
||
2661 | ret = process_specified_records(cf, &print_args->range, "Writing PSML", |
||
2662 | "selected packets", TRUE, |
||
2663 | write_psml_packet, &callback_args, TRUE); |
||
2664 | |||
2665 | epan_dissect_cleanup(&callback_args.edt); |
||
2666 | |||
2667 | switch (ret) { |
||
2668 | |||
2669 | case PSP_FINISHED: |
||
2670 | /* Completed successfully. */ |
||
2671 | break; |
||
2672 | |||
2673 | case PSP_STOPPED: |
||
2674 | /* Well, the user decided to abort the printing. */ |
||
2675 | break; |
||
2676 | |||
2677 | case PSP_FAILED: |
||
2678 | /* Error while printing. */ |
||
2679 | fclose(fh); |
||
2680 | return CF_PRINT_WRITE_ERROR; |
||
2681 | } |
||
2682 | |||
2683 | write_psml_finale(fh); |
||
2684 | if (ferror(fh)) { |
||
2685 | fclose(fh); |
||
2686 | return CF_PRINT_WRITE_ERROR; |
||
2687 | } |
||
2688 | |||
2689 | /* XXX - check for an error */ |
||
2690 | fclose(fh); |
||
2691 | |||
2692 | return CF_PRINT_OK; |
||
2693 | } |
||
2694 | |||
2695 | static gboolean |
||
2696 | write_csv_packet(capture_file *cf, frame_data *fdata, |
||
2697 | struct wtap_pkthdr *phdr, const guint8 *pd, |
||
2698 | void *argsp) |
||
2699 | { |
||
2700 | write_packet_callback_args_t *args = (write_packet_callback_args_t *)argsp; |
||
2701 | |||
2702 | /* Fill in the column information */ |
||
2703 | col_custom_prime_edt(&args->edt, &cf->cinfo); |
||
2704 | epan_dissect_run(&args->edt, cf->cd_t, phdr, frame_tvbuff_new(fdata, pd), fdata, &cf->cinfo); |
||
2705 | epan_dissect_fill_in_columns(&args->edt, FALSE, TRUE); |
||
2706 | |||
2707 | /* Write out the column information. */ |
||
2708 | write_csv_columns(&args->edt, args->fh); |
||
2709 | |||
2710 | epan_dissect_reset(&args->edt); |
||
2711 | |||
2712 | return !ferror(args->fh); |
||
2713 | } |
||
2714 | |||
2715 | cf_print_status_t |
||
2716 | cf_write_csv_packets(capture_file *cf, print_args_t *print_args) |
||
2717 | { |
||
2718 | write_packet_callback_args_t callback_args; |
||
2719 | gboolean proto_tree_needed; |
||
2720 | FILE *fh; |
||
2721 | psp_return_t ret; |
||
2722 | |||
2723 | fh = ws_fopen(print_args->file, "w"); |
||
2724 | if (fh == NULL) |
||
2725 | return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */ |
||
2726 | |||
2727 | write_csv_column_titles(&cf->cinfo, fh); |
||
2728 | if (ferror(fh)) { |
||
2729 | fclose(fh); |
||
2730 | return CF_PRINT_WRITE_ERROR; |
||
2731 | } |
||
2732 | |||
2733 | callback_args.fh = fh; |
||
2734 | callback_args.print_args = print_args; |
||
2735 | |||
2736 | /* only create the protocol tree if having custom columns or field extractors. */ |
||
2737 | proto_tree_needed = have_custom_cols(&cf->cinfo) || have_field_extractors(); |
||
2738 | epan_dissect_init(&callback_args.edt, cf->epan, proto_tree_needed, proto_tree_needed); |
||
2739 | |||
2740 | /* Iterate through the list of packets, printing the packets we were |
||
2741 | told to print. */ |
||
2742 | ret = process_specified_records(cf, &print_args->range, "Writing CSV", |
||
2743 | "selected packets", TRUE, |
||
2744 | write_csv_packet, &callback_args, TRUE); |
||
2745 | |||
2746 | epan_dissect_cleanup(&callback_args.edt); |
||
2747 | |||
2748 | switch (ret) { |
||
2749 | |||
2750 | case PSP_FINISHED: |
||
2751 | /* Completed successfully. */ |
||
2752 | break; |
||
2753 | |||
2754 | case PSP_STOPPED: |
||
2755 | /* Well, the user decided to abort the printing. */ |
||
2756 | break; |
||
2757 | |||
2758 | case PSP_FAILED: |
||
2759 | /* Error while printing. */ |
||
2760 | fclose(fh); |
||
2761 | return CF_PRINT_WRITE_ERROR; |
||
2762 | } |
||
2763 | |||
2764 | /* XXX - check for an error */ |
||
2765 | fclose(fh); |
||
2766 | |||
2767 | return CF_PRINT_OK; |
||
2768 | } |
||
2769 | |||
2770 | static gboolean |
||
2771 | carrays_write_packet(capture_file *cf, frame_data *fdata, |
||
2772 | struct wtap_pkthdr *phdr, |
||
2773 | const guint8 *pd, void *argsp) |
||
2774 | { |
||
2775 | write_packet_callback_args_t *args = (write_packet_callback_args_t *)argsp; |
||
2776 | |||
2777 | epan_dissect_run(&args->edt, cf->cd_t, phdr, frame_tvbuff_new(fdata, pd), fdata, NULL); |
||
2778 | write_carrays_hex_data(fdata->num, args->fh, &args->edt); |
||
2779 | epan_dissect_reset(&args->edt); |
||
2780 | |||
2781 | return !ferror(args->fh); |
||
2782 | } |
||
2783 | |||
2784 | cf_print_status_t |
||
2785 | cf_write_carrays_packets(capture_file *cf, print_args_t *print_args) |
||
2786 | { |
||
2787 | write_packet_callback_args_t callback_args; |
||
2788 | FILE *fh; |
||
2789 | psp_return_t ret; |
||
2790 | |||
2791 | fh = ws_fopen(print_args->file, "w"); |
||
2792 | |||
2793 | if (fh == NULL) |
||
2794 | return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */ |
||
2795 | |||
2796 | if (ferror(fh)) { |
||
2797 | fclose(fh); |
||
2798 | return CF_PRINT_WRITE_ERROR; |
||
2799 | } |
||
2800 | |||
2801 | callback_args.fh = fh; |
||
2802 | callback_args.print_args = print_args; |
||
2803 | epan_dissect_init(&callback_args.edt, cf->epan, TRUE, TRUE); |
||
2804 | |||
2805 | /* Iterate through the list of packets, printing the packets we were |
||
2806 | told to print. */ |
||
2807 | ret = process_specified_records(cf, &print_args->range, |
||
2808 | "Writing C Arrays", |
||
2809 | "selected packets", TRUE, |
||
2810 | carrays_write_packet, &callback_args, TRUE); |
||
2811 | |||
2812 | epan_dissect_cleanup(&callback_args.edt); |
||
2813 | |||
2814 | switch (ret) { |
||
2815 | case PSP_FINISHED: |
||
2816 | /* Completed successfully. */ |
||
2817 | break; |
||
2818 | case PSP_STOPPED: |
||
2819 | /* Well, the user decided to abort the printing. */ |
||
2820 | break; |
||
2821 | case PSP_FAILED: |
||
2822 | /* Error while printing. */ |
||
2823 | fclose(fh); |
||
2824 | return CF_PRINT_WRITE_ERROR; |
||
2825 | } |
||
2826 | |||
2827 | fclose(fh); |
||
2828 | return CF_PRINT_OK; |
||
2829 | } |
||
2830 | |||
2831 | static gboolean |
||
2832 | write_json_packet(capture_file *cf, frame_data *fdata, |
||
2833 | struct wtap_pkthdr *phdr, const guint8 *pd, |
||
2834 | void *argsp) |
||
2835 | { |
||
2836 | write_packet_callback_args_t *args = (write_packet_callback_args_t *)argsp; |
||
2837 | |||
2838 | /* Create the protocol tree, but don't fill in the column information. */ |
||
2839 | epan_dissect_run(&args->edt, cf->cd_t, phdr, frame_tvbuff_new(fdata, pd), fdata, NULL); |
||
2840 | |||
2841 | /* Write out the information in that tree. */ |
||
2842 | write_json_proto_tree(NULL, args->print_args, NULL, &args->edt, args->fh); |
||
2843 | |||
2844 | epan_dissect_reset(&args->edt); |
||
2845 | |||
2846 | return !ferror(args->fh); |
||
2847 | } |
||
2848 | |||
2849 | cf_print_status_t |
||
2850 | cf_write_json_packets(capture_file *cf, print_args_t *print_args) |
||
2851 | { |
||
2852 | write_packet_callback_args_t callback_args; |
||
2853 | FILE *fh; |
||
2854 | psp_return_t ret; |
||
2855 | |||
2856 | fh = ws_fopen(print_args->file, "w"); |
||
2857 | if (fh == NULL) |
||
2858 | return CF_PRINT_OPEN_ERROR; /* attempt to open destination failed */ |
||
2859 | |||
2860 | write_json_preamble(fh); |
||
2861 | if (ferror(fh)) { |
||
2862 | fclose(fh); |
||
2863 | return CF_PRINT_WRITE_ERROR; |
||
2864 | } |
||
2865 | |||
2866 | callback_args.fh = fh; |
||
2867 | callback_args.print_args = print_args; |
||
2868 | epan_dissect_init(&callback_args.edt, cf->epan, TRUE, TRUE); |
||
2869 | |||
2870 | /* Iterate through the list of packets, printing the packets we were |
||
2871 | told to print. */ |
||
2872 | ret = process_specified_records(cf, &print_args->range, "Writing PDML", |
||
2873 | "selected packets", TRUE, |
||
2874 | write_json_packet, &callback_args, TRUE); |
||
2875 | |||
2876 | epan_dissect_cleanup(&callback_args.edt); |
||
2877 | |||
2878 | switch (ret) { |
||
2879 | |||
2880 | case PSP_FINISHED: |
||
2881 | /* Completed successfully. */ |
||
2882 | break; |
||
2883 | |||
2884 | case PSP_STOPPED: |
||
2885 | /* Well, the user decided to abort the printing. */ |
||
2886 | break; |
||
2887 | |||
2888 | case PSP_FAILED: |
||
2889 | /* Error while printing. */ |
||
2890 | fclose(fh); |
||
2891 | return CF_PRINT_WRITE_ERROR; |
||
2892 | } |
||
2893 | |||
2894 | write_json_finale(fh); |
||
2895 | if (ferror(fh)) { |
||
2896 | fclose(fh); |
||
2897 | return CF_PRINT_WRITE_ERROR; |
||
2898 | } |
||
2899 | |||
2900 | /* XXX - check for an error */ |
||
2901 | fclose(fh); |
||
2902 | |||
2903 | return CF_PRINT_OK; |
||
2904 | } |
||
2905 | |||
2906 | gboolean |
||
2907 | cf_find_packet_protocol_tree(capture_file *cf, const char *string, |
||
2908 | search_direction dir) |
||
2909 | { |
||
2910 | match_data mdata; |
||
2911 | |||
2912 | mdata.string = string; |
||
2913 | mdata.string_len = strlen(string); |
||
2914 | return find_packet(cf, match_protocol_tree, &mdata, dir); |
||
2915 | } |
||
2916 | |||
2917 | gboolean |
||
2918 | cf_find_string_protocol_tree(capture_file *cf, proto_tree *tree, match_data *mdata) |
||
2919 | { |
||
2920 | mdata->frame_matched = FALSE; |
||
2921 | mdata->string = convert_string_case(cf->sfilter, cf->case_type); |
||
2922 | mdata->string_len = strlen(mdata->string); |
||
2923 | mdata->cf = cf; |
||
2924 | /* Iterate through all the nodes looking for matching text */ |
||
2925 | proto_tree_children_foreach(tree, match_subtree_text, mdata); |
||
2926 | return mdata->frame_matched ? MR_MATCHED : MR_NOTMATCHED; |
||
2927 | } |
||
2928 | |||
2929 | static match_result |
||
2930 | match_protocol_tree(capture_file *cf, frame_data *fdata, void *criterion) |
||
2931 | { |
||
2932 | match_data *mdata = (match_data *)criterion; |
||
2933 | epan_dissect_t edt; |
||
2934 | |||
2935 | /* Load the frame's data. */ |
||
2936 | if (!cf_read_record(cf, fdata)) { |
||
2937 | /* Attempt to get the packet failed. */ |
||
2938 | return MR_ERROR; |
||
2939 | } |
||
2940 | |||
2941 | /* Construct the protocol tree, including the displayed text */ |
||
2942 | epan_dissect_init(&edt, cf->epan, TRUE, TRUE); |
||
2943 | /* We don't need the column information */ |
||
2944 | epan_dissect_run(&edt, cf->cd_t, &cf->phdr, frame_tvbuff_new_buffer(fdata, &cf->buf), fdata, NULL); |
||
2945 | |||
2946 | /* Iterate through all the nodes, seeing if they have text that matches. */ |
||
2947 | mdata->cf = cf; |
||
2948 | mdata->frame_matched = FALSE; |
||
2949 | proto_tree_children_foreach(edt.tree, match_subtree_text, mdata); |
||
2950 | epan_dissect_cleanup(&edt); |
||
2951 | return mdata->frame_matched ? MR_MATCHED : MR_NOTMATCHED; |
||
2952 | } |
||
2953 | |||
2954 | static void |
||
2955 | match_subtree_text(proto_node *node, gpointer data) |
||
2956 | { |
||
2957 | match_data *mdata = (match_data *) data; |
||
2958 | const gchar *string = mdata->string; |
||
2959 | size_t string_len = mdata->string_len; |
||
2960 | capture_file *cf = mdata->cf; |
||
2961 | field_info *fi = PNODE_FINFO(node); |
||
2962 | gchar label_str[ITEM_LABEL_LENGTH]; |
||
2963 | gchar *label_ptr; |
||
2964 | size_t label_len; |
||
2965 | guint32 i; |
||
2966 | guint8 c_char; |
||
2967 | size_t c_match = 0; |
||
2968 | |||
2969 | /* dissection with an invisible proto tree? */ |
||
2970 | g_assert(fi); |
||
2971 | |||
2972 | if (mdata->frame_matched) { |
||
2973 | /* We already had a match; don't bother doing any more work. */ |
||
2974 | return; |
||
2975 | } |
||
2976 | |||
2977 | /* Don't match invisible entries. */ |
||
2978 | if (PROTO_ITEM_IS_HIDDEN(node)) |
||
2979 | return; |
||
2980 | |||
2981 | /* was a free format label produced? */ |
||
2982 | if (fi->rep) { |
||
2983 | label_ptr = fi->rep->representation; |
||
2984 | } else { |
||
2985 | /* no, make a generic label */ |
||
2986 | label_ptr = label_str; |
||
2987 | proto_item_fill_label(fi, label_str); |
||
2988 | } |
||
2989 | |||
2990 | if (cf->regex) { |
||
2991 | if (g_regex_match(cf->regex, label_ptr, (GRegexMatchFlags) 0, NULL)) { |
||
2992 | mdata->frame_matched = TRUE; |
||
2993 | mdata->finfo = fi; |
||
2994 | return; |
||
2995 | } |
||
2996 | } else { |
||
2997 | /* Does that label match? */ |
||
2998 | label_len = strlen(label_ptr); |
||
2999 | for (i = 0; i < label_len; i++) { |
||
3000 | c_char = label_ptr[i]; |
||
3001 | if (cf->case_type) |
||
3002 | c_char = g_ascii_toupper(c_char); |
||
3003 | if (c_char == string[c_match]) { |
||
3004 | c_match++; |
||
3005 | if (c_match == string_len) { |
||
3006 | /* No need to look further; we have a match */ |
||
3007 | mdata->frame_matched = TRUE; |
||
3008 | mdata->finfo = fi; |
||
3009 | return; |
||
3010 | } |
||
3011 | } else |
||
3012 | c_match = 0; |
||
3013 | } |
||
3014 | } |
||
3015 | |||
3016 | /* Recurse into the subtree, if it exists */ |
||
3017 | if (node->first_child != NULL) |
||
3018 | proto_tree_children_foreach(node, match_subtree_text, mdata); |
||
3019 | } |
||
3020 | |||
3021 | gboolean |
||
3022 | cf_find_packet_summary_line(capture_file *cf, const char *string, |
||
3023 | search_direction dir) |
||
3024 | { |
||
3025 | match_data mdata; |
||
3026 | |||
3027 | mdata.string = string; |
||
3028 | mdata.string_len = strlen(string); |
||
3029 | return find_packet(cf, match_summary_line, &mdata, dir); |
||
3030 | } |
||
3031 | |||
3032 | static match_result |
||
3033 | match_summary_line(capture_file *cf, frame_data *fdata, void *criterion) |
||
3034 | { |
||
3035 | match_data *mdata = (match_data *)criterion; |
||
3036 | const gchar *string = mdata->string; |
||
3037 | size_t string_len = mdata->string_len; |
||
3038 | epan_dissect_t edt; |
||
3039 | const char *info_column; |
||
3040 | size_t info_column_len; |
||
3041 | match_result result = MR_NOTMATCHED; |
||
3042 | gint colx; |
||
3043 | guint32 i; |
||
3044 | guint8 c_char; |
||
3045 | size_t c_match = 0; |
||
3046 | |||
3047 | /* Load the frame's data. */ |
||
3048 | if (!cf_read_record(cf, fdata)) { |
||
3049 | /* Attempt to get the packet failed. */ |
||
3050 | return MR_ERROR; |
||
3051 | } |
||
3052 | |||
3053 | /* Don't bother constructing the protocol tree */ |
||
3054 | epan_dissect_init(&edt, cf->epan, FALSE, FALSE); |
||
3055 | /* Get the column information */ |
||
3056 | epan_dissect_run(&edt, cf->cd_t, &cf->phdr, frame_tvbuff_new_buffer(fdata, &cf->buf), fdata, |
||
3057 | &cf->cinfo); |
||
3058 | |||
3059 | /* Find the Info column */ |
||
3060 | for (colx = 0; colx < cf->cinfo.num_cols; colx++) { |
||
3061 | if (cf->cinfo.columns[colx].fmt_matx[COL_INFO]) { |
||
3062 | /* Found it. See if we match. */ |
||
3063 | info_column = edt.pi.cinfo->columns[colx].col_data; |
||
3064 | info_column_len = strlen(info_column); |
||
3065 | if (cf->regex) { |
||
3066 | if (g_regex_match(cf->regex, info_column, (GRegexMatchFlags) 0, NULL)) { |
||
3067 | result = MR_MATCHED; |
||
3068 | break; |
||
3069 | } |
||
3070 | } else { |
||
3071 | for (i = 0; i < info_column_len; i++) { |
||
3072 | c_char = info_column[i]; |
||
3073 | if (cf->case_type) |
||
3074 | c_char = g_ascii_toupper(c_char); |
||
3075 | if (c_char == string[c_match]) { |
||
3076 | c_match++; |
||
3077 | if (c_match == string_len) { |
||
3078 | result = MR_MATCHED; |
||
3079 | break; |
||
3080 | } |
||
3081 | } else |
||
3082 | c_match = 0; |
||
3083 | } |
||
3084 | } |
||
3085 | break; |
||
3086 | } |
||
3087 | } |
||
3088 | epan_dissect_cleanup(&edt); |
||
3089 | return result; |
||
3090 | } |
||
3091 | |||
3092 | typedef struct { |
||
3093 | const guint8 *data; |
||
3094 | size_t data_len; |
||
3095 | } cbs_t; /* "Counted byte string" */ |
||
3096 | |||
3097 | |||
3098 | /* |
||
3099 | * The current match_* routines only support ASCII case insensitivity and don't |
||
3100 | * convert UTF-8 inputs to UTF-16 for matching. |
||
3101 | * |
||
3102 | * We could modify them to use the GLib Unicode routines or the International |
||
3103 | * Components for Unicode library but it's not apparent that we could do so |
||
3104 | * without consuming a lot more CPU and memory or that searching would be |
||
3105 | * significantly better. |
||
3106 | */ |
||
3107 | |||
3108 | gboolean |
||
3109 | cf_find_packet_data(capture_file *cf, const guint8 *string, size_t string_size, |
||
3110 | search_direction dir) |
||
3111 | { |
||
3112 | cbs_t info; |
||
3113 | |||
3114 | info.data = string; |
||
3115 | info.data_len = string_size; |
||
3116 | |||
3117 | /* Regex, String or hex search? */ |
||
3118 | if (cf->regex) { |
||
3119 | /* Regular Expression search */ |
||
3120 | return find_packet(cf, match_regex, NULL, dir); |
||
3121 | } else if (cf->string) { |
||
3122 | /* String search - what type of string? */ |
||
3123 | switch (cf->scs_type) { |
||
3124 | |||
3125 | case SCS_NARROW_AND_WIDE: |
||
3126 | return find_packet(cf, match_narrow_and_wide, &info, dir); |
||
3127 | |||
3128 | case SCS_NARROW: |
||
3129 | return find_packet(cf, match_narrow, &info, dir); |
||
3130 | |||
3131 | case SCS_WIDE: |
||
3132 | return find_packet(cf, match_wide, &info, dir); |
||
3133 | |||
3134 | default: |
||
3135 | g_assert_not_reached(); |
||
3136 | return FALSE; |
||
3137 | } |
||
3138 | } else |
||
3139 | return find_packet(cf, match_binary, &info, dir); |
||
3140 | } |
||
3141 | |||
3142 | static match_result |
||
3143 | match_narrow_and_wide(capture_file *cf, frame_data *fdata, void *criterion) |
||
3144 | { |
||
3145 | cbs_t *info = (cbs_t *)criterion; |
||
3146 | const guint8 *ascii_text = info->data; |
||
3147 | size_t textlen = info->data_len; |
||
3148 | match_result result; |
||
3149 | guint32 buf_len; |
||
3150 | guint8 *pd; |
||
3151 | guint32 i; |
||
3152 | guint8 c_char; |
||
3153 | size_t c_match = 0; |
||
3154 | |||
3155 | /* Load the frame's data. */ |
||
3156 | if (!cf_read_record(cf, fdata)) { |
||
3157 | /* Attempt to get the packet failed. */ |
||
3158 | return MR_ERROR; |
||
3159 | } |
||
3160 | |||
3161 | result = MR_NOTMATCHED; |
||
3162 | buf_len = fdata->cap_len; |
||
3163 | pd = ws_buffer_start_ptr(&cf->buf); |
||
3164 | i = 0; |
||
3165 | while (i < buf_len) { |
||
3166 | c_char = pd[i]; |
||
3167 | if (cf->case_type) |
||
3168 | c_char = g_ascii_toupper(c_char); |
||
3169 | if (c_char != '\0') { |
||
3170 | if (c_char == ascii_text[c_match]) { |
||
3171 | c_match += 1; |
||
3172 | if (c_match == textlen) { |
||
3173 | result = MR_MATCHED; |
||
3174 | cf->search_pos = i; /* Save the position of the last character |
||
3175 | for highlighting the field. */ |
||
3176 | cf->search_len = (guint32)textlen; |
||
3177 | break; |
||
3178 | } |
||
3179 | } |
||
3180 | else { |
||
3181 | g_assert(i>=c_match); |
||
3182 | i -= (guint32)c_match; |
||
3183 | c_match = 0; |
||
3184 | } |
||
3185 | } |
||
3186 | i += 1; |
||
3187 | } |
||
3188 | return result; |
||
3189 | } |
||
3190 | |||
3191 | static match_result |
||
3192 | match_narrow(capture_file *cf, frame_data *fdata, void *criterion) |
||
3193 | { |
||
3194 | guint8 *pd; |
||
3195 | cbs_t *info = (cbs_t *)criterion; |
||
3196 | const guint8 *ascii_text = info->data; |
||
3197 | size_t textlen = info->data_len; |
||
3198 | match_result result; |
||
3199 | guint32 buf_len; |
||
3200 | guint32 i; |
||
3201 | guint8 c_char; |
||
3202 | size_t c_match = 0; |
||
3203 | |||
3204 | /* Load the frame's data. */ |
||
3205 | if (!cf_read_record(cf, fdata)) { |
||
3206 | /* Attempt to get the packet failed. */ |
||
3207 | return MR_ERROR; |
||
3208 | } |
||
3209 | |||
3210 | result = MR_NOTMATCHED; |
||
3211 | buf_len = fdata->cap_len; |
||
3212 | pd = ws_buffer_start_ptr(&cf->buf); |
||
3213 | i = 0; |
||
3214 | while (i < buf_len) { |
||
3215 | c_char = pd[i]; |
||
3216 | if (cf->case_type) |
||
3217 | c_char = g_ascii_toupper(c_char); |
||
3218 | if (c_char == ascii_text[c_match]) { |
||
3219 | c_match += 1; |
||
3220 | if (c_match == textlen) { |
||
3221 | result = MR_MATCHED; |
||
3222 | cf->search_pos = i; /* Save the position of the last character |
||
3223 | for highlighting the field. */ |
||
3224 | cf->search_len = (guint32)textlen; |
||
3225 | break; |
||
3226 | } |
||
3227 | } |
||
3228 | else { |
||
3229 | g_assert(i>=c_match); |
||
3230 | i -= (guint32)c_match; |
||
3231 | c_match = 0; |
||
3232 | } |
||
3233 | i += 1; |
||
3234 | } |
||
3235 | |||
3236 | return result; |
||
3237 | } |
||
3238 | |||
3239 | static match_result |
||
3240 | match_wide(capture_file *cf, frame_data *fdata, void *criterion) |
||
3241 | { |
||
3242 | cbs_t *info = (cbs_t *)criterion; |
||
3243 | const guint8 *ascii_text = info->data; |
||
3244 | size_t textlen = info->data_len; |
||
3245 | match_result result; |
||
3246 | guint32 buf_len; |
||
3247 | guint8 *pd; |
||
3248 | guint32 i; |
||
3249 | guint8 c_char; |
||
3250 | size_t c_match = 0; |
||
3251 | |||
3252 | /* Load the frame's data. */ |
||
3253 | if (!cf_read_record(cf, fdata)) { |
||
3254 | /* Attempt to get the packet failed. */ |
||
3255 | return MR_ERROR; |
||
3256 | } |
||
3257 | |||
3258 | result = MR_NOTMATCHED; |
||
3259 | buf_len = fdata->cap_len; |
||
3260 | pd = ws_buffer_start_ptr(&cf->buf); |
||
3261 | i = 0; |
||
3262 | while (i < buf_len) { |
||
3263 | c_char = pd[i]; |
||
3264 | if (cf->case_type) |
||
3265 | c_char = g_ascii_toupper(c_char); |
||
3266 | if (c_char == ascii_text[c_match]) { |
||
3267 | c_match += 1; |
||
3268 | if (c_match == textlen) { |
||
3269 | result = MR_MATCHED; |
||
3270 | cf->search_pos = i; /* Save the position of the last character |
||
3271 | for highlighting the field. */ |
||
3272 | cf->search_len = (guint32)textlen; |
||
3273 | break; |
||
3274 | } |
||
3275 | i += 1; |
||
3276 | } |
||
3277 | else { |
||
3278 | g_assert(i>=(c_match*2)); |
||
3279 | i -= (guint32)c_match*2; |
||
3280 | c_match = 0; |
||
3281 | } |
||
3282 | i += 1; |
||
3283 | } |
||
3284 | return result; |
||
3285 | } |
||
3286 | |||
3287 | static match_result |
||
3288 | match_binary(capture_file *cf, frame_data *fdata, void *criterion) |
||
3289 | { |
||
3290 | cbs_t *info = (cbs_t *)criterion; |
||
3291 | const guint8 *binary_data = info->data; |
||
3292 | size_t datalen = info->data_len; |
||
3293 | match_result result; |
||
3294 | guint32 buf_len; |
||
3295 | guint8 *pd; |
||
3296 | guint32 i; |
||
3297 | size_t c_match = 0; |
||
3298 | |||
3299 | /* Load the frame's data. */ |
||
3300 | if (!cf_read_record(cf, fdata)) { |
||
3301 | /* Attempt to get the packet failed. */ |
||
3302 | return MR_ERROR; |
||
3303 | } |
||
3304 | |||
3305 | result = MR_NOTMATCHED; |
||
3306 | buf_len = fdata->cap_len; |
||
3307 | pd = ws_buffer_start_ptr(&cf->buf); |
||
3308 | i = 0; |
||
3309 | while (i < buf_len) { |
||
3310 | if (pd[i] == binary_data[c_match]) { |
||
3311 | c_match += 1; |
||
3312 | if (c_match == datalen) { |
||
3313 | result = MR_MATCHED; |
||
3314 | cf->search_pos = i; /* Save the position of the last character |
||
3315 | for highlighting the field. */ |
||
3316 | cf->search_len = (guint32)datalen; |
||
3317 | break; |
||
3318 | } |
||
3319 | } |
||
3320 | else { |
||
3321 | g_assert(i>=c_match); |
||
3322 | i -= (guint32)c_match; |
||
3323 | c_match = 0; |
||
3324 | } |
||
3325 | i += 1; |
||
3326 | } |
||
3327 | return result; |
||
3328 | } |
||
3329 | |||
3330 | static match_result |
||
3331 | match_regex(capture_file *cf, frame_data *fdata, void *criterion _U_) |
||
3332 | { |
||
3333 | match_result result = MR_NOTMATCHED; |
||
3334 | GMatchInfo *match_info = NULL; |
||
3335 | |||
3336 | /* Load the frame's data. */ |
||
3337 | if (!cf_read_record(cf, fdata)) { |
||
3338 | /* Attempt to get the packet failed. */ |
||
3339 | return MR_ERROR; |
||
3340 | } |
||
3341 | |||
3342 | if (g_regex_match_full(cf->regex, ws_buffer_start_ptr(&cf->buf), fdata->cap_len, |
||
3343 | 0, (GRegexMatchFlags) 0, &match_info, NULL)) |
||
3344 | { |
||
3345 | gint start_pos = 0, end_pos = 0; |
||
3346 | g_match_info_fetch_pos (match_info, 0, &start_pos, &end_pos); |
||
3347 | cf->search_pos = end_pos - 1; |
||
3348 | cf->search_len = end_pos - start_pos; |
||
3349 | result = MR_MATCHED; |
||
3350 | } |
||
3351 | return result; |
||
3352 | } |
||
3353 | |||
3354 | gboolean |
||
3355 | cf_find_packet_dfilter(capture_file *cf, dfilter_t *sfcode, |
||
3356 | search_direction dir) |
||
3357 | { |
||
3358 | return find_packet(cf, match_dfilter, sfcode, dir); |
||
3359 | } |
||
3360 | |||
3361 | gboolean |
||
3362 | cf_find_packet_dfilter_string(capture_file *cf, const char *filter, |
||
3363 | search_direction dir) |
||
3364 | { |
||
3365 | dfilter_t *sfcode; |
||
3366 | gboolean result; |
||
3367 | |||
3368 | if (!dfilter_compile(filter, &sfcode, NULL)) { |
||
3369 | /* |
||
3370 | * XXX - this shouldn't happen, as the filter string is machine |
||
3371 | * generated |
||
3372 | */ |
||
3373 | return FALSE; |
||
3374 | } |
||
3375 | if (sfcode == NULL) { |
||
3376 | /* |
||
3377 | * XXX - this shouldn't happen, as the filter string is machine |
||
3378 | * generated. |
||
3379 | */ |
||
3380 | return FALSE; |
||
3381 | } |
||
3382 | result = find_packet(cf, match_dfilter, sfcode, dir); |
||
3383 | dfilter_free(sfcode); |
||
3384 | return result; |
||
3385 | } |
||
3386 | |||
3387 | static match_result |
||
3388 | match_dfilter(capture_file *cf, frame_data *fdata, void *criterion) |
||
3389 | { |
||
3390 | dfilter_t *sfcode = (dfilter_t *)criterion; |
||
3391 | epan_dissect_t edt; |
||
3392 | match_result result; |
||
3393 | |||
3394 | /* Load the frame's data. */ |
||
3395 | if (!cf_read_record(cf, fdata)) { |
||
3396 | /* Attempt to get the packet failed. */ |
||
3397 | return MR_ERROR; |
||
3398 | } |
||
3399 | |||
3400 | epan_dissect_init(&edt, cf->epan, TRUE, FALSE); |
||
3401 | epan_dissect_prime_dfilter(&edt, sfcode); |
||
3402 | epan_dissect_run(&edt, cf->cd_t, &cf->phdr, frame_tvbuff_new_buffer(fdata, &cf->buf), fdata, NULL); |
||
3403 | result = dfilter_apply_edt(sfcode, &edt) ? MR_MATCHED : MR_NOTMATCHED; |
||
3404 | epan_dissect_cleanup(&edt); |
||
3405 | return result; |
||
3406 | } |
||
3407 | |||
3408 | gboolean |
||
3409 | cf_find_packet_marked(capture_file *cf, search_direction dir) |
||
3410 | { |
||
3411 | return find_packet(cf, match_marked, NULL, dir); |
||
3412 | } |
||
3413 | |||
3414 | static match_result |
||
3415 | match_marked(capture_file *cf _U_, frame_data *fdata, void *criterion _U_) |
||
3416 | { |
||
3417 | return fdata->flags.marked ? MR_MATCHED : MR_NOTMATCHED; |
||
3418 | } |
||
3419 | |||
3420 | gboolean |
||
3421 | cf_find_packet_time_reference(capture_file *cf, search_direction dir) |
||
3422 | { |
||
3423 | return find_packet(cf, match_time_reference, NULL, dir); |
||
3424 | } |
||
3425 | |||
3426 | static match_result |
||
3427 | match_time_reference(capture_file *cf _U_, frame_data *fdata, void *criterion _U_) |
||
3428 | { |
||
3429 | return fdata->flags.ref_time ? MR_MATCHED : MR_NOTMATCHED; |
||
3430 | } |
||
3431 | |||
3432 | static gboolean |
||
3433 | find_packet(capture_file *cf, |
||
3434 | match_result (*match_function)(capture_file *, frame_data *, void *), |
||
3435 | void *criterion, search_direction dir) |
||
3436 | { |
||
3437 | frame_data *start_fd; |
||
3438 | guint32 framenum; |
||
3439 | frame_data *fdata; |
||
3440 | frame_data *new_fd = NULL; |
||
3441 | progdlg_t *progbar = NULL; |
||
3442 | GTimer *prog_timer = g_timer_new(); |
||
3443 | int count; |
||
3444 | gboolean found; |
||
3445 | float progbar_val; |
||
3446 | GTimeVal start_time; |
||
3447 | gchar status_str[100]; |
||
3448 | const char *title; |
||
3449 | match_result result; |
||
3450 | |||
3451 | start_fd = cf->current_frame; |
||
3452 | if (start_fd != NULL) { |
||
3453 | /* Iterate through the list of packets, starting at the packet we've |
||
3454 | picked, calling a routine to run the filter on the packet, see if |
||
3455 | it matches, and stop if so. */ |
||
3456 | count = 0; |
||
3457 | framenum = start_fd->num; |
||
3458 | |||
3459 | g_timer_start(prog_timer); |
||
3460 | /* Progress so far. */ |
||
3461 | progbar_val = 0.0f; |
||
3462 | |||
3463 | cf->stop_flag = FALSE; |
||
3464 | g_get_current_time(&start_time); |
||
3465 | |||
3466 | title = cf->sfilter?cf->sfilter:""; |
||
3467 | for (;;) { |
||
3468 | /* Create the progress bar if necessary. |
||
3469 | We check on every iteration of the loop, so that it takes no |
||
3470 | longer than the standard time to create it (otherwise, for a |
||
3471 | large file, we might take considerably longer than that standard |
||
3472 | time in order to get to the next progress bar step). */ |
||
3473 | if (progbar == NULL) |
||
3474 | progbar = delayed_create_progress_dlg(cf->window, "Searching", title, |
||
3475 | FALSE, &cf->stop_flag, &start_time, progbar_val); |
||
3476 | |||
3477 | /* |
||
3478 | * Update the progress bar, but do it only after PROGBAR_UPDATE_INTERVAL |
||
3479 | * has elapsed. Calling update_progress_dlg and packets_bar_update will |
||
3480 | * likely trigger UI paint events, which might take a while depending on |
||
3481 | * the platform and display. Reset our timer *after* painting. |
||
3482 | */ |
||
3483 | if (g_timer_elapsed(prog_timer, NULL) > PROGBAR_UPDATE_INTERVAL) { |
||
3484 | /* let's not divide by zero. I should never be started |
||
3485 | * with count == 0, so let's assert that |
||
3486 | */ |
||
3487 | g_assert(cf->count > 0); |
||
3488 | |||
3489 | progbar_val = (gfloat) count / cf->count; |
||
3490 | |||
3491 | g_snprintf(status_str, sizeof(status_str), |
||
3492 | "%4u of %u packets", count, cf->count); |
||
3493 | update_progress_dlg(progbar, progbar_val, status_str); |
||
3494 | |||
3495 | g_timer_start(prog_timer); |
||
3496 | } |
||
3497 | |||
3498 | if (cf->stop_flag) { |
||
3499 | /* Well, the user decided to abort the search. Go back to the |
||
3500 | frame where we started. */ |
||
3501 | new_fd = start_fd; |
||
3502 | break; |
||
3503 | } |
||
3504 | |||
3505 | /* Go past the current frame. */ |
||
3506 | if (dir == SD_BACKWARD) { |
||
3507 | /* Go on to the previous frame. */ |
||
3508 | if (framenum == 1) { |
||
3509 | /* |
||
3510 | * XXX - other apps have a bit more of a detailed message |
||
3511 | * for this, and instead of offering "OK" and "Cancel", |
||
3512 | * they offer things such as "Continue" and "Cancel"; |
||
3513 | * we need an API for popping up alert boxes with |
||
3514 | * {Verb} and "Cancel". |
||
3515 | */ |
||
3516 | |||
3517 | if (prefs.gui_find_wrap) |
||
3518 | { |
||
3519 | statusbar_push_temporary_msg("Search reached the beginning. Continuing at end."); |
||
3520 | framenum = cf->count; /* wrap around */ |
||
3521 | } |
||
3522 | else |
||
3523 | { |
||
3524 | statusbar_push_temporary_msg("Search reached the beginning."); |
||
3525 | framenum = start_fd->num; /* stay on previous packet */ |
||
3526 | } |
||
3527 | } else |
||
3528 | framenum--; |
||
3529 | } else { |
||
3530 | /* Go on to the next frame. */ |
||
3531 | if (framenum == cf->count) { |
||
3532 | if (prefs.gui_find_wrap) |
||
3533 | { |
||
3534 | statusbar_push_temporary_msg("Search reached the end. Continuing at beginning."); |
||
3535 | framenum = 1; /* wrap around */ |
||
3536 | } |
||
3537 | else |
||
3538 | { |
||
3539 | statusbar_push_temporary_msg("Search reached the end."); |
||
3540 | framenum = start_fd->num; /* stay on previous packet */ |
||
3541 | } |
||
3542 | } else |
||
3543 | framenum++; |
||
3544 | } |
||
3545 | fdata = frame_data_sequence_find(cf->frames, framenum); |
||
3546 | |||
3547 | count++; |
||
3548 | |||
3549 | /* Is this packet in the display? */ |
||
3550 | if (fdata->flags.passed_dfilter) { |
||
3551 | /* Yes. Does it match the search criterion? */ |
||
3552 | result = (*match_function)(cf, fdata, criterion); |
||
3553 | if (result == MR_ERROR) { |
||
3554 | /* Error; our caller has reported the error. Go back to the frame |
||
3555 | where we started. */ |
||
3556 | new_fd = start_fd; |
||
3557 | break; |
||
3558 | } else if (result == MR_MATCHED) { |
||
3559 | /* Yes. Go to the new frame. */ |
||
3560 | new_fd = fdata; |
||
3561 | break; |
||
3562 | } |
||
3563 | } |
||
3564 | |||
3565 | if (fdata == start_fd) { |
||
3566 | /* We're back to the frame we were on originally, and that frame |
||
3567 | doesn't match the search filter. The search failed. */ |
||
3568 | break; |
||
3569 | } |
||
3570 | } |
||
3571 | |||
3572 | /* We're done scanning the packets; destroy the progress bar if it |
||
3573 | was created. */ |
||
3574 | if (progbar != NULL) |
||
3575 | destroy_progress_dlg(progbar); |
||
3576 | g_timer_destroy(prog_timer); |
||
3577 | } |
||
3578 | |||
3579 | if (new_fd != NULL) { |
||
3580 | /* Find and select */ |
||
3581 | cf->search_in_progress = TRUE; |
||
3582 | found = packet_list_select_row_from_data(new_fd); |
||
3583 | cf->search_in_progress = FALSE; |
||
3584 | cf->search_pos = 0; /* Reset the position */ |
||
3585 | cf->search_len = 0; /* Reset length */ |
||
3586 | if (!found) { |
||
3587 | /* We didn't find a row corresponding to this frame. |
||
3588 | This means that the frame isn't being displayed currently, |
||
3589 | so we can't select it. */ |
||
3590 | simple_message_box(ESD_TYPE_INFO, NULL, |
||
3591 | "The capture file is probably not fully dissected.", |
||
3592 | "End of capture exceeded."); |
||
3593 | return FALSE; |
||
3594 | } |
||
3595 | return TRUE; /* success */ |
||
3596 | } else |
||
3597 | return FALSE; /* failure */ |
||
3598 | } |
||
3599 | |||
3600 | gboolean |
||
3601 | cf_goto_frame(capture_file *cf, guint fnumber) |
||
3602 | { |
||
3603 | frame_data *fdata; |
||
3604 | |||
3605 | if (cf == NULL || cf->frames == NULL) { |
||
3606 | /* we don't have a loaded capture file - fix for bugs 11810 & 11989 */ |
||
3607 | statusbar_push_temporary_msg("There is no file loaded"); |
||
3608 | return FALSE; /* we failed to go to that packet */ |
||
3609 | } |
||
3610 | |||
3611 | fdata = frame_data_sequence_find(cf->frames, fnumber); |
||
3612 | |||
3613 | if (fdata == NULL) { |
||
3614 | /* we didn't find a packet with that packet number */ |
||
3615 | statusbar_push_temporary_msg("There is no packet number %u.", fnumber); |
||
3616 | return FALSE; /* we failed to go to that packet */ |
||
3617 | } |
||
3618 | if (!fdata->flags.passed_dfilter) { |
||
3619 | /* that packet currently isn't displayed */ |
||
3620 | /* XXX - add it to the set of displayed packets? */ |
||
3621 | statusbar_push_temporary_msg("Packet number %u isn't displayed.", fnumber); |
||
3622 | return FALSE; /* we failed to go to that packet */ |
||
3623 | } |
||
3624 | |||
3625 | if (!packet_list_select_row_from_data(fdata)) { |
||
3626 | /* We didn't find a row corresponding to this frame. |
||
3627 | This means that the frame isn't being displayed currently, |
||
3628 | so we can't select it. */ |
||
3629 | simple_message_box(ESD_TYPE_INFO, NULL, |
||
3630 | "The capture file is probably not fully dissected.", |
||
3631 | "End of capture exceeded."); |
||
3632 | return FALSE; |
||
3633 | } |
||
3634 | return TRUE; /* we got to that packet */ |
||
3635 | } |
||
3636 | |||
3637 | gboolean |
||
3638 | cf_goto_top_frame(void) |
||
3639 | { |
||
3640 | /* Find and select */ |
||
3641 | packet_list_select_first_row(); |
||
3642 | return TRUE; /* we got to that packet */ |
||
3643 | } |
||
3644 | |||
3645 | gboolean |
||
3646 | cf_goto_bottom_frame(void) |
||
3647 | { |
||
3648 | /* Find and select */ |
||
3649 | packet_list_select_last_row(); |
||
3650 | return TRUE; /* we got to that packet */ |
||
3651 | } |
||
3652 | |||
3653 | /* |
||
3654 | * Go to frame specified by currently selected protocol tree item. |
||
3655 | */ |
||
3656 | gboolean |
||
3657 | cf_goto_framenum(capture_file *cf) |
||
3658 | { |
||
3659 | header_field_info *hfinfo; |
||
3660 | guint32 framenum; |
||
3661 | |||
3662 | if (cf->finfo_selected) { |
||
3663 | hfinfo = cf->finfo_selected->hfinfo; |
||
3664 | g_assert(hfinfo); |
||
3665 | if (hfinfo->type == FT_FRAMENUM) { |
||
3666 | framenum = fvalue_get_uinteger(&cf->finfo_selected->value); |
||
3667 | if (framenum != 0) |
||
3668 | return cf_goto_frame(cf, framenum); |
||
3669 | } |
||
3670 | } |
||
3671 | |||
3672 | return FALSE; |
||
3673 | } |
||
3674 | |||
3675 | /* Select the packet on a given row. */ |
||
3676 | void |
||
3677 | cf_select_packet(capture_file *cf, int row) |
||
3678 | { |
||
3679 | epan_dissect_t *old_edt; |
||
3680 | frame_data *fdata; |
||
3681 | |||
3682 | /* Get the frame data struct pointer for this frame */ |
||
3683 | fdata = packet_list_get_row_data(row); |
||
3684 | |||
3685 | if (fdata == NULL) { |
||
3686 | /* XXX - if a GtkCList's selection mode is GTK_SELECTION_BROWSE, when |
||
3687 | the first entry is added to it by "real_insert_row()", that row |
||
3688 | is selected (see "real_insert_row()", in "ui/gtk/gtkclist.c", in both |
||
3689 | our version and the vanilla GTK+ version). |
||
3690 | |||
3691 | This means that a "select-row" signal is emitted; this causes |
||
3692 | "packet_list_select_cb()" to be called, which causes "cf_select_packet()" |
||
3693 | to be called. |
||
3694 | |||
3695 | "cf_select_packet()" fetches, above, the data associated with the |
||
3696 | row that was selected; however, as "gtk_clist_append()", which |
||
3697 | called "real_insert_row()", hasn't yet returned, we haven't yet |
||
3698 | associated any data with that row, so we get back a null pointer. |
||
3699 | |||
3700 | We can't assume that there's only one frame in the frame list, |
||
3701 | either, as we may be filtering the display. |
||
3702 | |||
3703 | We therefore assume that, if "row" is 0, i.e. the first row |
||
3704 | is being selected, and "cf->first_displayed" equals |
||
3705 | "cf->last_displayed", i.e. there's only one frame being |
||
3706 | displayed, that frame is the frame we want. |
||
3707 | |||
3708 | This means we have to set "cf->first_displayed" and |
||
3709 | "cf->last_displayed" before adding the row to the |
||
3710 | GtkCList; see the comment in "add_packet_to_packet_list()". */ |
||
3711 | |||
3712 | if (row == 0 && cf->first_displayed == cf->last_displayed) |
||
3713 | fdata = frame_data_sequence_find(cf->frames, cf->first_displayed); |
||
3714 | } |
||
3715 | |||
3716 | /* If fdata _still_ isn't set simply give up. */ |
||
3717 | if (fdata == NULL) { |
||
3718 | return; |
||
3719 | } |
||
3720 | |||
3721 | /* Get the data in that frame. */ |
||
3722 | if (!cf_read_record (cf, fdata)) { |
||
3723 | return; |
||
3724 | } |
||
3725 | |||
3726 | /* Record that this frame is the current frame. */ |
||
3727 | cf->current_frame = fdata; |
||
3728 | cf->current_row = row; |
||
3729 | |||
3730 | old_edt = cf->edt; |
||
3731 | /* Create the logical protocol tree. */ |
||
3732 | /* We don't need the columns here. */ |
||
3733 | cf->edt = epan_dissect_new(cf->epan, TRUE, TRUE); |
||
3734 | |||
3735 | tap_build_interesting(cf->edt); |
||
3736 | epan_dissect_run(cf->edt, cf->cd_t, &cf->phdr, frame_tvbuff_new_buffer(cf->current_frame, &cf->buf), |
||
3737 | cf->current_frame, NULL); |
||
3738 | |||
3739 | dfilter_macro_build_ftv_cache(cf->edt->tree); |
||
3740 | |||
3741 | cf_callback_invoke(cf_cb_packet_selected, cf); |
||
3742 | |||
3743 | if (old_edt != NULL) |
||
3744 | epan_dissect_free(old_edt); |
||
3745 | |||
3746 | } |
||
3747 | |||
3748 | /* Unselect the selected packet, if any. */ |
||
3749 | void |
||
3750 | cf_unselect_packet(capture_file *cf) |
||
3751 | { |
||
3752 | epan_dissect_t *old_edt = cf->edt; |
||
3753 | |||
3754 | cf->edt = NULL; |
||
3755 | |||
3756 | /* No packet is selected. */ |
||
3757 | cf->current_frame = NULL; |
||
3758 | cf->current_row = 0; |
||
3759 | |||
3760 | cf_callback_invoke(cf_cb_packet_unselected, cf); |
||
3761 | |||
3762 | /* No protocol tree means no selected field. */ |
||
3763 | cf_unselect_field(cf); |
||
3764 | |||
3765 | /* Destroy the epan_dissect_t for the unselected packet. */ |
||
3766 | if (old_edt != NULL) |
||
3767 | epan_dissect_free(old_edt); |
||
3768 | } |
||
3769 | |||
3770 | /* Unset the selected protocol tree field, if any. */ |
||
3771 | void |
||
3772 | cf_unselect_field(capture_file *cf) |
||
3773 | { |
||
3774 | cf->finfo_selected = NULL; |
||
3775 | |||
3776 | cf_callback_invoke(cf_cb_field_unselected, cf); |
||
3777 | } |
||
3778 | |||
3779 | /* |
||
3780 | * Mark a particular frame. |
||
3781 | */ |
||
3782 | void |
||
3783 | cf_mark_frame(capture_file *cf, frame_data *frame) |
||
3784 | { |
||
3785 | if (! frame->flags.marked) { |
||
3786 | frame->flags.marked = TRUE; |
||
3787 | if (cf->count > cf->marked_count) |
||
3788 | cf->marked_count++; |
||
3789 | } |
||
3790 | } |
||
3791 | |||
3792 | /* |
||
3793 | * Unmark a particular frame. |
||
3794 | */ |
||
3795 | void |
||
3796 | cf_unmark_frame(capture_file *cf, frame_data *frame) |
||
3797 | { |
||
3798 | if (frame->flags.marked) { |
||
3799 | frame->flags.marked = FALSE; |
||
3800 | if (cf->marked_count > 0) |
||
3801 | cf->marked_count--; |
||
3802 | } |
||
3803 | } |
||
3804 | |||
3805 | /* |
||
3806 | * Ignore a particular frame. |
||
3807 | */ |
||
3808 | void |
||
3809 | cf_ignore_frame(capture_file *cf, frame_data *frame) |
||
3810 | { |
||
3811 | if (! frame->flags.ignored) { |
||
3812 | frame->flags.ignored = TRUE; |
||
3813 | if (cf->count > cf->ignored_count) |
||
3814 | cf->ignored_count++; |
||
3815 | } |
||
3816 | } |
||
3817 | |||
3818 | /* |
||
3819 | * Un-ignore a particular frame. |
||
3820 | */ |
||
3821 | void |
||
3822 | cf_unignore_frame(capture_file *cf, frame_data *frame) |
||
3823 | { |
||
3824 | if (frame->flags.ignored) { |
||
3825 | frame->flags.ignored = FALSE; |
||
3826 | if (cf->ignored_count > 0) |
||
3827 | cf->ignored_count--; |
||
3828 | } |
||
3829 | } |
||
3830 | |||
3831 | /* |
||
3832 | * Read the comment in SHB block |
||
3833 | */ |
||
3834 | |||
3835 | const gchar * |
||
3836 | cf_read_shb_comment(capture_file *cf) |
||
3837 | { |
||
3838 | wtap_block_t shb_inf; |
||
3839 | char *shb_comment; |
||
3840 | |||
3841 | /* Get the SHB. */ |
||
3842 | /* XXX - support multiple SHBs */ |
||
3843 | shb_inf = wtap_file_get_shb(cf->wth); |
||
3844 | |||
3845 | /* Get the first comment from the SHB. */ |
||
3846 | /* XXX - support multiple comments */ |
||
3847 | if (wtap_block_get_nth_string_option_value(shb_inf, OPT_COMMENT, 0, &shb_comment) != WTAP_OPTTYPE_SUCCESS) |
||
3848 | return NULL; |
||
3849 | return shb_comment; |
||
3850 | } |
||
3851 | |||
3852 | void |
||
3853 | cf_update_capture_comment(capture_file *cf, gchar *comment) |
||
3854 | { |
||
3855 | wtap_block_t shb_inf; |
||
3856 | gchar *shb_comment; |
||
3857 | |||
3858 | /* Get the SHB. */ |
||
3859 | /* XXX - support multiple SHBs */ |
||
3860 | shb_inf = wtap_file_get_shb(cf->wth); |
||
3861 | |||
3862 | /* Get the first comment from the SHB. */ |
||
3863 | /* XXX - support multiple comments */ |
||
3864 | if (wtap_block_get_nth_string_option_value(shb_inf, OPT_COMMENT, 0, &shb_comment) != WTAP_OPTTYPE_SUCCESS) { |
||
3865 | /* There's no comment - add one. */ |
||
3866 | wtap_block_add_string_option(shb_inf, OPT_COMMENT, comment, strlen(comment)); |
||
3867 | } else { |
||
3868 | /* See if the comment has changed or not */ |
||
3869 | if (strcmp(shb_comment, comment) == 0) { |
||
3870 | g_free(comment); |
||
3871 | return; |
||
3872 | } |
||
3873 | |||
3874 | /* The comment has changed, let's update it */ |
||
3875 | wtap_block_set_nth_string_option_value(shb_inf, OPT_COMMENT, 0, comment, strlen(comment)); |
||
3876 | } |
||
3877 | /* Mark the file as having unsaved changes */ |
||
3878 | cf->unsaved_changes = TRUE; |
||
3879 | } |
||
3880 | |||
3881 | static const char * |
||
3882 | cf_get_user_packet_comment(capture_file *cf, const frame_data *fd) |
||
3883 | { |
||
3884 | if (cf->frames_user_comments) |
||
3885 | return (const char *)g_tree_lookup(cf->frames_user_comments, fd); |
||
3886 | |||
3887 | /* g_warning? */ |
||
3888 | return NULL; |
||
3889 | } |
||
3890 | |||
3891 | char * |
||
3892 | cf_get_comment(capture_file *cf, const frame_data *fd) |
||
3893 | { |
||
3894 | char *comment; |
||
3895 | |||
3896 | /* fetch user comment */ |
||
3897 | if (fd->flags.has_user_comment) |
||
3898 | return g_strdup(cf_get_user_packet_comment(cf, fd)); |
||
3899 | |||
3900 | /* fetch phdr comment */ |
||
3901 | if (fd->flags.has_phdr_comment) { |
||
3902 | struct wtap_pkthdr phdr; /* Packet header */ |
||
3903 | Buffer buf; /* Packet data */ |
||
3904 | |||
3905 | wtap_phdr_init(&phdr); |
||
3906 | ws_buffer_init(&buf, 1500); |
||
3907 | |||
3908 | if (!cf_read_record_r(cf, fd, &phdr, &buf)) |
||
3909 | { /* XXX, what we can do here? */ } |
||
3910 | |||
3911 | comment = phdr.opt_comment; |
||
3912 | wtap_phdr_cleanup(&phdr); |
||
3913 | ws_buffer_free(&buf); |
||
3914 | return comment; |
||
3915 | } |
||
3916 | return NULL; |
||
3917 | } |
||
3918 | |||
3919 | static int |
||
3920 | frame_cmp(gconstpointer a, gconstpointer b, gpointer user_data _U_) |
||
3921 | { |
||
3922 | const frame_data *fdata1 = (const frame_data *) a; |
||
3923 | const frame_data *fdata2 = (const frame_data *) b; |
||
3924 | |||
3925 | return (fdata1->num < fdata2->num) ? -1 : |
||
3926 | (fdata1->num > fdata2->num) ? 1 : |
||
3927 | 0; |
||
3928 | } |
||
3929 | |||
3930 | gboolean |
||
3931 | cf_set_user_packet_comment(capture_file *cf, frame_data *fd, const gchar *new_comment) |
||
3932 | { |
||
3933 | char *pkt_comment = cf_get_comment(cf, fd); |
||
3934 | |||
3935 | /* Check if the comment has changed */ |
||
3936 | if (!g_strcmp0(pkt_comment, new_comment)) { |
||
3937 | g_free(pkt_comment); |
||
3938 | return FALSE; |
||
3939 | } |
||
3940 | g_free(pkt_comment); |
||
3941 | |||
3942 | if (pkt_comment) |
||
3943 | cf->packet_comment_count--; |
||
3944 | |||
3945 | if (new_comment) |
||
3946 | cf->packet_comment_count++; |
||
3947 | |||
3948 | fd->flags.has_user_comment = TRUE; |
||
3949 | |||
3950 | if (!cf->frames_user_comments) |
||
3951 | cf->frames_user_comments = g_tree_new_full(frame_cmp, NULL, NULL, g_free); |
||
3952 | |||
3953 | /* insert new packet comment */ |
||
3954 | g_tree_replace(cf->frames_user_comments, fd, g_strdup(new_comment)); |
||
3955 | |||
3956 | expert_update_comment_count(cf->packet_comment_count); |
||
3957 | |||
3958 | /* OK, we have unsaved changes. */ |
||
3959 | cf->unsaved_changes = TRUE; |
||
3960 | return TRUE; |
||
3961 | } |
||
3962 | |||
3963 | /* |
||
3964 | * What types of comments does this capture file have? |
||
3965 | */ |
||
3966 | guint32 |
||
3967 | cf_comment_types(capture_file *cf) |
||
3968 | { |
||
3969 | guint32 comment_types = 0; |
||
3970 | |||
3971 | if (cf_read_shb_comment(cf) != NULL) |
||
3972 | comment_types |= WTAP_COMMENT_PER_SECTION; |
||
3973 | if (cf->packet_comment_count != 0) |
||
3974 | comment_types |= WTAP_COMMENT_PER_PACKET; |
||
3975 | return comment_types; |
||
3976 | } |
||
3977 | |||
3978 | /* |
||
3979 | * Add a resolved address to this file's list of resolved addresses. |
||
3980 | */ |
||
3981 | gboolean |
||
3982 | cf_add_ip_name_from_string(capture_file *cf, const char *addr, const char *name) |
||
3983 | { |
||
3984 | /* |
||
3985 | * XXX - support multiple resolved address lists, and add to the one |
||
3986 | * attached to this file? |
||
3987 | */ |
||
3988 | if (!add_ip_name_from_string(addr, name)) |
||
3989 | return FALSE; |
||
3990 | |||
3991 | /* OK, we have unsaved changes. */ |
||
3992 | cf->unsaved_changes = TRUE; |
||
3993 | return TRUE; |
||
3994 | } |
||
3995 | |||
3996 | #ifdef WANT_PACKET_EDITOR |
||
3997 | static gint |
||
3998 | g_direct_compare_func(gconstpointer a, gconstpointer b, gpointer user_data _U_) |
||
3999 | { |
||
4000 | if (a > b) |
||
4001 | return 1; |
||
4002 | else if (a < b) |
||
4003 | return -1; |
||
4004 | else |
||
4005 | return 0; |
||
4006 | } |
||
4007 | |||
4008 | static void |
||
4009 | modified_frame_data_free(gpointer data) |
||
4010 | { |
||
4011 | modified_frame_data *mfd = (modified_frame_data *)data; |
||
4012 | |||
4013 | g_free(mfd->pd); |
||
4014 | g_free(mfd); |
||
4015 | } |
||
4016 | |||
4017 | /* |
||
4018 | * Give a frame new, edited data. |
||
4019 | */ |
||
4020 | void |
||
4021 | cf_set_frame_edited(capture_file *cf, frame_data *fd, |
||
4022 | struct wtap_pkthdr *phdr, guint8 *pd) |
||
4023 | { |
||
4024 | modified_frame_data *mfd = (modified_frame_data *)g_malloc(sizeof(modified_frame_data)); |
||
4025 | |||
4026 | mfd->phdr = *phdr; |
||
4027 | mfd->pd = pd; |
||
4028 | |||
4029 | if (cf->edited_frames == NULL) |
||
4030 | cf->edited_frames = g_tree_new_full(g_direct_compare_func, NULL, NULL, |
||
4031 | modified_frame_data_free); |
||
4032 | g_tree_insert(cf->edited_frames, GINT_TO_POINTER(fd->num), mfd); |
||
4033 | fd->file_off = -1; |
||
4034 | |||
4035 | /* Mark the file as having unsaved changes */ |
||
4036 | cf->unsaved_changes = TRUE; |
||
4037 | } |
||
4038 | #endif |
||
4039 | |||
4040 | typedef struct { |
||
4041 | wtap_dumper *pdh; |
||
4042 | const char *fname; |
||
4043 | int file_type; |
||
4044 | } save_callback_args_t; |
||
4045 | |||
4046 | /* |
||
4047 | * Save a capture to a file, in a particular format, saving either |
||
4048 | * all packets, all currently-displayed packets, or all marked packets. |
||
4049 | * |
||
4050 | * Returns TRUE if it succeeds, FALSE otherwise; if it fails, it pops |
||
4051 | * up a message box for the failure. |
||
4052 | */ |
||
4053 | static gboolean |
||
4054 | save_record(capture_file *cf, frame_data *fdata, |
||
4055 | struct wtap_pkthdr *phdr, const guint8 *pd, |
||
4056 | void *argsp) |
||
4057 | { |
||
4058 | save_callback_args_t *args = (save_callback_args_t *)argsp; |
||
4059 | struct wtap_pkthdr hdr; |
||
4060 | int err; |
||
4061 | gchar *err_info; |
||
4062 | gchar *display_basename; |
||
4063 | const char *pkt_comment; |
||
4064 | |||
4065 | if (fdata->flags.has_user_comment) |
||
4066 | pkt_comment = cf_get_user_packet_comment(cf, fdata); |
||
4067 | else |
||
4068 | pkt_comment = phdr->opt_comment; |
||
4069 | |||
4070 | /* init the wtap header for saving */ |
||
4071 | /* TODO: reuse phdr */ |
||
4072 | /* XXX - these are the only flags that correspond to data that we have |
||
4073 | in the frame_data structure and that matter on a per-packet basis. |
||
4074 | |||
4075 | For WTAP_HAS_CAP_LEN, either the file format has separate "captured" |
||
4076 | and "on the wire" lengths, or it doesn't. |
||
4077 | |||
4078 | For WTAP_HAS_DROP_COUNT, Wiretap doesn't actually supply the value |
||
4079 | to its callers. |
||
4080 | |||
4081 | For WTAP_HAS_PACK_FLAGS, we currently don't save the FCS length |
||
4082 | from the packet flags. */ |
||
4083 | hdr.rec_type = phdr->rec_type; |
||
4084 | hdr.presence_flags = 0; |
||
4085 | if (fdata->flags.has_ts) |
||
4086 | hdr.presence_flags |= WTAP_HAS_TS; |
||
4087 | if (phdr->presence_flags & WTAP_HAS_INTERFACE_ID) |
||
4088 | hdr.presence_flags |= WTAP_HAS_INTERFACE_ID; |
||
4089 | if (phdr->presence_flags & WTAP_HAS_PACK_FLAGS) |
||
4090 | hdr.presence_flags |= WTAP_HAS_PACK_FLAGS; |
||
4091 | hdr.ts = phdr->ts; |
||
4092 | hdr.caplen = phdr->caplen; |
||
4093 | hdr.len = phdr->len; |
||
4094 | hdr.pkt_encap = phdr->pkt_encap; |
||
4095 | /* pcapng */ |
||
4096 | hdr.interface_id = phdr->interface_id; /* identifier of the interface. */ |
||
4097 | /* options */ |
||
4098 | hdr.pack_flags = phdr->pack_flags; |
||
4099 | hdr.opt_comment = g_strdup(pkt_comment); |
||
4100 | |||
4101 | /* pseudo */ |
||
4102 | hdr.pseudo_header = phdr->pseudo_header; |
||
4103 | #if 0 |
||
4104 | hdr.drop_count = |
||
4105 | hdr.pack_flags = /* XXX - 0 for now (any value for "we don't have it"?) */ |
||
4106 | #endif |
||
4107 | /* and save the packet */ |
||
4108 | if (!wtap_dump(args->pdh, &hdr, pd, &err, &err_info)) { |
||
4109 | if (err < 0) { |
||
4110 | /* Wiretap error. */ |
||
4111 | switch (err) { |
||
4112 | |||
4113 | case WTAP_ERR_UNWRITABLE_ENCAP: |
||
4114 | /* |
||
4115 | * This is a problem with the particular frame we're writing and |
||
4116 | * the file type and subtype we're writing; note that, and report |
||
4117 | * the frame number and file type/subtype. |
||
4118 | */ |
||
4119 | simple_error_message_box( |
||
4120 | "Frame %u has a network type that can't be saved in a \"%s\" file.", |
||
4121 | fdata->num, wtap_file_type_subtype_string(args->file_type)); |
||
4122 | break; |
||
4123 | |||
4124 | case WTAP_ERR_PACKET_TOO_LARGE: |
||
4125 | /* |
||
4126 | * This is a problem with the particular frame we're writing and |
||
4127 | * the file type and subtype we're writing; note that, and report |
||
4128 | * the frame number and file type/subtype. |
||
4129 | */ |
||
4130 | simple_error_message_box( |
||
4131 | "Frame %u is larger than Wireshark supports in a \"%s\" file.", |
||
4132 | fdata->num, wtap_file_type_subtype_string(args->file_type)); |
||
4133 | break; |
||
4134 | |||
4135 | case WTAP_ERR_UNWRITABLE_REC_TYPE: |
||
4136 | /* |
||
4137 | * This is a problem with the particular record we're writing and |
||
4138 | * the file type and subtype we're writing; note that, and report |
||
4139 | * the record number and file type/subtype. |
||
4140 | */ |
||
4141 | simple_error_message_box( |
||
4142 | "Record %u has a record type that can't be saved in a \"%s\" file.", |
||
4143 | fdata->num, wtap_file_type_subtype_string(args->file_type)); |
||
4144 | break; |
||
4145 | |||
4146 | case WTAP_ERR_UNWRITABLE_REC_DATA: |
||
4147 | /* |
||
4148 | * This is a problem with the particular frame we're writing and |
||
4149 | * the file type and subtype we're writing; note that, and report |
||
4150 | * the frame number and file type/subtype. |
||
4151 | */ |
||
4152 | simple_error_message_box( |
||
4153 | "Record %u has data that can't be saved in a \"%s\" file.\n(%s)", |
||
4154 | fdata->num, wtap_file_type_subtype_string(args->file_type), |
||
4155 | err_info != NULL ? err_info : "no information supplied"); |
||
4156 | g_free(err_info); |
||
4157 | break; |
||
4158 | |||
4159 | default: |
||
4160 | display_basename = g_filename_display_basename(args->fname); |
||
4161 | simple_error_message_box( |
||
4162 | "An error occurred while writing to the file \"%s\": %s.", |
||
4163 | display_basename, wtap_strerror(err)); |
||
4164 | g_free(display_basename); |
||
4165 | break; |
||
4166 | } |
||
4167 | } else { |
||
4168 | /* OS error. */ |
||
4169 | write_failure_alert_box(args->fname, err); |
||
4170 | } |
||
4171 | return FALSE; |
||
4172 | } |
||
4173 | |||
4174 | g_free(hdr.opt_comment); |
||
4175 | return TRUE; |
||
4176 | } |
||
4177 | |||
4178 | /* |
||
4179 | * Can this capture file be written out in any format using Wiretap |
||
4180 | * rather than by copying the raw data? |
||
4181 | */ |
||
4182 | gboolean |
||
4183 | cf_can_write_with_wiretap(capture_file *cf) |
||
4184 | { |
||
4185 | /* We don't care whether we support the comments in this file or not; |
||
4186 | if we can't, we'll offer the user the option of discarding the |
||
4187 | comments. */ |
||
4188 | return wtap_dump_can_write(cf->linktypes, 0); |
||
4189 | } |
||
4190 | |||
4191 | /* |
||
4192 | * Should we let the user do a save? |
||
4193 | * |
||
4194 | * We should if: |
||
4195 | * |
||
4196 | * the file has unsaved changes, and we can save it in some |
||
4197 | * format through Wiretap |
||
4198 | * |
||
4199 | * or |
||
4200 | * |
||
4201 | * the file is a temporary file and has no unsaved changes (so |
||
4202 | * that "saving" it just means copying it). |
||
4203 | * |
||
4204 | * XXX - we shouldn't allow files to be edited if they can't be saved, |
||
4205 | * so cf->unsaved_changes should be true only if the file can be saved. |
||
4206 | * |
||
4207 | * We don't care whether we support the comments in this file or not; |
||
4208 | * if we can't, we'll offer the user the option of discarding the |
||
4209 | * comments. |
||
4210 | */ |
||
4211 | gboolean |
||
4212 | cf_can_save(capture_file *cf) |
||
4213 | { |
||
4214 | if (cf->unsaved_changes && wtap_dump_can_write(cf->linktypes, 0)) { |
||
4215 | /* Saved changes, and we can write it out with Wiretap. */ |
||
4216 | return TRUE; |
||
4217 | } |
||
4218 | |||
4219 | if (cf->is_tempfile && !cf->unsaved_changes) { |
||
4220 | /* |
||
4221 | * Temporary file with no unsaved changes, so we can just do a |
||
4222 | * raw binary copy. |
||
4223 | */ |
||
4224 | return TRUE; |
||
4225 | } |
||
4226 | |||
4227 | /* Nothing to save. */ |
||
4228 | return FALSE; |
||
4229 | } |
||
4230 | |||
4231 | /* |
||
4232 | * Should we let the user do a "save as"? |
||
4233 | * |
||
4234 | * That's true if: |
||
4235 | * |
||
4236 | * we can save it in some format through Wiretap |
||
4237 | * |
||
4238 | * or |
||
4239 | * |
||
4240 | * the file is a temporary file and has no unsaved changes (so |
||
4241 | * that "saving" it just means copying it). |
||
4242 | * |
||
4243 | * XXX - we shouldn't allow files to be edited if they can't be saved, |
||
4244 | * so cf->unsaved_changes should be true only if the file can be saved. |
||
4245 | * |
||
4246 | * We don't care whether we support the comments in this file or not; |
||
4247 | * if we can't, we'll offer the user the option of discarding the |
||
4248 | * comments. |
||
4249 | */ |
||
4250 | gboolean |
||
4251 | cf_can_save_as(capture_file *cf) |
||
4252 | { |
||
4253 | if (wtap_dump_can_write(cf->linktypes, 0)) { |
||
4254 | /* We can write it out with Wiretap. */ |
||
4255 | return TRUE; |
||
4256 | } |
||
4257 | |||
4258 | if (cf->is_tempfile && !cf->unsaved_changes) { |
||
4259 | /* |
||
4260 | * Temporary file with no unsaved changes, so we can just do a |
||
4261 | * raw binary copy. |
||
4262 | */ |
||
4263 | return TRUE; |
||
4264 | } |
||
4265 | |||
4266 | /* Nothing to save. */ |
||
4267 | return FALSE; |
||
4268 | } |
||
4269 | |||
4270 | /* |
||
4271 | * Does this file have unsaved data? |
||
4272 | */ |
||
4273 | gboolean |
||
4274 | cf_has_unsaved_data(capture_file *cf) |
||
4275 | { |
||
4276 | /* |
||
4277 | * If this is a temporary file, or a file with unsaved changes, it |
||
4278 | * has unsaved data. |
||
4279 | */ |
||
4280 | return (cf->is_tempfile && cf->count>0) || cf->unsaved_changes; |
||
4281 | } |
||
4282 | |||
4283 | /* |
||
4284 | * Quick scan to find packet offsets. |
||
4285 | */ |
||
4286 | static cf_read_status_t |
||
4287 | rescan_file(capture_file *cf, const char *fname, gboolean is_tempfile, int *err) |
||
4288 | { |
||
4289 | const struct wtap_pkthdr *phdr; |
||
4290 | gchar *err_info; |
||
4291 | gchar *name_ptr; |
||
4292 | gint64 data_offset; |
||
4293 | progdlg_t *progbar = NULL; |
||
4294 | GTimer *prog_timer = g_timer_new(); |
||
4295 | gint64 size; |
||
4296 | float progbar_val; |
||
4297 | GTimeVal start_time; |
||
4298 | gchar status_str[100]; |
||
4299 | guint32 framenum; |
||
4300 | frame_data *fdata; |
||
4301 | int count = 0; |
||
4302 | |||
4303 | /* Close the old handle. */ |
||
4304 | wtap_close(cf->wth); |
||
4305 | |||
4306 | /* Open the new file. */ |
||
4307 | /* XXX: this will go through all open_routines for a matching one. But right |
||
4308 | now rescan_file() is only used when a file is being saved to a different |
||
4309 | format than the original, and the user is not given a choice of which |
||
4310 | reader to use (only which format to save it in), so doing this makes |
||
4311 | sense for now. */ |
||
4312 | cf->wth = wtap_open_offline(fname, WTAP_TYPE_AUTO, err, &err_info, TRUE); |
||
4313 | if (cf->wth == NULL) { |
||
4314 | cf_open_failure_alert_box(fname, *err, err_info, FALSE, 0); |
||
4315 | return CF_READ_ERROR; |
||
4316 | } |
||
4317 | |||
4318 | /* We're scanning a file whose contents should be the same as what |
||
4319 | we had before, so we don't discard dissection state etc.. */ |
||
4320 | cf->f_datalen = 0; |
||
4321 | |||
4322 | /* Set the file name because we need it to set the follow stream filter. |
||
4323 | XXX - is that still true? We need it for other reasons, though, |
||
4324 | in any case. */ |
||
4325 | cf->filename = g_strdup(fname); |
||
4326 | |||
4327 | /* Indicate whether it's a permanent or temporary file. */ |
||
4328 | cf->is_tempfile = is_tempfile; |
||
4329 | |||
4330 | /* No user changes yet. */ |
||
4331 | cf->unsaved_changes = FALSE; |
||
4332 | |||
4333 | cf->cd_t = wtap_file_type_subtype(cf->wth); |
||
4334 | cf->linktypes = g_array_sized_new(FALSE, FALSE, (guint) sizeof(int), 1); |
||
4335 | |||
4336 | cf->snap = wtap_snapshot_length(cf->wth); |
||
4337 | if (cf->snap == 0) { |
||
4338 | /* Snapshot length not known. */ |
||
4339 | cf->has_snap = FALSE; |
||
4340 | cf->snap = WTAP_MAX_PACKET_SIZE; |
||
4341 | } else |
||
4342 | cf->has_snap = TRUE; |
||
4343 | |||
4344 | name_ptr = g_filename_display_basename(cf->filename); |
||
4345 | |||
4346 | cf_callback_invoke(cf_cb_file_rescan_started, cf); |
||
4347 | |||
4348 | /* Record whether the file is compressed. |
||
4349 | XXX - do we know this at open time? */ |
||
4350 | cf->iscompressed = wtap_iscompressed(cf->wth); |
||
4351 | |||
4352 | /* Find the size of the file. */ |
||
4353 | size = wtap_file_size(cf->wth, NULL); |
||
4354 | |||
4355 | g_timer_start(prog_timer); |
||
4356 | |||
4357 | cf->stop_flag = FALSE; |
||
4358 | g_get_current_time(&start_time); |
||
4359 | |||
4360 | framenum = 0; |
||
4361 | phdr = wtap_phdr(cf->wth); |
||
4362 | while ((wtap_read(cf->wth, err, &err_info, &data_offset))) { |
||
4363 | framenum++; |
||
4364 | fdata = frame_data_sequence_find(cf->frames, framenum); |
||
4365 | fdata->file_off = data_offset; |
||
4366 | if (size >= 0) { |
||
4367 | count++; |
||
4368 | cf->f_datalen = wtap_read_so_far(cf->wth); |
||
4369 | |||
4370 | /* Create the progress bar if necessary. */ |
||
4371 | if (progress_is_slow(progbar, prog_timer, size, cf->f_datalen)) { |
||
4372 | progbar_val = calc_progbar_val(cf, size, cf->f_datalen, status_str, sizeof(status_str)); |
||
4373 | progbar = delayed_create_progress_dlg(cf->window, "Rescanning", name_ptr, |
||
4374 | TRUE, &cf->stop_flag, &start_time, progbar_val); |
||
4375 | } |
||
4376 | |||
4377 | /* |
||
4378 | * Update the progress bar, but do it only after PROGBAR_UPDATE_INTERVAL |
||
4379 | * has elapsed. Calling update_progress_dlg and packets_bar_update will |
||
4380 | * likely trigger UI paint events, which might take a while depending on |
||
4381 | * the platform and display. Reset our timer *after* painting. |
||
4382 | */ |
||
4383 | if (progbar && g_timer_elapsed(prog_timer, NULL) > PROGBAR_UPDATE_INTERVAL) { |
||
4384 | progbar_val = calc_progbar_val(cf, size, cf->f_datalen, status_str, sizeof(status_str)); |
||
4385 | /* update the packet bar content on the first run or frequently on very large files */ |
||
4386 | update_progress_dlg(progbar, progbar_val, status_str); |
||
4387 | packets_bar_update(); |
||
4388 | g_timer_start(prog_timer); |
||
4389 | } |
||
4390 | } |
||
4391 | |||
4392 | if (cf->stop_flag) { |
||
4393 | /* Well, the user decided to abort the rescan. Sadly, as this |
||
4394 | isn't a reread, recovering is difficult, so we'll just |
||
4395 | close the current capture. */ |
||
4396 | break; |
||
4397 | } |
||
4398 | |||
4399 | /* Add this packet's link-layer encapsulation type to cf->linktypes, if |
||
4400 | it's not already there. |
||
4401 | XXX - yes, this is O(N), so if every packet had a different |
||
4402 | link-layer encapsulation type, it'd be O(N^2) to read the file, but |
||
4403 | there are probably going to be a small number of encapsulation types |
||
4404 | in a file. */ |
||
4405 | cf_add_encapsulation_type(cf, phdr->pkt_encap); |
||
4406 | } |
||
4407 | |||
4408 | /* Free the display name */ |
||
4409 | g_free(name_ptr); |
||
4410 | |||
4411 | /* We're done reading the file; destroy the progress bar if it was created. */ |
||
4412 | if (progbar != NULL) |
||
4413 | destroy_progress_dlg(progbar); |
||
4414 | g_timer_destroy(prog_timer); |
||
4415 | |||
4416 | /* We're done reading sequentially through the file. */ |
||
4417 | cf->state = FILE_READ_DONE; |
||
4418 | |||
4419 | /* Close the sequential I/O side, to free up memory it requires. */ |
||
4420 | wtap_sequential_close(cf->wth); |
||
4421 | |||
4422 | /* compute the time it took to load the file */ |
||
4423 | compute_elapsed(cf, &start_time); |
||
4424 | |||
4425 | /* Set the file encapsulation type now; we don't know what it is until |
||
4426 | we've looked at all the packets, as we don't know until then whether |
||
4427 | there's more than one type (and thus whether it's |
||
4428 | WTAP_ENCAP_PER_PACKET). */ |
||
4429 | cf->lnk_t = wtap_file_encap(cf->wth); |
||
4430 | |||
4431 | cf_callback_invoke(cf_cb_file_rescan_finished, cf); |
||
4432 | |||
4433 | if (cf->stop_flag) { |
||
4434 | /* Our caller will give up at this point. */ |
||
4435 | return CF_READ_ABORTED; |
||
4436 | } |
||
4437 | |||
4438 | if (*err != 0) { |
||
4439 | /* Put up a message box noting that the read failed somewhere along |
||
4440 | the line. Don't throw out the stuff we managed to read, though, |
||
4441 | if any. */ |
||
4442 | switch (*err) { |
||
4443 | |||
4444 | case WTAP_ERR_UNSUPPORTED: |
||
4445 | simple_error_message_box( |
||
4446 | "The capture file contains record data that Wireshark doesn't support.\n(%s)", |
||
4447 | err_info != NULL ? err_info : "no information supplied"); |
||
4448 | g_free(err_info); |
||
4449 | break; |
||
4450 | |||
4451 | case WTAP_ERR_SHORT_READ: |
||
4452 | simple_error_message_box( |
||
4453 | "The capture file appears to have been cut short" |
||
4454 | " in the middle of a packet."); |
||
4455 | break; |
||
4456 | |||
4457 | case WTAP_ERR_BAD_FILE: |
||
4458 | simple_error_message_box( |
||
4459 | "The capture file appears to be damaged or corrupt.\n(%s)", |
||
4460 | err_info != NULL ? err_info : "no information supplied"); |
||
4461 | g_free(err_info); |
||
4462 | break; |
||
4463 | |||
4464 | case WTAP_ERR_DECOMPRESS: |
||
4465 | simple_error_message_box( |
||
4466 | "The compressed capture file appears to be damaged or corrupt.\n" |
||
4467 | "(%s)", |
||
4468 | err_info != NULL ? err_info : "no information supplied"); |
||
4469 | g_free(err_info); |
||
4470 | break; |
||
4471 | |||
4472 | default: |
||
4473 | simple_error_message_box( |
||
4474 | "An error occurred while reading the" |
||
4475 | " capture file: %s.", wtap_strerror(*err)); |
||
4476 | break; |
||
4477 | } |
||
4478 | return CF_READ_ERROR; |
||
4479 | } else |
||
4480 | return CF_READ_OK; |
||
4481 | } |
||
4482 | |||
4483 | cf_write_status_t |
||
4484 | cf_save_records(capture_file *cf, const char *fname, guint save_format, |
||
4485 | gboolean compressed, gboolean discard_comments, |
||
4486 | gboolean dont_reopen) |
||
4487 | { |
||
4488 | gchar *err_info; |
||
4489 | gchar *fname_new = NULL; |
||
4490 | wtap_dumper *pdh; |
||
4491 | frame_data *fdata; |
||
4492 | addrinfo_lists_t *addr_lists; |
||
4493 | guint framenum; |
||
4494 | int err; |
||
4495 | #ifdef _WIN32 |
||
4496 | gchar *display_basename; |
||
4497 | #endif |
||
4498 | enum { |
||
4499 | SAVE_WITH_MOVE, |
||
4500 | SAVE_WITH_COPY, |
||
4501 | SAVE_WITH_WTAP |
||
4502 | } how_to_save; |
||
4503 | save_callback_args_t callback_args; |
||
4504 | |||
4505 | cf_callback_invoke(cf_cb_file_save_started, (gpointer)fname); |
||
4506 | |||
4507 | addr_lists = get_addrinfo_list(); |
||
4508 | |||
4509 | if (save_format == cf->cd_t && compressed == cf->iscompressed |
||
4510 | && !discard_comments && !cf->unsaved_changes |
||
4511 | && !(addr_lists && wtap_dump_has_name_resolution(save_format))) { |
||
4512 | /* We're saving in the format it's already in, and we're |
||
4513 | not discarding comments, and there are no changes we have |
||
4514 | in memory that aren't saved to the file, and we have no name |
||
4515 | resolution blocks to write, so we can just move or copy the raw data. */ |
||
4516 | |||
4517 | if (cf->is_tempfile) { |
||
4518 | /* The file being saved is a temporary file from a live |
||
4519 | capture, so it doesn't need to stay around under that name; |
||
4520 | first, try renaming the capture buffer file to the new name. |
||
4521 | This acts as a "safe save", in that, if the file already |
||
4522 | exists, the existing file will be removed only if the rename |
||
4523 | succeeds. |
||
4524 | |||
4525 | Sadly, on Windows, as we have the current capture file |
||
4526 | open, even MoveFileEx() with MOVEFILE_REPLACE_EXISTING |
||
4527 | (to cause the rename to remove an existing target), as |
||
4528 | done by ws_stdio_rename() (ws_rename() is #defined to |
||
4529 | be ws_stdio_rename() on Windows) will fail. |
||
4530 | |||
4531 | According to the MSDN documentation for CreateFile(), if, |
||
4532 | when we open a capture file, we were to directly do a CreateFile(), |
||
4533 | opening with FILE_SHARE_DELETE|FILE_SHARE_READ, and then |
||
4534 | convert it to a file descriptor with _open_osfhandle(), |
||
4535 | that would allow the file to be renamed out from under us. |
||
4536 | |||
4537 | However, that doesn't work in practice. Perhaps the problem |
||
4538 | is that the process doing the rename is the process that |
||
4539 | has the file open. */ |
||
4540 | #ifndef _WIN32 |
||
4541 | if (ws_rename(cf->filename, fname) == 0) { |
||
4542 | /* That succeeded - there's no need to copy the source file. */ |
||
4543 | how_to_save = SAVE_WITH_MOVE; |
||
4544 | } else { |
||
4545 | if (errno == EXDEV) { |
||
4546 | /* They're on different file systems, so we have to copy the |
||
4547 | file. */ |
||
4548 | how_to_save = SAVE_WITH_COPY; |
||
4549 | } else { |
||
4550 | /* The rename failed, but not because they're on different |
||
4551 | file systems - put up an error message. (Or should we |
||
4552 | just punt and try to copy? The only reason why I'd |
||
4553 | expect the rename to fail and the copy to succeed would |
||
4554 | be if we didn't have permission to remove the file from |
||
4555 | the temporary directory, and that might be fixable - but |
||
4556 | is it worth requiring the user to go off and fix it?) */ |
||
4557 | cf_rename_failure_alert_box(fname, errno); |
||
4558 | goto fail; |
||
4559 | } |
||
4560 | } |
||
4561 | #else |
||
4562 | how_to_save = SAVE_WITH_COPY; |
||
4563 | #endif |
||
4564 | } else { |
||
4565 | /* It's a permanent file, so we should copy it, and not remove the |
||
4566 | original. */ |
||
4567 | how_to_save = SAVE_WITH_COPY; |
||
4568 | } |
||
4569 | |||
4570 | if (how_to_save == SAVE_WITH_COPY) { |
||
4571 | /* Copy the file, if we haven't moved it. If we're overwriting |
||
4572 | an existing file, we do it with a "safe save", by writing |
||
4573 | to a new file and, if the write succeeds, renaming the |
||
4574 | new file on top of the old file. */ |
||
4575 | if (file_exists(fname)) { |
||
4576 | fname_new = g_strdup_printf("%s~", fname); |
||
4577 | if (!copy_file_binary_mode(cf->filename, fname_new)) |
||
4578 | goto fail; |
||
4579 | } else { |
||
4580 | if (!copy_file_binary_mode(cf->filename, fname)) |
||
4581 | goto fail; |
||
4582 | } |
||
4583 | } |
||
4584 | } else { |
||
4585 | /* Either we're saving in a different format or we're saving changes, |
||
4586 | such as added, modified, or removed comments, that haven't yet |
||
4587 | been written to the underlying file; we can't do that by copying |
||
4588 | or moving the capture file, we have to do it by writing the packets |
||
4589 | out in Wiretap. */ |
||
4590 | |||
4591 | GArray *shb_hdrs = NULL; |
||
4592 | wtapng_iface_descriptions_t *idb_inf = NULL; |
||
4593 | GArray *nrb_hdrs = NULL; |
||
4594 | int encap; |
||
4595 | |||
4596 | /* XXX: what free's this shb_hdr? */ |
||
4597 | shb_hdrs = wtap_file_get_shb_for_new_file(cf->wth); |
||
4598 | idb_inf = wtap_file_get_idb_info(cf->wth); |
||
4599 | nrb_hdrs = wtap_file_get_nrb_for_new_file(cf->wth); |
||
4600 | |||
4601 | /* Determine what file encapsulation type we should use. */ |
||
4602 | encap = wtap_dump_file_encap_type(cf->linktypes); |
||
4603 | |||
4604 | if (file_exists(fname)) { |
||
4605 | /* We're overwriting an existing file; write out to a new file, |
||
4606 | and, if that succeeds, rename the new file on top of the |
||
4607 | old file. That makes this a "safe save", so that we don't |
||
4608 | lose the old file if we have a problem writing out the new |
||
4609 | file. (If the existing file is the current capture file, |
||
4610 | we *HAVE* to do that, otherwise we're overwriting the file |
||
4611 | from which we're reading the packets that we're writing!) */ |
||
4612 | fname_new = g_strdup_printf("%s~", fname); |
||
4613 | pdh = wtap_dump_open_ng(fname_new, save_format, encap, cf->snap, |
||
4614 | compressed, shb_hdrs, idb_inf, nrb_hdrs, &err); |
||
4615 | } else { |
||
4616 | pdh = wtap_dump_open_ng(fname, save_format, encap, cf->snap, |
||
4617 | compressed, shb_hdrs, idb_inf, nrb_hdrs, &err); |
||
4618 | } |
||
4619 | g_free(idb_inf); |
||
4620 | idb_inf = NULL; |
||
4621 | |||
4622 | if (pdh == NULL) { |
||
4623 | cf_open_failure_alert_box(fname, err, NULL, TRUE, save_format); |
||
4624 | goto fail; |
||
4625 | } |
||
4626 | |||
4627 | /* Add address resolution */ |
||
4628 | wtap_dump_set_addrinfo_list(pdh, addr_lists); |
||
4629 | |||
4630 | /* Iterate through the list of packets, processing all the packets. */ |
||
4631 | callback_args.pdh = pdh; |
||
4632 | callback_args.fname = fname; |
||
4633 | callback_args.file_type = save_format; |
||
4634 | switch (process_specified_records(cf, NULL, "Saving", "packets", |
||
4635 | TRUE, save_record, &callback_args, TRUE)) { |
||
4636 | |||
4637 | case PSP_FINISHED: |
||
4638 | /* Completed successfully. */ |
||
4639 | break; |
||
4640 | |||
4641 | case PSP_STOPPED: |
||
4642 | /* The user decided to abort the saving. |
||
4643 | If we're writing to a temporary file, remove it. |
||
4644 | XXX - should we do so even if we're not writing to a |
||
4645 | temporary file? */ |
||
4646 | wtap_dump_close(pdh, &err); |
||
4647 | if (fname_new != NULL) |
||
4648 | ws_unlink(fname_new); |
||
4649 | cf_callback_invoke(cf_cb_file_save_stopped, NULL); |
||
4650 | return CF_WRITE_ABORTED; |
||
4651 | |||
4652 | case PSP_FAILED: |
||
4653 | /* Error while saving. |
||
4654 | If we're writing to a temporary file, remove it. */ |
||
4655 | if (fname_new != NULL) |
||
4656 | ws_unlink(fname_new); |
||
4657 | wtap_dump_close(pdh, &err); |
||
4658 | goto fail; |
||
4659 | } |
||
4660 | |||
4661 | if (!wtap_dump_close(pdh, &err)) { |
||
4662 | cf_close_failure_alert_box(fname, err); |
||
4663 | goto fail; |
||
4664 | } |
||
4665 | |||
4666 | how_to_save = SAVE_WITH_WTAP; |
||
4667 | } |
||
4668 | |||
4669 | if (fname_new != NULL) { |
||
4670 | /* We wrote out to fname_new, and should rename it on top of |
||
4671 | fname. fname_new is now closed, so that should be possible even |
||
4672 | on Windows. However, on Windows, we first need to close whatever |
||
4673 | file descriptors we have open for fname. */ |
||
4674 | #ifdef _WIN32 |
||
4675 | wtap_fdclose(cf->wth); |
||
4676 | #endif |
||
4677 | /* Now do the rename. */ |
||
4678 | if (ws_rename(fname_new, fname) == -1) { |
||
4679 | /* Well, the rename failed. */ |
||
4680 | cf_rename_failure_alert_box(fname, errno); |
||
4681 | #ifdef _WIN32 |
||
4682 | /* Attempt to reopen the random file descriptor using the |
||
4683 | current file's filename. (At this point, the sequential |
||
4684 | file descriptor is closed.) */ |
||
4685 | if (!wtap_fdreopen(cf->wth, cf->filename, &err)) { |
||
4686 | /* Oh, well, we're screwed. */ |
||
4687 | display_basename = g_filename_display_basename(cf->filename); |
||
4688 | simple_error_message_box( |
||
4689 | file_open_error_message(err, FALSE), display_basename); |
||
4690 | g_free(display_basename); |
||
4691 | } |
||
4692 | #endif |
||
4693 | goto fail; |
||
4694 | } |
||
4695 | } |
||
4696 | |||
4697 | cf_callback_invoke(cf_cb_file_save_finished, NULL); |
||
4698 | cf->unsaved_changes = FALSE; |
||
4699 | |||
4700 | if (!dont_reopen) { |
||
4701 | switch (how_to_save) { |
||
4702 | |||
4703 | case SAVE_WITH_MOVE: |
||
4704 | /* We just moved the file, so the wtap structure refers to the |
||
4705 | new file, and all the information other than the filename |
||
4706 | and the "is temporary" status applies to the new file; just |
||
4707 | update that. */ |
||
4708 | g_free(cf->filename); |
||
4709 | cf->filename = g_strdup(fname); |
||
4710 | cf->is_tempfile = FALSE; |
||
4711 | cf_callback_invoke(cf_cb_file_fast_save_finished, cf); |
||
4712 | break; |
||
4713 | |||
4714 | case SAVE_WITH_COPY: |
||
4715 | /* We just copied the file, s all the information other than |
||
4716 | the wtap structure, the filename, and the "is temporary" |
||
4717 | status applies to the new file; just update that. */ |
||
4718 | wtap_close(cf->wth); |
||
4719 | /* Although we're just "copying" and then opening the copy, it will |
||
4720 | try all open_routine readers to open the copy, so we need to |
||
4721 | reset the cfile's open_type. */ |
||
4722 | cf->open_type = WTAP_TYPE_AUTO; |
||
4723 | cf->wth = wtap_open_offline(fname, WTAP_TYPE_AUTO, &err, &err_info, TRUE); |
||
4724 | if (cf->wth == NULL) { |
||
4725 | cf_open_failure_alert_box(fname, err, err_info, FALSE, 0); |
||
4726 | cf_close(cf); |
||
4727 | } else { |
||
4728 | g_free(cf->filename); |
||
4729 | cf->filename = g_strdup(fname); |
||
4730 | cf->is_tempfile = FALSE; |
||
4731 | } |
||
4732 | cf_callback_invoke(cf_cb_file_fast_save_finished, cf); |
||
4733 | break; |
||
4734 | |||
4735 | case SAVE_WITH_WTAP: |
||
4736 | /* Open and read the file we saved to. |
||
4737 | |||
4738 | XXX - this is somewhat of a waste; we already have the |
||
4739 | packets, all this gets us is updated file type information |
||
4740 | (which we could just stuff into "cf"), and having the new |
||
4741 | file be the one we have opened and from which we're reading |
||
4742 | the data, and it means we have to spend time opening and |
||
4743 | reading the file, which could be a significant amount of |
||
4744 | time if the file is large. |
||
4745 | |||
4746 | If the capture-file-writing code were to return the |
||
4747 | seek offset of each packet it writes, we could save that |
||
4748 | in the frame_data structure for the frame, and just open |
||
4749 | the file without reading it again... |
||
4750 | |||
4751 | ...as long as, for gzipped files, the process of writing |
||
4752 | out the file *also* generates the information needed to |
||
4753 | support fast random access to the compressed file. */ |
||
4754 | /* rescan_file will cause us to try all open_routines, so |
||
4755 | reset cfile's open_type */ |
||
4756 | cf->open_type = WTAP_TYPE_AUTO; |
||
4757 | if (rescan_file(cf, fname, FALSE, &err) != CF_READ_OK) { |
||
4758 | /* The rescan failed; just close the file. Either |
||
4759 | a dialog was popped up for the failure, so the |
||
4760 | user knows what happened, or they stopped the |
||
4761 | rescan, in which case they know what happened. */ |
||
4762 | cf_close(cf); |
||
4763 | } |
||
4764 | break; |
||
4765 | } |
||
4766 | |||
4767 | /* If we were told to discard the comments, do so. */ |
||
4768 | if (discard_comments) { |
||
4769 | /* Remove SHB comment, if any. */ |
||
4770 | wtap_write_shb_comment(cf->wth, NULL); |
||
4771 | |||
4772 | /* remove all user comments */ |
||
4773 | for (framenum = 1; framenum <= cf->count; framenum++) { |
||
4774 | fdata = frame_data_sequence_find(cf->frames, framenum); |
||
4775 | |||
4776 | fdata->flags.has_phdr_comment = FALSE; |
||
4777 | fdata->flags.has_user_comment = FALSE; |
||
4778 | } |
||
4779 | |||
4780 | if (cf->frames_user_comments) { |
||
4781 | g_tree_destroy(cf->frames_user_comments); |
||
4782 | cf->frames_user_comments = NULL; |
||
4783 | } |
||
4784 | |||
4785 | cf->packet_comment_count = 0; |
||
4786 | } |
||
4787 | } |
||
4788 | return CF_WRITE_OK; |
||
4789 | |||
4790 | fail: |
||
4791 | if (fname_new != NULL) { |
||
4792 | /* We were trying to write to a temporary file; get rid of it if it |
||
4793 | exists. (We don't care whether this fails, as, if it fails, |
||
4794 | there's not much we can do about it. I guess if it failed for |
||
4795 | a reason other than "it doesn't exist", we could report an |
||
4796 | error, so the user knows there's a junk file that they might |
||
4797 | want to clean up.) */ |
||
4798 | ws_unlink(fname_new); |
||
4799 | g_free(fname_new); |
||
4800 | } |
||
4801 | cf_callback_invoke(cf_cb_file_save_failed, NULL); |
||
4802 | return CF_WRITE_ERROR; |
||
4803 | } |
||
4804 | |||
4805 | cf_write_status_t |
||
4806 | cf_export_specified_packets(capture_file *cf, const char *fname, |
||
4807 | packet_range_t *range, guint save_format, |
||
4808 | gboolean compressed) |
||
4809 | { |
||
4810 | gchar *fname_new = NULL; |
||
4811 | int err; |
||
4812 | wtap_dumper *pdh; |
||
4813 | save_callback_args_t callback_args; |
||
4814 | GArray *shb_hdrs = NULL; |
||
4815 | wtapng_iface_descriptions_t *idb_inf = NULL; |
||
4816 | GArray *nrb_hdrs = NULL; |
||
4817 | int encap; |
||
4818 | |||
4819 | cf_callback_invoke(cf_cb_file_export_specified_packets_started, (gpointer)fname); |
||
4820 | |||
4821 | packet_range_process_init(range); |
||
4822 | |||
4823 | /* We're writing out specified packets from the specified capture |
||
4824 | file to another file. Even if all captured packets are to be |
||
4825 | written, don't special-case the operation - read each packet |
||
4826 | and then write it out if it's one of the specified ones. */ |
||
4827 | |||
4828 | /* XXX: what free's this shb_hdr? */ |
||
4829 | shb_hdrs = wtap_file_get_shb_for_new_file(cf->wth); |
||
4830 | idb_inf = wtap_file_get_idb_info(cf->wth); |
||
4831 | nrb_hdrs = wtap_file_get_nrb_for_new_file(cf->wth); |
||
4832 | |||
4833 | /* Determine what file encapsulation type we should use. */ |
||
4834 | encap = wtap_dump_file_encap_type(cf->linktypes); |
||
4835 | |||
4836 | if (file_exists(fname)) { |
||
4837 | /* We're overwriting an existing file; write out to a new file, |
||
4838 | and, if that succeeds, rename the new file on top of the |
||
4839 | old file. That makes this a "safe save", so that we don't |
||
4840 | lose the old file if we have a problem writing out the new |
||
4841 | file. (If the existing file is the current capture file, |
||
4842 | we *HAVE* to do that, otherwise we're overwriting the file |
||
4843 | from which we're reading the packets that we're writing!) */ |
||
4844 | fname_new = g_strdup_printf("%s~", fname); |
||
4845 | pdh = wtap_dump_open_ng(fname_new, save_format, encap, cf->snap, |
||
4846 | compressed, shb_hdrs, idb_inf, nrb_hdrs, &err); |
||
4847 | } else { |
||
4848 | pdh = wtap_dump_open_ng(fname, save_format, encap, cf->snap, |
||
4849 | compressed, shb_hdrs, idb_inf, nrb_hdrs, &err); |
||
4850 | } |
||
4851 | g_free(idb_inf); |
||
4852 | idb_inf = NULL; |
||
4853 | |||
4854 | if (pdh == NULL) { |
||
4855 | cf_open_failure_alert_box(fname, err, NULL, TRUE, save_format); |
||
4856 | goto fail; |
||
4857 | } |
||
4858 | |||
4859 | /* Add address resolution */ |
||
4860 | wtap_dump_set_addrinfo_list(pdh, get_addrinfo_list()); |
||
4861 | |||
4862 | /* Iterate through the list of packets, processing the packets we were |
||
4863 | told to process. |
||
4864 | |||
4865 | XXX - we've already called "packet_range_process_init(range)", but |
||
4866 | "process_specified_records()" will do it again. Fortunately, |
||
4867 | that's harmless in this case, as we haven't done anything to |
||
4868 | "range" since we initialized it. */ |
||
4869 | callback_args.pdh = pdh; |
||
4870 | callback_args.fname = fname; |
||
4871 | callback_args.file_type = save_format; |
||
4872 | switch (process_specified_records(cf, range, "Writing", "specified records", |
||
4873 | TRUE, save_record, &callback_args, TRUE)) { |
||
4874 | |||
4875 | case PSP_FINISHED: |
||
4876 | /* Completed successfully. */ |
||
4877 | break; |
||
4878 | |||
4879 | case PSP_STOPPED: |
||
4880 | /* The user decided to abort the saving. |
||
4881 | If we're writing to a temporary file, remove it. |
||
4882 | XXX - should we do so even if we're not writing to a |
||
4883 | temporary file? */ |
||
4884 | wtap_dump_close(pdh, &err); |
||
4885 | if (fname_new != NULL) |
||
4886 | ws_unlink(fname_new); |
||
4887 | cf_callback_invoke(cf_cb_file_export_specified_packets_stopped, NULL); |
||
4888 | return CF_WRITE_ABORTED; |
||
4889 | break; |
||
4890 | |||
4891 | case PSP_FAILED: |
||
4892 | /* Error while saving. |
||
4893 | If we're writing to a temporary file, remove it. */ |
||
4894 | if (fname_new != NULL) |
||
4895 | ws_unlink(fname_new); |
||
4896 | wtap_dump_close(pdh, &err); |
||
4897 | goto fail; |
||
4898 | } |
||
4899 | |||
4900 | if (!wtap_dump_close(pdh, &err)) { |
||
4901 | cf_close_failure_alert_box(fname, err); |
||
4902 | goto fail; |
||
4903 | } |
||
4904 | |||
4905 | if (fname_new != NULL) { |
||
4906 | /* We wrote out to fname_new, and should rename it on top of |
||
4907 | fname; fname is now closed, so that should be possible even |
||
4908 | on Windows. Do the rename. */ |
||
4909 | if (ws_rename(fname_new, fname) == -1) { |
||
4910 | /* Well, the rename failed. */ |
||
4911 | cf_rename_failure_alert_box(fname, errno); |
||
4912 | goto fail; |
||
4913 | } |
||
4914 | } |
||
4915 | |||
4916 | cf_callback_invoke(cf_cb_file_export_specified_packets_finished, NULL); |
||
4917 | return CF_WRITE_OK; |
||
4918 | |||
4919 | fail: |
||
4920 | if (fname_new != NULL) { |
||
4921 | /* We were trying to write to a temporary file; get rid of it if it |
||
4922 | exists. (We don't care whether this fails, as, if it fails, |
||
4923 | there's not much we can do about it. I guess if it failed for |
||
4924 | a reason other than "it doesn't exist", we could report an |
||
4925 | error, so the user knows there's a junk file that they might |
||
4926 | want to clean up.) */ |
||
4927 | ws_unlink(fname_new); |
||
4928 | g_free(fname_new); |
||
4929 | } |
||
4930 | cf_callback_invoke(cf_cb_file_export_specified_packets_failed, NULL); |
||
4931 | return CF_WRITE_ERROR; |
||
4932 | } |
||
4933 | |||
4934 | static void |
||
4935 | cf_open_failure_alert_box(const char *filename, int err, gchar *err_info, |
||
4936 | gboolean for_writing, int file_type) |
||
4937 | { |
||
4938 | gchar *display_basename; |
||
4939 | |||
4940 | if (err < 0) { |
||
4941 | /* Wiretap error. */ |
||
4942 | display_basename = g_filename_display_basename(filename); |
||
4943 | switch (err) { |
||
4944 | |||
4945 | case WTAP_ERR_NOT_REGULAR_FILE: |
||
4946 | simple_error_message_box( |
||
4947 | "The file \"%s\" is a \"special file\" or socket or other non-regular file.", |
||
4948 | display_basename); |
||
4949 | break; |
||
4950 | |||
4951 | case WTAP_ERR_RANDOM_OPEN_PIPE: |
||
4952 | /* Seen only when opening a capture file for reading. */ |
||
4953 | simple_error_message_box( |
||
4954 | "The file \"%s\" is a pipe or FIFO; Wireshark can't read pipe or FIFO files.\n" |
||
4955 | "To capture from a pipe or FIFO use wireshark -i -", |
||
4956 | display_basename); |
||
4957 | break; |
||
4958 | |||
4959 | case WTAP_ERR_FILE_UNKNOWN_FORMAT: |
||
4960 | /* Seen only when opening a capture file for reading. */ |
||
4961 | simple_error_message_box( |
||
4962 | "The file \"%s\" isn't a capture file in a format Wireshark understands.", |
||
4963 | display_basename); |
||
4964 | break; |
||
4965 | |||
4966 | case WTAP_ERR_UNSUPPORTED: |
||
4967 | /* Seen only when opening a capture file for reading. */ |
||
4968 | simple_error_message_box( |
||
4969 | "The file \"%s\" contains record data that Wireshark doesn't support.\n" |
||
4970 | "(%s)", |
||
4971 | display_basename, |
||
4972 | err_info != NULL ? err_info : "no information supplied"); |
||
4973 | g_free(err_info); |
||
4974 | break; |
||
4975 | |||
4976 | case WTAP_ERR_CANT_WRITE_TO_PIPE: |
||
4977 | /* Seen only when opening a capture file for writing. */ |
||
4978 | simple_error_message_box( |
||
4979 | "The file \"%s\" is a pipe, and %s capture files can't be " |
||
4980 | "written to a pipe.", |
||
4981 | display_basename, wtap_file_type_subtype_string(file_type)); |
||
4982 | break; |
||
4983 | |||
4984 | case WTAP_ERR_UNWRITABLE_FILE_TYPE: |
||
4985 | /* Seen only when opening a capture file for writing. */ |
||
4986 | simple_error_message_box( |
||
4987 | "Wireshark doesn't support writing capture files in that format."); |
||
4988 | break; |
||
4989 | |||
4990 | case WTAP_ERR_UNWRITABLE_ENCAP: |
||
4991 | /* Seen only when opening a capture file for writing. */ |
||
4992 | simple_error_message_box("Wireshark can't save this capture in that format."); |
||
4993 | break; |
||
4994 | |||
4995 | case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED: |
||
4996 | if (for_writing) { |
||
4997 | simple_error_message_box( |
||
4998 | "Wireshark can't save this capture in that format."); |
||
4999 | } else { |
||
5000 | simple_error_message_box( |
||
5001 | "The file \"%s\" is a capture for a network type that Wireshark doesn't support.", |
||
5002 | display_basename); |
||
5003 | } |
||
5004 | break; |
||
5005 | |||
5006 | case WTAP_ERR_BAD_FILE: |
||
5007 | /* Seen only when opening a capture file for reading. */ |
||
5008 | simple_error_message_box( |
||
5009 | "The file \"%s\" appears to be damaged or corrupt.\n" |
||
5010 | "(%s)", |
||
5011 | display_basename, |
||
5012 | err_info != NULL ? err_info : "no information supplied"); |
||
5013 | g_free(err_info); |
||
5014 | break; |
||
5015 | |||
5016 | case WTAP_ERR_CANT_OPEN: |
||
5017 | if (for_writing) { |
||
5018 | simple_error_message_box( |
||
5019 | "The file \"%s\" could not be created for some unknown reason.", |
||
5020 | display_basename); |
||
5021 | } else { |
||
5022 | simple_error_message_box( |
||
5023 | "The file \"%s\" could not be opened for some unknown reason.", |
||
5024 | display_basename); |
||
5025 | } |
||
5026 | break; |
||
5027 | |||
5028 | case WTAP_ERR_SHORT_READ: |
||
5029 | simple_error_message_box( |
||
5030 | "The file \"%s\" appears to have been cut short" |
||
5031 | " in the middle of a packet or other data.", |
||
5032 | display_basename); |
||
5033 | break; |
||
5034 | |||
5035 | case WTAP_ERR_SHORT_WRITE: |
||
5036 | simple_error_message_box( |
||
5037 | "A full header couldn't be written to the file \"%s\".", |
||
5038 | display_basename); |
||
5039 | break; |
||
5040 | |||
5041 | case WTAP_ERR_COMPRESSION_NOT_SUPPORTED: |
||
5042 | simple_error_message_box( |
||
5043 | "This file type cannot be written as a compressed file."); |
||
5044 | break; |
||
5045 | |||
5046 | case WTAP_ERR_DECOMPRESS: |
||
5047 | simple_error_message_box( |
||
5048 | "The compressed file \"%s\" appears to be damaged or corrupt.\n" |
||
5049 | "(%s)", display_basename, |
||
5050 | err_info != NULL ? err_info : "no information supplied"); |
||
5051 | g_free(err_info); |
||
5052 | break; |
||
5053 | |||
5054 | default: |
||
5055 | simple_error_message_box( |
||
5056 | "The file \"%s\" could not be %s: %s.", |
||
5057 | display_basename, |
||
5058 | for_writing ? "created" : "opened", |
||
5059 | wtap_strerror(err)); |
||
5060 | break; |
||
5061 | } |
||
5062 | g_free(display_basename); |
||
5063 | } else { |
||
5064 | /* OS error. */ |
||
5065 | open_failure_alert_box(filename, err, for_writing); |
||
5066 | } |
||
5067 | } |
||
5068 | |||
5069 | /* |
||
5070 | * XXX - whether we mention the source pathname, the target pathname, |
||
5071 | * or both depends on the error and on what we find if we look for |
||
5072 | * one or both of them. |
||
5073 | */ |
||
5074 | static void |
||
5075 | cf_rename_failure_alert_box(const char *filename, int err) |
||
5076 | { |
||
5077 | gchar *display_basename; |
||
5078 | |||
5079 | display_basename = g_filename_display_basename(filename); |
||
5080 | switch (err) { |
||
5081 | |||
5082 | case ENOENT: |
||
5083 | /* XXX - should check whether the source exists and, if not, |
||
5084 | report it as the problem and, if so, report the destination |
||
5085 | as the problem. */ |
||
5086 | simple_error_message_box("The path to the file \"%s\" doesn't exist.", |
||
5087 | display_basename); |
||
5088 | break; |
||
5089 | |||
5090 | case EACCES: |
||
5091 | /* XXX - if we're doing a rename after a safe save, we should |
||
5092 | probably say something else. */ |
||
5093 | simple_error_message_box("You don't have permission to move the capture file to \"%s\".", |
||
5094 | display_basename); |
||
5095 | break; |
||
5096 | |||
5097 | default: |
||
5098 | /* XXX - this should probably mention both the source and destination |
||
5099 | pathnames. */ |
||
5100 | simple_error_message_box("The file \"%s\" could not be moved: %s.", |
||
5101 | display_basename, wtap_strerror(err)); |
||
5102 | break; |
||
5103 | } |
||
5104 | g_free(display_basename); |
||
5105 | } |
||
5106 | |||
5107 | /* Check for write errors - if the file is being written to an NFS server, |
||
5108 | a write error may not show up until the file is closed, as NFS clients |
||
5109 | might not send writes to the server until the "write()" call finishes, |
||
5110 | so that the write may fail on the server but the "write()" may succeed. */ |
||
5111 | static void |
||
5112 | cf_close_failure_alert_box(const char *filename, int err) |
||
5113 | { |
||
5114 | gchar *display_basename; |
||
5115 | |||
5116 | if (err < 0) { |
||
5117 | /* Wiretap error. */ |
||
5118 | display_basename = g_filename_display_basename(filename); |
||
5119 | switch (err) { |
||
5120 | |||
5121 | case WTAP_ERR_CANT_CLOSE: |
||
5122 | simple_error_message_box( |
||
5123 | "The file \"%s\" couldn't be closed for some unknown reason.", |
||
5124 | display_basename); |
||
5125 | break; |
||
5126 | |||
5127 | case WTAP_ERR_SHORT_WRITE: |
||
5128 | simple_error_message_box( |
||
5129 | "Not all the packets could be written to the file \"%s\".", |
||
5130 | display_basename); |
||
5131 | break; |
||
5132 | |||
5133 | default: |
||
5134 | simple_error_message_box( |
||
5135 | "An error occurred while closing the file \"%s\": %s.", |
||
5136 | display_basename, wtap_strerror(err)); |
||
5137 | break; |
||
5138 | } |
||
5139 | g_free(display_basename); |
||
5140 | } else { |
||
5141 | /* OS error. |
||
5142 | We assume that a close error from the OS is really a write error. */ |
||
5143 | write_failure_alert_box(filename, err); |
||
5144 | } |
||
5145 | } |
||
5146 | |||
5147 | /* Reload the current capture file. */ |
||
5148 | void |
||
5149 | cf_reload(capture_file *cf) { |
||
5150 | gchar *filename; |
||
5151 | gboolean is_tempfile; |
||
5152 | int err; |
||
5153 | |||
5154 | /* If the file could be opened, "cf_open()" calls "cf_close()" |
||
5155 | to get rid of state for the old capture file before filling in state |
||
5156 | for the new capture file. "cf_close()" will remove the file if |
||
5157 | it's a temporary file; we don't want that to happen (for one thing, |
||
5158 | it'd prevent subsequent reopens from working). Remember whether it's |
||
5159 | a temporary file, mark it as not being a temporary file, and then |
||
5160 | reopen it as the type of file it was. |
||
5161 | |||
5162 | Also, "cf_close()" will free "cf->filename", so we must make |
||
5163 | a copy of it first. */ |
||
5164 | filename = g_strdup(cf->filename); |
||
5165 | is_tempfile = cf->is_tempfile; |
||
5166 | cf->is_tempfile = FALSE; |
||
5167 | if (cf_open(cf, filename, cf->open_type, is_tempfile, &err) == CF_OK) { |
||
5168 | switch (cf_read(cf, TRUE)) { |
||
5169 | |||
5170 | case CF_READ_OK: |
||
5171 | case CF_READ_ERROR: |
||
5172 | /* Just because we got an error, that doesn't mean we were unable |
||
5173 | to read any of the file; we handle what we could get from the |
||
5174 | file. */ |
||
5175 | break; |
||
5176 | |||
5177 | case CF_READ_ABORTED: |
||
5178 | /* The user bailed out of re-reading the capture file; the |
||
5179 | capture file has been closed - just free the capture file name |
||
5180 | string and return (without changing the last containing |
||
5181 | directory). */ |
||
5182 | g_free(filename); |
||
5183 | return; |
||
5184 | } |
||
5185 | } else { |
||
5186 | /* The open failed, so "cf->is_tempfile" wasn't set to "is_tempfile". |
||
5187 | Instead, the file was left open, so we should restore "cf->is_tempfile" |
||
5188 | ourselves. |
||
5189 | |||
5190 | XXX - change the menu? Presumably "cf_open()" will do that; |
||
5191 | make sure it does! */ |
||
5192 | cf->is_tempfile = is_tempfile; |
||
5193 | } |
||
5194 | /* "cf_open()" made a copy of the file name we handed it, so |
||
5195 | we should free up our copy. */ |
||
5196 | g_free(filename); |
||
5197 | } |
||
5198 | |||
5199 | /* |
||
5200 | * Editor modelines |
||
5201 | * |
||
5202 | * Local Variables: |
||
5203 | * c-basic-offset: 2 |
||
5204 | * tab-width: 8 |
||
5205 | * indent-tabs-mode: nil |
||
5206 | * End: |
||
5207 | * |
||
5208 | * ex: set shiftwidth=2 tabstop=8 expandtab: |
||
5209 | * :indentSize=2:tabSize=8:noTabs=true: |
||
5210 | */ |