opa: Add dissectors for Intel’s Omni-Path Architecture (OPA)
[metze/wireshark/wip.git] / wiretap / merge.c
1 /* Combine multiple dump files, either by appending or by merging by timestamp
2  *
3  * Written by Scott Renfro <scott@renfro.org> based on
4  * editcap by Richard Sharpe and Guy Harris
5  *
6  * Copyright 2013, Scott Renfro <scott[AT]renfro.org>
7  *
8  * Wireshark - Network traffic analyzer
9  * By Gerald Combs <gerald@wireshark.org>
10  * Copyright 1998 Gerald Combs
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License along
23  * with this program; if not, write to the Free Software Foundation, Inc.,
24  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25  */
26
27 #include "config.h"
28
29 #include <stdlib.h>
30 #include <errno.h>
31
32 #ifdef HAVE_UNISTD_H
33 #include <unistd.h>
34 #endif
35
36 #include <string.h>
37 #include "merge.h"
38 #include "wtap_opttypes.h"
39 #include "pcapng.h"
40
41 #include <wsutil/filesystem.h>
42 #include "wsutil/os_version_info.h"
43
44
45 #if 0
46 #define merge_debug(...) g_warning(__VA_ARGS__)
47 #else
48 #define merge_debug(...)
49 #endif
50
51
52 static const char* idb_merge_mode_strings[] = {
53     /* IDB_MERGE_MODE_NONE */
54     "none",
55     /* IDB_MERGE_MODE_ALL_SAME */
56     "all",
57     /* IDB_MERGE_MODE_ANY_SAME */
58     "any",
59     /* IDB_MERGE_MODE_MAX */
60     "UNKNOWN"
61 };
62
63 idb_merge_mode
64 merge_string_to_idb_merge_mode(const char *name)
65 {
66     int i;
67     for (i = 0; i < IDB_MERGE_MODE_MAX; i++) {
68         if (g_strcmp0(name, idb_merge_mode_strings[i]) == 0) {
69             return (idb_merge_mode) i;
70         }
71     }
72     return IDB_MERGE_MODE_MAX;
73 }
74
75 const char *
76 merge_idb_merge_mode_to_string(const int mode)
77 {
78     if (mode >= 0 && mode < IDB_MERGE_MODE_MAX) {
79         return idb_merge_mode_strings[mode];
80     }
81     return idb_merge_mode_strings[(int)IDB_MERGE_MODE_MAX];
82 }
83
84
85 static void
86 cleanup_in_file(merge_in_file_t *in_file)
87 {
88     g_assert(in_file != NULL);
89
90     wtap_close(in_file->wth);
91     in_file->wth = NULL;
92
93     g_array_free(in_file->idb_index_map, TRUE);
94     in_file->idb_index_map = NULL;
95 }
96
97 static void
98 add_idb_index_map(merge_in_file_t *in_file, const guint orig_index, const guint found_index)
99 {
100     g_assert(in_file != NULL);
101     g_assert(in_file->idb_index_map != NULL);
102
103     /*
104      * we didn't really need the orig_index, since just appending to the array
105      * should result in the orig_index being its location in the array; but we
106      * pass it into this function to do a sanity check here
107      */
108     g_assert(orig_index == in_file->idb_index_map->len);
109
110     g_array_append_val(in_file->idb_index_map, found_index);
111 }
112
113 /** Open a number of input files to merge.
114  *
115  * @param in_file_count number of entries in in_file_names and in_files
116  * @param in_file_names filenames of the input files
117  * @param in_files input file array to be filled (>= sizeof(merge_in_file_t) * in_file_count)
118  * @param err wiretap error, if failed
119  * @param err_info wiretap error string, if failed
120  * @param err_fileno file on which open failed, if failed
121  * @return TRUE if all files could be opened, FALSE otherwise
122  */
123 static gboolean
124 merge_open_in_files(guint in_file_count, const char *const *in_file_names,
125                     merge_in_file_t **in_files, int *err, gchar **err_info,
126                     guint *err_fileno)
127 {
128     guint i;
129     guint j;
130     size_t files_size = in_file_count * sizeof(merge_in_file_t);
131     merge_in_file_t *files;
132     gint64 size;
133
134     files = (merge_in_file_t *)g_malloc0(files_size);
135     *in_files = files;
136
137     for (i = 0; i < in_file_count; i++) {
138         files[i].filename    = in_file_names[i];
139         files[i].wth         = wtap_open_offline(in_file_names[i], WTAP_TYPE_AUTO, err, err_info, FALSE);
140         files[i].data_offset = 0;
141         files[i].state       = PACKET_NOT_PRESENT;
142         files[i].packet_num  = 0;
143
144         if (!files[i].wth) {
145             /* Close the files we've already opened. */
146             for (j = 0; j < i; j++)
147                 cleanup_in_file(&files[j]);
148             *err_fileno = i;
149             return FALSE;
150         }
151         size = wtap_file_size(files[i].wth, err);
152         if (size == -1) {
153             for (j = 0; j != G_MAXUINT && j <= i; j++)
154                 cleanup_in_file(&files[j]);
155             *err_fileno = i;
156             return FALSE;
157         }
158         files[i].size = size;
159         files[i].idb_index_map = g_array_new(FALSE, FALSE, sizeof(guint));
160     }
161     return TRUE;
162 }
163
164 /** Close the input files again.
165  *
166  * @param in_file_count number of entries in in_files
167  * @param in_files input file array to be closed
168  */
169 static void
170 merge_close_in_files(int in_file_count, merge_in_file_t in_files[])
171 {
172     int i;
173     for (i = 0; i < in_file_count; i++) {
174         cleanup_in_file(&in_files[i]);
175     }
176 }
177
178 /** Select an output frame type based on the input files
179  *
180  * If all files have the same frame type, then use that.
181  * Otherwise select WTAP_ENCAP_PER_PACKET.  If the selected
182  * output file type doesn't support per packet frame types,
183  * then the wtap_dump_open call will fail with a reasonable
184  * error condition.
185  *
186  * @param in_file_count number of entries in in_files
187  * @param in_files input file array
188  * @return the frame type
189  */
190 static int
191 merge_select_frame_type(int in_file_count, merge_in_file_t in_files[])
192 {
193     int i;
194     int selected_frame_type;
195
196     selected_frame_type = wtap_file_encap(in_files[0].wth);
197
198     for (i = 1; i < in_file_count; i++) {
199         int this_frame_type = wtap_file_encap(in_files[i].wth);
200         if (selected_frame_type != this_frame_type) {
201             selected_frame_type = WTAP_ENCAP_PER_PACKET;
202             break;
203         }
204     }
205
206     return selected_frame_type;
207 }
208
209 /*
210  * returns TRUE if first argument is earlier than second
211  */
212 static gboolean
213 is_earlier(nstime_t *l, nstime_t *r) /* XXX, move to nstime.c */
214 {
215     if (l->secs > r->secs) {  /* left is later */
216         return FALSE;
217     } else if (l->secs < r->secs) { /* left is earlier */
218         return TRUE;
219     } else if (l->nsecs > r->nsecs) { /* tv_sec equal, l.usec later */
220         return FALSE;
221     }
222     /* either one < two or one == two
223      * either way, return one
224      */
225     return TRUE;
226 }
227
228 /** Read the next packet, in chronological order, from the set of files to
229  * be merged.
230  *
231  * On success, set *err to 0 and return a pointer to the merge_in_file_t
232  * for the file from which the packet was read.
233  *
234  * On a read error, set *err to the error and return a pointer to the
235  * merge_in_file_t for the file on which we got an error.
236  *
237  * On an EOF (meaning all the files are at EOF), set *err to 0 and return
238  * NULL.
239  *
240  * @param in_file_count number of entries in in_files
241  * @param in_files input file array
242  * @param err wiretap error, if failed
243  * @param err_info wiretap error string, if failed
244  * @return pointer to merge_in_file_t for file from which that packet
245  * came, or NULL on error or EOF
246  */
247 static merge_in_file_t *
248 merge_read_packet(int in_file_count, merge_in_file_t in_files[],
249                   int *err, gchar **err_info)
250 {
251     int i;
252     int ei = -1;
253     nstime_t tv = { sizeof(time_t) > sizeof(int) ? LONG_MAX : INT_MAX, INT_MAX };
254     struct wtap_pkthdr *phdr;
255
256     /*
257      * Make sure we have a packet available from each file, if there are any
258      * packets left in the file in question, and search for the packet
259      * with the earliest time stamp.
260      */
261     for (i = 0; i < in_file_count; i++) {
262         if (in_files[i].state == PACKET_NOT_PRESENT) {
263             /*
264              * No packet available, and we haven't seen an error or EOF yet,
265              * so try to read the next packet.
266              */
267             if (!wtap_read(in_files[i].wth, err, err_info, &in_files[i].data_offset)) {
268                 if (*err != 0) {
269                     in_files[i].state = GOT_ERROR;
270                     return &in_files[i];
271                 }
272                 in_files[i].state = AT_EOF;
273             } else
274                 in_files[i].state = PACKET_PRESENT;
275         }
276
277         if (in_files[i].state == PACKET_PRESENT) {
278             phdr = wtap_phdr(in_files[i].wth);
279             if (is_earlier(&phdr->ts, &tv)) {
280                 tv = phdr->ts;
281                 ei = i;
282             }
283         }
284     }
285
286     if (ei == -1) {
287         /* All the streams are at EOF.  Return an EOF indication. */
288         *err = 0;
289         return NULL;
290     }
291
292     /* We'll need to read another packet from this file. */
293     in_files[ei].state = PACKET_NOT_PRESENT;
294
295     /* Count this packet. */
296     in_files[ei].packet_num++;
297
298     /*
299      * Return a pointer to the merge_in_file_t of the file from which the
300      * packet was read.
301      */
302     *err = 0;
303     return &in_files[ei];
304 }
305
306 /** Read the next packet, in file sequence order, from the set of files
307  * to be merged.
308  *
309  * On success, set *err to 0 and return a pointer to the merge_in_file_t
310  * for the file from which the packet was read.
311  *
312  * On a read error, set *err to the error and return a pointer to the
313  * merge_in_file_t for the file on which we got an error.
314  *
315  * On an EOF (meaning all the files are at EOF), set *err to 0 and return
316  * NULL.
317  *
318  * @param in_file_count number of entries in in_files
319  * @param in_files input file array
320  * @param err wiretap error, if failed
321  * @param err_info wiretap error string, if failed
322  * @return pointer to merge_in_file_t for file from which that packet
323  * came, or NULL on error or EOF
324  */
325 static merge_in_file_t *
326 merge_append_read_packet(int in_file_count, merge_in_file_t in_files[],
327                          int *err, gchar **err_info)
328 {
329     int i;
330
331     /*
332      * Find the first file not at EOF, and read the next packet from it.
333      */
334     for (i = 0; i < in_file_count; i++) {
335         if (in_files[i].state == AT_EOF)
336             continue; /* This file is already at EOF */
337         if (wtap_read(in_files[i].wth, err, err_info, &in_files[i].data_offset))
338             break; /* We have a packet */
339         if (*err != 0) {
340             /* Read error - quit immediately. */
341             in_files[i].state = GOT_ERROR;
342             return &in_files[i];
343         }
344         /* EOF - flag this file as being at EOF, and try the next one. */
345         in_files[i].state = AT_EOF;
346     }
347     if (i == in_file_count) {
348         /* All the streams are at EOF.  Return an EOF indication. */
349         *err = 0;
350         return NULL;
351     }
352
353     /*
354      * Return a pointer to the merge_in_file_t of the file from which the
355      * packet was read.
356      */
357     *err = 0;
358     return &in_files[i];
359 }
360
361
362 /* creates a section header block for the new output file */
363 static wtap_optionblock_t
364 create_shb_header(const merge_in_file_t *in_files, const guint in_file_count,
365                   const gchar *app_name)
366 {
367     wtap_optionblock_t shb_hdr;
368     GString *comment_gstr;
369     GString *os_info_str;
370     guint i;
371     char* shb_comment = NULL;
372     wtapng_mandatory_section_t* shb_data;
373
374     shb_hdr = wtap_file_get_shb_for_new_file(in_files[0].wth);
375
376     comment_gstr = g_string_new("");
377
378     /* TODO: merge comments from all files */
379
380     wtap_optionblock_get_option_string(shb_hdr, OPT_COMMENT, &shb_comment);
381
382     /* very lame way to save comments - does not save them from the other files */
383     if (shb_comment && strlen(shb_comment) > 0) {
384         g_string_append_printf(comment_gstr, "%s \n",shb_comment);
385     }
386
387     g_string_append_printf(comment_gstr, "File created by merging: \n");
388
389     for (i = 0; i < in_file_count; i++) {
390         g_string_append_printf(comment_gstr, "File%d: %s \n",i+1,in_files[i].filename);
391     }
392
393     os_info_str = g_string_new("");
394     get_os_version_info(os_info_str);
395
396     shb_data = (wtapng_mandatory_section_t*)wtap_optionblock_get_mandatory_data(shb_hdr);
397     shb_data->section_length = -1;
398     /* TODO: handle comments from each file being merged */
399     wtap_optionblock_set_option_string(shb_hdr, OPT_COMMENT, g_string_free(comment_gstr, TRUE)); /* section comment */
400     wtap_optionblock_set_option_string(shb_hdr, OPT_SHB_HARDWARE, NULL ); /* NULL if not available, UTF-8 string containing the        */
401                                                                                       /*  description of the hardware used to create this section. */
402
403     wtap_optionblock_set_option_string(shb_hdr, OPT_SHB_OS, g_string_free(os_info_str, TRUE)); /* UTF-8 string containing the name   */
404                                                                                                             /*  of the operating system used to create this section.     */
405     wtap_optionblock_set_option_string(shb_hdr, OPT_SHB_USERAPPL, (char*)app_name ); /* NULL if not available, UTF-8 string containing the name */
406                                                                                       /*  of the application used to create this section.          */
407
408     return shb_hdr;
409 }
410
411 static gboolean
412 is_duplicate_idb(const wtap_optionblock_t idb1, const wtap_optionblock_t idb2)
413 {
414     wtapng_if_descr_mandatory_t *idb1_mand, *idb2_mand;
415     guint64 idb1_if_speed, idb2_if_speed;
416     guint8 idb1_if_tsresol, idb2_if_tsresol;
417     guint8 idb1_if_fcslen, idb2_if_fcslen;
418     char *idb1_opt_comment, *idb2_opt_comment, *idb1_if_name, *idb2_if_name,
419          *idb1_if_description, *idb2_if_description, *idb1_if_os, *idb2_if_os;
420
421     g_assert(idb1 && idb2);
422     idb1_mand = (wtapng_if_descr_mandatory_t*)wtap_optionblock_get_mandatory_data(idb1);
423     idb2_mand = (wtapng_if_descr_mandatory_t*)wtap_optionblock_get_mandatory_data(idb2);
424
425     merge_debug("merge::is_duplicate_idb() called");
426     merge_debug("idb1_mand->wtap_encap == idb2_mand->wtap_encap: %s",
427                  (idb1_mand->wtap_encap == idb2_mand->wtap_encap) ? "TRUE":"FALSE");
428     merge_debug("idb1_mand->time_units_per_second == idb2_mand->time_units_per_second: %s",
429                  (idb1_mand->time_units_per_second == idb2_mand->time_units_per_second) ? "TRUE":"FALSE");
430     merge_debug("idb1_mand->tsprecision == idb2_mand->tsprecision: %s",
431                  (idb1_mand->tsprecision == idb2_mand->tsprecision) ? "TRUE":"FALSE");
432     merge_debug("idb1_mand->link_type == idb2_mand->link_type: %s",
433                  (idb1_mand->link_type == idb2_mand->link_type) ? "TRUE":"FALSE");
434     merge_debug("idb1_mand->snap_len == idb2_mand->snap_len: %s",
435                  (idb1_mand->snap_len == idb2_mand->snap_len) ? "TRUE":"FALSE");
436
437     wtap_optionblock_get_option_uint64(idb1, OPT_IDB_SPEED, &idb1_if_speed);
438     wtap_optionblock_get_option_uint64(idb2, OPT_IDB_SPEED, &idb2_if_speed);
439     merge_debug("idb1_if_speed == idb2_if_speed: %s",
440                  (idb1_if_speed == idb2_if_speed) ? "TRUE":"FALSE");
441
442     wtap_optionblock_get_option_uint8(idb1, OPT_IDB_TSRESOL, &idb1_if_tsresol);
443     wtap_optionblock_get_option_uint8(idb2, OPT_IDB_TSRESOL, &idb2_if_tsresol);
444     merge_debug("idb1_if_tsresol == idb2_if_tsresol: %s",
445                  (idb1_if_tsresol == idb2_if_tsresol) ? "TRUE":"FALSE");
446
447     wtap_optionblock_get_option_uint8(idb1, OPT_IDB_FCSLEN, &idb1_if_fcslen);
448     wtap_optionblock_get_option_uint8(idb2, OPT_IDB_FCSLEN, &idb2_if_fcslen);
449     merge_debug("idb1_if_fcslen == idb2_if_fcslen: %s",
450                  (idb1_if_fcslen == idb2_if_fcslen) ? "TRUE":"FALSE");
451
452     wtap_optionblock_get_option_string(idb1, OPT_COMMENT, &idb1_opt_comment);
453     wtap_optionblock_get_option_string(idb2, OPT_COMMENT, &idb2_opt_comment);
454     merge_debug("g_strcmp0(idb1_opt_comment, idb2_opt_comment) == 0: %s",
455                  (g_strcmp0(idb1_opt_comment, idb2_opt_comment) == 0) ? "TRUE":"FALSE");
456
457     wtap_optionblock_get_option_string(idb1, OPT_IDB_NAME, &idb1_if_name);
458     wtap_optionblock_get_option_string(idb2, OPT_IDB_NAME, &idb2_if_name);
459     merge_debug("g_strcmp0(idb1_if_name, idb2_if_name) == 0: %s",
460                  (g_strcmp0(idb1_if_name, idb2_if_name) == 0) ? "TRUE":"FALSE");
461
462     wtap_optionblock_get_option_string(idb1, OPT_IDB_DESCR, &idb1_if_description);
463     wtap_optionblock_get_option_string(idb2, OPT_IDB_DESCR, &idb2_if_description);
464     merge_debug("g_strcmp0(idb1_if_description, idb2_if_description) == 0: %s",
465                  (g_strcmp0(idb1_if_description, idb2_if_description) == 0) ? "TRUE":"FALSE");
466
467     wtap_optionblock_get_option_string(idb1, OPT_IDB_OS, &idb1_if_os);
468     wtap_optionblock_get_option_string(idb2, OPT_IDB_OS, &idb2_if_os);
469     merge_debug("g_strcmp0(idb1_if_os, idb2_if_os) == 0: %s",
470                  (g_strcmp0(idb1_if_os, idb2_if_os) == 0) ? "TRUE":"FALSE");
471     merge_debug("merge::is_duplicate_idb() returning");
472
473     /* does not compare filters nor interface statistics */
474     return (idb1_mand->wtap_encap == idb2_mand->wtap_encap &&
475             idb1_mand->time_units_per_second == idb2_mand->time_units_per_second &&
476             idb1_mand->tsprecision == idb2_mand->tsprecision &&
477             idb1_mand->link_type == idb2_mand->link_type &&
478             /* XXX: should snaplen not be compared? */
479             idb1_mand->snap_len == idb2_mand->snap_len &&
480             idb1_if_speed == idb2_if_speed &&
481             idb1_if_tsresol == idb2_if_tsresol &&
482             idb1_if_fcslen == idb2_if_fcslen &&
483             g_strcmp0(idb1_opt_comment, idb2_opt_comment) == 0 &&
484             g_strcmp0(idb1_if_name, idb2_if_name) == 0 &&
485             g_strcmp0(idb1_if_description, idb2_if_description) == 0 &&
486             g_strcmp0(idb1_if_os, idb2_if_os) == 0);
487 }
488
489 /*
490  * Returns true if all of the input files have duplicate IDBs to the other files.
491  */
492 static gboolean
493 all_idbs_are_duplicates(const merge_in_file_t *in_files, const guint in_file_count)
494 {
495     wtapng_iface_descriptions_t *first_idb_list = NULL;
496     wtapng_iface_descriptions_t *other_idb_list = NULL;
497     guint first_idb_list_size, other_idb_list_size;
498     wtap_optionblock_t first_file_idb, other_file_idb;
499     guint i, j;
500
501     g_assert(in_files != NULL);
502
503     /* get the first file's info */
504     first_idb_list = wtap_file_get_idb_info(in_files[0].wth);
505     g_assert(first_idb_list->interface_data);
506
507     first_idb_list_size = first_idb_list->interface_data->len;
508
509     /* now compare the other input files with that */
510     for (i = 1; i < in_file_count; i++) {
511         other_idb_list = wtap_file_get_idb_info(in_files[i].wth);
512         g_assert(other_idb_list->interface_data);
513         other_idb_list_size = other_idb_list->interface_data->len;
514
515         if (other_idb_list_size != first_idb_list_size) {
516             merge_debug("merge::all_idbs_are_duplicates: sizes of IDB lists don't match: first=%u, other=%u",
517                          first_idb_list_size, other_idb_list_size);
518             g_free(other_idb_list);
519             g_free(first_idb_list);
520             return FALSE;
521         }
522
523         for (j = 0; j < other_idb_list_size; j++) {
524             first_file_idb = g_array_index(first_idb_list->interface_data, wtap_optionblock_t, j);
525             other_file_idb = g_array_index(other_idb_list->interface_data, wtap_optionblock_t, j);
526
527             if (!is_duplicate_idb(first_file_idb, other_file_idb)) {
528                 merge_debug("merge::all_idbs_are_duplicates: IDBs at index %d do not match, returning FALSE", j);
529                 g_free(other_idb_list);
530                 g_free(first_idb_list);
531                 return FALSE;
532             }
533         }
534         g_free(other_idb_list);
535     }
536
537     merge_debug("merge::all_idbs_are_duplicates: returning TRUE");
538
539     g_free(first_idb_list);
540
541     return TRUE;
542 }
543
544 /*
545  * Returns true if the given input_file_idb is a duplicate of an existing one
546  * in the merged_idb_list; it's a duplicate if the interface description data
547  * is all identical to a previous one in another input file. For this
548  * function, the input file IDB's index does NOT need to match the index
549  * location of a previous one to be considered a duplicate; any match is
550  * considered a success. That means it will even match another IDB from its
551  * own (same) input file.
552  */
553 static gboolean
554 find_duplicate_idb(const wtap_optionblock_t input_file_idb,
555                const wtapng_iface_descriptions_t *merged_idb_list,
556                guint *found_index)
557 {
558     wtap_optionblock_t merged_idb;
559     guint i;
560
561     g_assert(input_file_idb != NULL);
562     g_assert(merged_idb_list != NULL);
563     g_assert(merged_idb_list->interface_data != NULL);
564     g_assert(found_index != NULL);
565
566     for (i = 0; i < merged_idb_list->interface_data->len; i++) {
567         merged_idb = g_array_index(merged_idb_list->interface_data, wtap_optionblock_t, i);
568
569         if (is_duplicate_idb(input_file_idb, merged_idb)) {
570             *found_index = i;
571             return TRUE;
572         }
573     }
574
575     return FALSE;
576 }
577
578 /* adds IDB to merged file info, returns its index */
579 static guint
580 add_idb_to_merged_file(wtapng_iface_descriptions_t *merged_idb_list,
581                        const wtap_optionblock_t input_file_idb)
582 {
583     wtap_optionblock_t idb = wtap_optionblock_create(WTAP_OPTION_BLOCK_IF_DESCR);
584     wtapng_if_descr_mandatory_t* idb_mand;
585     wtapng_if_descr_filter_t if_filter;
586
587
588     g_assert(merged_idb_list != NULL);
589     g_assert(merged_idb_list->interface_data != NULL);
590     g_assert(input_file_idb != NULL);
591
592     wtap_optionblock_copy_options(idb, input_file_idb);
593     idb_mand = (wtapng_if_descr_mandatory_t*)wtap_optionblock_get_mandatory_data(idb);
594
595     /* Don't copy filter or stat information */
596     memset(&if_filter, 0, sizeof(if_filter));
597     wtap_optionblock_set_option_custom(idb, OPT_IDB_FILTER, &if_filter);
598
599     idb_mand->num_stat_entries      = 0;          /* Number of ISB:s */
600     idb_mand->interface_statistics  = NULL;
601
602     g_array_append_val(merged_idb_list->interface_data, idb);
603
604     return merged_idb_list->interface_data->len - 1;
605 }
606
607 /*
608  * Create clone IDBs for the merge file, based on the input files and mode.
609  */
610 static wtapng_iface_descriptions_t *
611 generate_merged_idb(merge_in_file_t *in_files, const guint in_file_count, const idb_merge_mode mode)
612 {
613     wtapng_iface_descriptions_t *merged_idb_list = NULL;
614     wtapng_iface_descriptions_t *input_file_idb_list = NULL;
615     wtap_optionblock_t           input_file_idb;
616     guint                        itf_count, merged_index;
617     guint                        i;
618
619     /* create new IDB info */
620     merged_idb_list = g_new(wtapng_iface_descriptions_t,1);
621     merged_idb_list->interface_data = g_array_new(FALSE, FALSE, sizeof(wtap_optionblock_t));
622
623     if (mode == IDB_MERGE_MODE_ALL_SAME && all_idbs_are_duplicates(in_files, in_file_count)) {
624         guint num_idbs;
625
626         merge_debug("merge::generate_merged_idb: mode ALL set and all IDBs are duplicates");
627
628         /* they're all the same, so just get the first file's IDBs */
629         input_file_idb_list = wtap_file_get_idb_info(in_files[0].wth);
630         /* this is really one more than number of IDBs, but that's good for the for-loops */
631         num_idbs = input_file_idb_list->interface_data->len;
632
633         /* put them in the merged file */
634         for (itf_count = 0; itf_count < num_idbs; itf_count++) {
635             input_file_idb = g_array_index(input_file_idb_list->interface_data,
636                                             wtap_optionblock_t, itf_count);
637             merged_index = add_idb_to_merged_file(merged_idb_list, input_file_idb);
638             add_idb_index_map(&in_files[0], itf_count, merged_index);
639         }
640
641         /* and set all the other file index maps the same way */
642         for (i = 1; i < in_file_count; i++) {
643             for (itf_count = 0; itf_count < num_idbs; itf_count++) {
644                 add_idb_index_map(&in_files[i], itf_count, itf_count);
645             }
646         }
647
648         g_free(input_file_idb_list);
649     }
650     else {
651         for (i = 0; i < in_file_count; i++) {
652             input_file_idb_list = wtap_file_get_idb_info(in_files[i].wth);
653
654             for (itf_count = 0; itf_count < input_file_idb_list->interface_data->len; itf_count++) {
655                 input_file_idb = g_array_index(input_file_idb_list->interface_data,
656                                                 wtap_optionblock_t, itf_count);
657
658                 if (mode == IDB_MERGE_MODE_ANY_SAME &&
659                     find_duplicate_idb(input_file_idb, merged_idb_list, &merged_index))
660                 {
661                     merge_debug("merge::generate_merged_idb: mode ANY set and found a duplicate");
662                     /*
663                      * It's the same as a previous IDB, so we're going to "merge"
664                      * them into one by adding a map from its old IDB index to the new
665                      * one. This will be used later to change the phdr interface_id.
666                      */
667                     add_idb_index_map(&in_files[i], itf_count, merged_index);
668                 }
669                 else {
670                     merge_debug("merge::generate_merged_idb: mode NONE set or did not find a duplicate");
671                     /*
672                      * This IDB does not match a previous (or we want to save all IDBs),
673                      * so add the IDB to the merge file, and add a map of the indeces.
674                      */
675                     merged_index = add_idb_to_merged_file(merged_idb_list, input_file_idb);
676                     add_idb_index_map(&in_files[i], itf_count, merged_index);
677                 }
678             }
679
680             g_free(input_file_idb_list);
681         }
682     }
683
684     return merged_idb_list;
685 }
686
687 static gboolean
688 map_phdr_interface_id(struct wtap_pkthdr *phdr, const merge_in_file_t *in_file)
689 {
690     guint current_interface_id = 0;
691     g_assert(phdr != NULL);
692     g_assert(in_file != NULL);
693     g_assert(in_file->idb_index_map != NULL);
694
695     if (phdr->presence_flags & WTAP_HAS_INTERFACE_ID) {
696         current_interface_id = phdr->interface_id;
697     }
698
699     if (current_interface_id >= in_file->idb_index_map->len) {
700         /* this shouldn't happen, but in a malformed input file it could */
701         merge_debug("merge::map_phdr_interface_id: current_interface_id >= in_file->idb_index_map->len (ERROR?)");
702         return FALSE;
703     }
704
705     phdr->interface_id = g_array_index(in_file->idb_index_map, guint, current_interface_id);
706     phdr->presence_flags |= WTAP_HAS_INTERFACE_ID;
707
708     return TRUE;
709 }
710
711 static gchar*
712 get_read_error_string(const merge_in_file_t *in_files, const guint in_file_count,
713                       const int *err, gchar **err_info)
714 {
715     GString *err_message = g_string_new("");
716     gchar   *display_basename = NULL;
717     guint    i;
718
719     g_assert(in_files != NULL);
720     g_assert(err != NULL);
721     g_assert(err_info != NULL);
722
723     if (*err_info == NULL) {
724         *err_info = g_strdup("no information supplied");
725     }
726
727     /*
728      * Find the file on which we got the error, and report the error.
729      */
730     for (i = 0; i < in_file_count; i++) {
731         if (in_files[i].state == GOT_ERROR) {
732             display_basename = g_filename_display_basename(in_files[i].filename);
733
734             switch (*err) {
735
736                 case WTAP_ERR_SHORT_READ:
737                     g_string_printf(err_message,
738                          "The capture file %s appears to have been cut short"
739                           " in the middle of a packet.", display_basename);
740                     break;
741
742                 case WTAP_ERR_BAD_FILE:
743                     g_string_printf(err_message,
744                          "The capture file %s appears to be damaged or corrupt.\n(%s)",
745                          display_basename, *err_info);
746                     break;
747
748                 case WTAP_ERR_DECOMPRESS:
749                     g_string_printf(err_message,
750                          "The compressed capture file %s appears to be damaged or corrupt.\n"
751                          "(%s)", display_basename, *err_info);
752                     break;
753
754                 default:
755                     g_string_printf(err_message,
756                          "An error occurred while reading the"
757                          " capture file %s: %s.",
758                          display_basename,  wtap_strerror(*err));
759                     break;
760             }
761
762             g_free(display_basename);
763             break;
764         }
765     }
766
767     g_free(*err_info);
768     *err_info = g_string_free(err_message, FALSE);
769
770     return *err_info;
771 }
772
773 static gchar*
774 get_write_error_string(const merge_in_file_t *in_file, const int file_type,
775                        const gchar* out_filename, const int *err, gchar **err_info)
776 {
777     GString *err_message = g_string_new("");
778     gchar *display_basename = NULL;
779     int write_err;
780
781     /* in_file may be NULL */
782     g_assert(err != NULL);
783     g_assert(err_info != NULL);
784
785     if (*err_info == NULL) {
786         *err_info = g_strdup("no information supplied");
787     }
788
789     write_err = *err;
790
791     display_basename = g_filename_display_basename(in_file ? in_file->filename : "UNKNOWN");
792
793     if (write_err < 0) {
794
795         switch (write_err) {
796
797             case WTAP_ERR_UNWRITABLE_ENCAP:
798                 /*
799                  * This is a problem with the particular frame we're writing and
800                  * the file type and subtype we're wwriting; note that, and
801                  * report the frame number and file type/subtype.
802                  */
803                 g_string_printf(err_message,
804                     "Frame %u of \"%s\" has a network type that can't be saved in a \"%s\" file.\n",
805                     in_file ? in_file->packet_num : 0, display_basename,
806                     wtap_file_type_subtype_string(file_type));
807                 break;
808
809             case WTAP_ERR_PACKET_TOO_LARGE:
810                 /*
811                  * This is a problem with the particular frame we're writing and
812                  * the file type and subtype we're writing; note that, and report
813                  * the frame number and file type/subtype.
814                  */
815                 g_string_printf(err_message,
816                     "Frame %u of \"%s\" is too large for a \"%s\" file.",
817                     in_file ? in_file->packet_num : 0, display_basename,
818                     wtap_file_type_subtype_string(file_type));
819                 break;
820
821             case WTAP_ERR_UNWRITABLE_REC_TYPE:
822                 /*
823                  * This is a problem with the particular record we're writing and
824                  * the file type and subtype we're writing; note that, and report
825                  * the record number and file type/subtype.
826                  */
827                 g_string_printf(err_message,
828                     "Record %u of \"%s\" has a record type that can't be saved in a \"%s\" file.",
829                     in_file ? in_file->packet_num : 0, display_basename,
830                     wtap_file_type_subtype_string(file_type));
831                 break;
832
833             case WTAP_ERR_UNWRITABLE_REC_DATA:
834                 /*
835                  * This is a problem with the particular record we're writing and
836                  * the file type and subtype we're writing; note that, and report
837                  * the frame number and file type/subtype.
838                  */
839                 g_string_printf(err_message,
840                     "Record %u of \"%s\" has data that can't be saved in a \"%s\" file.\n(%s)",
841                     in_file ? in_file->packet_num : 0, display_basename,
842                     wtap_file_type_subtype_string(file_type), *err_info);
843                 break;
844
845             default:
846                 g_string_printf(err_message,
847                     "An error occurred while writing to the file \"%s\": %s.",
848                     out_filename, wtap_strerror(write_err));
849                 break;
850         }
851     }
852     else {
853         /* OS error. */
854         g_string_printf(err_message, file_write_error_message(write_err), out_filename);
855     }
856
857     g_free(display_basename);
858     g_free(*err_info);
859     *err_info = g_string_free(err_message, FALSE);
860
861     return *err_info;
862 }
863
864
865 /*
866  * Merges the files based on given input, and invokes callback during
867  * execution. Returns MERGE_OK on success, or a MERGE_ERR_XXX on failure; note
868  * that the passed-in 'err' variable will be more specific to what failed, and
869  * err_info will have pretty output.
870  */
871 merge_result
872 merge_files(int out_fd, const gchar* out_filename, const int file_type,
873             const char *const *in_filenames, const guint in_file_count,
874             const gboolean do_append, const idb_merge_mode mode,
875             guint snaplen, const gchar *app_name, merge_progress_callback_t* cb,
876             int *err, gchar **err_info, guint *err_fileno)
877 {
878     merge_in_file_t    *in_files = NULL, *in_file = NULL;
879     int                 frame_type = WTAP_ENCAP_PER_PACKET;
880     merge_result        status = MERGE_OK;
881     wtap_dumper        *pdh;
882     struct wtap_pkthdr *phdr, snap_phdr;
883     int                 count = 0;
884     gboolean            stop_flag = FALSE;
885     wtap_optionblock_t          shb_hdr = NULL;
886     wtapng_iface_descriptions_t *idb_inf = NULL;
887
888     g_assert(out_fd > 0);
889     g_assert(in_file_count > 0);
890     g_assert(in_filenames != NULL);
891     g_assert(err != NULL);
892     g_assert(err_info != NULL);
893     g_assert(err_fileno != NULL);
894
895     /* if a callback was given, it has to have a callback function ptr */
896     g_assert((cb != NULL) ? (cb->callback_func != NULL) : TRUE);
897
898     merge_debug("merge_files: begin");
899
900     /* open the input files */
901     if (!merge_open_in_files(in_file_count, in_filenames, &in_files,
902                              err, err_info, err_fileno)) {
903         merge_debug("merge_files: merge_open_in_files() failed with err=%d", *err);
904         return MERGE_ERR_CANT_OPEN_INFILE;
905     }
906
907     if (cb)
908         cb->callback_func(MERGE_EVENT_INPUT_FILES_OPENED, 0, in_files, in_file_count, cb->data);
909
910     if (snaplen == 0) {
911         /* Snapshot length not specified - default to the maximum. */
912         snaplen = WTAP_MAX_PACKET_SIZE;
913     }
914
915     /*
916      * This doesn't tell us that much. It tells us what to set the outfile's
917      * encap type to, but that's all - for example, it does *not* tells us
918      * whether the input files had the same number of IDBs, for the same exact
919      * interfaces, and only one IDB each, so it doesn't actually tell us
920      * whether we can merge IDBs into one or not.
921      */
922     frame_type = merge_select_frame_type(in_file_count, in_files);
923     merge_debug("merge_files: got frame_type=%d", frame_type);
924
925     if (cb)
926         cb->callback_func(MERGE_EVENT_FRAME_TYPE_SELECTED, frame_type, in_files, in_file_count, cb->data);
927
928     /* prepare the outfile */
929     if (file_type == WTAP_FILE_TYPE_SUBTYPE_PCAPNG) {
930         shb_hdr = create_shb_header(in_files, in_file_count, app_name);
931         merge_debug("merge_files: SHB created");
932
933         idb_inf = generate_merged_idb(in_files, in_file_count, mode);
934         merge_debug("merge_files: IDB merge operation complete, got %u IDBs", idb_inf ? idb_inf->interface_data->len : 0);
935
936         pdh = wtap_dump_fdopen_ng(out_fd, file_type, frame_type, snaplen,
937                                   FALSE /* compressed */, shb_hdr, idb_inf,
938                                   NULL, err);
939     }
940     else {
941         pdh = wtap_dump_fdopen(out_fd, file_type, frame_type, snaplen, FALSE /* compressed */, err);
942     }
943
944     if (pdh == NULL) {
945         merge_close_in_files(in_file_count, in_files);
946         g_free(in_files);
947         wtap_optionblock_free(shb_hdr);
948         wtap_free_idb_info(idb_inf);
949         return MERGE_ERR_CANT_OPEN_OUTFILE;
950     }
951
952     if (cb)
953         cb->callback_func(MERGE_EVENT_READY_TO_MERGE, 0, in_files, in_file_count, cb->data);
954
955     for (;;) {
956         *err = 0;
957
958         if (do_append) {
959             in_file = merge_append_read_packet(in_file_count, in_files, err,
960                                                err_info);
961         }
962         else {
963             in_file = merge_read_packet(in_file_count, in_files, err,
964                                         err_info);
965         }
966
967         if (in_file == NULL) {
968             /* EOF */
969             break;
970         }
971
972         if (*err != 0) {
973             /* I/O error reading from in_file */
974             status = MERGE_ERR_CANT_READ_INFILE;
975             break;
976         }
977
978         count++;
979         if (cb)
980             stop_flag = cb->callback_func(MERGE_EVENT_PACKET_WAS_READ, count, in_files, in_file_count, cb->data);
981
982         if (stop_flag) {
983             /* The user decided to abort the merge. */
984             status = MERGE_USER_ABORTED;
985             break;
986         }
987
988         phdr = wtap_phdr(in_file->wth);
989
990         if (snaplen != 0 && phdr->caplen > snaplen) {
991             /*
992              * The dumper will only write up to caplen bytes out, so we only
993              * need to change that value, instead of cloning the whole packet
994              * with fewer bytes.
995              *
996              * XXX: but do we need to change the IDBs' snap_len?
997              */
998             snap_phdr = *phdr;
999             snap_phdr.caplen = snaplen;
1000             phdr = &snap_phdr;
1001         }
1002
1003         if (file_type == WTAP_FILE_TYPE_SUBTYPE_PCAPNG) {
1004             if (!map_phdr_interface_id(phdr, in_file)) {
1005                 status = MERGE_ERR_BAD_PHDR_INTERFACE_ID;
1006                 break;
1007             }
1008         }
1009
1010         if (!wtap_dump(pdh, phdr, wtap_buf_ptr(in_file->wth), err, err_info)) {
1011             status = MERGE_ERR_CANT_WRITE_OUTFILE;
1012             break;
1013         }
1014     }
1015
1016     if (cb)
1017         cb->callback_func(MERGE_EVENT_DONE, count, in_files, in_file_count, cb->data);
1018
1019     merge_close_in_files(in_file_count, in_files);
1020
1021     if (status == MERGE_OK || status == MERGE_USER_ABORTED) {
1022         if (!wtap_dump_close(pdh, err))
1023             status = MERGE_ERR_CANT_CLOSE_OUTFILE;
1024     } else {
1025         /*
1026          * We already got some error; no need to report another error on
1027          * close.
1028          *
1029          * Don't overwrite the earlier error.
1030          */
1031         int close_err = 0;
1032         (void)wtap_dump_close(pdh, &close_err);
1033     }
1034
1035     if (status != MERGE_OK) {
1036         GString *err_message = NULL;
1037         gchar   *display_basename = NULL;
1038
1039         switch(status) {
1040
1041             case MERGE_ERR_CANT_READ_INFILE:
1042                 *err_info = get_read_error_string(in_files, in_file_count, err, err_info);
1043                 break;
1044
1045             case MERGE_ERR_CANT_WRITE_OUTFILE: /* fall through */
1046             case MERGE_ERR_CANT_CLOSE_OUTFILE:
1047                 *err_info = get_write_error_string(in_file, file_type, out_filename, err, err_info);
1048                 break;
1049
1050             case MERGE_ERR_BAD_PHDR_INTERFACE_ID:
1051                 display_basename = g_filename_display_basename(in_file ? in_file->filename : "UNKNOWN");
1052                 if (*err_info != NULL)
1053                     g_free(*err_info);
1054                 err_message = g_string_new("");
1055                 g_string_printf(err_message,
1056                     "Record %u of \"%s\" has an interface ID which does not match any IDB in its file.",
1057                     in_file ? in_file->packet_num : 0, display_basename);
1058                 g_free(display_basename);
1059                 *err_info = g_string_free(err_message, FALSE);
1060                 break;
1061
1062             case MERGE_USER_ABORTED: /* not really an error */
1063             default:
1064                 break;
1065         }
1066     }
1067
1068     g_free(in_files);
1069     wtap_optionblock_free(shb_hdr);
1070     wtap_free_idb_info(idb_inf);
1071
1072     return status;
1073 }
1074
1075 /*
1076  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
1077  *
1078  * Local Variables:
1079  * c-basic-offset: 4
1080  * tab-width: 8
1081  * indent-tabs-mode: nil
1082  * End:
1083  *
1084  * vi: set shiftwidth=4 tabstop=8 expandtab:
1085  * :indentSize=4:tabSize=8:noTabs=true:
1086  */