aboutsummaryrefslogtreecommitdiffstats
path: root/merge.c
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2004-10-29 00:36:52 +0000
committerGuy Harris <guy@alum.mit.edu>2004-10-29 00:36:52 +0000
commite09e12621adefe25905804de8ba7e2687c2c72f2 (patch)
treec12d542a15efb8683f2228ca69aff9142672b6a7 /merge.c
parent24f30a8850a1f11ae2470fd5124e827f443fa62b (diff)
The common merge code merely needs to offer the abstraction of routines
that return the next packet from a set of {chronologically sorted, sequential-by-file} packets; it doesn't need to have a loop over all those packets, or any code to write packets. Supply those abstractions, change the code that merges packets to do its own writing, and have the Ethereal version manage a progress bar and have the mergecap version print packet numbers in verbose mode, as the common merge code used to do. svn path=/trunk/; revision=12427
Diffstat (limited to 'merge.c')
-rw-r--r--merge.c222
1 files changed, 85 insertions, 137 deletions
diff --git a/merge.c b/merge.c
index 81f2a78ec2..d82c14136b 100644
--- a/merge.c
+++ b/merge.c
@@ -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;
}