Make the IPv4 NRB code's comments match the IPv6 NRB code's comments.
[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 GArray*
364 create_shb_header(const merge_in_file_t *in_files, const guint in_file_count,
365                   const gchar *app_name)
366 {
367     GArray  *shb_hdrs;
368     wtap_optionblock_t shb_hdr;
369     GString *comment_gstr;
370     GString *os_info_str;
371     guint i;
372     char* shb_comment = NULL;
373     wtapng_mandatory_section_t* shb_data;
374     gsize opt_len;
375
376     shb_hdrs = wtap_file_get_shb_for_new_file(in_files[0].wth);
377     shb_hdr = g_array_index(shb_hdrs, wtap_optionblock_t, 0);
378
379     comment_gstr = g_string_new("");
380
381     /* TODO: merge comments from all files */
382
383     wtap_optionblock_get_option_string(shb_hdr, OPT_COMMENT, &shb_comment);
384
385     /* very lame way to save comments - does not save them from the other files */
386     if (shb_comment && strlen(shb_comment) > 0) {
387         g_string_append_printf(comment_gstr, "%s \n",shb_comment);
388     }
389
390     g_string_append_printf(comment_gstr, "File created by merging: \n");
391
392     for (i = 0; i < in_file_count; i++) {
393         g_string_append_printf(comment_gstr, "File%d: %s \n",i+1,in_files[i].filename);
394     }
395
396     os_info_str = g_string_new("");
397     get_os_version_info(os_info_str);
398
399     shb_data = (wtapng_mandatory_section_t*)wtap_optionblock_get_mandatory_data(shb_hdr);
400     shb_data->section_length = -1;
401     /* TODO: handle comments from each file being merged */
402     opt_len = comment_gstr->len;
403     wtap_optionblock_set_option_string(shb_hdr, OPT_COMMENT, g_string_free(comment_gstr, TRUE), opt_len); /* section comment */
404     wtap_optionblock_set_option_string(shb_hdr, OPT_SHB_HARDWARE, NULL, 0 ); /* NULL if not available, UTF-8 string containing the        */
405                                                                                       /*  description of the hardware used to create this section. */
406
407     opt_len = os_info_str->len;
408     wtap_optionblock_set_option_string(shb_hdr, OPT_SHB_OS, g_string_free(os_info_str, TRUE), opt_len); /* UTF-8 string containing the name   */
409                                                                                                             /*  of the operating system used to create this section.     */
410     wtap_optionblock_set_option_string(shb_hdr, OPT_SHB_USERAPPL, (char*)app_name, app_name ? strlen(app_name): 0 ); /* NULL if not available, UTF-8 string containing the name */
411                                                                                       /*  of the application used to create this section.          */
412
413     return shb_hdrs;
414 }
415
416 static gboolean
417 is_duplicate_idb(const wtap_optionblock_t idb1, const wtap_optionblock_t idb2)
418 {
419     wtapng_if_descr_mandatory_t *idb1_mand, *idb2_mand;
420     guint64 idb1_if_speed, idb2_if_speed;
421     guint8 idb1_if_tsresol, idb2_if_tsresol;
422     guint8 idb1_if_fcslen, idb2_if_fcslen;
423     char *idb1_opt_comment, *idb2_opt_comment, *idb1_if_name, *idb2_if_name,
424          *idb1_if_description, *idb2_if_description, *idb1_if_os, *idb2_if_os;
425
426     g_assert(idb1 && idb2);
427     idb1_mand = (wtapng_if_descr_mandatory_t*)wtap_optionblock_get_mandatory_data(idb1);
428     idb2_mand = (wtapng_if_descr_mandatory_t*)wtap_optionblock_get_mandatory_data(idb2);
429
430     merge_debug("merge::is_duplicate_idb() called");
431     merge_debug("idb1_mand->wtap_encap == idb2_mand->wtap_encap: %s",
432                  (idb1_mand->wtap_encap == idb2_mand->wtap_encap) ? "TRUE":"FALSE");
433     merge_debug("idb1_mand->time_units_per_second == idb2_mand->time_units_per_second: %s",
434                  (idb1_mand->time_units_per_second == idb2_mand->time_units_per_second) ? "TRUE":"FALSE");
435     merge_debug("idb1_mand->tsprecision == idb2_mand->tsprecision: %s",
436                  (idb1_mand->tsprecision == idb2_mand->tsprecision) ? "TRUE":"FALSE");
437     merge_debug("idb1_mand->link_type == idb2_mand->link_type: %s",
438                  (idb1_mand->link_type == idb2_mand->link_type) ? "TRUE":"FALSE");
439     merge_debug("idb1_mand->snap_len == idb2_mand->snap_len: %s",
440                  (idb1_mand->snap_len == idb2_mand->snap_len) ? "TRUE":"FALSE");
441
442     wtap_optionblock_get_option_uint64(idb1, OPT_IDB_SPEED, &idb1_if_speed);
443     wtap_optionblock_get_option_uint64(idb2, OPT_IDB_SPEED, &idb2_if_speed);
444     merge_debug("idb1_if_speed == idb2_if_speed: %s",
445                  (idb1_if_speed == idb2_if_speed) ? "TRUE":"FALSE");
446
447     wtap_optionblock_get_option_uint8(idb1, OPT_IDB_TSRESOL, &idb1_if_tsresol);
448     wtap_optionblock_get_option_uint8(idb2, OPT_IDB_TSRESOL, &idb2_if_tsresol);
449     merge_debug("idb1_if_tsresol == idb2_if_tsresol: %s",
450                  (idb1_if_tsresol == idb2_if_tsresol) ? "TRUE":"FALSE");
451
452     wtap_optionblock_get_option_uint8(idb1, OPT_IDB_FCSLEN, &idb1_if_fcslen);
453     wtap_optionblock_get_option_uint8(idb2, OPT_IDB_FCSLEN, &idb2_if_fcslen);
454     merge_debug("idb1_if_fcslen == idb2_if_fcslen: %s",
455                  (idb1_if_fcslen == idb2_if_fcslen) ? "TRUE":"FALSE");
456
457     wtap_optionblock_get_option_string(idb1, OPT_COMMENT, &idb1_opt_comment);
458     wtap_optionblock_get_option_string(idb2, OPT_COMMENT, &idb2_opt_comment);
459     merge_debug("g_strcmp0(idb1_opt_comment, idb2_opt_comment) == 0: %s",
460                  (g_strcmp0(idb1_opt_comment, idb2_opt_comment) == 0) ? "TRUE":"FALSE");
461
462     wtap_optionblock_get_option_string(idb1, OPT_IDB_NAME, &idb1_if_name);
463     wtap_optionblock_get_option_string(idb2, OPT_IDB_NAME, &idb2_if_name);
464     merge_debug("g_strcmp0(idb1_if_name, idb2_if_name) == 0: %s",
465                  (g_strcmp0(idb1_if_name, idb2_if_name) == 0) ? "TRUE":"FALSE");
466
467     wtap_optionblock_get_option_string(idb1, OPT_IDB_DESCR, &idb1_if_description);
468     wtap_optionblock_get_option_string(idb2, OPT_IDB_DESCR, &idb2_if_description);
469     merge_debug("g_strcmp0(idb1_if_description, idb2_if_description) == 0: %s",
470                  (g_strcmp0(idb1_if_description, idb2_if_description) == 0) ? "TRUE":"FALSE");
471
472     wtap_optionblock_get_option_string(idb1, OPT_IDB_OS, &idb1_if_os);
473     wtap_optionblock_get_option_string(idb2, OPT_IDB_OS, &idb2_if_os);
474     merge_debug("g_strcmp0(idb1_if_os, idb2_if_os) == 0: %s",
475                  (g_strcmp0(idb1_if_os, idb2_if_os) == 0) ? "TRUE":"FALSE");
476     merge_debug("merge::is_duplicate_idb() returning");
477
478     /* does not compare filters nor interface statistics */
479     return (idb1_mand->wtap_encap == idb2_mand->wtap_encap &&
480             idb1_mand->time_units_per_second == idb2_mand->time_units_per_second &&
481             idb1_mand->tsprecision == idb2_mand->tsprecision &&
482             idb1_mand->link_type == idb2_mand->link_type &&
483             /* XXX: should snaplen not be compared? */
484             idb1_mand->snap_len == idb2_mand->snap_len &&
485             idb1_if_speed == idb2_if_speed &&
486             idb1_if_tsresol == idb2_if_tsresol &&
487             idb1_if_fcslen == idb2_if_fcslen &&
488             g_strcmp0(idb1_opt_comment, idb2_opt_comment) == 0 &&
489             g_strcmp0(idb1_if_name, idb2_if_name) == 0 &&
490             g_strcmp0(idb1_if_description, idb2_if_description) == 0 &&
491             g_strcmp0(idb1_if_os, idb2_if_os) == 0);
492 }
493
494 /*
495  * Returns true if all of the input files have duplicate IDBs to the other files.
496  */
497 static gboolean
498 all_idbs_are_duplicates(const merge_in_file_t *in_files, const guint in_file_count)
499 {
500     wtapng_iface_descriptions_t *first_idb_list = NULL;
501     wtapng_iface_descriptions_t *other_idb_list = NULL;
502     guint first_idb_list_size, other_idb_list_size;
503     wtap_optionblock_t first_file_idb, other_file_idb;
504     guint i, j;
505
506     g_assert(in_files != NULL);
507
508     /* get the first file's info */
509     first_idb_list = wtap_file_get_idb_info(in_files[0].wth);
510     g_assert(first_idb_list->interface_data);
511
512     first_idb_list_size = first_idb_list->interface_data->len;
513
514     /* now compare the other input files with that */
515     for (i = 1; i < in_file_count; i++) {
516         other_idb_list = wtap_file_get_idb_info(in_files[i].wth);
517         g_assert(other_idb_list->interface_data);
518         other_idb_list_size = other_idb_list->interface_data->len;
519
520         if (other_idb_list_size != first_idb_list_size) {
521             merge_debug("merge::all_idbs_are_duplicates: sizes of IDB lists don't match: first=%u, other=%u",
522                          first_idb_list_size, other_idb_list_size);
523             g_free(other_idb_list);
524             g_free(first_idb_list);
525             return FALSE;
526         }
527
528         for (j = 0; j < other_idb_list_size; j++) {
529             first_file_idb = g_array_index(first_idb_list->interface_data, wtap_optionblock_t, j);
530             other_file_idb = g_array_index(other_idb_list->interface_data, wtap_optionblock_t, j);
531
532             if (!is_duplicate_idb(first_file_idb, other_file_idb)) {
533                 merge_debug("merge::all_idbs_are_duplicates: IDBs at index %d do not match, returning FALSE", j);
534                 g_free(other_idb_list);
535                 g_free(first_idb_list);
536                 return FALSE;
537             }
538         }
539         g_free(other_idb_list);
540     }
541
542     merge_debug("merge::all_idbs_are_duplicates: returning TRUE");
543
544     g_free(first_idb_list);
545
546     return TRUE;
547 }
548
549 /*
550  * Returns true if the given input_file_idb is a duplicate of an existing one
551  * in the merged_idb_list; it's a duplicate if the interface description data
552  * is all identical to a previous one in another input file. For this
553  * function, the input file IDB's index does NOT need to match the index
554  * location of a previous one to be considered a duplicate; any match is
555  * considered a success. That means it will even match another IDB from its
556  * own (same) input file.
557  */
558 static gboolean
559 find_duplicate_idb(const wtap_optionblock_t input_file_idb,
560                const wtapng_iface_descriptions_t *merged_idb_list,
561                guint *found_index)
562 {
563     wtap_optionblock_t merged_idb;
564     guint i;
565
566     g_assert(input_file_idb != NULL);
567     g_assert(merged_idb_list != NULL);
568     g_assert(merged_idb_list->interface_data != NULL);
569     g_assert(found_index != NULL);
570
571     for (i = 0; i < merged_idb_list->interface_data->len; i++) {
572         merged_idb = g_array_index(merged_idb_list->interface_data, wtap_optionblock_t, i);
573
574         if (is_duplicate_idb(input_file_idb, merged_idb)) {
575             *found_index = i;
576             return TRUE;
577         }
578     }
579
580     return FALSE;
581 }
582
583 /* adds IDB to merged file info, returns its index */
584 static guint
585 add_idb_to_merged_file(wtapng_iface_descriptions_t *merged_idb_list,
586                        const wtap_optionblock_t input_file_idb)
587 {
588     wtap_optionblock_t idb = wtap_optionblock_create(WTAP_OPTION_BLOCK_IF_DESCR);
589     wtapng_if_descr_mandatory_t* idb_mand;
590     wtapng_if_descr_filter_t if_filter;
591
592
593     g_assert(merged_idb_list != NULL);
594     g_assert(merged_idb_list->interface_data != NULL);
595     g_assert(input_file_idb != NULL);
596
597     wtap_optionblock_copy_options(idb, input_file_idb);
598     idb_mand = (wtapng_if_descr_mandatory_t*)wtap_optionblock_get_mandatory_data(idb);
599
600     /* Don't copy filter or stat information */
601     memset(&if_filter, 0, sizeof(if_filter));
602     wtap_optionblock_set_option_custom(idb, OPT_IDB_FILTER, &if_filter);
603
604     idb_mand->num_stat_entries      = 0;          /* Number of ISB:s */
605     idb_mand->interface_statistics  = NULL;
606
607     g_array_append_val(merged_idb_list->interface_data, idb);
608
609     return merged_idb_list->interface_data->len - 1;
610 }
611
612 /*
613  * Create clone IDBs for the merge file, based on the input files and mode.
614  */
615 static wtapng_iface_descriptions_t *
616 generate_merged_idb(merge_in_file_t *in_files, const guint in_file_count, const idb_merge_mode mode)
617 {
618     wtapng_iface_descriptions_t *merged_idb_list = NULL;
619     wtapng_iface_descriptions_t *input_file_idb_list = NULL;
620     wtap_optionblock_t           input_file_idb;
621     guint                        itf_count, merged_index;
622     guint                        i;
623
624     /* create new IDB info */
625     merged_idb_list = g_new(wtapng_iface_descriptions_t,1);
626     merged_idb_list->interface_data = g_array_new(FALSE, FALSE, sizeof(wtap_optionblock_t));
627
628     if (mode == IDB_MERGE_MODE_ALL_SAME && all_idbs_are_duplicates(in_files, in_file_count)) {
629         guint num_idbs;
630
631         merge_debug("merge::generate_merged_idb: mode ALL set and all IDBs are duplicates");
632
633         /* they're all the same, so just get the first file's IDBs */
634         input_file_idb_list = wtap_file_get_idb_info(in_files[0].wth);
635         /* this is really one more than number of IDBs, but that's good for the for-loops */
636         num_idbs = input_file_idb_list->interface_data->len;
637
638         /* put them in the merged file */
639         for (itf_count = 0; itf_count < num_idbs; itf_count++) {
640             input_file_idb = g_array_index(input_file_idb_list->interface_data,
641                                             wtap_optionblock_t, itf_count);
642             merged_index = add_idb_to_merged_file(merged_idb_list, input_file_idb);
643             add_idb_index_map(&in_files[0], itf_count, merged_index);
644         }
645
646         /* and set all the other file index maps the same way */
647         for (i = 1; i < in_file_count; i++) {
648             for (itf_count = 0; itf_count < num_idbs; itf_count++) {
649                 add_idb_index_map(&in_files[i], itf_count, itf_count);
650             }
651         }
652
653         g_free(input_file_idb_list);
654     }
655     else {
656         for (i = 0; i < in_file_count; i++) {
657             input_file_idb_list = wtap_file_get_idb_info(in_files[i].wth);
658
659             for (itf_count = 0; itf_count < input_file_idb_list->interface_data->len; itf_count++) {
660                 input_file_idb = g_array_index(input_file_idb_list->interface_data,
661                                                 wtap_optionblock_t, itf_count);
662
663                 if (mode == IDB_MERGE_MODE_ANY_SAME &&
664                     find_duplicate_idb(input_file_idb, merged_idb_list, &merged_index))
665                 {
666                     merge_debug("merge::generate_merged_idb: mode ANY set and found a duplicate");
667                     /*
668                      * It's the same as a previous IDB, so we're going to "merge"
669                      * them into one by adding a map from its old IDB index to the new
670                      * one. This will be used later to change the phdr interface_id.
671                      */
672                     add_idb_index_map(&in_files[i], itf_count, merged_index);
673                 }
674                 else {
675                     merge_debug("merge::generate_merged_idb: mode NONE set or did not find a duplicate");
676                     /*
677                      * This IDB does not match a previous (or we want to save all IDBs),
678                      * so add the IDB to the merge file, and add a map of the indeces.
679                      */
680                     merged_index = add_idb_to_merged_file(merged_idb_list, input_file_idb);
681                     add_idb_index_map(&in_files[i], itf_count, merged_index);
682                 }
683             }
684
685             g_free(input_file_idb_list);
686         }
687     }
688
689     return merged_idb_list;
690 }
691
692 static gboolean
693 map_phdr_interface_id(struct wtap_pkthdr *phdr, const merge_in_file_t *in_file)
694 {
695     guint current_interface_id = 0;
696     g_assert(phdr != NULL);
697     g_assert(in_file != NULL);
698     g_assert(in_file->idb_index_map != NULL);
699
700     if (phdr->presence_flags & WTAP_HAS_INTERFACE_ID) {
701         current_interface_id = phdr->interface_id;
702     }
703
704     if (current_interface_id >= in_file->idb_index_map->len) {
705         /* this shouldn't happen, but in a malformed input file it could */
706         merge_debug("merge::map_phdr_interface_id: current_interface_id >= in_file->idb_index_map->len (ERROR?)");
707         return FALSE;
708     }
709
710     phdr->interface_id = g_array_index(in_file->idb_index_map, guint, current_interface_id);
711     phdr->presence_flags |= WTAP_HAS_INTERFACE_ID;
712
713     return TRUE;
714 }
715
716 static gchar*
717 get_read_error_string(const merge_in_file_t *in_files, const guint in_file_count,
718                       const int *err, gchar **err_info)
719 {
720     GString *err_message = g_string_new("");
721     gchar   *display_basename = NULL;
722     guint    i;
723
724     g_assert(in_files != NULL);
725     g_assert(err != NULL);
726     g_assert(err_info != NULL);
727
728     if (*err_info == NULL) {
729         *err_info = g_strdup("no information supplied");
730     }
731
732     /*
733      * Find the file on which we got the error, and report the error.
734      */
735     for (i = 0; i < in_file_count; i++) {
736         if (in_files[i].state == GOT_ERROR) {
737             display_basename = g_filename_display_basename(in_files[i].filename);
738
739             switch (*err) {
740
741                 case WTAP_ERR_SHORT_READ:
742                     g_string_printf(err_message,
743                          "The capture file %s appears to have been cut short"
744                           " in the middle of a packet.", display_basename);
745                     break;
746
747                 case WTAP_ERR_BAD_FILE:
748                     g_string_printf(err_message,
749                          "The capture file %s appears to be damaged or corrupt.\n(%s)",
750                          display_basename, *err_info);
751                     break;
752
753                 case WTAP_ERR_DECOMPRESS:
754                     g_string_printf(err_message,
755                          "The compressed capture file %s appears to be damaged or corrupt.\n"
756                          "(%s)", display_basename, *err_info);
757                     break;
758
759                 default:
760                     g_string_printf(err_message,
761                          "An error occurred while reading the"
762                          " capture file %s: %s.",
763                          display_basename,  wtap_strerror(*err));
764                     break;
765             }
766
767             g_free(display_basename);
768             break;
769         }
770     }
771
772     g_free(*err_info);
773     *err_info = g_string_free(err_message, FALSE);
774
775     return *err_info;
776 }
777
778 static gchar*
779 get_write_error_string(const merge_in_file_t *in_file, const int file_type,
780                        const gchar* out_filename, const int *err, gchar **err_info)
781 {
782     GString *err_message = g_string_new("");
783     gchar *display_basename = NULL;
784     int write_err;
785
786     /* in_file may be NULL */
787     g_assert(err != NULL);
788     g_assert(err_info != NULL);
789
790     if (*err_info == NULL) {
791         *err_info = g_strdup("no information supplied");
792     }
793
794     write_err = *err;
795
796     display_basename = g_filename_display_basename(in_file ? in_file->filename : "UNKNOWN");
797
798     if (write_err < 0) {
799
800         switch (write_err) {
801
802             case WTAP_ERR_UNWRITABLE_ENCAP:
803                 /*
804                  * This is a problem with the particular frame we're writing and
805                  * the file type and subtype we're wwriting; note that, and
806                  * report the frame number and file type/subtype.
807                  */
808                 g_string_printf(err_message,
809                     "Frame %u of \"%s\" has a network type that can't be saved in a \"%s\" file.\n",
810                     in_file ? in_file->packet_num : 0, display_basename,
811                     wtap_file_type_subtype_string(file_type));
812                 break;
813
814             case WTAP_ERR_PACKET_TOO_LARGE:
815                 /*
816                  * This is a problem with the particular frame we're writing and
817                  * the file type and subtype we're writing; note that, and report
818                  * the frame number and file type/subtype.
819                  */
820                 g_string_printf(err_message,
821                     "Frame %u of \"%s\" is too large for a \"%s\" file.",
822                     in_file ? in_file->packet_num : 0, display_basename,
823                     wtap_file_type_subtype_string(file_type));
824                 break;
825
826             case WTAP_ERR_UNWRITABLE_REC_TYPE:
827                 /*
828                  * This is a problem with the particular record we're writing and
829                  * the file type and subtype we're writing; note that, and report
830                  * the record number and file type/subtype.
831                  */
832                 g_string_printf(err_message,
833                     "Record %u of \"%s\" has a record type that can't be saved in a \"%s\" file.",
834                     in_file ? in_file->packet_num : 0, display_basename,
835                     wtap_file_type_subtype_string(file_type));
836                 break;
837
838             case WTAP_ERR_UNWRITABLE_REC_DATA:
839                 /*
840                  * This is a problem with the particular record we're writing and
841                  * the file type and subtype we're writing; note that, and report
842                  * the frame number and file type/subtype.
843                  */
844                 g_string_printf(err_message,
845                     "Record %u of \"%s\" has data that can't be saved in a \"%s\" file.\n(%s)",
846                     in_file ? in_file->packet_num : 0, display_basename,
847                     wtap_file_type_subtype_string(file_type), *err_info);
848                 break;
849
850             default:
851                 g_string_printf(err_message,
852                     "An error occurred while writing to the file \"%s\": %s.",
853                     out_filename, wtap_strerror(write_err));
854                 break;
855         }
856     }
857     else {
858         /* OS error. */
859         g_string_printf(err_message, file_write_error_message(write_err), out_filename);
860     }
861
862     g_free(display_basename);
863     g_free(*err_info);
864     *err_info = g_string_free(err_message, FALSE);
865
866     return *err_info;
867 }
868
869
870 /*
871  * Merges the files based on given input, and invokes callback during
872  * execution. Returns MERGE_OK on success, or a MERGE_ERR_XXX on failure; note
873  * that the passed-in 'err' variable will be more specific to what failed, and
874  * err_info will have pretty output.
875  */
876 merge_result
877 merge_files(int out_fd, const gchar* out_filename, const int file_type,
878             const char *const *in_filenames, const guint in_file_count,
879             const gboolean do_append, const idb_merge_mode mode,
880             guint snaplen, const gchar *app_name, merge_progress_callback_t* cb,
881             int *err, gchar **err_info, guint *err_fileno)
882 {
883     merge_in_file_t    *in_files = NULL, *in_file = NULL;
884     int                 frame_type = WTAP_ENCAP_PER_PACKET;
885     merge_result        status = MERGE_OK;
886     wtap_dumper        *pdh;
887     struct wtap_pkthdr *phdr, snap_phdr;
888     int                 count = 0;
889     gboolean            stop_flag = FALSE;
890     GArray             *shb_hdrs = NULL;
891     wtapng_iface_descriptions_t *idb_inf = NULL;
892
893     g_assert(out_fd > 0);
894     g_assert(in_file_count > 0);
895     g_assert(in_filenames != NULL);
896     g_assert(err != NULL);
897     g_assert(err_info != NULL);
898     g_assert(err_fileno != NULL);
899
900     /* if a callback was given, it has to have a callback function ptr */
901     g_assert((cb != NULL) ? (cb->callback_func != NULL) : TRUE);
902
903     merge_debug("merge_files: begin");
904
905     /* open the input files */
906     if (!merge_open_in_files(in_file_count, in_filenames, &in_files,
907                              err, err_info, err_fileno)) {
908         merge_debug("merge_files: merge_open_in_files() failed with err=%d", *err);
909         return MERGE_ERR_CANT_OPEN_INFILE;
910     }
911
912     if (cb)
913         cb->callback_func(MERGE_EVENT_INPUT_FILES_OPENED, 0, in_files, in_file_count, cb->data);
914
915     if (snaplen == 0) {
916         /* Snapshot length not specified - default to the maximum. */
917         snaplen = WTAP_MAX_PACKET_SIZE;
918     }
919
920     /*
921      * This doesn't tell us that much. It tells us what to set the outfile's
922      * encap type to, but that's all - for example, it does *not* tells us
923      * whether the input files had the same number of IDBs, for the same exact
924      * interfaces, and only one IDB each, so it doesn't actually tell us
925      * whether we can merge IDBs into one or not.
926      */
927     frame_type = merge_select_frame_type(in_file_count, in_files);
928     merge_debug("merge_files: got frame_type=%d", frame_type);
929
930     if (cb)
931         cb->callback_func(MERGE_EVENT_FRAME_TYPE_SELECTED, frame_type, in_files, in_file_count, cb->data);
932
933     /* prepare the outfile */
934     if (file_type == WTAP_FILE_TYPE_SUBTYPE_PCAPNG) {
935         shb_hdrs = create_shb_header(in_files, in_file_count, app_name);
936         merge_debug("merge_files: SHB created");
937
938         idb_inf = generate_merged_idb(in_files, in_file_count, mode);
939         merge_debug("merge_files: IDB merge operation complete, got %u IDBs", idb_inf ? idb_inf->interface_data->len : 0);
940
941         pdh = wtap_dump_fdopen_ng(out_fd, file_type, frame_type, snaplen,
942                                   FALSE /* compressed */, shb_hdrs, idb_inf,
943                                   NULL, err);
944     }
945     else {
946         pdh = wtap_dump_fdopen(out_fd, file_type, frame_type, snaplen, FALSE /* compressed */, err);
947     }
948
949     if (pdh == NULL) {
950         merge_close_in_files(in_file_count, in_files);
951         g_free(in_files);
952         wtap_optionblock_array_free(shb_hdrs);
953         wtap_free_idb_info(idb_inf);
954         return MERGE_ERR_CANT_OPEN_OUTFILE;
955     }
956
957     if (cb)
958         cb->callback_func(MERGE_EVENT_READY_TO_MERGE, 0, in_files, in_file_count, cb->data);
959
960     for (;;) {
961         *err = 0;
962
963         if (do_append) {
964             in_file = merge_append_read_packet(in_file_count, in_files, err,
965                                                err_info);
966         }
967         else {
968             in_file = merge_read_packet(in_file_count, in_files, err,
969                                         err_info);
970         }
971
972         if (in_file == NULL) {
973             /* EOF */
974             break;
975         }
976
977         if (*err != 0) {
978             /* I/O error reading from in_file */
979             status = MERGE_ERR_CANT_READ_INFILE;
980             break;
981         }
982
983         count++;
984         if (cb)
985             stop_flag = cb->callback_func(MERGE_EVENT_PACKET_WAS_READ, count, in_files, in_file_count, cb->data);
986
987         if (stop_flag) {
988             /* The user decided to abort the merge. */
989             status = MERGE_USER_ABORTED;
990             break;
991         }
992
993         phdr = wtap_phdr(in_file->wth);
994
995         if (snaplen != 0 && phdr->caplen > snaplen) {
996             /*
997              * The dumper will only write up to caplen bytes out, so we only
998              * need to change that value, instead of cloning the whole packet
999              * with fewer bytes.
1000              *
1001              * XXX: but do we need to change the IDBs' snap_len?
1002              */
1003             snap_phdr = *phdr;
1004             snap_phdr.caplen = snaplen;
1005             phdr = &snap_phdr;
1006         }
1007
1008         if (file_type == WTAP_FILE_TYPE_SUBTYPE_PCAPNG) {
1009             if (!map_phdr_interface_id(phdr, in_file)) {
1010                 status = MERGE_ERR_BAD_PHDR_INTERFACE_ID;
1011                 break;
1012             }
1013         }
1014
1015         if (!wtap_dump(pdh, phdr, wtap_buf_ptr(in_file->wth), err, err_info)) {
1016             status = MERGE_ERR_CANT_WRITE_OUTFILE;
1017             break;
1018         }
1019     }
1020
1021     if (cb)
1022         cb->callback_func(MERGE_EVENT_DONE, count, in_files, in_file_count, cb->data);
1023
1024     merge_close_in_files(in_file_count, in_files);
1025
1026     if (status == MERGE_OK || status == MERGE_USER_ABORTED) {
1027         if (!wtap_dump_close(pdh, err))
1028             status = MERGE_ERR_CANT_CLOSE_OUTFILE;
1029     } else {
1030         /*
1031          * We already got some error; no need to report another error on
1032          * close.
1033          *
1034          * Don't overwrite the earlier error.
1035          */
1036         int close_err = 0;
1037         (void)wtap_dump_close(pdh, &close_err);
1038     }
1039
1040     if (status != MERGE_OK) {
1041         GString *err_message = NULL;
1042         gchar   *display_basename = NULL;
1043
1044         switch(status) {
1045
1046             case MERGE_ERR_CANT_READ_INFILE:
1047                 *err_info = get_read_error_string(in_files, in_file_count, err, err_info);
1048                 break;
1049
1050             case MERGE_ERR_CANT_WRITE_OUTFILE: /* fall through */
1051             case MERGE_ERR_CANT_CLOSE_OUTFILE:
1052                 *err_info = get_write_error_string(in_file, file_type, out_filename, err, err_info);
1053                 break;
1054
1055             case MERGE_ERR_BAD_PHDR_INTERFACE_ID:
1056                 display_basename = g_filename_display_basename(in_file ? in_file->filename : "UNKNOWN");
1057                 if (*err_info != NULL)
1058                     g_free(*err_info);
1059                 err_message = g_string_new("");
1060                 g_string_printf(err_message,
1061                     "Record %u of \"%s\" has an interface ID which does not match any IDB in its file.",
1062                     in_file ? in_file->packet_num : 0, display_basename);
1063                 g_free(display_basename);
1064                 *err_info = g_string_free(err_message, FALSE);
1065                 break;
1066
1067             case MERGE_USER_ABORTED: /* not really an error */
1068             default:
1069                 break;
1070         }
1071     }
1072
1073     g_free(in_files);
1074     wtap_optionblock_array_free(shb_hdrs);
1075     wtap_free_idb_info(idb_inf);
1076
1077     return status;
1078 }
1079
1080 /*
1081  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
1082  *
1083  * Local Variables:
1084  * c-basic-offset: 4
1085  * tab-width: 8
1086  * indent-tabs-mode: nil
1087  * End:
1088  *
1089  * vi: set shiftwidth=4 tabstop=8 expandtab:
1090  * :indentSize=4:tabSize=8:noTabs=true:
1091  */