From dd98856afce144eb19104a6f40c1abedc9069558 Mon Sep 17 00:00:00 2001 From: Guy Harris Date: Sat, 3 Dec 2016 17:57:34 -0800 Subject: Have separate merge APIs for regular file/temporary file/standard output. This is similar to what we have for opening a dump file - one API that uses the file name as specified, one that creates a temporary file and provides the file name, and one that uses the standard output. All of those APIs handle closing the output file. Change-Id: I56beea7be347402773460b9148ab31a8f8bc51e1 Reviewed-on: https://code.wireshark.org/review/19059 Reviewed-by: Guy Harris --- debian/libwiretap0.symbols | 2 + file.c | 42 ++--- file.h | 12 +- mergecap.c | 38 +++-- ui/gtk/capture_file_dlg.c | 7 +- ui/gtk/drag_and_drop.c | 5 +- ui/qt/main_window.cpp | 7 +- wiretap/merge.c | 392 +++++++++++++++++++++++++++++++++++---------- wiretap/merge.h | 55 ++++++- 9 files changed, 399 insertions(+), 161 deletions(-) diff --git a/debian/libwiretap0.symbols b/debian/libwiretap0.symbols index 683ac16f73..f92a210f5f 100644 --- a/debian/libwiretap0.symbols +++ b/debian/libwiretap0.symbols @@ -10,6 +10,8 @@ libwiretap.so.0 libwiretap0 #MINVER# file_tell@Base 1.9.1 init_open_routines@Base 1.12.0~rc1 merge_files@Base 1.99.9 + merge_files_to_stdout@Base 2.3.0 + merge_files_to_tempfile@Base 2.3.0 merge_idb_merge_mode_to_string@Base 1.99.9 merge_string_to_idb_merge_mode@Base 1.99.9 open_info_name_to_type@Base 1.12.0~rc1 diff --git a/file.c b/file.c index 30259ce4fe..d5ffa48a76 100644 --- a/file.c +++ b/file.c @@ -1335,45 +1335,27 @@ merge_callback(merge_event event, int num _U_, cf_status_t -cf_merge_files(char **out_filenamep, int in_file_count, - char *const *in_filenames, int file_type, gboolean do_append) +cf_merge_files_to_tempfile(char **out_filenamep, int in_file_count, + char *const *in_filenames, int file_type, + gboolean do_append) { - char *out_filename; - char *tmpname; - int out_fd; int err = 0; gchar *err_info = NULL; guint err_fileno; merge_result status; merge_progress_callback_t cb; - - if (*out_filenamep != NULL) { - out_filename = *out_filenamep; - out_fd = ws_open(out_filename, O_CREAT|O_TRUNC|O_BINARY, 0600); - if (out_fd == -1) - err = errno; - } else { - out_fd = create_tempfile(&tmpname, "wireshark", NULL); - if (out_fd == -1) - err = errno; - out_filename = g_strdup(tmpname); - *out_filenamep = out_filename; - } - if (out_fd == -1) { - cf_open_failure_alert_box(out_filename, err, NULL, TRUE, file_type); - return CF_ERROR; - } - /* prepare our callback routine */ cb.callback_func = merge_callback; cb.data = g_malloc0(sizeof(callback_data_t)); /* merge the files */ - status = merge_files(out_fd, out_filename, file_type, - (const char *const *) in_filenames, in_file_count, - do_append, IDB_MERGE_MODE_ALL_SAME, 0 /* snaplen */, - "Wireshark", &cb, &err, &err_info, &err_fileno); + status = merge_files_to_tempfile(out_filenamep, "wireshark", file_type, + (const char *const *) in_filenames, + in_file_count, do_append, + IDB_MERGE_MODE_ALL_SAME, 0 /* snaplen */, + "Wireshark", &cb, &err, &err_info, + &err_fileno); g_free(cb.data); @@ -1388,13 +1370,11 @@ cf_merge_files(char **out_filenamep, int in_file_count, case MERGE_ERR_CANT_OPEN_INFILE: cf_open_failure_alert_box(in_filenames[err_fileno], err, err_info, FALSE, 0); - ws_close(out_fd); break; case MERGE_ERR_CANT_OPEN_OUTFILE: - cf_open_failure_alert_box(out_filename, err, err_info, TRUE, + cf_open_failure_alert_box(*out_filenamep, err, err_info, TRUE, file_type); - ws_close(out_fd); break; case MERGE_ERR_CANT_READ_INFILE: /* fall through */ @@ -1407,8 +1387,6 @@ cf_merge_files(char **out_filenamep, int in_file_count, } g_free(err_info); - /* for general case, no need to close out_fd: file handle associated to this file - descriptor was already closed by the call to wtap_dump_close() in merge_files() */ if (status != MERGE_OK) { /* Callers aren't expected to treat an error or an explicit abort diff --git a/file.h b/file.h index 65354e7d47..025e5d1971 100644 --- a/file.h +++ b/file.h @@ -645,12 +645,11 @@ void cf_ignore_frame(capture_file *cf, frame_data *frame); void cf_unignore_frame(capture_file *cf, frame_data *frame); /** - * Merge two (or more) capture files into one. + * Merge two or more capture files into a temporary file. * @todo is this the right place for this function? It doesn't have to do a lot with capture_file. * - * @param out_filename pointer to output filename; if output filename is - * NULL, a temporary file name is generated and *out_filename is set - * to point to the generated file name + * @param out_filenamep Points to a pointer that's set to point to the + * pathname of the temporary file; it's allocated with g_malloc() * @param in_file_count the number of input files to merge * @param in_filenames array of input filenames * @param file_type the output filetype @@ -658,8 +657,9 @@ void cf_unignore_frame(capture_file *cf, frame_data *frame); * @return one of cf_status_t */ cf_status_t -cf_merge_files(char **out_filename, int in_file_count, - char *const *in_filenames, int file_type, gboolean do_append); +cf_merge_files_to_tempfile(char **out_filenamep, int in_file_count, + char *const *in_filenames, int file_type, + gboolean do_append); /** diff --git a/mergecap.c b/mergecap.c index 94fb70b7f0..c64341dd3b 100644 --- a/mergecap.c +++ b/mergecap.c @@ -257,7 +257,6 @@ main(int argc, char *argv[]) #else int file_type = WTAP_FILE_TYPE_SUBTYPE_PCAP; /* default to pcapng format */ #endif - int out_fd; int err = 0; gchar *err_info = NULL; int err_fileno; @@ -428,25 +427,21 @@ main(int argc, char *argv[]) /* open the outfile */ if (strcmp(out_filename, "-") == 0) { - /* use stdout as the outfile */ + /* merge the files to the standard output */ use_stdout = TRUE; - out_fd = 1 /*stdout*/; + status = merge_files_to_stdout(file_type, + (const char *const *) &argv[optind], + in_file_count, do_append, mode, snaplen, + "mergecap", verbose ? &cb : NULL, + &err, &err_info, &err_fileno); } else { - /* open the outfile */ - out_fd = ws_open(out_filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644); - if (out_fd == -1) { - fprintf(stderr, "mergecap: Couldn't open output file %s: %s\n", - out_filename, g_strerror(errno)); - exit(1); - } + /* merge the files to the outfile */ + status = merge_files(out_filename, file_type, + (const char *const *) &argv[optind], in_file_count, + do_append, mode, snaplen, "mergecap", verbose ? &cb : NULL, + &err, &err_info, &err_fileno); } - /* merge the files */ - status = merge_files(out_fd, out_filename, file_type, - (const char *const *) &argv[optind], in_file_count, - do_append, mode, snaplen, "mergecap", verbose ? &cb : NULL, - &err, &err_info, &err_fileno); - switch (status) { case MERGE_OK: break; @@ -462,10 +457,13 @@ main(int argc, char *argv[]) break; case MERGE_ERR_CANT_OPEN_OUTFILE: - fprintf(stderr, "mergecap: Can't open or create %s: %s\n", out_filename, - wtap_strerror(err)); - if (!use_stdout) - ws_close(out_fd); + if (use_stdout) { + fprintf(stderr, "mergecap: Can't set up the standard output: %s\n", + wtap_strerror(err)); + } else { + fprintf(stderr, "mergecap: Can't open or create %s: %s\n", out_filename, + wtap_strerror(err)); + } break; case MERGE_ERR_CANT_READ_INFILE: /* fall through */ diff --git a/ui/gtk/capture_file_dlg.c b/ui/gtk/capture_file_dlg.c index 2c7e0cab52..56267d761e 100644 --- a/ui/gtk/capture_file_dlg.c +++ b/ui/gtk/capture_file_dlg.c @@ -912,22 +912,21 @@ file_merge_cmd(GtkWidget *w _U_) file_type = cfile.cd_t; /* Try to merge or append the two files */ - tmpname = NULL; if (merge_type == 0) { /* chronological order */ in_filenames[0] = cfile.filename; in_filenames[1] = file_name->str; - merge_status = cf_merge_files(&tmpname, 2, in_filenames, file_type, FALSE); + merge_status = cf_merge_files_to_tempfile(&tmpname, 2, in_filenames, file_type, FALSE); } else if (merge_type < 0) { /* prepend file */ in_filenames[0] = file_name->str; in_filenames[1] = cfile.filename; - merge_status = cf_merge_files(&tmpname, 2, in_filenames, file_type, TRUE); + merge_status = cf_merge_files_to_tempfile(&tmpname, 2, in_filenames, file_type, TRUE); } else { /* append file */ in_filenames[0] = cfile.filename; in_filenames[1] = file_name->str; - merge_status = cf_merge_files(&tmpname, 2, in_filenames, file_type, TRUE); + merge_status = cf_merge_files_to_tempfile(&tmpname, 2, in_filenames, file_type, TRUE); } if (merge_status != CF_OK) { diff --git a/ui/gtk/drag_and_drop.c b/ui/gtk/drag_and_drop.c index 8f0d390c3e..4c34d29258 100644 --- a/ui/gtk/drag_and_drop.c +++ b/ui/gtk/drag_and_drop.c @@ -208,9 +208,8 @@ dnd_open_file_cmd(gchar *cf_names_freeme) } } else { /* merge the files in chronological order */ - tmpname = NULL; - if (cf_merge_files(&tmpname, in_file_count, in_filenames, - WTAP_FILE_TYPE_SUBTYPE_PCAPNG, FALSE) == CF_OK) { + if (cf_merge_files_to_tempfile(&tmpname, in_file_count, in_filenames, + WTAP_FILE_TYPE_SUBTYPE_PCAPNG, FALSE) == CF_OK) { /* Merge succeeded; close the currently-open file and try to open the merged capture file. */ cf_close(&cfile); diff --git a/ui/qt/main_window.cpp b/ui/qt/main_window.cpp index 8ed0f6a087..506907917d 100644 --- a/ui/qt/main_window.cpp +++ b/ui/qt/main_window.cpp @@ -1075,22 +1075,21 @@ void MainWindow::mergeCaptureFile() file_type = capture_file_.capFile()->cd_t; /* Try to merge or append the two files */ - tmpname = NULL; if (merge_dlg.mergeType() == 0) { /* chronological order */ in_filenames[0] = g_strdup(capture_file_.capFile()->filename); in_filenames[1] = qstring_strdup(file_name); - merge_status = cf_merge_files(&tmpname, 2, in_filenames, file_type, FALSE); + merge_status = cf_merge_files_to_tempfile(&tmpname, 2, in_filenames, file_type, FALSE); } else if (merge_dlg.mergeType() <= 0) { /* prepend file */ in_filenames[0] = qstring_strdup(file_name); in_filenames[1] = g_strdup(capture_file_.capFile()->filename); - merge_status = cf_merge_files(&tmpname, 2, in_filenames, file_type, TRUE); + merge_status = cf_merge_files_to_tempfile(&tmpname, 2, in_filenames, file_type, TRUE); } else { /* append file */ in_filenames[0] = g_strdup(capture_file_.capFile()->filename); in_filenames[1] = qstring_strdup(file_name); - merge_status = cf_merge_files(&tmpname, 2, in_filenames, file_type, TRUE); + merge_status = cf_merge_files_to_tempfile(&tmpname, 2, in_filenames, file_type, TRUE); } g_free(in_filenames[0]); diff --git a/wiretap/merge.c b/wiretap/merge.c index a1b9f7ef8c..8ad6530c60 100644 --- a/wiretap/merge.c +++ b/wiretap/merge.c @@ -122,8 +122,8 @@ add_idb_index_map(merge_in_file_t *in_file, const guint orig_index, const guint */ static gboolean merge_open_in_files(guint in_file_count, const char *const *in_file_names, - merge_in_file_t **in_files, int *err, gchar **err_info, - guint *err_fileno) + merge_in_file_t **in_files, merge_progress_callback_t* cb, + int *err, gchar **err_info, guint *err_fileno) { guint i; guint j; @@ -158,6 +158,10 @@ merge_open_in_files(guint in_file_count, const char *const *in_file_names, files[i].size = size; files[i].idb_index_map = g_array_new(FALSE, FALSE, sizeof(guint)); } + + if (cb) + cb->callback_func(MERGE_EVENT_INPUT_FILES_OPENED, 0, files, in_file_count, cb->data); + return TRUE; } @@ -960,96 +964,19 @@ get_write_error_string(const merge_in_file_t *in_file, const int file_type, return *err_info; } - -/* - * Merges the files based on given input, and invokes callback during - * execution. Returns MERGE_OK on success, or a MERGE_ERR_XXX on failure; note - * that the passed-in 'err' variable will be more specific to what failed, and - * err_info will have pretty output. - */ -merge_result -merge_files(int out_fd, 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) +static merge_result +merge_process_packets(const gchar* out_filename, wtap_dumper *pdh, + const int file_type, + merge_in_file_t *in_files, const guint in_file_count, + const gboolean do_append, guint snaplen, + merge_progress_callback_t* cb, + int *err, gchar **err_info) { - merge_in_file_t *in_files = NULL, *in_file = NULL; - int frame_type = WTAP_ENCAP_PER_PACKET; merge_result status = MERGE_OK; - wtap_dumper *pdh; - struct wtap_pkthdr *phdr, snap_phdr; + merge_in_file_t *in_file; int count = 0; gboolean stop_flag = FALSE; - GArray *shb_hdrs = NULL; - wtapng_iface_descriptions_t *idb_inf = NULL; - - g_assert(out_fd > 0); - 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); - - /* 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, - err, err_info, err_fileno)) { - merge_debug("merge_files: merge_open_in_files() failed with err=%d", *err); - return MERGE_ERR_CANT_OPEN_INFILE; - } - - if (cb) - cb->callback_func(MERGE_EVENT_INPUT_FILES_OPENED, 0, in_files, in_file_count, cb->data); - - if (snaplen == 0) { - /* Snapshot length not specified - default to the maximum. */ - snaplen = WTAP_MAX_PACKET_SIZE; - } - - /* - * 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 */ - 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); - - pdh = wtap_dump_fdopen_ng(out_fd, file_type, frame_type, snaplen, - FALSE /* compressed */, shb_hdrs, idb_inf, - NULL, err); - } - else { - pdh = wtap_dump_fdopen(out_fd, file_type, frame_type, snaplen, FALSE /* compressed */, err); - } - - 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); - return MERGE_ERR_CANT_OPEN_OUTFILE; - } - - if (cb) - cb->callback_func(MERGE_EVENT_READY_TO_MERGE, 0, in_files, in_file_count, cb->data); + struct wtap_pkthdr *phdr, snap_phdr; for (;;) { *err = 0; @@ -1172,6 +1099,295 @@ merge_files(int out_fd, const gchar* out_filename, const int file_type, } } + return status; +} + +/* + * 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; note that the passed-in + * 'err' variable will be more specific to what failed, and err_info will + * have pretty output. + */ +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) +{ + 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(out_filename != 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); + + /* 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); + return MERGE_ERR_CANT_OPEN_INFILE; + } + + if (snaplen == 0) { + /* Snapshot length not specified - default to the maximum. */ + snaplen = WTAP_MAX_PACKET_SIZE; + } + + /* + * 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 */ + 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); + + pdh = wtap_dump_open_ng(out_filename, file_type, frame_type, snaplen, + FALSE /* compressed */, shb_hdrs, idb_inf, + NULL, err); + } + else { + pdh = wtap_dump_open(out_filename, file_type, frame_type, snaplen, + FALSE /* compressed */, err); + } + + 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); + return MERGE_ERR_CANT_OPEN_OUTFILE; + } + + if (cb) + cb->callback_func(MERGE_EVENT_READY_TO_MERGE, 0, in_files, in_file_count, cb->data); + + status = merge_process_packets(out_filename, pdh, file_type, in_files, + in_file_count, do_append, snaplen, cb, + err, err_info); + + g_free(in_files); + wtap_block_array_free(shb_hdrs); + wtap_free_idb_info(idb_inf); + + return status; +} + +/* + * 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 + * on failure; note that the passed-in 'err' variable will be more specific + * to what failed, and err_info will have pretty output. + */ +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, + int *err, gchar **err_info, guint *err_fileno) +{ + 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(out_filenamep != 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); + + /* 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"); + + /* no temporary file name yet */ + *out_filenamep = NULL; + + /* 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); + return MERGE_ERR_CANT_OPEN_INFILE; + } + + if (snaplen == 0) { + /* Snapshot length not specified - default to the maximum. */ + snaplen = WTAP_MAX_PACKET_SIZE; + } + + /* + * 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 */ + 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); + + pdh = wtap_dump_open_tempfile_ng(out_filenamep, pfx, file_type, + frame_type, snaplen, + FALSE /* compressed */, + shb_hdrs, idb_inf, NULL, err); + } + else { + pdh = wtap_dump_open_tempfile(out_filenamep, pfx, file_type, frame_type, + snaplen, FALSE /* compressed */, err); + } + + 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); + return MERGE_ERR_CANT_OPEN_OUTFILE; + } + + if (cb) + cb->callback_func(MERGE_EVENT_READY_TO_MERGE, 0, in_files, in_file_count, cb->data); + + status = merge_process_packets(*out_filenamep, pdh, file_type, in_files, + in_file_count, do_append, snaplen, cb, + err, err_info); + + g_free(in_files); + wtap_block_array_free(shb_hdrs); + wtap_free_idb_info(idb_inf); + + return status; +} + +/* + * 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 + * on failure; note that the passed-in 'err' variable will be more specific + * to what failed, and err_info will have pretty output. + */ +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, + int *err, gchar **err_info, guint *err_fileno) +{ + 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); + + /* 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); + return MERGE_ERR_CANT_OPEN_INFILE; + } + + if (snaplen == 0) { + /* Snapshot length not specified - default to the maximum. */ + snaplen = WTAP_MAX_PACKET_SIZE; + } + + /* + * 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 */ + 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); + + pdh = wtap_dump_open_stdout_ng(file_type, frame_type, snaplen, + FALSE /* compressed */, shb_hdrs, + idb_inf, NULL, err); + } + else { + pdh = wtap_dump_open_stdout(file_type, frame_type, snaplen, + FALSE /* compressed */, err); + } + + 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); + return MERGE_ERR_CANT_OPEN_OUTFILE; + } + + if (cb) + cb->callback_func(MERGE_EVENT_READY_TO_MERGE, 0, in_files, in_file_count, cb->data); + + status = merge_process_packets("standard output", pdh, file_type, in_files, + in_file_count, do_append, snaplen, cb, + err, err_info); + g_free(in_files); wtap_block_array_free(shb_hdrs); wtap_free_idb_info(idb_inf); diff --git a/wiretap/merge.h b/wiretap/merge.h index 4fa0882868..502c0955d3 100644 --- a/wiretap/merge.h +++ b/wiretap/merge.h @@ -122,10 +122,9 @@ typedef struct { } merge_progress_callback_t; -/** Merge the given input files to the output file descriptor. +/** Merge the given input files to a file with the given filename * - * @param out_fd The already opened output file decriptor - * @param out_filename The output filename, used in error messages + * @param out_filename The output filename * @param file_type The WTAP_FILE_TYPE_SUBTYPE_XXX output file type * @param in_filenames An array of input filenames to merge from * @param in_file_count The number of entries in in_filenames @@ -140,12 +139,60 @@ typedef struct { * @return the frame type */ WS_DLL_PUBLIC merge_result -merge_files(int out_fd, const gchar* out_filename, const int file_type, +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); +/** Merge the given input files to a temporary file + * + * @param out_filenamep Points to a pointer that's set to point to the + * pathname of the temporary file; it's allocated with g_malloc() + * @param pfx A string to be used as the prefix for the temporary file name + * @param file_type The WTAP_FILE_TYPE_SUBTYPE_XXX output file type + * @param in_filenames An array of input filenames to merge from + * @param in_file_count The number of entries in in_filenames + * @param do_append Whether to append by file order instead of chronological order + * @param mode The IDB_MERGE_MODE_XXX merge mode for interface data + * @param snaplen The snaplen to limit it to, or 0 to leave as it is in the files + * @param app_name The application name performing the merge, used in SHB info + * @param cb The callback information to use during execution + * @param[out] err Set to the internal WTAP_ERR_XXX error code if it failed + * @param[out] err_info Set to a descriptive error string, which must be g_free'd + * @param[out] err_fileno Set to the input file number which failed, if it failed + * @return the frame type + */ +WS_DLL_PUBLIC 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, + int *err, gchar **err_info, guint *err_fileno); + +/** Merge the given input files to the standard output + * + * @param file_type The WTAP_FILE_TYPE_SUBTYPE_XXX output file type + * @param in_filenames An array of input filenames to merge from + * @param in_file_count The number of entries in in_filenames + * @param do_append Whether to append by file order instead of chronological order + * @param mode The IDB_MERGE_MODE_XXX merge mode for interface data + * @param snaplen The snaplen to limit it to, or 0 to leave as it is in the files + * @param app_name The application name performing the merge, used in SHB info + * @param cb The callback information to use during execution + * @param[out] err Set to the internal WTAP_ERR_XXX error code if it failed + * @param[out] err_info Set to a descriptive error string, which must be g_free'd + * @param[out] err_fileno Set to the input file number which failed, if it failed + * @return the frame type + */ +WS_DLL_PUBLIC 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, + int *err, gchar **err_info, guint *err_fileno); + #ifdef __cplusplus } #endif /* __cplusplus */ -- cgit v1.2.1