2014-05-09 05:18:49 +00:00
/* Combine multiple dump files, either by appending or by merging by timestamp
2004-06-17 21:53:26 +00:00
*
* Written by Scott Renfro < scott @ renfro . org > based on
* editcap by Richard Sharpe and Guy Harris
*
2013-01-15 02:17:16 +00:00
* Copyright 2013 , Scott Renfro < scott [ AT ] renfro . org >
*
* Wireshark - Network traffic analyzer
* By Gerald Combs < gerald @ wireshark . org >
* Copyright 1998 Gerald Combs
*
2018-02-18 21:40:50 +00:00
* SPDX - License - Identifier : GPL - 2.0 - or - later
*/
2004-06-17 21:53:26 +00:00
# include "config.h"
# include <stdlib.h>
2004-10-29 00:36:52 +00:00
# include <errno.h>
2004-06-17 21:53:26 +00:00
# ifdef HAVE_UNISTD_H
# include <unistd.h>
# endif
# include <string.h>
2004-06-18 10:01:59 +00:00
# include "merge.h"
2016-01-26 01:17:21 +00:00
# include "wtap_opttypes.h"
# include "pcapng.h"
2004-06-17 21:53:26 +00:00
2015-08-16 16:37:11 +00:00
# include <wsutil/filesystem.h>
# include "wsutil/os_version_info.h"
2015-08-19 22:42:59 +00:00
#if 0
2015-10-04 14:27:02 +00:00
# define merge_debug(...) g_warning(__VA_ARGS__)
2015-08-19 20:25:54 +00:00
# else
2015-10-04 14:27:02 +00:00
# define merge_debug(...)
2015-08-19 20:25:54 +00:00
# endif
2015-08-16 16:37:11 +00:00
static const char * idb_merge_mode_strings [ ] = {
/* IDB_MERGE_MODE_NONE */
" none " ,
/* IDB_MERGE_MODE_ALL_SAME */
" all " ,
/* IDB_MERGE_MODE_ANY_SAME */
" any " ,
/* IDB_MERGE_MODE_MAX */
" UNKNOWN "
} ;
idb_merge_mode
merge_string_to_idb_merge_mode ( const char * name )
{
int i ;
for ( i = 0 ; i < IDB_MERGE_MODE_MAX ; i + + ) {
if ( g_strcmp0 ( name , idb_merge_mode_strings [ i ] ) = = 0 ) {
return ( idb_merge_mode ) i ;
}
}
return IDB_MERGE_MODE_MAX ;
}
const char *
merge_idb_merge_mode_to_string ( const int mode )
{
if ( mode > = 0 & & mode < IDB_MERGE_MODE_MAX ) {
return idb_merge_mode_strings [ mode ] ;
}
return idb_merge_mode_strings [ ( int ) IDB_MERGE_MODE_MAX ] ;
}
static void
cleanup_in_file ( merge_in_file_t * in_file )
{
g_assert ( in_file ! = NULL ) ;
wtap_close ( in_file - > wth ) ;
in_file - > wth = NULL ;
g_array_free ( in_file - > idb_index_map , TRUE ) ;
in_file - > idb_index_map = NULL ;
}
static void
add_idb_index_map ( merge_in_file_t * in_file , const guint orig_index , const guint found_index )
{
g_assert ( in_file ! = NULL ) ;
g_assert ( in_file - > idb_index_map ! = NULL ) ;
/*
* we didn ' t really need the orig_index , since just appending to the array
* should result in the orig_index being its location in the array ; but we
* pass it into this function to do a sanity check here
*/
g_assert ( orig_index = = in_file - > idb_index_map - > len ) ;
g_array_append_val ( in_file - > idb_index_map , found_index ) ;
}
2015-11-10 18:23:10 +00:00
/** Open a number of input files to merge.
*
2018-01-22 19:09:46 +00:00
* @ param in_file_count number of entries in in_file_names
2015-11-10 18:23:10 +00:00
* @ param in_file_names filenames of the input files
2018-01-22 19:09:46 +00:00
* @ param out_files output pointer with filled file array , or NULL
2015-11-10 18:23:10 +00:00
* @ param err wiretap error , if failed
* @ param err_info wiretap error string , if failed
* @ param err_fileno file on which open failed , if failed
* @ return TRUE if all files could be opened , FALSE otherwise
2004-06-17 21:53:26 +00:00
*/
2015-11-10 18:23:10 +00:00
static gboolean
2016-02-11 01:48:46 +00:00
merge_open_in_files ( guint in_file_count , const char * const * in_file_names ,
2018-01-22 19:09:46 +00:00
merge_in_file_t * * out_files , merge_progress_callback_t * cb ,
2016-12-04 01:57:34 +00:00
int * err , gchar * * err_info , guint * err_fileno )
2004-10-28 01:06:11 +00:00
{
2016-02-11 01:48:46 +00:00
guint i ;
guint j ;
2015-08-14 14:44:11 +00:00
size_t files_size = in_file_count * sizeof ( merge_in_file_t ) ;
merge_in_file_t * files ;
gint64 size ;
2004-06-17 21:53:26 +00:00
2015-08-16 16:37:11 +00:00
files = ( merge_in_file_t * ) g_malloc0 ( files_size ) ;
2018-01-22 19:09:46 +00:00
* out_files = NULL ;
2004-10-28 01:06:11 +00:00
2015-08-14 14:44:11 +00:00
for ( i = 0 ; i < in_file_count ; i + + ) {
files [ i ] . filename = in_file_names [ i ] ;
files [ i ] . wth = wtap_open_offline ( in_file_names [ i ] , WTAP_TYPE_AUTO , err , err_info , FALSE ) ;
2018-02-05 20:55:00 +00:00
files [ i ] . state = RECORD_NOT_PRESENT ;
2015-08-14 14:44:11 +00:00
files [ i ] . packet_num = 0 ;
2015-08-16 16:37:11 +00:00
2015-08-14 14:44:11 +00:00
if ( ! files [ i ] . wth ) {
/* Close the files we've already opened. */
for ( j = 0 ; j < i ; j + + )
2015-08-16 16:37:11 +00:00
cleanup_in_file ( & files [ j ] ) ;
2018-01-22 19:09:46 +00:00
g_free ( files ) ;
2015-08-14 14:44:11 +00:00
* err_fileno = i ;
return FALSE ;
}
size = wtap_file_size ( files [ i ] . wth , err ) ;
if ( size = = - 1 ) {
2016-02-11 01:48:46 +00:00
for ( j = 0 ; j ! = G_MAXUINT & & j < = i ; j + + )
2015-08-16 16:37:11 +00:00
cleanup_in_file ( & files [ j ] ) ;
2018-01-22 19:09:46 +00:00
g_free ( files ) ;
2015-08-14 14:44:11 +00:00
* err_fileno = i ;
return FALSE ;
}
files [ i ] . size = size ;
2015-08-16 16:37:11 +00:00
files [ i ] . idb_index_map = g_array_new ( FALSE , FALSE , sizeof ( guint ) ) ;
2004-10-29 00:36:52 +00:00
}
2016-12-04 01:57:34 +00:00
if ( cb )
cb - > callback_func ( MERGE_EVENT_INPUT_FILES_OPENED , 0 , files , in_file_count , cb - > data ) ;
2018-01-22 19:09:46 +00:00
* out_files = files ;
2015-08-14 14:44:11 +00:00
return TRUE ;
2004-10-28 01:06:11 +00:00
}
2004-06-17 21:53:26 +00:00
2015-11-10 18:23:10 +00:00
/** Close the input files again.
*
* @ param in_file_count number of entries in in_files
* @ param in_files input file array to be closed
2004-06-17 21:53:26 +00:00
*/
2015-11-10 18:23:10 +00:00
static void
2015-11-21 07:55:22 +00:00
merge_close_in_files ( int in_file_count , merge_in_file_t in_files [ ] )
2004-06-17 21:53:26 +00:00
{
2015-08-14 14:44:11 +00:00
int i ;
2015-11-21 07:55:22 +00:00
for ( i = 0 ; i < in_file_count ; i + + ) {
2015-08-16 16:37:11 +00:00
cleanup_in_file ( & in_files [ i ] ) ;
2015-08-14 14:44:11 +00:00
}
2004-10-28 01:06:11 +00:00
}
2004-06-17 21:53:26 +00:00
2015-11-10 18:23:10 +00:00
/** Select an output frame type based on the input files
*
* If all files have the same frame type , then use that .
* Otherwise select WTAP_ENCAP_PER_PACKET . If the selected
* output file type doesn ' t support per packet frame types ,
* then the wtap_dump_open call will fail with a reasonable
* error condition .
*
* @ param in_file_count number of entries in in_files
* @ param in_files input file array
* @ return the frame type
2004-10-28 01:06:11 +00:00
*/
2015-11-10 18:23:10 +00:00
static int
2015-11-21 07:55:22 +00:00
merge_select_frame_type ( int in_file_count , merge_in_file_t in_files [ ] )
2004-10-28 01:06:11 +00:00
{
2015-08-14 14:44:11 +00:00
int i ;
int selected_frame_type ;
2004-06-17 21:53:26 +00:00
2015-11-21 07:55:22 +00:00
selected_frame_type = wtap_file_encap ( in_files [ 0 ] . wth ) ;
2004-10-28 01:06:11 +00:00
2015-11-21 07:55:22 +00:00
for ( i = 1 ; i < in_file_count ; i + + ) {
int this_frame_type = wtap_file_encap ( in_files [ i ] . wth ) ;
2015-08-14 14:44:11 +00:00
if ( selected_frame_type ! = this_frame_type ) {
selected_frame_type = WTAP_ENCAP_PER_PACKET ;
break ;
}
2004-10-28 01:06:11 +00:00
}
2015-08-14 14:44:11 +00:00
return selected_frame_type ;
2004-10-28 01:06:11 +00:00
}
2004-06-17 21:53:26 +00:00
/*
* returns TRUE if first argument is earlier than second
*/
static gboolean
2013-11-09 10:38:02 +00:00
is_earlier ( nstime_t * l , nstime_t * r ) /* XXX, move to nstime.c */
{
2015-08-14 14:44:11 +00:00
if ( l - > secs > r - > secs ) { /* left is later */
return FALSE ;
} else if ( l - > secs < r - > secs ) { /* left is earlier */
return TRUE ;
} else if ( l - > nsecs > r - > nsecs ) { /* tv_sec equal, l.usec later */
return FALSE ;
}
/* either one < two or one == two
* either way , return one
*/
2004-06-17 21:53:26 +00:00
return TRUE ;
}
2015-11-10 18:23:10 +00:00
/** Read the next packet, in chronological order, from the set of files to
* be merged .
2011-11-21 06:26:03 +00:00
*
* On success , set * err to 0 and return a pointer to the merge_in_file_t
* for the file from which the packet was read .
*
* On a read error , set * err to the error and return a pointer to the
* merge_in_file_t for the file on which we got an error .
*
* On an EOF ( meaning all the files are at EOF ) , set * err to 0 and return
* NULL .
2015-11-10 18:23:10 +00:00
*
* @ param in_file_count number of entries in in_files
* @ param in_files input file array
* @ param err wiretap error , if failed
* @ param err_info wiretap error string , if failed
* @ return pointer to merge_in_file_t for file from which that packet
2017-12-26 18:33:22 +00:00
* came or on which we got a read error , or NULL if we ' re at EOF on
* all files
2004-06-17 21:53:26 +00:00
*/
2015-11-10 18:23:10 +00:00
static merge_in_file_t *
When reporting "sorry, *this* packet can't be written to a file of that
type" when writing out a capture file (i.e., writing a
per-packet-encapsulation capture to a file type that supports it but
doesn't support one of the packet's encapsulations), report the packet
number and, when doing this in a merge operation, report the file from
which it came.
When reporting "sorry, that file can't be written to a file of that
type, period", show the file type rather than the input file link-layer
type that causes the problem. (We could show both. We could be
*really* ambitious and iterate through all possible file types and show
the ones that will or at least might work....)
file_write_error_message() is documented as handling only UNIX-style
errnos, and libwireshark should be usable without libwiretap, so leave
it up to its callers to handle Wiretap errors such as
WTAP_ERR_SHORT_WRITE.
Clean up indentation.
svn path=/trunk/; revision=39949
2011-11-19 20:18:01 +00:00
merge_read_packet ( int in_file_count , merge_in_file_t in_files [ ] ,
int * err , gchar * * err_info )
2004-10-29 00:36:52 +00:00
{
2015-08-14 14:44:11 +00:00
int i ;
int ei = - 1 ;
2018-06-28 03:39:15 +00:00
nstime_t tv = NSTIME_INIT_MAX ;
2018-02-09 00:19:12 +00:00
wtap_rec * rec ;
2004-06-17 21:53:26 +00:00
2015-08-14 14:44:11 +00:00
/*
2018-02-05 21:26:40 +00:00
* Make sure we have a record available from each file that ' s not at
* EOF , and search for the record with the earliest time stamp or
* with no time stamp ( those records are treated as earlier than
* all other records ) . Yes , this means you won ' t get a chronological
* merge of those records , but you obviously * can ' t * get that .
2015-08-14 14:44:11 +00:00
*/
for ( i = 0 ; i < in_file_count ; i + + ) {
2018-02-08 03:27:40 +00:00
gint64 data_offset ;
2018-02-08 03:25:35 +00:00
2018-02-05 20:55:00 +00:00
if ( in_files [ i ] . state = = RECORD_NOT_PRESENT ) {
2015-08-14 14:44:11 +00:00
/*
* No packet available , and we haven ' t seen an error or EOF yet ,
* so try to read the next packet .
*/
2018-02-08 03:25:35 +00:00
if ( ! wtap_read ( in_files [ i ] . wth , err , err_info , & data_offset ) ) {
2015-08-14 14:44:11 +00:00
if ( * err ! = 0 ) {
in_files [ i ] . state = GOT_ERROR ;
return & in_files [ i ] ;
}
in_files [ i ] . state = AT_EOF ;
} else
2018-02-05 20:55:00 +00:00
in_files [ i ] . state = RECORD_PRESENT ;
2004-10-29 00:36:52 +00:00
}
2013-01-15 02:17:16 +00:00
2018-02-05 20:55:00 +00:00
if ( in_files [ i ] . state = = RECORD_PRESENT ) {
2018-02-09 00:19:12 +00:00
rec = wtap_get_rec ( in_files [ i ] . wth ) ;
if ( ! ( rec - > presence_flags & WTAP_HAS_TS ) ) {
2018-02-05 21:26:40 +00:00
/*
* No time stamp . Pick this record , and stop looking .
*/
ei = i ;
break ;
}
2018-02-09 00:19:12 +00:00
if ( is_earlier ( & rec - > ts , & tv ) ) {
2018-02-05 21:26:40 +00:00
/*
* This record ' s time stamp is earlier than any of the
* records we ' ve seen so far . Pick it , for now , but
* keep looking .
*/
2018-02-09 00:19:12 +00:00
tv = rec - > ts ;
2015-08-14 14:44:11 +00:00
ei = i ;
}
}
2004-06-17 21:53:26 +00:00
}
2015-08-14 14:44:11 +00:00
if ( ei = = - 1 ) {
/* All the streams are at EOF. Return an EOF indication. */
* err = 0 ;
return NULL ;
}
2004-06-17 21:53:26 +00:00
2015-08-14 14:44:11 +00:00
/* We'll need to read another packet from this file. */
2018-02-05 20:55:00 +00:00
in_files [ ei ] . state = RECORD_NOT_PRESENT ;
2004-06-17 21:53:26 +00:00
2015-08-14 14:44:11 +00:00
/* Count this packet. */
in_files [ ei ] . packet_num + + ;
When reporting "sorry, *this* packet can't be written to a file of that
type" when writing out a capture file (i.e., writing a
per-packet-encapsulation capture to a file type that supports it but
doesn't support one of the packet's encapsulations), report the packet
number and, when doing this in a merge operation, report the file from
which it came.
When reporting "sorry, that file can't be written to a file of that
type, period", show the file type rather than the input file link-layer
type that causes the problem. (We could show both. We could be
*really* ambitious and iterate through all possible file types and show
the ones that will or at least might work....)
file_write_error_message() is documented as handling only UNIX-style
errnos, and libwireshark should be usable without libwiretap, so leave
it up to its callers to handle Wiretap errors such as
WTAP_ERR_SHORT_WRITE.
Clean up indentation.
svn path=/trunk/; revision=39949
2011-11-19 20:18:01 +00:00
2015-08-14 14:44:11 +00:00
/*
* Return a pointer to the merge_in_file_t of the file from which the
* packet was read .
*/
* err = 0 ;
return & in_files [ ei ] ;
2004-06-17 21:53:26 +00:00
}
2015-11-10 18:23:10 +00:00
/** Read the next packet, in file sequence order, from the set of files
2011-11-21 06:26:03 +00:00
* to be merged .
*
* On success , set * err to 0 and return a pointer to the merge_in_file_t
* for the file from which the packet was read .
*
* On a read error , set * err to the error and return a pointer to the
* merge_in_file_t for the file on which we got an error .
*
* On an EOF ( meaning all the files are at EOF ) , set * err to 0 and return
* NULL .
2015-11-10 18:23:10 +00:00
*
* @ param in_file_count number of entries in in_files
* @ param in_files input file array
* @ param err wiretap error , if failed
* @ param err_info wiretap error string , if failed
* @ return pointer to merge_in_file_t for file from which that packet
2017-12-26 18:33:22 +00:00
* came or on which we got a read error , or NULL if we ' re at EOF on
* all files
2004-06-17 21:53:26 +00:00
*/
2015-11-10 18:23:10 +00:00
static merge_in_file_t *
2004-10-29 00:36:52 +00:00
merge_append_read_packet ( int in_file_count , merge_in_file_t in_files [ ] ,
int * err , gchar * * err_info )
2004-06-17 21:53:26 +00:00
{
2015-08-14 14:44:11 +00:00
int i ;
2018-02-08 03:25:35 +00:00
gint64 data_offset ;
2004-06-17 21:53:26 +00:00
2015-08-14 14:44:11 +00:00
/*
* Find the first file not at EOF , and read the next packet from it .
*/
for ( i = 0 ; i < in_file_count ; i + + ) {
if ( in_files [ i ] . state = = AT_EOF )
continue ; /* This file is already at EOF */
2018-02-08 03:25:35 +00:00
if ( wtap_read ( in_files [ i ] . wth , err , err_info , & data_offset ) )
2015-08-14 14:44:11 +00:00
break ; /* We have a packet */
if ( * err ! = 0 ) {
/* Read error - quit immediately. */
in_files [ i ] . state = GOT_ERROR ;
return & in_files [ i ] ;
}
/* EOF - flag this file as being at EOF, and try the next one. */
in_files [ i ] . state = AT_EOF ;
2004-10-29 00:36:52 +00:00
}
2015-08-14 14:44:11 +00:00
if ( i = = in_file_count ) {
/* All the streams are at EOF. Return an EOF indication. */
* err = 0 ;
return NULL ;
}
/*
* Return a pointer to the merge_in_file_t of the file from which the
* packet was read .
*/
2004-10-29 00:36:52 +00:00
* err = 0 ;
2015-08-14 14:44:11 +00:00
return & in_files [ i ] ;
2015-08-16 16:37:11 +00:00
}
/* creates a section header block for the new output file */
2016-05-31 03:42:41 +00:00
static GArray *
2015-08-16 16:37:11 +00:00
create_shb_header ( const merge_in_file_t * in_files , const guint in_file_count ,
const gchar * app_name )
{
2016-05-31 03:42:41 +00:00
GArray * shb_hdrs ;
2016-07-14 23:01:57 +00:00
wtap_block_t shb_hdr ;
2015-08-16 16:37:11 +00:00
GString * comment_gstr ;
GString * os_info_str ;
guint i ;
2016-01-26 01:17:21 +00:00
char * shb_comment = NULL ;
wtapng_mandatory_section_t * shb_data ;
2016-05-20 02:28:43 +00:00
gsize opt_len ;
2016-07-26 11:58:55 +00:00
gchar * opt_str ;
2015-08-16 16:37:11 +00:00
2016-05-31 03:42:41 +00:00
shb_hdrs = wtap_file_get_shb_for_new_file ( in_files [ 0 ] . wth ) ;
2016-07-14 23:01:57 +00:00
shb_hdr = g_array_index ( shb_hdrs , wtap_block_t , 0 ) ;
2015-08-16 16:37:11 +00:00
comment_gstr = g_string_new ( " " ) ;
2016-07-14 23:01:57 +00:00
/*
* TODO : merge comments from all files
*
* XXX - do we want some way to record which comments , hardware / OS / app
* descriptions , IDBs , etc . ? came from which files ?
*
* XXX - fix this to handle multiple comments from a single file .
*/
if ( wtap_block_get_nth_string_option_value ( shb_hdr , OPT_COMMENT , 0 , & shb_comment ) = = WTAP_OPTTYPE_SUCCESS & &
2016-07-21 00:27:36 +00:00
strlen ( shb_comment ) > 0 ) {
2016-07-14 23:01:57 +00:00
/* very lame way to save comments - does not save them from the other files */
2016-01-26 01:17:21 +00:00
g_string_append_printf ( comment_gstr , " %s \n " , shb_comment ) ;
2015-08-16 16:37:11 +00:00
}
g_string_append_printf ( comment_gstr , " File created by merging: \n " ) ;
for ( i = 0 ; i < in_file_count ; i + + ) {
g_string_append_printf ( comment_gstr , " File%d: %s \n " , i + 1 , in_files [ i ] . filename ) ;
}
os_info_str = g_string_new ( " " ) ;
get_os_version_info ( os_info_str ) ;
2016-07-14 23:01:57 +00:00
shb_data = ( wtapng_mandatory_section_t * ) wtap_block_get_mandatory_data ( shb_hdr ) ;
2016-01-26 01:17:21 +00:00
shb_data - > section_length = - 1 ;
2015-08-16 16:37:11 +00:00
/* TODO: handle comments from each file being merged */
2016-05-20 02:28:43 +00:00
opt_len = comment_gstr - > len ;
2016-10-27 21:41:51 +00:00
opt_str = g_string_free ( comment_gstr , FALSE ) ;
wtap_block_set_nth_string_option_value ( shb_hdr , OPT_COMMENT , 0 , opt_str , opt_len ) ; /* section comment */
g_free ( opt_str ) ;
2016-07-14 23:01:57 +00:00
/*
* XXX - and how do we preserve all the OPT_SHB_HARDWARE , OPT_SHB_OS ,
* and OPT_SHB_USERAPPL values from all the previous files ?
*/
2016-07-21 02:53:33 +00:00
wtap_block_remove_option ( shb_hdr , OPT_SHB_HARDWARE ) ;
2016-05-20 02:28:43 +00:00
opt_len = os_info_str - > len ;
2016-07-26 11:58:55 +00:00
opt_str = g_string_free ( os_info_str , FALSE ) ;
if ( opt_str ) {
wtap_block_set_string_option_value ( shb_hdr , OPT_SHB_OS , opt_str , opt_len ) ; /* UTF-8 string containing the name */
/* of the operating system used to create this section. */
g_free ( opt_str ) ;
2016-07-27 21:31:21 +00:00
} else {
/*
* No OS information ; remove the old version .
*/
wtap_block_remove_option ( shb_hdr , OPT_SHB_OS ) ;
2016-07-26 11:58:55 +00:00
}
2016-12-04 02:54:15 +00:00
wtap_block_set_string_option_value ( shb_hdr , OPT_SHB_USERAPPL , app_name , app_name ? strlen ( app_name ) : 0 ) ; /* NULL if not available, UTF-8 string containing the name */
2016-01-26 01:17:21 +00:00
/* of the application used to create this section. */
2015-08-16 16:37:11 +00:00
2016-05-31 03:42:41 +00:00
return shb_hdrs ;
2015-08-16 16:37:11 +00:00
}
static gboolean
2016-07-14 23:01:57 +00:00
is_duplicate_idb ( const wtap_block_t idb1 , const wtap_block_t idb2 )
2015-08-16 16:37:11 +00:00
{
2016-01-26 01:17:21 +00:00
wtapng_if_descr_mandatory_t * idb1_mand , * idb2_mand ;
2016-07-14 23:01:57 +00:00
gboolean have_idb1_value , have_idb2_value ;
2016-01-26 01:17:21 +00:00
guint64 idb1_if_speed , idb2_if_speed ;
guint8 idb1_if_tsresol , idb2_if_tsresol ;
guint8 idb1_if_fcslen , idb2_if_fcslen ;
2018-08-11 02:08:40 +00:00
char * idb1_opt_comment , * idb2_opt_comment ;
char * idb1_if_name , * idb2_if_name ;
char * idb1_if_description , * idb2_if_description ;
char * idb1_if_hardware , * idb2_if_hardware ;
char * idb1_if_os , * idb2_if_os ;
2016-01-26 01:17:21 +00:00
2015-08-16 16:37:11 +00:00
g_assert ( idb1 & & idb2 ) ;
2016-07-14 23:01:57 +00:00
idb1_mand = ( wtapng_if_descr_mandatory_t * ) wtap_block_get_mandatory_data ( idb1 ) ;
idb2_mand = ( wtapng_if_descr_mandatory_t * ) wtap_block_get_mandatory_data ( idb2 ) ;
2015-08-16 16:37:11 +00:00
2015-10-04 14:27:02 +00:00
merge_debug ( " merge::is_duplicate_idb() called " ) ;
2016-01-26 01:17:21 +00:00
merge_debug ( " idb1_mand->wtap_encap == idb2_mand->wtap_encap: %s " ,
( idb1_mand - > wtap_encap = = idb2_mand - > wtap_encap ) ? " TRUE " : " FALSE " ) ;
2016-07-15 07:29:41 +00:00
if ( idb1_mand - > wtap_encap ! = idb2_mand - > wtap_encap ) {
/* Clearly not the same interface. */
merge_debug ( " merge::is_duplicate_idb() returning FALSE " ) ;
return FALSE ;
}
merge_debug ( " idb1_mand->time_units_per_second == idb2_mand->time_units_per_second: %s " ,
( idb1_mand - > time_units_per_second = = idb2_mand - > time_units_per_second ) ? " TRUE " : " FALSE " ) ;
if ( idb1_mand - > time_units_per_second ! = idb2_mand - > time_units_per_second ) {
/*
* Probably not the same interface , and we can ' t combine them
* in any case .
*/
merge_debug ( " merge::is_duplicate_idb() returning FALSE " ) ;
return FALSE ;
}
merge_debug ( " idb1_mand->tsprecision == idb2_mand->tsprecision: %s " ,
( idb1_mand - > tsprecision = = idb2_mand - > tsprecision ) ? " TRUE " : " FALSE " ) ;
if ( idb1_mand - > tsprecision ! = idb2_mand - > tsprecision ) {
2016-07-14 23:01:57 +00:00
/*
* Probably not the same interface , and we can ' t combine them
* in any case .
*/
merge_debug ( " merge::is_duplicate_idb() returning FALSE " ) ;
return FALSE ;
}
/* XXX: should snaplen not be compared? */
2016-07-15 07:29:41 +00:00
merge_debug ( " idb1_mand->snap_len == idb2_mand->snap_len: %s " ,
( idb1_mand - > snap_len = = idb2_mand - > snap_len ) ? " TRUE " : " FALSE " ) ;
if ( idb1_mand - > snap_len ! = idb2_mand - > snap_len ) {
2016-07-14 23:01:57 +00:00
merge_debug ( " merge::is_duplicate_idb() returning FALSE " ) ;
return FALSE ;
}
/* XXX - what do to if we have only one value? */
have_idb1_value = ( wtap_block_get_uint64_option_value ( idb1 , OPT_IDB_SPEED , & idb1_if_speed ) = = WTAP_OPTTYPE_SUCCESS ) ;
have_idb2_value = ( wtap_block_get_uint64_option_value ( idb2 , OPT_IDB_SPEED , & idb2_if_speed ) = = WTAP_OPTTYPE_SUCCESS ) ;
if ( have_idb1_value & & have_idb2_value ) {
merge_debug ( " idb1_if_speed == idb2_if_speed: %s " ,
( idb1_if_speed = = idb2_if_speed ) ? " TRUE " : " FALSE " ) ;
if ( idb1_if_speed ! = idb2_if_speed ) {
merge_debug ( " merge::is_duplicate_idb() returning FALSE " ) ;
return FALSE ;
}
}
/* XXX - what do to if we have only one value? */
have_idb1_value = ( wtap_block_get_uint8_option_value ( idb1 , OPT_IDB_TSRESOL , & idb1_if_tsresol ) = = WTAP_OPTTYPE_SUCCESS ) ;
have_idb2_value = ( wtap_block_get_uint8_option_value ( idb2 , OPT_IDB_TSRESOL , & idb2_if_tsresol ) = = WTAP_OPTTYPE_SUCCESS ) ;
if ( have_idb1_value & & have_idb2_value ) {
merge_debug ( " idb1_if_tsresol == idb2_if_tsresol: %s " ,
( idb1_if_tsresol = = idb2_if_tsresol ) ? " TRUE " : " FALSE " ) ;
if ( idb1_if_tsresol ! = idb2_if_tsresol ) {
merge_debug ( " merge::is_duplicate_idb() returning FALSE " ) ;
return FALSE ;
}
}
/* XXX - what do to if we have only one value? */
have_idb1_value = ( wtap_block_get_uint8_option_value ( idb1 , OPT_IDB_FCSLEN , & idb1_if_fcslen ) = = WTAP_OPTTYPE_SUCCESS ) ;
have_idb2_value = ( wtap_block_get_uint8_option_value ( idb2 , OPT_IDB_FCSLEN , & idb2_if_fcslen ) = = WTAP_OPTTYPE_SUCCESS ) ;
if ( have_idb1_value & & have_idb2_value ) {
merge_debug ( " idb1_if_fcslen == idb2_if_fcslen: %s " ,
( idb1_if_fcslen = = idb2_if_fcslen ) ? " TRUE " : " FALSE " ) ;
if ( idb1_if_fcslen = = idb2_if_fcslen ) {
merge_debug ( " merge::is_duplicate_idb() returning FALSE " ) ;
return FALSE ;
}
}
/*
* XXX - handle multiple comments ?
* XXX - if the comments are different , just combine them if we
* decide the two interfaces are really the same ? As comments
* can be arbitrary strings added by people , the fact that they ' re
* different doesn ' t necessarily mean the interfaces are different .
*/
have_idb1_value = ( wtap_block_get_nth_string_option_value ( idb1 , OPT_COMMENT , 0 , & idb1_opt_comment ) = = WTAP_OPTTYPE_SUCCESS ) ;
have_idb2_value = ( wtap_block_get_nth_string_option_value ( idb2 , OPT_COMMENT , 0 , & idb2_opt_comment ) = = WTAP_OPTTYPE_SUCCESS ) ;
if ( have_idb1_value & & have_idb2_value ) {
merge_debug ( " g_strcmp0(idb1_opt_comment, idb2_opt_comment) == 0: %s " ,
( g_strcmp0 ( idb1_opt_comment , idb2_opt_comment ) = = 0 ) ? " TRUE " : " FALSE " ) ;
if ( g_strcmp0 ( idb1_opt_comment , idb2_opt_comment ) ! = 0 ) {
merge_debug ( " merge::is_duplicate_idb() returning FALSE " ) ;
return FALSE ;
}
}
/* XXX - what do to if we have only one value? */
have_idb1_value = ( wtap_block_get_string_option_value ( idb1 , OPT_IDB_NAME , & idb1_if_name ) = = WTAP_OPTTYPE_SUCCESS ) ;
have_idb2_value = ( wtap_block_get_string_option_value ( idb2 , OPT_IDB_NAME , & idb2_if_name ) = = WTAP_OPTTYPE_SUCCESS ) ;
if ( have_idb1_value & & have_idb2_value ) {
merge_debug ( " g_strcmp0(idb1_if_name, idb2_if_name) == 0: %s " ,
( g_strcmp0 ( idb1_if_name , idb2_if_name ) = = 0 ) ? " TRUE " : " FALSE " ) ;
if ( g_strcmp0 ( idb1_if_name , idb2_if_name ) ! = 0 ) {
merge_debug ( " merge::is_duplicate_idb() returning FALSE " ) ;
return FALSE ;
}
}
/* XXX - what do to if we have only one value? */
have_idb1_value = ( wtap_block_get_string_option_value ( idb1 , OPT_IDB_DESCR , & idb1_if_description ) = = WTAP_OPTTYPE_SUCCESS ) ;
have_idb2_value = ( wtap_block_get_string_option_value ( idb2 , OPT_IDB_DESCR , & idb2_if_description ) = = WTAP_OPTTYPE_SUCCESS ) ;
if ( have_idb1_value & & have_idb2_value ) {
merge_debug ( " g_strcmp0(idb1_if_description, idb2_if_description) == 0: %s " ,
( g_strcmp0 ( idb1_if_description , idb2_if_description ) = = 0 ) ? " TRUE " : " FALSE " ) ;
if ( g_strcmp0 ( idb1_if_description , idb2_if_description ) ! = 0 ) {
merge_debug ( " merge::is_duplicate_idb() returning FALSE " ) ;
return FALSE ;
}
}
2018-08-11 02:08:40 +00:00
/* XXX - what do to if we have only one value? */
have_idb1_value = ( wtap_block_get_string_option_value ( idb1 , OPT_IDB_HARDWARE , & idb1_if_hardware ) = = WTAP_OPTTYPE_SUCCESS ) ;
have_idb2_value = ( wtap_block_get_string_option_value ( idb2 , OPT_IDB_HARDWARE , & idb2_if_hardware ) = = WTAP_OPTTYPE_SUCCESS ) ;
if ( have_idb1_value & & have_idb2_value ) {
merge_debug ( " g_strcmp0(idb1_if_hardware, idb2_if_hardware) == 0: %s " ,
( g_strcmp0 ( idb1_if_hardware , idb2_if_hardware ) = = 0 ) ? " TRUE " : " FALSE " ) ;
if ( g_strcmp0 ( idb1_if_hardware , idb2_if_hardware ) ! = 0 ) {
merge_debug ( " merge::is_duplicate_idb() returning FALSE " ) ;
return FALSE ;
}
}
2016-07-14 23:01:57 +00:00
/* XXX - what do to if we have only one value? */
have_idb1_value = ( wtap_block_get_string_option_value ( idb1 , OPT_IDB_OS , & idb1_if_os ) = = WTAP_OPTTYPE_SUCCESS ) ;
have_idb2_value = ( wtap_block_get_string_option_value ( idb2 , OPT_IDB_OS , & idb2_if_os ) = = WTAP_OPTTYPE_SUCCESS ) ;
if ( have_idb1_value & & have_idb2_value ) {
merge_debug ( " g_strcmp0(idb1_if_os, idb2_if_os) == 0: %s " ,
( g_strcmp0 ( idb1_if_os , idb2_if_os ) = = 0 ) ? " TRUE " : " FALSE " ) ;
if ( g_strcmp0 ( idb1_if_os , idb2_if_os ) ! = 0 ) {
merge_debug ( " merge::is_duplicate_idb() returning FALSE " ) ;
return FALSE ;
}
}
2015-08-19 21:59:27 +00:00
2015-08-16 16:37:11 +00:00
/* does not compare filters nor interface statistics */
2016-07-14 23:01:57 +00:00
merge_debug ( " merge::is_duplicate_idb() returning TRUE " ) ;
return TRUE ;
2015-08-16 16:37:11 +00:00
}
/*
* Returns true if all of the input files have duplicate IDBs to the other files .
*/
static gboolean
all_idbs_are_duplicates ( const merge_in_file_t * in_files , const guint in_file_count )
{
2015-08-20 18:38:35 +00:00
wtapng_iface_descriptions_t * first_idb_list = NULL ;
wtapng_iface_descriptions_t * other_idb_list = NULL ;
2015-08-16 16:37:11 +00:00
guint first_idb_list_size , other_idb_list_size ;
2016-07-14 23:01:57 +00:00
wtap_block_t first_file_idb , other_file_idb ;
2015-08-16 16:37:11 +00:00
guint i , j ;
g_assert ( in_files ! = NULL ) ;
/* get the first file's info */
first_idb_list = wtap_file_get_idb_info ( in_files [ 0 ] . wth ) ;
g_assert ( first_idb_list - > interface_data ) ;
first_idb_list_size = first_idb_list - > interface_data - > len ;
/* now compare the other input files with that */
for ( i = 1 ; i < in_file_count ; i + + ) {
other_idb_list = wtap_file_get_idb_info ( in_files [ i ] . wth ) ;
g_assert ( other_idb_list - > interface_data ) ;
other_idb_list_size = other_idb_list - > interface_data - > len ;
if ( other_idb_list_size ! = first_idb_list_size ) {
2015-10-04 14:27:02 +00:00
merge_debug ( " merge::all_idbs_are_duplicates: sizes of IDB lists don't match: first=%u, other=%u " ,
2015-08-19 20:25:54 +00:00
first_idb_list_size , other_idb_list_size ) ;
2015-08-20 18:38:35 +00:00
g_free ( other_idb_list ) ;
g_free ( first_idb_list ) ;
2015-08-16 16:37:11 +00:00
return FALSE ;
}
for ( j = 0 ; j < other_idb_list_size ; j + + ) {
2016-07-14 23:01:57 +00:00
first_file_idb = g_array_index ( first_idb_list - > interface_data , wtap_block_t , j ) ;
other_file_idb = g_array_index ( other_idb_list - > interface_data , wtap_block_t , j ) ;
2015-08-16 16:37:11 +00:00
if ( ! is_duplicate_idb ( first_file_idb , other_file_idb ) ) {
2015-10-04 14:27:02 +00:00
merge_debug ( " merge::all_idbs_are_duplicates: IDBs at index %d do not match, returning FALSE " , j ) ;
2015-08-20 18:38:35 +00:00
g_free ( other_idb_list ) ;
g_free ( first_idb_list ) ;
2015-08-16 16:37:11 +00:00
return FALSE ;
}
}
2015-08-20 18:38:35 +00:00
g_free ( other_idb_list ) ;
2015-08-16 16:37:11 +00:00
}
2015-10-04 14:27:02 +00:00
merge_debug ( " merge::all_idbs_are_duplicates: returning TRUE " ) ;
2015-08-19 20:25:54 +00:00
2015-08-20 18:38:35 +00:00
g_free ( first_idb_list ) ;
2015-08-16 16:37:11 +00:00
return TRUE ;
}
/*
* Returns true if the given input_file_idb is a duplicate of an existing one
* in the merged_idb_list ; it ' s a duplicate if the interface description data
* is all identical to a previous one in another input file . For this
* function , the input file IDB ' s index does NOT need to match the index
* location of a previous one to be considered a duplicate ; any match is
* considered a success . That means it will even match another IDB from its
* own ( same ) input file .
*/
static gboolean
2016-07-14 23:01:57 +00:00
find_duplicate_idb ( const wtap_block_t input_file_idb ,
2015-08-16 16:37:11 +00:00
const wtapng_iface_descriptions_t * merged_idb_list ,
guint * found_index )
{
2016-07-14 23:01:57 +00:00
wtap_block_t merged_idb ;
2015-08-16 16:37:11 +00:00
guint i ;
g_assert ( input_file_idb ! = NULL ) ;
g_assert ( merged_idb_list ! = NULL ) ;
g_assert ( merged_idb_list - > interface_data ! = NULL ) ;
g_assert ( found_index ! = NULL ) ;
for ( i = 0 ; i < merged_idb_list - > interface_data - > len ; i + + ) {
2016-07-14 23:01:57 +00:00
merged_idb = g_array_index ( merged_idb_list - > interface_data , wtap_block_t , i ) ;
2015-08-16 16:37:11 +00:00
if ( is_duplicate_idb ( input_file_idb , merged_idb ) ) {
* found_index = i ;
return TRUE ;
}
}
return FALSE ;
}
/* adds IDB to merged file info, returns its index */
static guint
add_idb_to_merged_file ( wtapng_iface_descriptions_t * merged_idb_list ,
2016-07-14 23:01:57 +00:00
const wtap_block_t input_file_idb )
2015-08-16 16:37:11 +00:00
{
2016-07-14 23:01:57 +00:00
wtap_block_t idb = wtap_block_create ( WTAP_BLOCK_IF_DESCR ) ;
2016-01-26 01:17:21 +00:00
wtapng_if_descr_mandatory_t * idb_mand ;
2015-08-16 16:37:11 +00:00
g_assert ( merged_idb_list ! = NULL ) ;
g_assert ( merged_idb_list - > interface_data ! = NULL ) ;
g_assert ( input_file_idb ! = NULL ) ;
2016-07-14 23:01:57 +00:00
wtap_block_copy ( idb , input_file_idb ) ;
idb_mand = ( wtapng_if_descr_mandatory_t * ) wtap_block_get_mandatory_data ( idb ) ;
2016-01-26 01:17:21 +00:00
/* Don't copy filter or stat information */
idb_mand - > num_stat_entries = 0 ; /* Number of ISB:s */
idb_mand - > interface_statistics = NULL ;
2015-08-16 16:37:11 +00:00
g_array_append_val ( merged_idb_list - > interface_data , idb ) ;
return merged_idb_list - > interface_data - > len - 1 ;
}
/*
* Create clone IDBs for the merge file , based on the input files and mode .
*/
static wtapng_iface_descriptions_t *
generate_merged_idb ( merge_in_file_t * in_files , const guint in_file_count , const idb_merge_mode mode )
{
wtapng_iface_descriptions_t * merged_idb_list = NULL ;
wtapng_iface_descriptions_t * input_file_idb_list = NULL ;
2016-07-14 23:01:57 +00:00
wtap_block_t input_file_idb ;
2015-08-16 16:37:11 +00:00
guint itf_count , merged_index ;
guint i ;
/* create new IDB info */
merged_idb_list = g_new ( wtapng_iface_descriptions_t , 1 ) ;
2016-07-14 23:01:57 +00:00
merged_idb_list - > interface_data = g_array_new ( FALSE , FALSE , sizeof ( wtap_block_t ) ) ;
2015-08-16 16:37:11 +00:00
if ( mode = = IDB_MERGE_MODE_ALL_SAME & & all_idbs_are_duplicates ( in_files , in_file_count ) ) {
guint num_idbs ;
2015-08-19 20:25:54 +00:00
2015-10-04 14:27:02 +00:00
merge_debug ( " merge::generate_merged_idb: mode ALL set and all IDBs are duplicates " ) ;
2015-08-19 20:25:54 +00:00
2015-08-16 16:37:11 +00:00
/* they're all the same, so just get the first file's IDBs */
input_file_idb_list = wtap_file_get_idb_info ( in_files [ 0 ] . wth ) ;
/* this is really one more than number of IDBs, but that's good for the for-loops */
num_idbs = input_file_idb_list - > interface_data - > len ;
/* put them in the merged file */
for ( itf_count = 0 ; itf_count < num_idbs ; itf_count + + ) {
2016-01-26 01:17:21 +00:00
input_file_idb = g_array_index ( input_file_idb_list - > interface_data ,
2016-07-14 23:01:57 +00:00
wtap_block_t , itf_count ) ;
2015-08-16 16:37:11 +00:00
merged_index = add_idb_to_merged_file ( merged_idb_list , input_file_idb ) ;
add_idb_index_map ( & in_files [ 0 ] , itf_count , merged_index ) ;
}
/* and set all the other file index maps the same way */
for ( i = 1 ; i < in_file_count ; i + + ) {
for ( itf_count = 0 ; itf_count < num_idbs ; itf_count + + ) {
add_idb_index_map ( & in_files [ i ] , itf_count , itf_count ) ;
}
}
g_free ( input_file_idb_list ) ;
}
else {
for ( i = 0 ; i < in_file_count ; i + + ) {
input_file_idb_list = wtap_file_get_idb_info ( in_files [ i ] . wth ) ;
for ( itf_count = 0 ; itf_count < input_file_idb_list - > interface_data - > len ; itf_count + + ) {
2016-01-26 01:17:21 +00:00
input_file_idb = g_array_index ( input_file_idb_list - > interface_data ,
2016-07-14 23:01:57 +00:00
wtap_block_t , itf_count ) ;
2015-08-16 16:37:11 +00:00
if ( mode = = IDB_MERGE_MODE_ANY_SAME & &
find_duplicate_idb ( input_file_idb , merged_idb_list , & merged_index ) )
{
2015-10-04 14:27:02 +00:00
merge_debug ( " merge::generate_merged_idb: mode ANY set and found a duplicate " ) ;
2015-08-16 16:37:11 +00:00
/*
* It ' s the same as a previous IDB , so we ' re going to " merge "
* them into one by adding a map from its old IDB index to the new
2018-02-09 00:19:12 +00:00
* one . This will be used later to change the rec interface_id .
2015-08-16 16:37:11 +00:00
*/
add_idb_index_map ( & in_files [ i ] , itf_count , merged_index ) ;
}
else {
2015-10-04 14:27:02 +00:00
merge_debug ( " merge::generate_merged_idb: mode NONE set or did not find a duplicate " ) ;
2015-08-16 16:37:11 +00:00
/*
* This IDB does not match a previous ( or we want to save all IDBs ) ,
* so add the IDB to the merge file , and add a map of the indeces .
*/
merged_index = add_idb_to_merged_file ( merged_idb_list , input_file_idb ) ;
add_idb_index_map ( & in_files [ i ] , itf_count , merged_index ) ;
}
}
g_free ( input_file_idb_list ) ;
}
}
return merged_idb_list ;
}
static gboolean
2018-02-09 00:19:12 +00:00
map_rec_interface_id ( wtap_rec * rec , const merge_in_file_t * in_file )
2015-08-16 16:37:11 +00:00
{
guint current_interface_id = 0 ;
2018-02-09 00:19:12 +00:00
g_assert ( rec ! = NULL ) ;
2015-08-16 16:37:11 +00:00
g_assert ( in_file ! = NULL ) ;
g_assert ( in_file - > idb_index_map ! = NULL ) ;
2018-02-09 00:19:12 +00:00
if ( rec - > presence_flags & WTAP_HAS_INTERFACE_ID ) {
current_interface_id = rec - > rec_header . packet_header . interface_id ;
2015-08-16 16:37:11 +00:00
}
if ( current_interface_id > = in_file - > idb_index_map - > len ) {
/* this shouldn't happen, but in a malformed input file it could */
2018-02-09 00:19:12 +00:00
merge_debug ( " merge::map_rec_interface_id: current_interface_id (%u) >= in_file->idb_index_map->len (%u) (ERROR?) " ,
2016-04-24 18:21:50 +00:00
current_interface_id , in_file - > idb_index_map - > len ) ;
2015-08-16 16:37:11 +00:00
return FALSE ;
}
2018-02-09 00:19:12 +00:00
rec - > rec_header . packet_header . interface_id = g_array_index ( in_file - > idb_index_map , guint , current_interface_id ) ;
rec - > presence_flags | = WTAP_HAS_INTERFACE_ID ;
2015-08-16 16:37:11 +00:00
return TRUE ;
}
2016-12-04 01:57:34 +00:00
static merge_result
2017-04-20 20:25:21 +00:00
merge_process_packets ( wtap_dumper * pdh , const int file_type ,
2016-12-04 01:57:34 +00:00
merge_in_file_t * in_files , const guint in_file_count ,
const gboolean do_append , guint snaplen ,
merge_progress_callback_t * cb ,
2017-04-20 20:25:21 +00:00
int * err , gchar * * err_info , guint * err_fileno ,
guint32 * err_framenum )
2015-08-16 16:37:11 +00:00
{
merge_result status = MERGE_OK ;
2016-12-04 01:57:34 +00:00
merge_in_file_t * in_file ;
2015-08-16 16:37:11 +00:00
int count = 0 ;
gboolean stop_flag = FALSE ;
2018-02-09 00:19:12 +00:00
wtap_rec * rec , snap_rec ;
2015-08-16 16:37:11 +00:00
for ( ; ; ) {
* err = 0 ;
if ( do_append ) {
in_file = merge_append_read_packet ( in_file_count , in_files , err ,
err_info ) ;
}
else {
in_file = merge_read_packet ( in_file_count , in_files , err ,
err_info ) ;
}
if ( in_file = = NULL ) {
2017-12-26 18:33:22 +00:00
/* We're at EOF on all input files */
2015-08-16 16:37:11 +00:00
break ;
}
if ( * err ! = 0 ) {
/* I/O error reading from in_file */
status = MERGE_ERR_CANT_READ_INFILE ;
break ;
}
count + + ;
if ( cb )
2018-02-05 20:55:00 +00:00
stop_flag = cb - > callback_func ( MERGE_EVENT_RECORD_WAS_READ , count , in_files , in_file_count , cb - > data ) ;
2015-08-16 16:37:11 +00:00
if ( stop_flag ) {
/* The user decided to abort the merge. */
status = MERGE_USER_ABORTED ;
break ;
}
2018-02-09 00:19:12 +00:00
rec = wtap_get_rec ( in_file - > wth ) ;
2015-08-16 16:37:11 +00:00
2018-02-09 00:19:12 +00:00
switch ( rec - > rec_type ) {
case REC_TYPE_PACKET :
if ( rec - > presence_flags & WTAP_HAS_CAP_LEN ) {
if ( snaplen ! = 0 & &
rec - > rec_header . packet_header . caplen > snaplen ) {
/*
* The dumper will only write up to caplen bytes out ,
* so we only need to change that value , instead of
* cloning the whole packet with fewer bytes .
*
* XXX : but do we need to change the IDBs ' snap_len ?
*/
snap_rec = * rec ;
snap_rec . rec_header . packet_header . caplen = snaplen ;
rec = & snap_rec ;
}
2018-02-05 21:26:40 +00:00
}
2018-02-09 00:19:12 +00:00
break ;
2015-08-16 16:37:11 +00:00
}
if ( file_type = = WTAP_FILE_TYPE_SUBTYPE_PCAPNG ) {
2016-06-15 19:15:54 +00:00
/*
* XXX - We should do this only for record types
* that pertain to a particular interface ; for
* now , we hardcode that , but we need to figure
* out a more general way to handle this .
*/
2018-02-09 00:19:12 +00:00
if ( rec - > rec_type = = REC_TYPE_PACKET ) {
if ( ! map_rec_interface_id ( rec , in_file ) ) {
2016-06-15 19:15:54 +00:00
status = MERGE_ERR_BAD_PHDR_INTERFACE_ID ;
break ;
}
2015-08-16 16:37:11 +00:00
}
}
2018-02-09 00:19:12 +00:00
if ( ! wtap_dump ( pdh , rec , wtap_get_buf_ptr ( in_file - > wth ) , err , err_info ) ) {
2015-08-16 16:37:11 +00:00
status = MERGE_ERR_CANT_WRITE_OUTFILE ;
break ;
}
}
if ( cb )
cb - > callback_func ( MERGE_EVENT_DONE , count , in_files , in_file_count , cb - > data ) ;
merge_close_in_files ( in_file_count , in_files ) ;
if ( status = = MERGE_OK | | status = = MERGE_USER_ABORTED ) {
if ( ! wtap_dump_close ( pdh , err ) )
status = MERGE_ERR_CANT_CLOSE_OUTFILE ;
} else {
/*
* We already got some error ; no need to report another error on
* close .
*
* Don ' t overwrite the earlier error .
*/
int close_err = 0 ;
( void ) wtap_dump_close ( pdh , & close_err ) ;
}
2017-04-20 20:25:21 +00:00
if ( status = = MERGE_OK | | in_file = = NULL ) {
* err_fileno = 0 ;
* err_framenum = 0 ;
} else {
* err_fileno = ( guint ) ( in_file - in_files ) ;
2017-12-25 22:12:55 +00:00
* err_framenum = in_file - > packet_num ;
2015-08-16 16:37:11 +00:00
}
2016-12-04 01:57:34 +00:00
return status ;
}
2018-11-17 16:02:37 +00:00
static merge_result
merge_files_common ( const gchar * out_filename , /* normal output mode */
gchar * * out_filenamep , const char * pfx , /* tempfile mode */
const int file_type , const char * const * in_filenames ,
const guint in_file_count , const gboolean do_append ,
const idb_merge_mode mode , guint snaplen ,
const gchar * app_name , merge_progress_callback_t * cb ,
int * err , gchar * * err_info , guint * err_fileno ,
guint32 * err_framenum )
2016-12-04 01:57:34 +00:00
{
merge_in_file_t * in_files = NULL ;
int frame_type = WTAP_ENCAP_PER_PACKET ;
merge_result status = MERGE_OK ;
wtap_dumper * pdh ;
GArray * shb_hdrs = NULL ;
wtapng_iface_descriptions_t * idb_inf = NULL ;
g_assert ( in_file_count > 0 ) ;
g_assert ( in_filenames ! = NULL ) ;
g_assert ( err ! = NULL ) ;
g_assert ( err_info ! = NULL ) ;
g_assert ( err_fileno ! = NULL ) ;
2017-04-20 20:25:21 +00:00
g_assert ( err_framenum ! = NULL ) ;
2016-12-04 01:57:34 +00:00
/* if a callback was given, it has to have a callback function ptr */
g_assert ( ( cb ! = NULL ) ? ( cb - > callback_func ! = NULL ) : TRUE ) ;
merge_debug ( " merge_files: begin " ) ;
/* open the input files */
if ( ! merge_open_in_files ( in_file_count , in_filenames , & in_files , cb ,
err , err_info , err_fileno ) ) {
merge_debug ( " merge_files: merge_open_in_files() failed with err=%d " , * err ) ;
2017-04-20 20:25:21 +00:00
* err_framenum = 0 ;
2016-12-04 01:57:34 +00:00
return MERGE_ERR_CANT_OPEN_INFILE ;
}
if ( snaplen = = 0 ) {
/* Snapshot length not specified - default to the maximum. */
Allow bigger snapshot lengths for D-Bus captures.
Use WTAP_MAX_PACKET_SIZE_STANDARD, set to 256KB, for everything except
for D-Bus captures. Use WTAP_MAX_PACKET_SIZE_DBUS, set to 128MB, for
them, because that's the largest possible D-Bus message size. See
https://bugs.freedesktop.org/show_bug.cgi?id=100220
for an example of the problems caused by limiting the snapshot length to
256KB for D-Bus.
Have a snapshot length of 0 in a capture_file structure mean "there is
no snapshot length for the file"; we don't need the has_snap field in
that case, a value of 0 mean "no, we don't have a snapshot length".
In dumpcap, start out with a pipe buffer size of 2KB, and grow it as
necessary. When checking for a too-big packet from a pipe, check
against the appropriate maximum - 128MB for DLT_DBUS, 256KB for
everything else.
Change-Id: Ib2ce7a0cf37b971fbc0318024fd011e18add8b20
Reviewed-on: https://code.wireshark.org/review/21952
Petri-Dish: Guy Harris <guy@alum.mit.edu>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Guy Harris <guy@alum.mit.edu>
2017-06-05 01:58:40 +00:00
snaplen = WTAP_MAX_PACKET_SIZE_STANDARD ;
2016-12-04 01:57:34 +00:00
}
/*
* This doesn ' t tell us that much . It tells us what to set the outfile ' s
* encap type to , but that ' s all - for example , it does * not * tells us
* whether the input files had the same number of IDBs , for the same exact
* interfaces , and only one IDB each , so it doesn ' t actually tell us
* whether we can merge IDBs into one or not .
*/
frame_type = merge_select_frame_type ( in_file_count , in_files ) ;
merge_debug ( " merge_files: got frame_type=%d " , frame_type ) ;
if ( cb )
cb - > callback_func ( MERGE_EVENT_FRAME_TYPE_SELECTED , frame_type , in_files , in_file_count , cb - > data ) ;
/* prepare the outfile */
2018-11-14 00:10:53 +00:00
wtap_dump_params params = WTAP_DUMP_PARAMS_INIT ;
params . encap = frame_type ;
params . snaplen = snaplen ;
2016-12-04 01:57:34 +00:00
if ( file_type = = WTAP_FILE_TYPE_SUBTYPE_PCAPNG ) {
shb_hdrs = create_shb_header ( in_files , in_file_count , app_name ) ;
merge_debug ( " merge_files: SHB created " ) ;
idb_inf = generate_merged_idb ( in_files , in_file_count , mode ) ;
merge_debug ( " merge_files: IDB merge operation complete, got %u IDBs " , idb_inf ? idb_inf - > interface_data - > len : 0 ) ;
2018-11-11 14:49:12 +00:00
/* XXX other blocks like NRB are now discarded. */
2018-11-14 00:10:53 +00:00
params . shb_hdrs = shb_hdrs ;
params . idb_inf = idb_inf ;
2016-12-04 01:57:34 +00:00
}
2018-11-17 16:02:37 +00:00
if ( out_filename ) {
pdh = wtap_dump_open ( out_filename , file_type , WTAP_UNCOMPRESSED , & params , err ) ;
} else if ( out_filenamep ) {
pdh = wtap_dump_open_tempfile ( out_filenamep , pfx , file_type ,
WTAP_UNCOMPRESSED , & params , err ) ;
} else {
pdh = wtap_dump_open_stdout ( file_type , WTAP_UNCOMPRESSED , & params , err ) ;
}
2016-12-04 01:57:34 +00:00
if ( pdh = = NULL ) {
merge_close_in_files ( in_file_count , in_files ) ;
g_free ( in_files ) ;
wtap_block_array_free ( shb_hdrs ) ;
wtap_free_idb_info ( idb_inf ) ;
2017-04-20 20:25:21 +00:00
* err_framenum = 0 ;
2016-12-04 01:57:34 +00:00
return MERGE_ERR_CANT_OPEN_OUTFILE ;
}
if ( cb )
cb - > callback_func ( MERGE_EVENT_READY_TO_MERGE , 0 , in_files , in_file_count , cb - > data ) ;
2017-04-20 20:25:21 +00:00
status = merge_process_packets ( pdh , file_type , in_files , in_file_count ,
do_append , snaplen , cb , err , err_info ,
err_fileno , err_framenum ) ;
2016-12-04 01:57:34 +00:00
g_free ( in_files ) ;
wtap_block_array_free ( shb_hdrs ) ;
wtap_free_idb_info ( idb_inf ) ;
return status ;
}
2018-11-17 16:02:37 +00:00
/*
* Merges the files to an output file whose name is supplied as an argument ,
* based on given input , and invokes callback during execution . Returns
* MERGE_OK on success , or a MERGE_ERR_XXX on failure .
*/
merge_result
merge_files ( const gchar * out_filename , const int file_type ,
const char * const * in_filenames , const guint in_file_count ,
const gboolean do_append , const idb_merge_mode mode ,
guint snaplen , const gchar * app_name , merge_progress_callback_t * cb ,
int * err , gchar * * err_info , guint * err_fileno ,
guint32 * err_framenum )
{
g_assert ( out_filename ! = NULL ) ;
return merge_files_common ( out_filename , NULL , NULL ,
file_type , in_filenames , in_file_count ,
do_append , mode , snaplen , app_name , cb , err ,
err_info , err_fileno , err_framenum ) ;
}
2016-12-04 01:57:34 +00:00
/*
* Merges the files to a temporary file based on given input , and invokes
* callback during execution . Returns MERGE_OK on success , or a MERGE_ERR_XXX
2017-04-20 20:25:21 +00:00
* on failure .
2016-12-04 01:57:34 +00:00
*/
merge_result
merge_files_to_tempfile ( gchar * * out_filenamep , const char * pfx ,
const int file_type , const char * const * in_filenames ,
const guint in_file_count , const gboolean do_append ,
const idb_merge_mode mode , guint snaplen ,
const gchar * app_name , merge_progress_callback_t * cb ,
2017-04-20 20:25:21 +00:00
int * err , gchar * * err_info , guint * err_fileno ,
guint32 * err_framenum )
2016-12-04 01:57:34 +00:00
{
g_assert ( out_filenamep ! = NULL ) ;
/* no temporary file name yet */
* out_filenamep = NULL ;
2018-11-17 16:02:37 +00:00
return merge_files_common ( NULL , out_filenamep , pfx ,
file_type , in_filenames , in_file_count ,
do_append , mode , snaplen , app_name , cb , err ,
err_info , err_fileno , err_framenum ) ;
2016-12-04 01:57:34 +00:00
}
/*
* Merges the files to the standard output based on given input , and invokes
* callback during execution . Returns MERGE_OK on success , or a MERGE_ERR_XXX
2017-04-20 20:25:21 +00:00
* on failure .
2016-12-04 01:57:34 +00:00
*/
merge_result
merge_files_to_stdout ( const int file_type , const char * const * in_filenames ,
const guint in_file_count , const gboolean do_append ,
const idb_merge_mode mode , guint snaplen ,
const gchar * app_name , merge_progress_callback_t * cb ,
2017-04-20 20:25:21 +00:00
int * err , gchar * * err_info , guint * err_fileno ,
guint32 * err_framenum )
2016-12-04 01:57:34 +00:00
{
2018-11-17 16:02:37 +00:00
return merge_files_common ( NULL , NULL , NULL ,
file_type , in_filenames , in_file_count ,
do_append , mode , snaplen , app_name , cb , err ,
err_info , err_fileno , err_framenum ) ;
2015-08-16 16:37:11 +00:00
}
2004-06-17 21:53:26 +00:00
2015-01-02 00:45:22 +00:00
/*
* Editor modelines - http : //www.wireshark.org/tools/modelines.html
*
* Local Variables :
2015-08-14 14:44:11 +00:00
* c - basic - offset : 4
2016-02-25 21:34:07 +00:00
* tab - width : 8
2015-01-02 00:45:22 +00:00
* indent - tabs - mode : nil
* End :
*
2016-02-25 21:34:07 +00:00
* vi : set shiftwidth = 4 tabstop = 8 expandtab :
* : indentSize = 4 : tabSize = 8 : noTabs = true :
2015-01-02 00:45:22 +00:00
*/