Revert "TODO SMB2 NegotiateContext...."
[metze/wireshark/wip.git] / editcap.c
index 3e684fe234a711cd9636376d4db273384fdf39e3..5114135d7d58856b427071f40caec0d47f25420b 100644 (file)
--- a/editcap.c
+++ b/editcap.c
  * By Gerald Combs <gerald@wireshark.org>
  * Copyright 1998 Gerald Combs
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * SPDX-License-Identifier: GPL-2.0-or-later
  */
 
 #include <config.h>
@@ -58,6 +46,7 @@
 #include <wiretap/wtap.h>
 
 #include "epan/etypes.h"
+#include "epan/dissectors/packet-ieee80211-radiotap-defs.h"
 
 #ifndef HAVE_GETOPT_LONG
 #include "wsutil/wsgetopt.h"
 #ifdef _WIN32
 #include <wsutil/unicode-utils.h>
 #include <process.h>    /* getpid */
-#ifdef HAVE_WINSOCK2_H
 #include <winsock2.h>
 #endif
-#endif
 
 #ifndef HAVE_STRPTIME
 # include "wsutil/strptime.h"
@@ -86,7 +73,7 @@
 #include <wsutil/report_message.h>
 #include <wsutil/strnatcmp.h>
 #include <wsutil/str_util.h>
-#include <ws_version_info.h>
+#include <version_info.h>
 #include <wsutil/pint.h>
 #include <wsutil/strtoi.h>
 #include <wiretap/wtap_opttypes.h>
@@ -173,23 +160,24 @@ static int                    out_file_type_subtype     = WTAP_FILE_TYPE_SUBTYPE
 #endif
 static int                    out_frame_type            = -2; /* Leave frame type alone */
 static int                    verbose                   = 0;  /* Not so verbose         */
-static struct time_adjustment time_adj                  = {{0, 0}, 0}; /* no adjustment */
-static nstime_t               relative_time_window      = {0, 0}; /* de-dup time window */
-static double                 err_prob                  = 0.0;
+static struct time_adjustment time_adj                  = {NSTIME_INIT_ZERO, 0}; /* no adjustment */
+static nstime_t               relative_time_window      = NSTIME_INIT_ZERO; /* de-dup time window */
+static double                 err_prob                  = -1.0;
 static time_t                 starttime                 = 0;
 static time_t                 stoptime                  = 0;
 static gboolean               check_startstop           = FALSE;
 static gboolean               rem_vlan                  = FALSE;
 static gboolean               dup_detect                = FALSE;
 static gboolean               dup_detect_by_time        = FALSE;
+static gboolean               skip_radiotap             = FALSE;
 
 static int                    do_strict_time_adjustment = FALSE;
-static struct time_adjustment strict_time_adj           = {{0, 0}, 0}; /* strict time adjustment */
-static nstime_t               previous_time             = {0, 0}; /* previous time */
+static struct time_adjustment strict_time_adj           = {NSTIME_INIT_ZERO, 0}; /* strict time adjustment */
+static nstime_t               previous_time             = NSTIME_INIT_ZERO; /* previous time */
 
 static int find_dct2000_real_data(guint8 *buf);
-static void handle_chopping(chop_t chop, struct wtap_pkthdr *out_phdr,
-                            const struct wtap_pkthdr *in_phdr, guint8 **buf,
+static void handle_chopping(chop_t chop, wtap_packet_header *out_phdr,
+                            const wtap_packet_header *in_phdr, guint8 **buf,
                             gboolean adjlen);
 
 static gchar *
@@ -216,7 +204,7 @@ abs_time_to_str_with_sec_resolution(const nstime_t *abs_time)
 }
 
 static gchar *
