diff options
-rw-r--r-- | file.c | 141 | ||||
-rw-r--r-- | merge.c | 222 | ||||
-rw-r--r-- | merge.h | 89 | ||||
-rw-r--r-- | mergecap.c | 92 |
4 files changed, 282 insertions, 262 deletions
@@ -975,60 +975,136 @@ cf_merge_files(const char *out_filename, int out_fd, int in_file_count, char *const *in_filenames, int file_type, gboolean do_append) { merge_in_file_t *in_files; - merge_out_file_t out_file; - int err, close_err; + wtap *wth; + wtap_dumper *pdh; + int open_err, read_err, write_err, close_err; gchar *err_info; int err_fileno; - merge_status_e status; int i; char errmsg_errno[1024+1]; gchar err_str[2048+1]; char *errmsg; + gboolean got_read_error = FALSE, got_write_error = FALSE; + long data_offset; + progdlg_t *progbar = NULL; + gboolean stop_flag; + /* + * XXX - should be "off_t", but Wiretap would need more work to handle + * the full size of "off_t" on platforms where it's more than a "long" + * as well. + */ + long f_len, file_pos; + float prog_val; + GTimeVal start_time; + gchar status_str[100]; + int progbar_nextstep; + int progbar_quantum; /* open the input files */ if (!merge_open_in_files(in_file_count, in_filenames, &in_files, - &err, &err_info, &err_fileno)) { + &open_err, &err_info, &err_fileno)) { free(in_files); - cf_open_failure_alert_box(in_filenames[err_fileno], err, err_info, FALSE, 0); + cf_open_failure_alert_box(in_filenames[err_fileno], open_err, err_info, + FALSE, 0); return FALSE; } - if (!merge_open_outfile(&out_file, out_fd, file_type, + pdh = wtap_dump_fdopen(out_fd, file_type, merge_select_frame_type(in_file_count, in_files), - merge_max_snapshot_length(in_file_count, in_files), &err)) { + merge_max_snapshot_length(in_file_count, in_files), &open_err); + if (pdh == NULL) { merge_close_in_files(in_file_count, in_files); free(in_files); - cf_open_failure_alert_box(out_filename, err, err_info, TRUE, file_type); + cf_open_failure_alert_box(out_filename, open_err, err_info, TRUE, + file_type); return FALSE; } + /* Get the sum of the sizes of all the files. */ + f_len = 0; + for (i = 0; i < in_file_count; i++) + f_len += in_files[i].size; + + /* Update the progress bar when it gets to this value. */ + progbar_nextstep = 0; + /* When we reach the value that triggers a progress bar update, + bump that value by this amount. */ + progbar_quantum = f_len/N_PROGBAR_UPDATES; + + stop_flag = FALSE; + g_get_current_time(&start_time); + /* do the merge (or append) */ - if (do_append) - status = merge_append_files(in_file_count, in_files, &out_file, &err); - else - status = merge_files(in_file_count, in_files, &out_file, &err); + for (;;) { + if (do_append) + wth = merge_append_read_packet(in_file_count, in_files, &read_err, + &err_info); + else + wth = merge_read_packet(in_file_count, in_files, &read_err, + &err_info); + if (wth == NULL) { + if (read_err != 0) + got_read_error = TRUE; + break; + } - merge_close_in_files(in_file_count, in_files); - if (status == MERGE_SUCCESS) { - if (!merge_close_outfile(&out_file, &err)) - status = MERGE_WRITE_ERROR; - } else - merge_close_outfile(&out_file, &close_err); + /* Get the sum of the data offsets in all of the files. */ + data_offset = 0; + for (i = 0; i < in_file_count; i++) + data_offset += in_files[i].data_offset; + + if (data_offset >= progbar_nextstep) { + /* Get the sum of the seek positions in all of the files. */ + file_pos = 0; + for (i = 0; i < in_file_count; i++) + file_pos += lseek(wtap_fd(in_files[i].wth), 0, SEEK_CUR); + prog_val = (gfloat) file_pos / (gfloat) f_len; + if (prog_val > 1.0) { + /* Some file probably grew while we were reading it. + That "shouldn't happen", so we'll just clip the progress + value at 1.0. */ + prog_val = 1.0; + } + if (progbar == NULL) { + /* Create the progress bar if necessary */ + progbar = delayed_create_progress_dlg("Merging", "files", + &stop_flag, &start_time, prog_val); + } + if (progbar != NULL) { + g_snprintf(status_str, sizeof(status_str), + "%luKB of %luKB", file_pos / 1024, f_len / 1024); + update_progress_dlg(progbar, prog_val, status_str); + } + progbar_nextstep += progbar_quantum; + } - switch (status) { + if (!wtap_dump(pdh, wtap_phdr(wth), wtap_pseudoheader(wth), + wtap_buf_ptr(wth), &write_err)) { + got_write_error = TRUE; + break; + } + } - case MERGE_SUCCESS: - break; + /* We're done merging the files; destroy the progress bar if it was created. */ + if (progbar != NULL) + destroy_progress_dlg(progbar); - case MERGE_READ_ERROR: + merge_close_in_files(in_file_count, in_files); + if (!got_read_error && !got_write_error) { + if (!wtap_dump_close(pdh, &write_err)) + got_write_error = TRUE; + } else + wtap_dump_close(pdh, &close_err); + + if (got_read_error) { /* * Find the file on which we got the error, and report the error. */ for (i = 0; i < in_file_count; i++) { - if (!in_files[i].ok) { - /* Put up a message box noting that the read failed somewhere along + if (in_files[i].state == GOT_ERROR) { + /* Put up a message box noting that a read failed somewhere along the line. */ - switch (err) { + switch (read_err) { case WTAP_ERR_UNSUPPORTED_ENCAP: snprintf(errmsg_errno, sizeof(errmsg_errno), @@ -1050,7 +1126,7 @@ cf_merge_files(const char *out_filename, int out_fd, int in_file_count, case WTAP_ERR_BAD_RECORD: snprintf(errmsg_errno, sizeof(errmsg_errno), - "The capture file %%sappears to be damaged or corrupt.\n(%s)", + "The capture file %%s appears to be damaged or corrupt.\n(%s)", err_info); g_free(err_info); errmsg = errmsg_errno; @@ -1059,7 +1135,7 @@ cf_merge_files(const char *out_filename, int out_fd, int in_file_count, default: snprintf(errmsg_errno, sizeof(errmsg_errno), "An error occurred while reading the" - " capture file %%s: %s.", wtap_strerror(err)); + " capture file %%s: %s.", wtap_strerror(read_err)); errmsg = errmsg_errno; break; } @@ -1067,13 +1143,14 @@ cf_merge_files(const char *out_filename, int out_fd, int in_file_count, simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, err_str); } } - break; + } - case MERGE_WRITE_ERROR: - cf_write_failure_alert_box(out_filename, err); - break; + if (got_write_error) { + /* Put up an alert box for the write error. */ + cf_write_failure_alert_box(out_filename, write_err); } - return (status == MERGE_SUCCESS); + + return (!got_read_error && !got_write_error); } gboolean @@ -1,4 +1,4 @@ -/* Combine two dump files, either by appending or by merging by timestamp +/* Combine multiple dump files, either by appending or by merging by timestamp * * $Id$ * @@ -14,6 +14,7 @@ #include <stdio.h> #include <stdlib.h> #include <glib.h> +#include <errno.h> #ifdef HAVE_UNISTD_H #include <unistd.h> @@ -23,6 +24,10 @@ #include <sys/time.h> #endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif + #include <string.h> #include "wtap.h" #include "merge.h" @@ -38,6 +43,7 @@ merge_open_in_files(int in_file_count, char *const *in_file_names, int i, j; int files_size = in_file_count * sizeof(merge_in_file_t); merge_in_file_t *files; + struct stat statb; files = g_malloc(files_size); *in_files = files; @@ -45,9 +51,8 @@ merge_open_in_files(int in_file_count, char *const *in_file_names, 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], err, err_info, FALSE); - files[i].err = 0; files[i].data_offset = 0; - files[i].ok = TRUE; + files[i].state = PACKET_NOT_PRESENT; if (!files[i].wth) { /* Close the files we've already opened. */ for (j = 0; j < i; j++) @@ -55,6 +60,14 @@ merge_open_in_files(int in_file_count, char *const *in_file_names, *err_fileno = i; return FALSE; } + if (fstat(wtap_fd(files[i].wth), &statb) < 0) { + *err = errno; + for (j = 0; j <= i; j++) + wtap_close(files[j].wth); + *err_fileno = i; + return FALSE; + } + files[i].size = statb.st_size; } return TRUE; } @@ -72,37 +85,6 @@ merge_close_in_files(int count, merge_in_file_t in_files[]) } /* - * Open the output file - * - * Return FALSE if file cannot be opened (so caller can report an error - * and clean up) - */ -gboolean -merge_open_outfile(merge_out_file_t *out_file, int fd, int file_type, - int frame_type, int snapshot_len, int *err) -{ - out_file->pdh = wtap_dump_fdopen(fd, file_type, frame_type, snapshot_len, - err); - if (!out_file->pdh) - return FALSE; - - out_file->snaplen = snapshot_len; - out_file->count = 1; - return TRUE; -} - -/* - * Close the output file - */ -gboolean -merge_close_outfile(merge_out_file_t *out_file, int *err) -{ - if (!wtap_dump_close(out_file->pdh, err)) - return FALSE; - return TRUE; -} - -/* * Select an output frame type based on the input files * From Guy: If all files have the same frame type, then use that. * Otherwise select WTAP_ENCAP_PER_PACKET. If the selected @@ -152,29 +134,6 @@ merge_max_snapshot_length(int count, merge_in_file_t in_files[]) } /* - * Routine to write frame to output file - */ -static gboolean -write_frame(wtap *wth, merge_out_file_t *out_file, int *err) -{ - const struct wtap_pkthdr *phdr = wtap_phdr(wth); - struct wtap_pkthdr snap_phdr; - - /* We simply write it, perhaps after truncating it; we could do other - * things, like modify it. */ - if (out_file->snaplen != 0 && phdr->caplen > out_file->snaplen) { - snap_phdr = *phdr; - snap_phdr.caplen = out_file->snaplen; - phdr = &snap_phdr; - } - - if (!wtap_dump(out_file->pdh, phdr, wtap_pseudoheader(wth), wtap_buf_ptr(wth), err)) - return FALSE; - - return TRUE; -} - -/* * returns TRUE if first argument is earlier than second */ static gboolean @@ -192,105 +151,94 @@ is_earlier(struct timeval *l, struct timeval *r) { return TRUE; } - /* - * returns index of earliest timestamp in set of input files - * or -1 if no valid files remain + * Read the next packet, in chronological order, from the set of files + * to be merged. */ -static int -earliest(int count, merge_in_file_t in_files[]) { +wtap * +merge_read_packet(int in_file_count, merge_in_file_t in_files[], int *err, + gchar **err_info) +{ int i; int ei = -1; struct timeval tv = {LONG_MAX, LONG_MAX}; + struct wtap_pkthdr *phdr; - for (i = 0; i < count; i++) { - struct wtap_pkthdr *phdr = wtap_phdr(in_files[i].wth); - - if (in_files[i].ok && is_earlier(&(phdr->ts), &tv)) { - tv = phdr->ts; - ei = i; + /* + * Make sure we have a packet available from each file, if there are any + * packets left in the file in question, and search for the packet + * with the earliest time stamp. + */ + for (i = 0; i < in_file_count; i++) { + if (in_files[i].state == PACKET_NOT_PRESENT) { + /* + * No packet available, and we haven't seen an error or EOF yet, + * so try to read the next packet. + */ + if (!wtap_read(in_files[i].wth, err, err_info, &in_files[i].data_offset)) { + if (*err != 0) { + in_files[i].state = GOT_ERROR; + return NULL; + } + in_files[i].state = AT_EOF; + } else + in_files[i].state = PACKET_PRESENT; + } + + if (in_files[i].state == PACKET_PRESENT) { + phdr = wtap_phdr(in_files[i].wth); + if (is_earlier(&phdr->ts, &tv)) { + tv = phdr->ts; + ei = i; + } } - } - return ei; -} - -/* - * actually merge the files - */ -merge_status_e -merge_files(int count, merge_in_file_t in_files[], merge_out_file_t *out_file, int *err) -{ - int i; - - /* prime the pump (read in first frame from each file) */ - for (i = 0; i < count; i++) { - in_files[i].ok = wtap_read(in_files[i].wth, &(in_files[i].err), - &(in_files[i].err_info), - &(in_files[i].data_offset)); - if (!in_files[i].ok) - return MERGE_READ_ERROR; } - /* now keep writing the earliest frame until we're out of frames */ - while ( -1 != (i = earliest(count, in_files))) { - - /* write out earliest frame, and fetch another from its - * input file - */ - if(!write_frame(in_files[i].wth, out_file, err)) - return MERGE_WRITE_ERROR; - in_files[i].ok = wtap_read(in_files[i].wth, &(in_files[i].err), - &(in_files[i].err_info), - &(in_files[i].data_offset)); - if (!in_files[i].ok) - return MERGE_READ_ERROR; + if (ei == -1) { + /* All the streams are at EOF. Return an EOF indication. */ + *err = 0; + return NULL; } - return MERGE_SUCCESS; -} - -static merge_status_e -append_loop(merge_in_file_t in_files[], int i, int count, - merge_out_file_t *out_file, int *err) -{ - gchar *err_info; - long data_offset; - int loop = 0; - - /* Start by clearing error flag */ - *err = 0; - - while ( (wtap_read(in_files[i].wth, err, &err_info, &data_offset)) ) { - if(!write_frame(in_files[i].wth, out_file, err)) - return MERGE_WRITE_ERROR; - if (count > 0 && ++loop >= count) - break; - } + /* We'll need to read another packet from this file. */ + in_files[ei].state = PACKET_NOT_PRESENT; - if (*err != 0) { - in_files[i].ok = FALSE; - in_files[i].err = *err; - in_files[i].err_info = err_info; - return MERGE_READ_ERROR; - } - return MERGE_SUCCESS; + /* Return a pointer to the wtap structure for the file with that frame. */ + return in_files[ei].wth; } /* - * routine to concatenate files + * Read the next packet, in file sequence order, from the set of files + * to be merged. */ -merge_status_e -merge_append_files(int count, merge_in_file_t in_files[], - merge_out_file_t *out_file, int *err) +wtap * +merge_append_read_packet(int in_file_count, merge_in_file_t in_files[], + int *err, gchar **err_info) { int i; - merge_status_e status; - for (i = 0; i < count; i++) { - status = append_loop(in_files, i, 0, out_file, err); - if (status != MERGE_SUCCESS) - return status; + /* + * 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 */ + if (wtap_read(in_files[i].wth, err, err_info, &in_files[i].data_offset)) + break; /* We have a packet */ + if (*err != 0) { + /* Read error - quit immediately. */ + in_files[i].state = GOT_ERROR; + return NULL; + } + /* EOF - flag this file as being at EOF, and try the next one. */ + in_files[i].state = AT_EOF; + } + if (i == in_file_count) { + /* All the streams are at EOF. Return an EOF indication. */ + *err = 0; + return NULL; } - return MERGE_SUCCESS; + /* Return a pointer to the wtap structure for the file with that frame. */ + return in_files[i].wth; } @@ -29,27 +29,24 @@ extern "C" { #endif /* __cplusplus */ +typedef enum { + PACKET_PRESENT, + PACKET_NOT_PRESENT, + AT_EOF, + GOT_ERROR +} in_file_state_e; + /** * Structures to manage our input files. */ typedef struct merge_in_file_s { - const char *filename; - wtap *wth; - int err; - gchar *err_info; - long data_offset; - gboolean ok; + const char *filename; + wtap *wth; + long data_offset; + in_file_state_e state; + long size; /* file size */ } merge_in_file_t; -/** - * Structures to manage our output file. - */ -typedef struct merge_out_file_s { - wtap_dumper *pdh; - unsigned int snaplen; - int count; -} merge_out_file_t; - /** Open a number of input files to merge. * * @param in_file_count number of entries in in_file_names and in_files @@ -73,29 +70,6 @@ merge_open_in_files(int in_file_count, char *const *in_file_names, extern void merge_close_in_files(int in_file_count, merge_in_file_t in_files[]); -/** Open the output file. - * - * @param out_file the output file array, which we fill in - * @param fd the file descriptor to use for the output file - * @param file_type the file type to write - * @param frame_type the frame type to write - * @param snapshot_len the snapshot length of the output file - * @param err wiretap error, if failed - * @return TRUE, if the output file could be opened, and FALSE otherwise - */ -extern gboolean -merge_open_outfile(merge_out_file_t *out_file, int fd, int file_type, - int frame_type, int snapshot_len, int *err); - -/** Close the output file again. - * - * @param out_file the output file array - * @param err wiretap error, if failed - * @return TRUE if the close succeeded, FALSE otherwise - */ -extern gboolean -merge_close_outfile(merge_out_file_t *out_file, int *err); - /** Try to get the frame type from the input files. * * @param in_file_count number of entries in in_files @@ -114,39 +88,34 @@ merge_select_frame_type(int in_file_count, merge_in_file_t in_files[]); extern int merge_max_snapshot_length(int in_file_count, merge_in_file_t in_files[]); -/* - * Status from the merge-files routines. - */ -typedef enum { - MERGE_SUCCESS, - MERGE_READ_ERROR, - MERGE_WRITE_ERROR -} merge_status_e; - -/** Merge the packets from the input files into the output file sorted chronologically. +/** Read the next packet, in chronological order, from the set of files to + * be merged. * * @param in_file_count number of entries in in_files * @param in_files input file array - * @param out_file the output file array * @param err wiretap error, if failed - * @return MERGE_SUCCESS on success, MERGE_READ_ERROR on read error, - * MERGE_WRITE_ERROR on write error + * @param err_info wiretap error string, if failed + * @return pointer to wtap for file from which that packet came, or NULL on + * error or EOF */ -extern merge_status_e -merge_files(int in_file_count, merge_in_file_t in_files[], merge_out_file_t *out_file, int *err); +extern wtap * +merge_read_packet(int in_file_count, merge_in_file_t in_files[], int *err, + gchar **err_info); -/** Append the packets from the input files into the output file. + +/** Read the next packet, in file sequence order, from the set of files + * to be merged. * * @param in_file_count number of entries in in_files * @param in_files input file array - * @param out_file the output file array * @param err wiretap error, if failed - * @return MERGE_SUCCESS on success, MERGE_READ_ERROR on read error, - * MERGE_WRITE_ERROR on write error + * @param err_info wiretap error string, if failed + * @return pointer to wtap for file from which that packet came, or NULL on + * error or EOF */ -extern merge_status_e -merge_append_files(int in_file_count, merge_in_file_t in_files[], - merge_out_file_t *out_file, int *err); +extern wtap * +merge_append_read_packet(int in_file_count, merge_in_file_t in_files[], + int *err, gchar **err_info); #ifdef __cplusplus } diff --git a/mergecap.c b/mergecap.c index 19116a42ee..54bffc5539 100644 --- a/mergecap.c +++ b/mergecap.c @@ -131,18 +131,21 @@ main(int argc, char *argv[]) gboolean do_append = FALSE; gboolean verbose = FALSE; int in_file_count = 0; - int snaplen = 0; + guint snaplen = 0; int file_type = WTAP_FILE_PCAP; /* default to libpcap format */ int frame_type = -2; int out_fd; merge_in_file_t *in_files = NULL; int i; - merge_out_file_t out_file; - int err, close_err; + wtap *wth; + struct wtap_pkthdr *phdr, snap_phdr; + wtap_dumper *pdh; + int open_err, read_err, write_err, close_err; gchar *err_info; int err_fileno; char *out_filename = NULL; - merge_status_e status; + gboolean got_read_error = FALSE, got_write_error = FALSE; + int count; /* Process the options first */ while ((opt = getopt(argc, argv, "hvas:T:F:w:")) != -1) { @@ -217,10 +220,10 @@ main(int argc, char *argv[]) /* open the input files */ if (!merge_open_in_files(in_file_count, &argv[optind], &in_files, - &err, &err_info, &err_fileno)) { + &open_err, &err_info, &err_fileno)) { fprintf(stderr, "mergecap: Can't open %s: %s\n", argv[optind + err_fileno], - wtap_strerror(err)); - switch (err) { + wtap_strerror(open_err)); + switch (open_err) { case WTAP_ERR_UNSUPPORTED: case WTAP_ERR_UNSUPPORTED_ENCAP: @@ -298,60 +301,83 @@ main(int argc, char *argv[]) } /* prepare the outfile */ - if (!merge_open_outfile(&out_file, out_fd, file_type, frame_type, snaplen, - &err)) { + pdh = wtap_dump_fdopen(out_fd, file_type, frame_type, snaplen, &open_err); + if (pdh == NULL) { merge_close_in_files(in_file_count, in_files); free(in_files); fprintf(stderr, "mergecap: Can't open or create %s: %s\n", out_filename, - wtap_strerror(err)); + wtap_strerror(open_err)); exit(1); } /* do the merge (or append) */ - if (do_append) - status = merge_append_files(in_file_count, in_files, &out_file, &err); - else - status = merge_files(in_file_count, in_files, &out_file, &err); + count = 1; + for (;;) { + if (do_append) + wth = merge_append_read_packet(in_file_count, in_files, &read_err, + &err_info); + else + wth = merge_read_packet(in_file_count, in_files, &read_err, + &err_info); + if (wth == NULL) { + if (read_err != 0) + got_read_error = TRUE; + break; + } + + if (verbose) + fprintf(stderr, "Record: %u\n", count++); + + /* We simply write it, perhaps after truncating it; we could do other + * things, like modify it. */ + phdr = wtap_phdr(wth); + if (snaplen != 0 && phdr->caplen > snaplen) { + snap_phdr = *phdr; + snap_phdr.caplen = snaplen; + phdr = &snap_phdr; + } + + if (!wtap_dump(pdh, phdr, wtap_pseudoheader(wth), + wtap_buf_ptr(wth), &write_err)) { + got_write_error = TRUE; + break; + } + } merge_close_in_files(in_file_count, in_files); - if (status == MERGE_SUCCESS) { - if (!merge_close_outfile(&out_file, &err)) - status = MERGE_WRITE_ERROR; + if (!got_read_error && !got_write_error) { + if (!wtap_dump_close(pdh, &write_err)) + got_write_error = TRUE; } else - merge_close_outfile(&out_file, &close_err); - switch (status) { + wtap_dump_close(pdh, &close_err); - case MERGE_SUCCESS: - break; - - case MERGE_READ_ERROR: + if (got_read_error) { /* * Find the file on which we got the error, and report the error. */ for (i = 0; i < in_file_count; i++) { - if (!in_files[i].ok) { + if (in_files[i].state == GOT_ERROR) { fprintf(stderr, "mergecap: Error reading %s: %s\n", - in_files[i].filename, wtap_strerror(in_files[i].err)); - switch (err) { + in_files[i].filename, wtap_strerror(read_err)); + switch (read_err) { case WTAP_ERR_UNSUPPORTED: case WTAP_ERR_UNSUPPORTED_ENCAP: case WTAP_ERR_BAD_RECORD: - fprintf(stderr, "(%s)\n", in_files[i].err_info); - g_free(in_files[i].err_info); + fprintf(stderr, "(%s)\n", err_info); + g_free(err_info); break; } } } - break; + } - case MERGE_WRITE_ERROR: + if (got_write_error) { fprintf(stderr, "mergecap: Error writing to outfile: %s\n", - wtap_strerror(err)); - break; + wtap_strerror(write_err)); } free(in_files); - return (status == MERGE_SUCCESS) ? 0 : 2; + return (!got_read_error && !got_write_error) ? 0 : 2; } |