-fileset_get_filename_by_pattern(guint idx, const struct wtap_pkthdr *phdr,
+fileset_get_filename_by_pattern(guint idx, const wtap_rec *rec,
                                 gchar *fprefix, gchar *fsuffix)
 {
     gchar  filenum[5+1];
@@ -224,8 +212,8 @@ fileset_get_filename_by_pattern(guint idx, const struct wtap_pkthdr *phdr,
     gchar *abs_str;
 
     g_snprintf(filenum, sizeof(filenum), "%05u", idx % RINGBUFFER_MAX_NUM_FILES);
-    if (phdr->presence_flags & WTAP_HAS_TS) {
-        timestr = abs_time_to_str_with_sec_resolution(&phdr->ts);
+    if (rec->presence_flags & WTAP_HAS_TS) {
+        timestr = abs_time_to_str_with_sec_resolution(&rec->ts);
         abs_str = g_strconcat(fprefix, "_", filenum, "_", timestr, fsuffix, NULL);
         g_free(timestr);
     } else
@@ -396,7 +384,7 @@ set_time_adjustment(char *optarg_str_p)
             val = strtol(&(frac[1]), &end, 10);
         }
         if (*frac != '.' || end == NULL || end == frac || val < 0
-            || val > ONE_BILLION || val == LONG_MIN || val == LONG_MAX) {
+            || val >= ONE_BILLION || val == LONG_MIN || val == LONG_MAX) {
             fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
                     optarg_str_p);
             return FALSE;
@@ -470,7 +458,7 @@ set_strict_time_adj(char *optarg_str_p)
             val = strtol(&(frac[1]), &end, 10);
         }
         if (*frac != '.' || end == NULL || end == frac || val < 0
-            || val > ONE_BILLION || val == LONG_MIN || val == LONG_MAX) {
+            || val >= ONE_BILLION || val == LONG_MIN || val == LONG_MAX) {
             fprintf(stderr, "editcap: \"%s\" isn't a valid time adjustment\n",
                     optarg_str_p);
             return FALSE;
@@ -538,7 +526,7 @@ set_rel_time(char *optarg_str_p)
             val = strtol(&(frac[1]), &end, 10);
         }
         if (*frac != '.' || end == NULL || end == frac || val < 0
-            || val > ONE_BILLION || val == LONG_MIN || val == LONG_MAX) {
+            || val >= ONE_BILLION || val == LONG_MIN || val == LONG_MAX) {
             fprintf(stderr, "3: editcap: \"%s\" isn't a valid rel time value\n",
                     optarg_str_p);
             return FALSE;
@@ -576,7 +564,7 @@ sll_remove_vlan_info(guint8* fd, guint32* len) {
 }
 
 static void
-remove_vlan_info(const struct wtap_pkthdr *phdr, guint8* fd, guint32* len) {
+remove_vlan_info(const wtap_packet_header *phdr, guint8* fd, guint32* len) {
     switch (phdr->pkt_encap) {
         case WTAP_ENCAP_SLL:
             sll_remove_vlan_info(fd, len);
@@ -590,6 +578,7 @@ remove_vlan_info(const struct wtap_pkthdr *phdr, guint8* fd, guint32* len) {
 static gboolean
 is_duplicate(guint8* fd, guint32 len) {
     int i;
+    const struct ieee80211_radiotap_header* tap_header;
 
     /*Hint to ignore some bytes at the start of the frame for the digest calculation(-I option) */
     guint32 offset = ignored_bytes;
@@ -600,6 +589,14 @@ is_duplicate(guint8* fd, guint32 len) {
         offset = 0;
     }
 
+    /* Get the size of radiotap header and use that as offset (-p option) */
+    if (skip_radiotap == TRUE) {
+        tap_header = (const struct ieee80211_radiotap_header*)fd;
+        offset = pletoh16(&tap_header->it_len);
+        if (offset >= len)
+            offset = 0;
+    }
+
     new_fd  = &fd[offset];
     new_len = len - (offset);
 
@@ -766,21 +763,13 @@ print_usage(FILE *output)
     fprintf(output, "                         LESS THAN <dup time window> prior to current packet.\n");
     fprintf(output, "                         A <dup time window> is specified in relative seconds\n");
     fprintf(output, "                         (e.g. 0.000001).\n");
-    fprintf(output, "  -a <framenum>:<comment> Add or replace comment for given frame number\n");
-    fprintf(output, "\n");
-    fprintf(output, "  -I <bytes to ignore>   ignore the specified number of bytes at the beginning\n");
-    fprintf(output, "                         of the frame during MD5 hash calculation, unless the\n");
-    fprintf(output, "                         frame is too short, then the full frame is used.\n");
-    fprintf(output, "                         Useful to remove duplicated packets taken on\n");
-    fprintf(output, "                         several routers (different mac addresses for\n");
-    fprintf(output, "                         example).\n");
-    fprintf(output, "                         e.g. -I 26 in case of Ether/IP will ignore\n");
-    fprintf(output, "                         ether(14) and IP header(20 - 4(src ip) - 4(dst ip)).\n");
-    fprintf(output, "\n");
     fprintf(output, "           NOTE: The use of the 'Duplicate packet removal' options with\n");
     fprintf(output, "           other editcap options except -v may not always work as expected.\n");
     fprintf(output, "           Specifically the -r, -t or -S options will very likely NOT have the\n");
     fprintf(output, "           desired effect if combined with the -d, -D or -w.\n");
+    fprintf(output, "  --skip-radiotap-header skip radiotap header when checking for packet duplicates.\n");
+    fprintf(output, "                         Useful when processing packets captured by multiple radios\n");
+    fprintf(output, "                         on the same channel in the vicinity of each other.\n");
     fprintf(output, "\n");
     fprintf(output, "Packet manipulation:\n");
     fprintf(output, "  -s <snaplen>           truncate each packet to max. <snaplen> bytes of data.\n");
@@ -810,6 +799,18 @@ print_usage(FILE *output)
     fprintf(output, "  -o <change offset>     When used in conjunction with -E, skip some bytes from the\n");
     fprintf(output, "                         beginning of the packet. This allows one to preserve some\n");
     fprintf(output, "                         bytes, in order to have some headers untouched.\n");
+    fprintf(output, "  --seed <seed>          When used in conjunction with -E, set the seed to use for\n");
+    fprintf(output, "                         the pseudo-random number generator. This allows one to\n");
+    fprintf(output, "                         repeat a particular sequence of errors.\n");
+    fprintf(output, "  -I <bytes to ignore>   ignore the specified number of bytes at the beginning\n");
+    fprintf(output, "                         of the frame during MD5 hash calculation, unless the\n");
+    fprintf(output, "                         frame is too short, then the full frame is used.\n");
+    fprintf(output, "                         Useful to remove duplicated packets taken on\n");
+    fprintf(output, "                         several routers (different mac addresses for\n");
+    fprintf(output, "                         example).\n");
+    fprintf(output, "                         e.g. -I 26 in case of Ether/IP will ignore\n");
+    fprintf(output, "                         ether(14) and IP header(20 - 4(src ip) - 4(dst ip)).\n");
+    fprintf(output, "  -a <framenum>:<comment> Add or replace comment for given frame number\n");
     fprintf(output, "\n");
     fprintf(output, "Output File(s):\n");
     fprintf(output, "  -c <packets per file>  split the packet output to different files based on\n");
@@ -830,7 +831,6 @@ print_usage(FILE *output)
     fprintf(output, "                         If -v is used with any of the 'Duplicate Packet\n");
     fprintf(output, "                         Removal' options (-d, -D or -w) then Packet lengths\n");
     fprintf(output, "                         and MD5 hashes are printed to standard-error.\n");
-    fprintf(output, "\n");
 }
 
 struct string_elem {
@@ -853,21 +853,21 @@ string_nat_compare(gconstpointer a, gconstpointer b)
 }
 
 static void
-string_elem_print(gpointer data, gpointer not_used _U_)
+string_elem_print(gpointer data, gpointer stream_ptr)
 {
-    fprintf(stderr, "    %s - %s\n",
+    fprintf((FILE *) stream_ptr, "    %s - %s\n",
         ((struct string_elem *)data)->sstr,
         ((struct string_elem *)data)->lstr);
 }
 
 static void
-list_capture_types(void) {
+list_capture_types(FILE *stream) {
     int i;
     struct string_elem *captypes;
     GSList *list = NULL;
 
     captypes = g_new(struct string_elem,WTAP_NUM_FILE_TYPES_SUBTYPES);
-    fprintf(stderr, "editcap: The available capture file types for the \"-F\" flag are:\n");
+    fprintf(stream, "editcap: The available capture file types for the \"-F\" flag are:\n");
     for (i = 0; i < WTAP_NUM_FILE_TYPES_SUBTYPES; i++) {
         if (wtap_dump_can_open(i)) {
             captypes[i].sstr = wtap_file_type_subtype_short_string(i);
@@ -875,19 +875,19 @@ list_capture_types(void) {
             list = g_slist_insert_sorted(list, &captypes[i], string_compare);
         }
     }
-    g_slist_foreach(list, string_elem_print, NULL);
+    g_slist_foreach(list, string_elem_print, stream);
     g_slist_free(list);
     g_free(captypes);
 }
 
 static void
-list_encap_types(void) {
+list_encap_types(FILE *stream) {
     int i;
     struct string_elem *encaps;
     GSList *list = NULL;
 
     encaps = (struct string_elem *)g_malloc(sizeof(struct string_elem) * WTAP_NUM_ENCAP_TYPES);
-    fprintf(stderr, "editcap: The available encapsulation types for the \"-T\" flag are:\n");
+    fprintf(stream, "editcap: The available encapsulation types for the \"-T\" flag are:\n");
     for (i = 0; i < WTAP_NUM_ENCAP_TYPES; i++) {
         encaps[i].sstr = wtap_encap_short_string(i);
         if (encaps[i].sstr != NULL) {
@@ -895,7 +895,7 @@ list_encap_types(void) {
             list = g_slist_insert_sorted(list, &encaps[i], string_nat_compare);
         }
     }
-    g_slist_foreach(list, string_elem_print, NULL);
+    g_slist_foreach(list, string_elem_print, stream);
     g_slist_free(list);
     g_free(encaps);
 }
@@ -955,8 +955,8 @@ editcap_dump_open(const char *filename, guint32 snaplen,
   return pdh;
 }
 
-int
-main(int argc, char *argv[])
+static int
+real_main(int argc, char *argv[])
 {
     GString      *comp_info_str;
     GString      *runtime_info_str;
@@ -967,6 +967,8 @@ main(int argc, char *argv[])
     int           opt;
     static const struct option long_options[] = {
         {"novlan", no_argument, NULL, 0x8100},
+        {"skip-radiotap-header", no_argument, NULL, 0x8101},
+        {"seed", required_argument, NULL, 0x8102},
         {"help", no_argument, NULL, 'h'},
         {"version", no_argument, NULL, 'V'},
         {0, 0, 0, 0 }
@@ -994,18 +996,21 @@ main(int argc, char *argv[])
     gchar        *fsuffix            = NULL;
     guint32       change_offset      = 0;
     guint         max_packet_number  = 0;
-    const struct wtap_pkthdr    *phdr;
-    struct wtap_pkthdr           temp_phdr;
+    const wtap_rec              *rec;
+    wtap_rec                     temp_rec;
     wtapng_iface_descriptions_t *idb_inf = NULL;
     GArray                      *shb_hdrs = NULL;
     GArray                      *nrb_hdrs = NULL;
     char                        *shb_user_appl;
+    gboolean                     do_mutation;
+    guint32                      caplen;
     int                          ret = EXIT_SUCCESS;
+    gboolean                     valid_seed = FALSE;
+    unsigned int                 seed = 0;
 
     cmdarg_err_init(failure_warning_message, failure_message_cont);
 
 #ifdef _WIN32
-    arg_list_utf_16to8(argc, argv);
     create_app_running_mutex();
 #endif /* _WIN32 */
 
@@ -1034,7 +1039,7 @@ main(int argc, char *argv[])
      * Attempt to get the pathname of the directory containing the
      * executable file.
      */
-    init_progfile_dir_error = init_progfile_dir(argv[0], main);
+    init_progfile_dir_error = init_progfile_dir(argv[0]);
     if (init_progfile_dir_error != NULL) {
         fprintf(stderr,
                 "editcap: Can't get pathname of directory containing the editcap program: %s.\n",
@@ -1042,27 +1047,13 @@ main(int argc, char *argv[])
         g_free(init_progfile_dir_error);
     }
 
-    wtap_init();
-
-#ifdef HAVE_PLUGINS
-    /* Register wiretap plugins */
     init_report_message(failure_warning_message, failure_warning_message,
                         NULL, NULL, NULL);
 
-    /* Scan for plugins.  This does *not* call their registration routines;
-       that's done later.
-
-       Don't report failures to load plugins because most (non-wiretap)
-       plugins *should* fail to load (because we're not linked against
-       libwireshark and dissector plugins need libwireshark). */
-    scan_plugins(DONT_REPORT_LOAD_FAILURE);
-
-    /* Register all libwiretap plugin modules. */
-    register_all_wiretap_modules();
-#endif
+    wtap_init(TRUE);
 
     /* Process the options */
-    while ((opt = getopt_long(argc, argv, "a:A:B:c:C:dD:E:F:hi:I:Lo:rs:S:t:T:vVw:", long_options, NULL)) != -1) {
+    while ((opt = getopt_long(argc, argv, ":a:A:B:c:C:dD:E:F:hi:I:Lo:rs:S:t:T:vVw:", long_options, NULL)) != -1) {
         switch (opt) {
         case 0x8100:
         {
@@ -1070,6 +1061,24 @@ main(int argc, char *argv[])
             break;
         }
 
+        case 0x8101:
+        {
+            skip_radiotap = TRUE;
+            break;
+        }
+
+        case 0x8102:
+        {
+            if (sscanf(optarg, "%u", &seed) != 1) {
+                fprintf(stderr, "editcap: \"%s\" isn't a valid seed\n\n",
+                        optarg);
+                ret = INVALID_OPTION;
+                goto clean_exit;
+            }
+            valid_seed = TRUE;
+            break;
+        }
+
         case 'a':
         {
             guint frame_number;
@@ -1197,7 +1206,6 @@ main(int argc, char *argv[])
                 ret = INVALID_OPTION;
                 goto clean_exit;
             }
-            srand( (unsigned int) (time(NULL) + ws_getpid()) );
             break;
 
         case 'F':
@@ -1205,7 +1213,7 @@ main(int argc, char *argv[])
             if (out_file_type_subtype < 0) {
                 fprintf(stderr, "editcap: \"%s\" isn't a valid capture file type\n\n",
                         optarg);
-                list_capture_types();
+                list_capture_types(stderr);
                 ret = INVALID_OPTION;
                 goto clean_exit;
             }
@@ -1264,7 +1272,7 @@ main(int argc, char *argv[])
             if (out_frame_type < 0) {
                 fprintf(stderr, "editcap: \"%s\" isn't a valid encapsulation type\n\n",
                         optarg);
-                list_encap_types();
+                list_encap_types(stderr);
                 ret = INVALID_OPTION;
                 goto clean_exit;
             }
@@ -1294,18 +1302,24 @@ main(int argc, char *argv[])
             break;
 
         case '?':              /* Bad options if GNU getopt */
+        case ':':              /* missing option argument */
             switch(optopt) {
             case'F':
-                list_capture_types();
+                list_capture_types(stdout);
                 break;
             case'T':
-                list_encap_types();
+                list_encap_types(stdout);
                 break;
             default:
+                if (opt == '?') {
+                    fprintf(stderr, "editcap: invalid option -- '%c'\n", optopt);
+                } else {
+                    fprintf(stderr, "editcap: option requires an argument -- '%c'\n", optopt);
+                }
                 print_usage(stderr);
+                ret = INVALID_OPTION;
                 break;
             }
-            ret = INVALID_OPTION;
             goto clean_exit;
             break;
         }
@@ -1319,6 +1333,17 @@ main(int argc, char *argv[])
         print_usage(stderr);
         ret = INVALID_OPTION;
         goto clean_exit;
+
+    }
+
+    if (err_prob >= 0.0) {
+        if (!valid_seed) {
+            seed = (unsigned int) (time(NULL) + ws_getpid());
+        }
+        if (verbose) {
+            fprintf(stderr, "Using seed %u\n", seed);
+        }
+        srand(seed);
     }
 
     if (check_startstop && !stoptime) {
@@ -1329,6 +1354,7 @@ main(int argc, char *argv[])
         stoptm.tm_year = 135;
         stoptm.tm_mday = 31;
         stoptm.tm_mon = 11;
+        stoptm.tm_isdst = -1;
 
         stoptime = mktime(&stoptm);
     }
@@ -1351,8 +1377,8 @@ main(int argc, char *argv[])
     wth = wtap_open_offline(argv[optind], WTAP_TYPE_AUTO, &read_err, &read_err_info, FALSE);
 
     if (!wth) {
-        cfile_open_failure_message("editap", argv[optind], read_err,
-                                   read_err_info, FALSE, WTAP_TYPE_AUTO);
+        cfile_open_failure_message("editcap", argv[optind], read_err,
+                                   read_err_info);
         ret = INVALID_FILE;
         goto clean_exit;
     }
@@ -1362,6 +1388,22 @@ main(int argc, char *argv[])
                 wtap_file_type_subtype_string(wtap_file_type_subtype(wth)));
     }
 
+    if (ignored_bytes != 0 && skip_radiotap == TRUE) {
+        fprintf(stderr, "editcap: can't skip radiotap headers and %d byte(s)\n", ignored_bytes);
+        fprintf(stderr, "editcap: at the start of packet at the same time\n");
+        ret = INVALID_OPTION;
+        goto clean_exit;
+    }
+
+    if (skip_radiotap == TRUE && wtap_file_encap(wth) != WTAP_ENCAP_IEEE_802_11_RADIOTAP) {
+        fprintf(stderr, "editcap: can't skip radiotap header because input file is incorrect\n");
+        fprintf(stderr, "editcap: expected '%s', input is '%s'\n",
+                wtap_encap_string(WTAP_ENCAP_IEEE_802_11_RADIOTAP),
+                wtap_encap_string(wtap_file_type_subtype(wth)));
+        ret = INVALID_OPTION;
+        goto clean_exit;
+    }
+
     shb_hdrs = wtap_file_get_shb_for_new_file(wth);
     idb_inf = wtap_file_get_idb_info(wth);
     nrb_hdrs = wtap_file_get_nrb_for_new_file(wth);
@@ -1397,7 +1439,7 @@ main(int argc, char *argv[])
 
             read_count++;
 
-            phdr = wtap_phdr(wth);
+            rec = wtap_get_rec(wth);
 
             /* Extra actions for the first packet */
             if (read_count == 1) {
@@ -1407,7 +1449,7 @@ main(int argc, char *argv[])
                         goto clean_exit;
                     }
 
-                    filename = fileset_get_filename_by_pattern(block_cnt++, phdr, fprefix, fsuffix);
+                    filename = fileset_get_filename_by_pattern(block_cnt++, rec, fprefix, fsuffix);
                 } else {
                     filename = g_strdup(argv[optind+1]);
                 }
@@ -1423,29 +1465,29 @@ main(int argc, char *argv[])
                                         shb_hdrs, idb_inf, nrb_hdrs, &write_err);
 
                 if (pdh == NULL) {
-                    cfile_open_failure_message("editcap", filename,
-                                               write_err, NULL, TRUE,
-                                               out_frame_type);
+                    cfile_dump_open_failure_message("editcap", filename,
+                                                    write_err,
+                                                    out_file_type_subtype);
                     ret = INVALID_FILE;
                     goto clean_exit;
                 }
             } /* first packet only handling */
 
 
-            buf = wtap_buf_ptr(wth);
+            buf = wtap_get_buf_ptr(wth);
 
             /*
              * Not all packets have time stamps. Only process the time
              * stamp if we have one.
              */
-            if (phdr->presence_flags & WTAP_HAS_TS) {
+            if (rec->presence_flags & WTAP_HAS_TS) {
                 if (nstime_is_unset(&block_start)) {
-                    block_start = phdr->ts;
+                    block_start = rec->ts;
                 }
                 if (secs_per_block != 0) {
-                    while (((guint32)(phdr->ts.secs - block_start.secs) >  secs_per_block)
-                           || ((guint32)(phdr->ts.secs - block_start.secs) == secs_per_block
-                               && phdr->ts.nsecs >= block_start.nsecs )) { /* time for the next file */
+                    while (((guint32)(rec->ts.secs - block_start.secs) >  secs_per_block)
+                           || ((guint32)(rec->ts.secs - block_start.secs) == secs_per_block
+                               && rec->ts.nsecs >= block_start.nsecs )) { /* time for the next file */
 
                         if (!wtap_dump_close(pdh, &write_err)) {
                             cfile_close_failure_message(filename, write_err);
@@ -1454,7 +1496,7 @@ main(int argc, char *argv[])
                         }
                         block_start.secs = block_start.secs +  secs_per_block; /* reset for next interval */
                         g_free(filename);
-                        filename = fileset_get_filename_by_pattern(block_cnt++, phdr, fprefix, fsuffix);
+                        filename = fileset_get_filename_by_pattern(block_cnt++, rec, fprefix, fsuffix);
                         g_assert(filename);
 
                         if (verbose)
@@ -1465,9 +1507,9 @@ main(int argc, char *argv[])
                                                 shb_hdrs, idb_inf, nrb_hdrs, &write_err);
 
                         if (pdh == NULL) {
-                            cfile_open_failure_message("editcap", filename,
-                                                       write_err, NULL, TRUE,
-                                                       out_frame_type);
+                            cfile_dump_open_failure_message("editcap", filename,
+                                                            write_err,
+                                                            out_file_type_subtype);
                             ret = INVALID_FILE;
                             goto clean_exit;
                         }
@@ -1485,7 +1527,7 @@ main(int argc, char *argv[])
                     }
 
                     g_free(filename);
-                    filename = fileset_get_filename_by_pattern(block_cnt++, phdr, fprefix, fsuffix);
+                    filename = fileset_get_filename_by_pattern(block_cnt++, rec, fprefix, fsuffix);
                     g_assert(filename);
 
                     if (verbose)
@@ -1495,9 +1537,9 @@ main(int argc, char *argv[])
                                             snaplen ? MIN(snaplen, wtap_snapshot_length(wth)) : wtap_snapshot_length(wth),
                                             shb_hdrs, idb_inf, nrb_hdrs, &write_err);
                     if (pdh == NULL) {
-                        cfile_open_failure_message("editcap", filename,
-                                                   write_err, NULL, TRUE,
-                                                   out_frame_type);
+                        cfile_dump_open_failure_message("editcap", filename,
+                                                        write_err,
+                                                        out_file_type_subtype);
                         ret = INVALID_FILE;
                         goto clean_exit;
                     }
@@ -1509,8 +1551,8 @@ main(int argc, char *argv[])
                  * Is the packet in the selected timeframe?
                  * If the packet has no time stamp, the answer is "no".
                  */
-                if (phdr->presence_flags & WTAP_HAS_TS)
-                    ts_okay = (phdr->ts.secs >= starttime) && (phdr->ts.secs < stoptime);
+                if (rec->presence_flags & WTAP_HAS_TS)
+                    ts_okay = (rec->ts.secs >= starttime) && (rec->ts.secs < stoptime);
                 else
                     ts_okay = FALSE;
             } else {
@@ -1530,31 +1572,9 @@ main(int argc, char *argv[])
                 /* We simply write it, perhaps after truncating it; we could
                  * do other things, like modify it. */
 
-                phdr = wtap_phdr(wth);
+                rec = wtap_get_rec(wth);
 
-                if (snaplen != 0) {
-                    /* Limit capture length to snaplen */
-                    if (phdr->caplen > snaplen) {
-                        /* Copy and change rather than modify returned phdr */
-                        temp_phdr = *phdr;
-                        temp_phdr.caplen = snaplen;
-                        phdr = &temp_phdr;
-                    }
-                    /* If -L, also set reported length to snaplen */
-                    if (adjlen && phdr->len > snaplen) {
-                        /* Copy and change rather than modify returned phdr */
-                        temp_phdr = *phdr;
-                        temp_phdr.len = snaplen;
-                        phdr = &temp_phdr;
-                    }
-                }
-
-                /* CHOP */
-                temp_phdr = *phdr;
-                handle_chopping(chop, &temp_phdr, phdr, &buf, adjlen);
-                phdr = &temp_phdr;
-
-                if (phdr->presence_flags & WTAP_HAS_TS) {
+                if (rec->presence_flags & WTAP_HAS_TS) {
                     /* Do we adjust timestamps to ensure strict chronological
                      * order? */
                     if (do_strict_time_adjustment) {
@@ -1563,7 +1583,7 @@ main(int argc, char *argv[])
                                 nstime_t current;
                                 nstime_t delta;
 
-                                current = phdr->ts;
+                                current = rec->ts;
 
                                 nstime_delta(&delta, &current, &previous_time);
 
@@ -1574,116 +1594,122 @@ main(int argc, char *argv[])
                                      * that it is being compared to.  This is NOT a normal
                                      * situation since trace files usually have packets in
                                      * chronological order (oldest to newest).
+                                     * Copy and change rather than modify
+                                     * returned rec.
                                      */
                                     /* fprintf(stderr, "++out of order, need to adjust this packet!\n"); */
-                                    temp_phdr = *phdr;
-                                    temp_phdr.ts.secs = previous_time.secs + strict_time_adj.tv.secs;
-                                    temp_phdr.ts.nsecs = previous_time.nsecs;
-                                    if (temp_phdr.ts.nsecs + strict_time_adj.tv.nsecs > ONE_BILLION) {
+                                    temp_rec = *rec;
+                                    temp_rec.ts.secs = previous_time.secs + strict_time_adj.tv.secs;
+                                    temp_rec.ts.nsecs = previous_time.nsecs;
+                                    if (temp_rec.ts.nsecs + strict_time_adj.tv.nsecs >= ONE_BILLION) {
                                         /* carry */
-                                        temp_phdr.ts.secs++;
-                                        temp_phdr.ts.nsecs += strict_time_adj.tv.nsecs - ONE_BILLION;
+                                        temp_rec.ts.secs++;
+                                        temp_rec.ts.nsecs += strict_time_adj.tv.nsecs - ONE_BILLION;
                                     } else {
-                                        temp_phdr.ts.nsecs += strict_time_adj.tv.nsecs;
+                                        temp_rec.ts.nsecs += strict_time_adj.tv.nsecs;
                                     }
-                                    phdr = &temp_phdr;
+                                    rec = &temp_rec;
                                 }
                             } else {
                                 /*
                                  * A negative strict time adjustment is requested.
                                  * Unconditionally set each timestamp to previous
                                  * packet's timestamp plus delta.
+                                 * Copy and change rather than modify returned
+                                 * rec.
                                  */
-                                temp_phdr = *phdr;
-                                temp_phdr.ts.secs = previous_time.secs + strict_time_adj.tv.secs;
-                                temp_phdr.ts.nsecs = previous_time.nsecs;
-                                if (temp_phdr.ts.nsecs + strict_time_adj.tv.nsecs > ONE_BILLION) {
+                                temp_rec = *rec;
+                                temp_rec.ts.secs = previous_time.secs + strict_time_adj.tv.secs;
+                                temp_rec.ts.nsecs = previous_time.nsecs;
+                                if (temp_rec.ts.nsecs + strict_time_adj.tv.nsecs >= ONE_BILLION) {
                                     /* carry */
-                                    temp_phdr.ts.secs++;
-                                    temp_phdr.ts.nsecs += strict_time_adj.tv.nsecs - ONE_BILLION;
+                                    temp_rec.ts.secs++;
+                                    temp_rec.ts.nsecs += strict_time_adj.tv.nsecs - ONE_BILLION;
                                 } else {
-                                    temp_phdr.ts.nsecs += strict_time_adj.tv.nsecs;
+                                    temp_rec.ts.nsecs += strict_time_adj.tv.nsecs;
                                 }
-                                phdr = &temp_phdr;
+                                rec = &temp_rec;
                             }
                         }
-                        previous_time = phdr->ts;
+                        previous_time = rec->ts;
                     }
 
                     if (time_adj.tv.secs != 0) {
-                        temp_phdr = *phdr;
+                        /* Copy and change rather than modify returned rec */
+                        temp_rec = *rec;
                         if (time_adj.is_negative)
-                            temp_phdr.ts.secs -= time_adj.tv.secs;
+                            temp_rec.ts.secs -= time_adj.tv.secs;
                         else
-                            temp_phdr.ts.secs += time_adj.tv.secs;
-                        phdr = &temp_phdr;
+                            temp_rec.ts.secs += time_adj.tv.secs;
+                        rec = &temp_rec;
                     }
 
                     if (time_adj.tv.nsecs != 0) {
-                        temp_phdr = *phdr;
+                        /* Copy and change rather than modify returned rec */
+                        temp_rec = *rec;
                         if (time_adj.is_negative) { /* subtract */
-                            if (temp_phdr.ts.nsecs < time_adj.tv.nsecs) { /* borrow */
-                                temp_phdr.ts.secs--;
-                                temp_phdr.ts.nsecs += ONE_BILLION;
+                            if (temp_rec.ts.nsecs < time_adj.tv.nsecs) { /* borrow */
+                                temp_rec.ts.secs--;
+                                temp_rec.ts.nsecs += ONE_BILLION;
                             }
-                            temp_phdr.ts.nsecs -= time_adj.tv.nsecs;
+                            temp_rec.ts.nsecs -= time_adj.tv.nsecs;
                         } else {                  /* add */
-                            if (temp_phdr.ts.nsecs + time_adj.tv.nsecs > ONE_BILLION) {
+                            if (temp_rec.ts.nsecs + time_adj.tv.nsecs >= ONE_BILLION) {
                                 /* carry */
-                                temp_phdr.ts.secs++;
-                                temp_phdr.ts.nsecs += time_adj.tv.nsecs - ONE_BILLION;
+                                temp_rec.ts.secs++;
+                                temp_rec.ts.nsecs += time_adj.tv.nsecs - ONE_BILLION;
                             } else {
-                                temp_phdr.ts.nsecs += time_adj.tv.nsecs;
+                                temp_rec.ts.nsecs += time_adj.tv.nsecs;
                             }
                         }
-                        phdr = &temp_phdr;
+                        rec = &temp_rec;
                     }
                 } /* time stamp adjustment */
 
-                /* remove vlan info */
-                if (rem_vlan) {
-                    /* TODO: keep casting const like this? change pointer instead of value? */
-                    remove_vlan_info(phdr, buf, (guint32 *) &phdr->caplen);
-                }
-
-                /* suppress duplicates by packet window */
-                if (dup_detect) {
-                    if (is_duplicate(buf, phdr->caplen)) {
-                        if (verbose) {
-                            fprintf(stderr, "Skipped: %u, Len: %u, MD5 Hash: ",
-                                    count, phdr->caplen);
-                            for (i = 0; i < 16; i++)
-                                fprintf(stderr, "%02x",
-                                        (unsigned char)fd_hash[cur_dup_entry].digest[i]);
-                            fprintf(stderr, "\n");
+                if (rec->rec_type == REC_TYPE_PACKET) {
+                    if (snaplen != 0) {
+                        /* Limit capture length to snaplen */
+                        if (rec->rec_header.packet_header.caplen > snaplen) {
+                            /* Copy and change rather than modify returned wtap_rec */
+                            temp_rec = *rec;
+                            temp_rec.rec_header.packet_header.caplen = snaplen;
+                            rec = &temp_rec;
                         }
-                        duplicate_count++;
-                        count++;
-                        continue;
-                    } else {
-                        if (verbose) {
-                            fprintf(stderr, "Packet: %u, Len: %u, MD5 Hash: ",
-                                    count, phdr->caplen);
-                            for (i = 0; i < 16; i++)
-                                fprintf(stderr, "%02x",
-                                        (unsigned char)fd_hash[cur_dup_entry].digest[i]);
-                            fprintf(stderr, "\n");
+                        /* If -L, also set reported length to snaplen */
+                        if (adjlen && rec->rec_header.packet_header.len > snaplen) {
+                            /* Copy and change rather than modify returned phdr */
+                            temp_rec = *rec;
+                            temp_rec.rec_header.packet_header.len = snaplen;
+                            rec = &temp_rec;
                         }
                     }
-                } /* suppression of duplicates */
 
-                if (phdr->presence_flags & WTAP_HAS_TS) {
-                    /* suppress duplicates by time window */
-                    if (dup_detect_by_time) {
-                        nstime_t current;
-
-                        current.secs  = phdr->ts.secs;
-                        current.nsecs = phdr->ts.nsecs;
+                    /*
+                     * CHOP
+                     * Copy and change rather than modify returned phdr.
+                     */
+                    temp_rec = *rec;
+                    handle_chopping(chop, &temp_rec.rec_header.packet_header,
+                                    &rec->rec_header.packet_header, &buf,
+                                    adjlen);
+                    rec = &temp_rec;
+
+                    /* remove vlan info */
+                    if (rem_vlan) {
+                        /* Copy and change rather than modify returned rec */
+                        temp_rec = *rec;
+                        remove_vlan_info(&rec->rec_header.packet_header, buf,
+                                         &temp_rec.rec_header.packet_header.caplen);
+                        rec = &temp_rec;
+                    }
 
-                        if (is_duplicate_rel_time(buf, phdr->caplen, &current)) {
+                    /* suppress duplicates by packet window */
+                    if (dup_detect) {
+                        if (is_duplicate(buf, rec->rec_header.packet_header.caplen)) {
                             if (verbose) {
                                 fprintf(stderr, "Skipped: %u, Len: %u, MD5 Hash: ",
-                                        count, phdr->caplen);
+                                        count,
+                                        rec->rec_header.packet_header.caplen);
                                 for (i = 0; i < 16; i++)
                                     fprintf(stderr, "%02x",
                                             (unsigned char)fd_hash[cur_dup_entry].digest[i]);
@@ -1695,32 +1721,99 @@ main(int argc, char *argv[])
                         } else {
                             if (verbose) {
                                 fprintf(stderr, "Packet: %u, Len: %u, MD5 Hash: ",
-                                        count, phdr->caplen);
+                                        count,
+                                        rec->rec_header.packet_header.caplen);
                                 for (i = 0; i < 16; i++)
                                     fprintf(stderr, "%02x",
                                             (unsigned char)fd_hash[cur_dup_entry].digest[i]);
                                 fprintf(stderr, "\n");
                             }
                         }
+                    } /* suppression of duplicates */
+
+                    if (rec->presence_flags & WTAP_HAS_TS) {
+                        /* suppress duplicates by time window */
+                        if (dup_detect_by_time) {
+                            nstime_t current;
+
+                            current.secs  = rec->ts.secs;
+                            current.nsecs = rec->ts.nsecs;
+
+                            if (is_duplicate_rel_time(buf,
+                                                      rec->rec_header.packet_header.caplen,
+                                                      &current)) {
+                                if (verbose) {
+                                    fprintf(stderr, "Skipped: %u, Len: %u, MD5 Hash: ",
+                                            count,
+                                            rec->rec_header.packet_header.caplen);
+                                    for (i = 0; i < 16; i++)
+                                        fprintf(stderr, "%02x",
+                                                (unsigned char)fd_hash[cur_dup_entry].digest[i]);
+                                    fprintf(stderr, "\n");
+                                }
+                                duplicate_count++;
+                                count++;
+                                continue;
+                            } else {
+                                if (verbose) {
+                                    fprintf(stderr, "Packet: %u, Len: %u, MD5 Hash: ",
+                                            count,
+                                            rec->rec_header.packet_header.caplen);
+                                    for (i = 0; i < 16; i++)
+                                        fprintf(stderr, "%02x",
+                                                (unsigned char)fd_hash[cur_dup_entry].digest[i]);
+                                    fprintf(stderr, "\n");
+                                }
+                            }
+                        }
+                    } /* suppress duplicates by time window */
+                }
+
+                /* Random error mutation */
+                do_mutation = FALSE;
+                caplen = 0;
+                if (err_prob > 0.0) {
+                    switch (rec->rec_type) {
+
+                    case REC_TYPE_PACKET:
+                        caplen = rec->rec_header.packet_header.caplen;
+                        do_mutation = TRUE;
+                        break;
+
+                    case REC_TYPE_FT_SPECIFIC_EVENT:
+                    case REC_TYPE_FT_SPECIFIC_REPORT:
+                        caplen = rec->rec_header.ft_specific_header.record_len;
+                        do_mutation = TRUE;
+                        break;
+
+                    case REC_TYPE_SYSCALL:
+                        caplen = rec->rec_header.syscall_header.event_filelen;
+                        do_mutation = TRUE;
+                        break;
                     }
-                } /* suppress duplicates by time window */
 
-                if (change_offset > phdr->caplen) {
-                    fprintf(stderr, "change offset %u is longer than caplen %u in packet %u\n",
-                        change_offset, phdr->caplen, count);
+                    if (change_offset > caplen) {
+                        fprintf(stderr, "change offset %u is longer than caplen %u in packet %u\n",
+                            change_offset, caplen, count);
+                        do_mutation = FALSE;
+                    }
                 }
 
-                /* Random error mutation */
-                if (err_prob > 0.0 && change_offset <= phdr->caplen) {
+                if (do_mutation) {
                     int real_data_start = 0;
 
                     /* Protect non-protocol data */
-                    if (wtap_file_type_subtype(wth) == WTAP_FILE_TYPE_SUBTYPE_CATAPULT_DCT2000)
-                        real_data_start = find_dct2000_real_data(buf);
+                    switch (rec->rec_type) {
+
+                    case REC_TYPE_PACKET:
+                        if (wtap_file_type_subtype(wth) == WTAP_FILE_TYPE_SUBTYPE_CATAPULT_DCT2000)
+                            real_data_start = find_dct2000_real_data(buf);
+                        break;
+                    }
 
                     real_data_start += change_offset;
 
-                    for (i = real_data_start; i < (int) phdr->caplen; i++) {
+                    for (i = real_data_start; i < (int) caplen; i++) {
                         if (rand() <= err_prob * RAND_MAX) {
                             err_type = rand() / (RAND_MAX / ERR_WT_TOTAL + 1);
 
@@ -1746,7 +1839,7 @@ main(int argc, char *argv[])
                             }
 
                             if (err_type < ERR_WT_FMT) {
-                                if ((unsigned int)i < phdr->caplen - 2)
+                                if ((unsigned int)i < caplen - 2)
                                     g_strlcpy((char*) &buf[i], "%s", 2);
                                 err_type = ERR_WT_TOTAL;
                             } else {
@@ -1754,9 +1847,9 @@ main(int argc, char *argv[])
                             }
 
                             if (err_type < ERR_WT_AA) {
-                                for (j = i; j < (int) phdr->caplen; j++)
+                                for (j = i; j < (int) caplen; j++)
                                     buf[j] = 0xAA;
-                                i = phdr->caplen;
+                                i = caplen;
                             }
                         }
                     }
@@ -1766,17 +1859,25 @@ main(int argc, char *argv[])
                 if (frames_user_comments) {
                     const char *comment =
                         (const char*)g_tree_lookup(frames_user_comments, GUINT_TO_POINTER(read_count));
+                    /* XXX: What about comment changed to no comment? */
                     if (comment != NULL) {
-                        /* Copy and change rather than modify returned phdr */
-                        temp_phdr = *phdr;
-                        temp_phdr.opt_comment = g_strdup(comment);
-                        phdr = &temp_phdr;
+                        /* Copy and change rather than modify returned rec */
+                        temp_rec = *rec;
+                        temp_rec.opt_comment = g_strdup(comment);
+                        temp_rec.has_comment_changed = TRUE;
+                        rec = &temp_rec;
+                    } else {
+                        /* Copy and change rather than modify returned rec */
+                        temp_rec = *rec;
+                        temp_rec.has_comment_changed = FALSE;
+                        rec = &temp_rec;
                     }
                 }
 
                 /* Attempt to dump out current frame to the output file */
-                if (!wtap_dump(pdh, phdr, buf, &write_err, &write_err_info)) {
-                    cfile_write_failure_message(argv[optind], filename,
+                if (!wtap_dump(pdh, rec, buf, &write_err, &write_err_info)) {
+                    cfile_write_failure_message("editcap", argv[optind],
+                                                filename,
                                                 write_err, write_err_info,
                                                 read_count,
                                                 out_file_type_subtype);
@@ -1808,9 +1909,9 @@ main(int argc, char *argv[])
                                     snaplen ? MIN(snaplen, wtap_snapshot_length(wth)): wtap_snapshot_length(wth),
                                     shb_hdrs, idb_inf, nrb_hdrs, &write_err);
             if (pdh == NULL) {
-                cfile_open_failure_message("editcap", filename,
-                                           write_err, NULL, TRUE,
-                                           out_frame_type);
+                cfile_dump_open_failure_message("editcap", filename,
+                                                write_err,
+                                                out_file_type_subtype);
                 ret = INVALID_FILE;
                 goto clean_exit;
             }
@@ -1848,12 +1949,26 @@ clean_exit:
         wtap_close(wth);
     wtap_cleanup();
     free_progdirs();
-#ifdef HAVE_PLUGINS
-    plugins_cleanup();
-#endif
     return ret;
 }
 
+#ifdef _WIN32
+int
+wmain(int argc, wchar_t *wc_argv[])
+{
+    char **argv;
+
+    argv = arg_list_utf_16to8(argc, wc_argv);
+    return real_main(argc, argv);
+}
+#else
+int
+main(int argc, char *argv[])
+{
+    return real_main(argc, argv);
+}
+#endif
+
 /* Skip meta-information read from file to return offset of real
  * protocol data */
 static int
@@ -1882,14 +1997,10 @@ find_dct2000_real_data(guint8 *buf)
  * positive chop length, and one by the negative chop length.
  */
 static void
-handle_chopping(chop_t chop, struct wtap_pkthdr *out_phdr,
-                const struct wtap_pkthdr *in_phdr, guint8 **buf,
+handle_chopping(chop_t chop, wtap_packet_header *out_phdr,
+                const wtap_packet_header *in_phdr, guint8 **buf,
                 gboolean adjlen)
 {
-    /* Only packets can be chopped. */
-    if (in_phdr->rec_type != REC_TYPE_PACKET)
-        return;
-
     /* If we're not chopping anything from one side, then the offset for that
      * side is meaningless. */
     if (chop.len_begin == 0)