Make the time stamp resolution per-packet.
[metze/wireshark/wip.git] / wiretap / file_access.c
1 /* file_access.c
2  *
3  * Wiretap Library
4  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20
21 #include "config.h"
22
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdlib.h>
26
27 #ifdef HAVE_FCNTL_H
28 #include <fcntl.h>
29 #endif
30
31 #ifdef HAVE_UNISTD_H
32 #include <unistd.h>
33 #endif
34
35 #include <errno.h>
36
37 #include <wsutil/file_util.h>
38
39 #include "wtap-int.h"
40 #include "file_wrappers.h"
41 #include <wsutil/buffer.h>
42 #include "lanalyzer.h"
43 #include "ngsniffer.h"
44 #include "radcom.h"
45 #include "ascendtext.h"
46 #include "nettl.h"
47 #include "libpcap.h"
48 #include "snoop.h"
49 #include "iptrace.h"
50 #include "iseries.h"
51 #include "netmon.h"
52 #include "netxray.h"
53 #include "toshiba.h"
54 #include "eyesdn.h"
55 #include "i4btrace.h"
56 #include "csids.h"
57 #include "pppdump.h"
58 #include "peekclassic.h"
59 #include "peektagged.h"
60 #include "vms.h"
61 #include "dbs-etherwatch.h"
62 #include "visual.h"
63 #include "cosine.h"
64 #include "5views.h"
65 #include "erf.h"
66 #include "hcidump.h"
67 #include "logcat.h"
68 #include "logcat_text.h"
69 #include "network_instruments.h"
70 #include "k12.h"
71 #include "ber.h"
72 #include "catapult_dct2000.h"
73 #include "mp2t.h"
74 #include "mpeg.h"
75 #include "netscreen.h"
76 #include "commview.h"
77 #include "pcapng.h"
78 #include "aethra.h"
79 #include "btsnoop.h"
80 #include "tnef.h"
81 #include "dct3trace.h"
82 #include "packetlogger.h"
83 #include "daintree-sna.h"
84 #include "netscaler.h"
85 #include "mime_file.h"
86 #include "ipfix.h"
87 #include "vwr.h"
88 #include "camins.h"
89 #include "stanag4607.h"
90 #include "pcap-encap.h"
91
92 /*
93  * Add an extension, and all compressed versions thereof, to a GSList
94  * of extensions.
95  */
96 static GSList *
97 add_extensions(GSList *extensions, const gchar *extension,
98     GSList *compressed_file_extensions)
99 {
100         GSList *compressed_file_extension;
101
102         /*
103          * Add the specified extension.
104          */
105         extensions = g_slist_append(extensions, g_strdup(extension));
106
107         /*
108          * Now add the extensions for compressed-file versions of
109          * that extension.
110          */
111         for (compressed_file_extension = compressed_file_extensions;
112             compressed_file_extension != NULL;
113             compressed_file_extension = g_slist_next(compressed_file_extension)) {
114                 extensions = g_slist_append(extensions,
115                     g_strdup_printf("%s.%s", extension,
116                       (gchar *)compressed_file_extension->data));
117         }
118
119         return extensions;
120 }
121
122 /*
123  * File types that can be identified by file extensions.
124  */
125 static const struct file_extension_info file_type_extensions_base[] = {
126         { "Wireshark/tcpdump/... - pcap", "pcap;cap;dmp" },
127         { "Wireshark/... - pcapng", "pcapng;ntar" },
128         { "Network Monitor, Surveyor, NetScaler", "cap" },
129         { "InfoVista 5View capture", "5vw" },
130         { "Sniffer (DOS)", "cap;enc;trc;fdc;syc" },
131         { "NetXRay, Sniffer (Windows)", "cap;caz" },
132         { "Endace ERF capture", "erf" },
133         { "EyeSDN USB S0/E1 ISDN trace format", "trc" },
134         { "HP-UX nettl trace", "trc0;trc1" },
135         { "Network Instruments Observer", "bfr" },
136         { "Novell LANalyzer", "tr1" },
137         { "Tektronix K12xx 32-bit .rf5 format", "rf5" },
138         { "WildPackets *Peek", "pkt;tpc;apc;wpz" },
139         { "Catapult DCT2000 trace (.out format)", "out" },
140         { "MPEG files", "mpg;mp3" },
141         { "CommView", "ncf" },
142         { "Symbian OS btsnoop", "log" },
143         { "Transport-Neutral Encapsulation Format", "tnef" },
144         { "XML files (including Gammu DCT3 traces)", "xml" },
145         { "OS X PacketLogger", "pklg" },
146         { "Daintree SNA", "dcf" },
147         { "JPEG/JFIF files", "jpg;jpeg;jfif" },
148         { "IPFIX File Format", "pfx;ipfix" },
149         { "Aethra .aps file", "aps" },
150         { "MPEG2 transport stream", "mp2t;ts;mpg" },
151         { "Ixia IxVeriWave .vwr Raw 802.11 Capture", "vwr" },
152         { "CAM Inspector file", "camins" },
153 };
154
155 #define N_FILE_TYPE_EXTENSIONS  (sizeof file_type_extensions_base / sizeof file_type_extensions_base[0])
156
157 static const struct file_extension_info* file_type_extensions = NULL;
158
159 static GArray* file_type_extensions_arr = NULL;
160
161 /* initialize the extensions array if it has not been initialized yet */
162 static void
163 init_file_type_extensions(void)
164 {
165
166         if (file_type_extensions_arr) return;
167
168         file_type_extensions_arr = g_array_new(FALSE,TRUE,sizeof(struct file_extension_info));
169
170         g_array_append_vals(file_type_extensions_arr,file_type_extensions_base,N_FILE_TYPE_EXTENSIONS);
171
172         file_type_extensions = (struct file_extension_info*)(void *)file_type_extensions_arr->data;
173 }
174
175 void
176 wtap_register_file_type_extension(const struct file_extension_info *ei)
177 {
178         init_file_type_extensions();
179
180         g_array_append_val(file_type_extensions_arr,*ei);
181
182         file_type_extensions = (const struct file_extension_info*)(void *)file_type_extensions_arr->data;
183 }
184
185 int
186 wtap_get_num_file_type_extensions(void)
187 {
188         return file_type_extensions_arr->len;
189 }
190
191 const char *
192 wtap_get_file_extension_type_name(int extension_type)
193 {
194         return file_type_extensions[extension_type].name;
195 }
196
197 static GSList *
198 add_extensions_for_file_extensions_type(int extension_type,
199     GSList *extensions, GSList *compressed_file_extensions)
200 {
201         gchar **extensions_set, **extensionp, *extension;
202
203         /*
204          * Split the extension-list string into a set of extensions.
205          */
206         extensions_set = g_strsplit(file_type_extensions[extension_type].extensions,
207             ";", 0);
208
209         /*
210          * Add each of those extensions to the list.
211          */
212         for (extensionp = extensions_set; *extensionp != NULL; extensionp++) {
213                 extension = *extensionp;
214
215                 /*
216                  * Add the extension, and all compressed variants
217                  * of it.
218                  */
219                 extensions = add_extensions(extensions, extension,
220                     compressed_file_extensions);
221         }
222
223         g_strfreev(extensions_set);
224         return extensions;
225 }
226
227 /* Return a list of file extensions that are used by the specified file
228    extension type.
229
230    All strings in the list are allocated with g_malloc() and must be freed
231    with g_free(). */
232 GSList *
233 wtap_get_file_extension_type_extensions(guint extension_type)
234 {
235         GSList *compressed_file_extensions;
236         GSList *extensions;
237
238         if (extension_type >= file_type_extensions_arr->len)
239                 return NULL;    /* not a valid extension type */
240
241         extensions = NULL;      /* empty list, to start with */
242
243         /*
244          * Get the list of compressed-file extensions.
245          */
246         compressed_file_extensions = wtap_get_compressed_file_extensions();
247
248         /*
249          * Add all this file extension type's extensions, with compressed
250          * variants.
251          */
252         extensions = add_extensions_for_file_extensions_type(extension_type,
253             extensions, compressed_file_extensions);
254
255         g_slist_free(compressed_file_extensions);
256         return extensions;
257 }
258
259 /* Return a list of all extensions that are used by all file types,
260    including compressed extensions, e.g. not just "pcap" but also
261    "pcap.gz" if we can read gzipped files.
262
263    All strings in the list are allocated with g_malloc() and must be freed
264    with g_free(). */
265 GSList *
266 wtap_get_all_file_extensions_list(void)
267 {
268         GSList *compressed_file_extensions;
269         GSList *extensions;
270         unsigned int i;
271
272         init_file_type_extensions();
273
274         extensions = NULL;      /* empty list, to start with */
275
276         /*
277          * Get the list of compressed-file extensions.
278          */
279         compressed_file_extensions = wtap_get_compressed_file_extensions();
280
281         for (i = 0; i < file_type_extensions_arr->len; i++) {
282                 /*
283                  * Add all this file extension type's extensions, with
284                  * compressed variants.
285                  */
286                 extensions = add_extensions_for_file_extensions_type(i,
287                     extensions, compressed_file_extensions);
288         }
289
290         g_slist_free(compressed_file_extensions);
291         return extensions;
292 }
293
294 /*
295  * The open_file_* routines should return:
296  *
297  *      -1 on an I/O error;
298  *
299  *      1 if the file they're reading is one of the types it handles;
300  *
301  *      0 if the file they're reading isn't the type they're checking for.
302  *
303  * If the routine handles this type of file, it should set the "file_type"
304  * field in the "struct wtap" to the type of the file.
305  *
306  * Note that the routine does not have to free the private data pointer on
307  * error. The caller takes care of that by calling wtap_close on error.
308  * (See https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=8518)
309  *
310  * However, the caller does have to free the private data pointer when
311  * returning 0, since the next file type will be called and will likely
312  * just overwrite the pointer.
313  */
314 static struct open_info open_info_base[] = {
315         { "Pcap",                        OPEN_INFO_MAGIC,     libpcap_open,             "pcap",     NULL, NULL },
316         { "PcapNG",                      OPEN_INFO_MAGIC,     pcapng_open,              "pcapng",   NULL, NULL },
317         { "NgSniffer",                   OPEN_INFO_MAGIC,     ngsniffer_open,           NULL,       NULL, NULL },
318         { "Snoop",                       OPEN_INFO_MAGIC,     snoop_open,               NULL,       NULL, NULL },
319         { "IP Trace",                    OPEN_INFO_MAGIC,     iptrace_open,             NULL,       NULL, NULL },
320         { "Netmon",                      OPEN_INFO_MAGIC,     netmon_open,              NULL,       NULL, NULL },
321         { "Netxray",                     OPEN_INFO_MAGIC,     netxray_open,             NULL,       NULL, NULL },
322         { "Radcom",                      OPEN_INFO_MAGIC,     radcom_open,              NULL,       NULL, NULL },
323         { "Nettl",                       OPEN_INFO_MAGIC,     nettl_open,               NULL,       NULL, NULL },
324         { "Visual",                      OPEN_INFO_MAGIC,     visual_open,              NULL,       NULL, NULL },
325         { "5 Views",                     OPEN_INFO_MAGIC,     _5views_open,             NULL,       NULL, NULL },
326         { "Network Instruments",         OPEN_INFO_MAGIC,     network_instruments_open, NULL,       NULL, NULL },
327         { "Peek Tagged",                 OPEN_INFO_MAGIC,     peektagged_open,          NULL,       NULL, NULL },
328         { "DBS Etherwatch",              OPEN_INFO_MAGIC,     dbs_etherwatch_open,      NULL,       NULL, NULL },
329         { "K12",                         OPEN_INFO_MAGIC,     k12_open,                 NULL,       NULL, NULL },
330         { "Catapult DCT 2000",           OPEN_INFO_MAGIC,     catapult_dct2000_open,    NULL,       NULL, NULL },
331         { "Aethra",                      OPEN_INFO_MAGIC,     aethra_open,              NULL,       NULL, NULL },
332         { "BTSNOOP",                     OPEN_INFO_MAGIC,     btsnoop_open,             "log",      NULL, NULL },
333         { "EYESDN",                      OPEN_INFO_MAGIC,     eyesdn_open,              NULL,       NULL, NULL },
334         { "TNEF",                        OPEN_INFO_MAGIC,     tnef_open,                NULL,       NULL, NULL },
335         { "MIME Files with Magic Bytes", OPEN_INFO_MAGIC,     mime_file_open,           NULL,       NULL, NULL },
336         { "Lanalyzer",                   OPEN_INFO_HEURISTIC, lanalyzer_open,           "tr1",      NULL, NULL },
337         /*
338          * PacketLogger must come before MPEG, because its files
339          * are sometimes grabbed by mpeg_open.
340          */
341         { "Packet Logger",               OPEN_INFO_HEURISTIC, packetlogger_open,        "pklg",     NULL, NULL },
342         /* Some MPEG files have magic numbers, others just have heuristics. */
343         { "Mpeg",                        OPEN_INFO_HEURISTIC, mpeg_open,                "mpg;mp3",  NULL, NULL },
344         { "DCT3 Trace",                  OPEN_INFO_HEURISTIC, dct3trace_open,           "xml",      NULL, NULL },
345         { "Daintree SNA",                OPEN_INFO_HEURISTIC, daintree_sna_open,        "dcf",      NULL, NULL },
346         { "Stanag 4607",                 OPEN_INFO_HEURISTIC, stanag4607_open,          NULL,       NULL, NULL },
347         { "BER",                         OPEN_INFO_HEURISTIC, ber_open,                 NULL,       NULL, NULL },
348         /*
349          * I put NetScreen *before* erf, because there were some
350          * false positives with my test-files (Sake Blok, July 2007)
351          *
352          * I put VWR *after* ERF, because there were some cases where
353          * ERF files were misidentified as vwr files (Stephen
354          * Donnelly, August 2013; see bug 9054)
355          *
356          * I put VWR *after* Peek Classic, CommView, iSeries text,
357          * Toshiba text, K12 text, VMS tcpiptrace text, and NetScaler,
358          * because there were some cases where files of those types were
359          * misidentified as vwr files (Guy Harris, December 2013)
360          */
361         { "Netscreen",                   OPEN_INFO_HEURISTIC, netscreen_open,           "txt",      NULL, NULL },
362         { "ERF",                         OPEN_INFO_HEURISTIC, erf_open,                 "erf",      NULL, NULL },
363         { "IPfix",                       OPEN_INFO_HEURISTIC, ipfix_open,               "pfx;ipfix",NULL, NULL },
364         { "K12 Text",                    OPEN_INFO_HEURISTIC, k12text_open,             "txt",      NULL, NULL },
365         { "Peek Classic",                OPEN_INFO_HEURISTIC, peekclassic_open,         "pkt;tpc;apc;wpz", NULL, NULL },
366         { "PPP Dump",                    OPEN_INFO_HEURISTIC, pppdump_open,             NULL,       NULL, NULL },
367         { "iSeries",                     OPEN_INFO_HEURISTIC, iseries_open,             "txt",      NULL, NULL },
368         { "i4btrace",                    OPEN_INFO_HEURISTIC, i4btrace_open,            NULL,       NULL, NULL },
369         { "Mp2t",                        OPEN_INFO_HEURISTIC, mp2t_open,                "ts;mpg",   NULL, NULL },
370         { "Csids",                       OPEN_INFO_HEURISTIC, csids_open,               NULL,       NULL, NULL },
371         { "VMS",                         OPEN_INFO_HEURISTIC, vms_open,                 "txt",      NULL, NULL },
372         { "Cosine",                      OPEN_INFO_HEURISTIC, cosine_open,              "txt",      NULL, NULL },
373         { "Hcidump",                     OPEN_INFO_HEURISTIC, hcidump_open,             NULL,       NULL, NULL },
374         { "Commview",                    OPEN_INFO_HEURISTIC, commview_open,            "ncf",      NULL, NULL },
375         { "Nstrace",                     OPEN_INFO_HEURISTIC, nstrace_open,             "cap",      NULL, NULL },
376         { "Logcat ",                     OPEN_INFO_HEURISTIC, logcat_open,              "logcat",   NULL, NULL },
377         { "Logcat Text",                 OPEN_INFO_HEURISTIC, logcat_text_open,         "txt",      NULL, NULL },
378         /* ASCII trace files from Telnet sessions. */
379         { "Ascend",                      OPEN_INFO_HEURISTIC, ascend_open,              "txt",      NULL, NULL },
380         { "Toshiba",                     OPEN_INFO_HEURISTIC, toshiba_open,             "txt",      NULL, NULL },
381         /* Extremely weak heuristics - put them at the end. */
382         { "VWR",                         OPEN_INFO_HEURISTIC, vwr_open,                 "vwr",      NULL, NULL },
383         { "Camins",                      OPEN_INFO_HEURISTIC, camins_open,              "camins",   NULL, NULL },
384 };
385
386 /* this is only used to build the dynamic array on load, do NOT use this
387  * for anything else, because the size of the actual array will change if
388  *  Lua scripts register a new file reader.
389  */
390 #define N_OPEN_INFO_ROUTINES  ((sizeof open_info_base / sizeof open_info_base[0]))
391
392 static GArray *open_info_arr = NULL;
393
394 /* this always points to the top of the created array */
395 struct open_info *open_routines = NULL;
396
397 /* this points to the first OPEN_INFO_HEURISTIC type in the array */
398 static guint heuristic_open_routine_idx = 0;
399
400 static void
401 set_heuristic_routine(void)
402 {
403         guint i;
404         g_assert(open_info_arr != NULL);
405
406         for (i = 0; i < open_info_arr->len; i++) {
407                 if (open_routines[i].type == OPEN_INFO_HEURISTIC) {
408                         heuristic_open_routine_idx = i;
409                         break;
410                 }
411                 /* sanity check */
412                 g_assert(open_routines[i].type == OPEN_INFO_MAGIC);
413         }
414
415         g_assert(heuristic_open_routine_idx > 0);
416 }
417
418 void
419 init_open_routines(void)
420 {
421         unsigned int i;
422         struct open_info *i_open;
423
424         if (open_info_arr)
425                 return;
426
427         open_info_arr = g_array_new(TRUE,TRUE,sizeof(struct open_info));
428
429         g_array_append_vals(open_info_arr, open_info_base, N_OPEN_INFO_ROUTINES);
430
431         open_routines = (struct open_info *)(void*) open_info_arr->data;
432
433         /* Populate the extensions_set list now */
434         for (i = 0, i_open = open_routines; i < open_info_arr->len; i++, i_open++) {
435                 if (i_open->extensions != NULL)
436                         i_open->extensions_set = g_strsplit(i_open->extensions, ";", 0);
437         }
438
439         set_heuristic_routine();
440 }
441
442 /*
443  * Registers a new file reader - currently only called by wslua code for Lua readers.
444  * If first_routine is true, it's added before other readers of its type (magic or heuristic).
445  * Also, it checks for an existing reader of the same name and errors if it finds one; if
446  * you want to handle that condition more gracefully, call wtap_has_open_info() first.
447  */
448 void
449 wtap_register_open_info(struct open_info *oi, const gboolean first_routine)
450 {
451         init_open_routines();
452
453         if (!oi || !oi->name) {
454                 g_error("No open_info name given to register");
455                 return;
456         }
457
458         /* verify name doesn't already exist */
459         if (wtap_has_open_info(oi->name)) {
460                 g_error("Name given to register_open_info already exists");
461                 return;
462         }
463
464         if (oi->extensions != NULL)
465                 oi->extensions_set = g_strsplit(oi->extensions, ";", 0);
466
467         /* if it's magic and first, prepend it; if it's heuristic and not first,
468            append it; if it's anything else, stick it in the middle */
469         if (first_routine && oi->type == OPEN_INFO_MAGIC) {
470                 g_array_prepend_val(open_info_arr, *oi);
471         } else if (!first_routine && oi->type == OPEN_INFO_HEURISTIC) {
472                 g_array_append_val(open_info_arr, *oi);
473         } else {
474                 g_array_insert_val(open_info_arr, heuristic_open_routine_idx, *oi);
475         }
476
477         open_routines = (struct open_info *)(void*) open_info_arr->data;
478         set_heuristic_routine();
479 }
480
481 /* De-registers a file reader by removign it from the GArray based on its name.
482  * This function must NOT be called during wtap_open_offline(), since it changes the array.
483  * Note: this function will error if it doesn't find the given name; if you want to handle
484  * that condition more gracefully, call wtap_has_open_info() first.
485  */
486 void
487 wtap_deregister_open_info(const gchar *name)
488 {
489         guint i;
490         init_open_routines();
491
492         if (!name) {
493                 g_error("Missing open_info name to de-register");
494                 return;
495         }
496
497         for (i = 0; i < open_info_arr->len; i++) {
498                 if (open_routines[i].name && strcmp(open_routines[i].name, name) == 0) {
499                         if (open_routines[i].extensions_set != NULL)
500                                 g_strfreev(open_routines[i].extensions_set);
501                         open_info_arr = g_array_remove_index(open_info_arr, i);
502                         set_heuristic_routine();
503                         return;
504                 }
505         }
506
507         g_error("deregister_open_info: name not found");
508 }
509
510 /* Determines if a open routine short name already exists
511  */
512 gboolean
513 wtap_has_open_info(const gchar *name)
514 {
515         guint i;
516         init_open_routines();
517
518         if (!name) {
519                 g_error("No name given to wtap_has_open_info!");
520                 return FALSE;
521         }
522
523
524         for (i = 0; i < open_info_arr->len; i++) {
525                 if (open_routines[i].name && strcmp(open_routines[i].name, name) == 0) {
526                         return TRUE;
527                 }
528         }
529
530         return FALSE;
531 }
532
533 /*
534  * Visual C++ on Win32 systems doesn't define these.  (Old UNIX systems don't
535  * define them either.)
536  *
537  * Visual C++ on Win32 systems doesn't define S_IFIFO, it defines _S_IFIFO.
538  */
539 #ifndef S_ISREG
540 #define S_ISREG(mode)   (((mode) & S_IFMT) == S_IFREG)
541 #endif
542 #ifndef S_IFIFO
543 #define S_IFIFO _S_IFIFO
544 #endif
545 #ifndef S_ISFIFO
546 #define S_ISFIFO(mode)  (((mode) & S_IFMT) == S_IFIFO)
547 #endif
548 #ifndef S_ISDIR
549 #define S_ISDIR(mode)   (((mode) & S_IFMT) == S_IFDIR)
550 #endif
551
552 /* returns the 'type' number to use for wtap_open_offline based on the
553    passed-in name (the name in the open_info struct). It returns WTAP_TYPE_AUTO
554    on failure, which is the number 0. The 'type' number is the entry's index+1,
555    because that's what wtap_open_offline() expects it to be. */
556 unsigned int
557 open_info_name_to_type(const char *name)
558 {
559         unsigned int i;
560         init_open_routines();
561
562         if (!name)
563                 return WTAP_TYPE_AUTO;
564
565         for (i = 0; i < open_info_arr->len; i++) {
566                 if (open_routines[i].name != NULL &&
567                     strcmp(name, open_routines[i].name) == 0)
568                         return i+1;
569         }
570
571         return WTAP_TYPE_AUTO; /* no such file type */
572 }
573
574 static char *
575 get_file_extension(const char *pathname)
576 {
577         gchar *filename;
578         gchar **components;
579         size_t ncomponents;
580         GSList *compressed_file_extensions, *compressed_file_extension;
581         gchar *extensionp;
582
583         /*
584          * Is the pathname empty?
585          */
586         if (strcmp(pathname, "") == 0)
587                 return NULL;    /* no extension */
588
589         /*
590          * Find the last component of the pathname.
591          */
592         filename = g_path_get_basename(pathname);
593
594         /*
595          * Does it have an extension?
596          */
597         if (strchr(filename, '.') == NULL) {
598                 g_free(filename);
599                 return NULL;    /* no extension whatsoever */
600         }
601
602         /*
603          * Yes.  Split it into components separated by ".".
604          */
605         components = g_strsplit(filename, ".", 0);
606         g_free(filename);
607
608         /*
609          * Count the components.
610          */
611         for (ncomponents = 0; components[ncomponents] != NULL; ncomponents++)
612                 ;
613
614         if (ncomponents == 0) {
615                 g_strfreev(components);
616                 return NULL;    /* no components */
617         }
618         if (ncomponents == 1) {
619                 g_strfreev(components);
620                 return NULL;    /* only one component, with no "." */
621         }
622
623         /*
624          * Is the last component one of the extensions used for compressed
625          * files?
626          */
627         compressed_file_extensions = wtap_get_compressed_file_extensions();
628         if (compressed_file_extensions == NULL) {
629                 /*
630                  * We don't support reading compressed files, so just
631                  * return a copy of whatever extension we did find.
632                  */
633                 extensionp = g_strdup(components[ncomponents - 1]);
634                 g_strfreev(components);
635                 return extensionp;
636         }
637         extensionp = components[ncomponents - 1];
638         for (compressed_file_extension = compressed_file_extensions;
639             compressed_file_extension != NULL;
640             compressed_file_extension = g_slist_next(compressed_file_extension)) {
641                 if (strcmp(extensionp, (char *)compressed_file_extension->data) == 0) {
642                         /*
643                          * Yes, it's one of the compressed-file extensions.
644                          * Is there an extension before that?
645                          */
646                         if (ncomponents == 2) {
647                                 g_strfreev(components);
648                                 return NULL;    /* no, only two components */
649                         }
650
651                         /*
652                          * Yes, return that extension.
653                          */
654                         extensionp = g_strdup(components[ncomponents - 2]);
655                         g_strfreev(components);
656                         return extensionp;
657                 }
658         }
659
660         /*
661          * The extension isn't one of the compressed-file extensions;
662          * return it.
663          */
664         extensionp = g_strdup(extensionp);
665         g_strfreev(components);
666         return extensionp;
667 }
668
669 /*
670  * Check if file extension is used in this heuristic
671  */
672 static gboolean
673 heuristic_uses_extension(unsigned int i, const char *extension)
674 {
675         gchar **extensionp;
676
677         /*
678          * Does this file type *have* any extensions?
679          */
680         if (open_routines[i].extensions == NULL)
681                 return FALSE;   /* no */
682
683         /*
684          * Check each of them against the specified extension.
685          */
686         for (extensionp = open_routines[i].extensions_set; *extensionp != NULL;
687             extensionp++) {
688                 if (strcmp(extension, *extensionp) == 0) {
689                         return TRUE;    /* it's one of them */
690                 }
691         }
692
693         return FALSE;   /* it's not one of them */
694 }
695
696 /* Opens a file and prepares a wtap struct.
697    If "do_random" is TRUE, it opens the file twice; the second open
698    allows the application to do random-access I/O without moving
699    the seek offset for sequential I/O, which is used by Wireshark
700    so that it can do sequential I/O to a capture file that's being
701    written to as new packets arrive independently of random I/O done
702    to display protocol trees for packets when they're selected. */
703 wtap *
704 wtap_open_offline(const char *filename, unsigned int type, int *err, char **err_info,
705                   gboolean do_random)
706 {
707         int     fd;
708         ws_statb64 statb;
709         wtap    *wth;
710         unsigned int    i;
711         gboolean use_stdin = FALSE;
712         gchar *extension;
713
714         init_open_routines();
715
716         /* open standard input if filename is '-' */
717         if (strcmp(filename, "-") == 0)
718                 use_stdin = TRUE;
719
720         /* First, make sure the file is valid */
721         if (use_stdin) {
722                 if (ws_fstat64(0, &statb) < 0) {
723                         *err = errno;
724                         return NULL;
725                 }
726         } else {
727                 if (ws_stat64(filename, &statb) < 0) {
728                         *err = errno;
729                         return NULL;
730                 }
731         }
732         if (S_ISFIFO(statb.st_mode)) {
733                 /*
734                  * Opens of FIFOs are allowed only when not opening
735                  * for random access.
736                  *
737                  * XXX - currently, we do seeking when trying to find
738                  * out the file type, so we don't actually support
739                  * opening FIFOs.  However, we may eventually
740                  * do buffering that allows us to do at least some
741                  * file type determination even on pipes, so we
742                  * allow FIFO opens and let things fail later when
743                  * we try to seek.
744                  */
745                 if (do_random) {
746                         *err = WTAP_ERR_RANDOM_OPEN_PIPE;
747                         return NULL;
748                 }
749         } else if (S_ISDIR(statb.st_mode)) {
750                 /*
751                  * Return different errors for "this is a directory"
752                  * and "this is some random special file type", so
753                  * the user can get a potentially more helpful error.
754                  */
755                 *err = EISDIR;
756                 return NULL;
757         } else if (! S_ISREG(statb.st_mode)) {
758                 *err = WTAP_ERR_NOT_REGULAR_FILE;
759                 return NULL;
760         }
761
762         /*
763          * We need two independent descriptors for random access, so
764          * they have different file positions.  If we're opening the
765          * standard input, we can only dup it to get additional
766          * descriptors, so we can't have two independent descriptors,
767          * and thus can't do random access.
768          */
769         if (use_stdin && do_random) {
770                 *err = WTAP_ERR_RANDOM_OPEN_STDIN;
771                 return NULL;
772         }
773
774         errno = ENOMEM;
775         wth = (wtap *)g_malloc0(sizeof(wtap));
776
777         /* Open the file */
778         errno = WTAP_ERR_CANT_OPEN;
779         if (use_stdin) {
780                 /*
781                  * We dup FD 0, so that we don't have to worry about
782                  * a file_close of wth->fh closing the standard
783                  * input of the process.
784                  */
785                 fd = ws_dup(0);
786                 if (fd < 0) {
787                         *err = errno;
788                         g_free(wth);
789                         return NULL;
790                 }
791 #ifdef _WIN32
792                 if (_setmode(fd, O_BINARY) == -1) {
793                         /* "Shouldn't happen" */
794                         *err = errno;
795                         g_free(wth);
796                         return NULL;
797                 }
798 #endif
799                 if (!(wth->fh = file_fdopen(fd))) {
800                         *err = errno;
801                         ws_close(fd);
802                         g_free(wth);
803                         return NULL;
804                 }
805         } else {
806                 if (!(wth->fh = file_open(filename))) {
807                         *err = errno;
808                         g_free(wth);
809                         return NULL;
810                 }
811         }
812
813         if (do_random) {
814                 if (!(wth->random_fh = file_open(filename))) {
815                         *err = errno;
816                         file_close(wth->fh);
817                         g_free(wth);
818                         return NULL;
819                 }
820         } else
821                 wth->random_fh = NULL;
822
823         /* initialization */
824         wth->file_encap = WTAP_ENCAP_UNKNOWN;
825         wth->subtype_sequential_close = NULL;
826         wth->subtype_close = NULL;
827         wth->file_tsprec = WTAP_TSPREC_USEC;
828         wth->priv = NULL;
829         wth->wslua_data = NULL;
830
831         /* Initialize the array containing a list of interfaces. pcapng_open and
832          * erf_open needs this (and libpcap_open for ERF encapsulation types).
833          * Always initing it here saves checking for a NULL ptr later. */
834         wth->interface_data = g_array_new(FALSE, FALSE, sizeof(wtapng_if_descr_t));
835
836         if (wth->random_fh) {
837                 wth->fast_seek = g_ptr_array_new();
838
839                 file_set_random_access(wth->fh, FALSE, wth->fast_seek);
840                 file_set_random_access(wth->random_fh, TRUE, wth->fast_seek);
841         }
842
843         /* 'type' is 1 greater than the array index */
844         if (type != WTAP_TYPE_AUTO && type <= open_info_arr->len) {
845                 int result;
846
847                 if (file_seek(wth->fh, 0, SEEK_SET, err) == -1) {
848                         /* I/O error - give up */
849                         wtap_close(wth);
850                         return NULL;
851                 }
852
853                 /* Set wth with wslua data if any - this is how we pass the data
854                  * to the file reader, kinda like the priv member but not free'd later.
855                  * It's ok for this to copy a NULL.
856                  */
857                 wth->wslua_data = open_routines[type - 1].wslua_data;
858
859                 result = (*open_routines[type - 1].open_routine)(wth, err, err_info);
860
861                 switch (result) {
862                         case -1:
863                                 /* I/O error - give up */
864                                 wtap_close(wth);
865                                 return NULL;
866
867                         case 0:
868                                 /* No I/O error, but not that type of file */
869                                 goto fail;
870
871                         case 1:
872                                 /* We found the file type */
873                                 goto success;
874                 }
875         }
876
877         /* Try all file types that support magic numbers */
878         for (i = 0; i < heuristic_open_routine_idx; i++) {
879                 /* Seek back to the beginning of the file; the open routine
880                    for the previous file type may have left the file
881                    position somewhere other than the beginning, and the
882                    open routine for this file type will probably want
883                    to start reading at the beginning.
884
885                    Initialize the data offset while we're at it. */
886                 if (file_seek(wth->fh, 0, SEEK_SET, err) == -1) {
887                         /* I/O error - give up */
888                         wtap_close(wth);
889                         return NULL;
890                 }
891
892                 /* Set wth with wslua data if any - this is how we pass the data
893                  * to the file reader, kinda like the priv member but not free'd later.
894                  * It's ok for this to copy a NULL.
895                  */
896                 wth->wslua_data = open_routines[i].wslua_data;
897
898                 switch ((*open_routines[i].open_routine)(wth, err, err_info)) {
899
900                 case -1:
901                         /* I/O error - give up */
902                         wtap_close(wth);
903                         return NULL;
904
905                 case 0:
906                         /* No I/O error, but not that type of file */
907                         break;
908
909                 case 1:
910                         /* We found the file type */
911                         goto success;
912                 }
913         }
914
915
916         /* Does this file's name have an extension? */
917         extension = get_file_extension(filename);
918         if (extension != NULL) {
919                 /* Yes - try the heuristic types that use that extension first. */
920                 for (i = heuristic_open_routine_idx; i < open_info_arr->len; i++) {
921                         /* Does this type use that extension? */
922                         if (heuristic_uses_extension(i, extension)) {
923                                 /* Yes. */
924                                 if (file_seek(wth->fh, 0, SEEK_SET, err) == -1) {
925                                         /* I/O error - give up */
926                                         g_free(extension);
927                                         wtap_close(wth);
928                                         return NULL;
929                                 }
930
931                                 /* Set wth with wslua data if any - this is how we pass the data
932                                  * to the file reader, kind of like priv but not free'd later.
933                                  */
934                                 wth->wslua_data = open_routines[i].wslua_data;
935
936                                 switch ((*open_routines[i].open_routine)(wth,
937                                     err, err_info)) {
938
939                                 case -1:
940                                         /* I/O error - give up */
941                                         g_free(extension);
942                                         wtap_close(wth);
943                                         return NULL;
944
945                                 case 0:
946                                         /* No I/O error, but not that type of file */
947                                         break;
948
949                                 case 1:
950                                         /* We found the file type */
951                                         g_free(extension);
952                                         goto success;
953                                 }
954                         }
955                 }
956
957                 /* Now try the ones that don't use it. */
958                 for (i = heuristic_open_routine_idx; i < open_info_arr->len; i++) {
959                         /* Does this type use that extension? */
960                         if (!heuristic_uses_extension(i, extension)) {
961                                 /* No. */
962                                 if (file_seek(wth->fh, 0, SEEK_SET, err) == -1) {
963                                         /* I/O error - give up */
964                                         g_free(extension);
965                                         wtap_close(wth);
966                                         return NULL;
967                                 }
968
969                                 /* Set wth with wslua data if any - this is how we pass the data
970                                  * to the file reader, kind of like priv but not free'd later.
971                                  */
972                                 wth->wslua_data = open_routines[i].wslua_data;
973
974                                 switch ((*open_routines[i].open_routine)(wth,
975                                     err, err_info)) {
976
977                                 case -1:
978                                         /* I/O error - give up */
979                                         g_free(extension);
980                                         wtap_close(wth);
981                                         return NULL;
982
983                                 case 0:
984                                         /* No I/O error, but not that type of file */
985                                         break;
986
987                                 case 1:
988                                         /* We found the file type */
989                                         g_free(extension);
990                                         goto success;
991                                 }
992                         }
993                 }
994                 g_free(extension);
995         } else {
996                 /* No - try all the heuristics types in order. */
997                 for (i = heuristic_open_routine_idx; i < open_info_arr->len; i++) {
998
999                         if (file_seek(wth->fh, 0, SEEK_SET, err) == -1) {
1000                                 /* I/O error - give up */
1001                                 wtap_close(wth);
1002                                 return NULL;
1003                         }
1004
1005                         /* Set wth with wslua data if any - this is how we pass the data
1006                          * to the file reader, kind of like priv but not free'd later.
1007                          */
1008                         wth->wslua_data = open_routines[i].wslua_data;
1009
1010                         switch ((*open_routines[i].open_routine)(wth, err, err_info)) {
1011
1012                         case -1:
1013                                 /* I/O error - give up */
1014                                 wtap_close(wth);
1015                                 return NULL;
1016
1017                         case 0:
1018                                 /* No I/O error, but not that type of file */
1019                                 break;
1020
1021                         case 1:
1022                                 /* We found the file type */
1023                                 goto success;
1024                         }
1025                 }
1026         }
1027
1028 fail:
1029
1030         /* Well, it's not one of the types of file we know about. */
1031         wtap_close(wth);
1032         *err = WTAP_ERR_FILE_UNKNOWN_FORMAT;
1033         return NULL;
1034
1035 success:
1036         wth->frame_buffer = (struct Buffer *)g_malloc(sizeof(struct Buffer));
1037         ws_buffer_init(wth->frame_buffer, 1500);
1038
1039         if(wth->file_type_subtype == WTAP_FILE_TYPE_SUBTYPE_PCAP){
1040
1041                 wtapng_if_descr_t descr;
1042
1043                 descr.wtap_encap = wth->file_encap;
1044                 descr.time_units_per_second = 1000000; /* default microsecond resolution */
1045                 descr.link_type = wtap_wtap_encap_to_pcap_encap(wth->file_encap);
1046                 descr.snap_len = wth->snapshot_length;
1047                 descr.opt_comment = NULL;
1048                 descr.if_name = NULL;
1049                 descr.if_description = NULL;
1050                 descr.if_speed = 0;
1051                 descr.if_tsresol = 6;
1052                 descr.if_filter_str= NULL;
1053                 descr.bpf_filter_len= 0;
1054                 descr.if_filter_bpf_bytes= NULL;
1055                 descr.if_os = NULL;
1056                 descr.if_fcslen = -1;
1057                 descr.num_stat_entries = 0;          /* Number of ISB:s */
1058                 descr.interface_statistics = NULL;
1059                 g_array_append_val(wth->interface_data, descr);
1060
1061         }
1062         return wth;
1063 }
1064
1065 /*
1066  * Given the pathname of the file we just closed with wtap_fdclose(), attempt
1067  * to reopen that file and assign the new file descriptor(s) to the sequential
1068  * stream and, if do_random is TRUE, to the random stream.  Used on Windows
1069  * after the rename of a file we had open was done or if the rename of a
1070  * file on top of a file we had open failed.
1071  *
1072  * This is only required by Wireshark, not TShark, and, at the point that
1073  * Wireshark is doing this, the sequential stream is closed, and the
1074  * random stream is open, so this refuses to open pipes, and only
1075  * reopens the random stream.
1076  */
1077 gboolean
1078 wtap_fdreopen(wtap *wth, const char *filename, int *err)
1079 {
1080         ws_statb64 statb;
1081
1082         /*
1083          * We need two independent descriptors for random access, so
1084          * they have different file positions.  If we're opening the
1085          * standard input, we can only dup it to get additional
1086          * descriptors, so we can't have two independent descriptors,
1087          * and thus can't do random access.
1088          */
1089         if (strcmp(filename, "-") == 0) {
1090                 *err = WTAP_ERR_RANDOM_OPEN_STDIN;
1091                 return FALSE;
1092         }
1093
1094         /* First, make sure the file is valid */
1095         if (ws_stat64(filename, &statb) < 0) {
1096                 *err = errno;
1097                 return FALSE;
1098         }
1099         if (S_ISFIFO(statb.st_mode)) {
1100                 /*
1101                  * Opens of FIFOs are not allowed; see above.
1102                  */
1103                 *err = WTAP_ERR_RANDOM_OPEN_PIPE;
1104                 return FALSE;
1105         } else if (S_ISDIR(statb.st_mode)) {
1106                 /*
1107                  * Return different errors for "this is a directory"
1108                  * and "this is some random special file type", so
1109                  * the user can get a potentially more helpful error.
1110                  */
1111                 *err = EISDIR;
1112                 return FALSE;
1113         } else if (! S_ISREG(statb.st_mode)) {
1114                 *err = WTAP_ERR_NOT_REGULAR_FILE;
1115                 return FALSE;
1116         }
1117
1118         /* Open the file */
1119         errno = WTAP_ERR_CANT_OPEN;
1120         if (!file_fdreopen(wth->random_fh, filename)) {
1121                 *err = errno;
1122                 return FALSE;
1123         }
1124         return TRUE;
1125 }
1126
1127 /* Table of the file types we know about.
1128    Entries must be sorted by WTAP_FILE_TYPE_SUBTYPE_xxx values in ascending order */
1129 static const struct file_type_subtype_info dump_open_table_base[] = {
1130         /* WTAP_FILE_TYPE_SUBTYPE_UNKNOWN (only used internally for initialization) */
1131         { NULL, NULL, NULL, NULL,
1132           FALSE, FALSE, 0,
1133           NULL, NULL, NULL },
1134
1135         /* WTAP_FILE_TYPE_SUBTYPE_PCAP */
1136         /* Gianluca Varenni suggests that we add "deprecated" to the description. */
1137         { "Wireshark/tcpdump/... - pcap", "pcap", "pcap", "cap;dmp",
1138           FALSE, FALSE, 0,
1139           libpcap_dump_can_write_encap, libpcap_dump_open, NULL },
1140
1141         /* WTAP_FILE_TYPE_SUBTYPE_PCAPNG */
1142         { "Wireshark/... - pcapng", "pcapng", "pcapng", "ntar",
1143           FALSE, TRUE, WTAP_COMMENT_PER_SECTION|WTAP_COMMENT_PER_INTERFACE|WTAP_COMMENT_PER_PACKET,
1144           pcapng_dump_can_write_encap, pcapng_dump_open, NULL },
1145
1146         /* WTAP_FILE_TYPE_SUBTYPE_PCAP_NSEC */
1147         { "Wireshark - nanosecond libpcap", "nseclibpcap", "pcap", "cap;dmp",
1148           FALSE, FALSE, 0,
1149           libpcap_dump_can_write_encap, libpcap_dump_open, NULL },
1150
1151         /* WTAP_FILE_TYPE_SUBTYPE_PCAP_AIX */
1152         { "AIX tcpdump - libpcap", "aixlibpcap", "pcap", "cap;dmp",
1153           FALSE, FALSE, 0,
1154           NULL, NULL, NULL },
1155
1156         /* WTAP_FILE_TYPE_SUBTYPE_PCAP_SS991029 */
1157         { "Modified tcpdump - libpcap", "modlibpcap", "pcap", "cap;dmp",
1158           FALSE, FALSE, 0,
1159           libpcap_dump_can_write_encap, libpcap_dump_open, NULL },
1160
1161         /* WTAP_FILE_TYPE_SUBTYPE_PCAP_NOKIA */
1162         { "Nokia tcpdump - libpcap ", "nokialibpcap", "pcap", "cap;dmp",
1163           FALSE, FALSE, 0,
1164           libpcap_dump_can_write_encap, libpcap_dump_open, NULL },
1165
1166         /* WTAP_FILE_TYPE_SUBTYPE_PCAP_SS990417 */
1167         { "RedHat 6.1 tcpdump - libpcap", "rh6_1libpcap", "pcap", "cap;dmp",
1168           FALSE, FALSE, 0,
1169           libpcap_dump_can_write_encap, libpcap_dump_open, NULL },
1170
1171         /* WTAP_FILE_TYPE_SUBTYPE_PCAP_SS990915 */
1172         { "SuSE 6.3 tcpdump - libpcap", "suse6_3libpcap", "pcap", "cap;dmp",
1173           FALSE, FALSE, 0,
1174           libpcap_dump_can_write_encap, libpcap_dump_open, NULL },
1175
1176         /* WTAP_FILE_TYPE_SUBTYPE_5VIEWS */
1177         { "InfoVista 5View capture", "5views", "5vw", NULL,
1178            TRUE, FALSE, 0,
1179           _5views_dump_can_write_encap, _5views_dump_open, NULL },
1180
1181         /* WTAP_FILE_TYPE_SUBTYPE_IPTRACE_1_0 */
1182         { "AIX iptrace 1.0", "iptrace_1", NULL, NULL,
1183           FALSE, FALSE, 0,
1184           NULL, NULL, NULL },
1185
1186         /* WTAP_FILE_TYPE_SUBTYPE_IPTRACE_2_0 */
1187         { "AIX iptrace 2.0", "iptrace_2", NULL, NULL,
1188           FALSE, FALSE, 0,
1189           NULL, NULL, NULL },
1190
1191         /* WTAP_FILE_TYPE_SUBTYPE_BER */
1192         { "ASN.1 Basic Encoding Rules", "ber", NULL, NULL,
1193           FALSE, FALSE, 0,
1194           NULL, NULL, NULL },
1195
1196         /* WTAP_FILE_TYPE_SUBTYPE_HCIDUMP */
1197         { "Bluetooth HCI dump", "hcidump", NULL, NULL,
1198           FALSE, FALSE, 0,
1199           NULL, NULL, NULL },
1200
1201         /* WTAP_FILE_TYPE_SUBTYPE_CATAPULT_DCT2000 */
1202         { "Catapult DCT2000 trace (.out format)", "dct2000", "out", NULL,
1203           FALSE, FALSE, 0,
1204           catapult_dct2000_dump_can_write_encap, catapult_dct2000_dump_open, NULL },
1205
1206         /* WTAP_FILE_TYPE_SUBTYPE_NETXRAY_OLD */
1207         { "Cinco Networks NetXRay 1.x", "netxray1", "cap", NULL,
1208           TRUE, FALSE, 0,
1209           NULL, NULL, NULL },
1210
1211         /* WTAP_FILE_TYPE_SUBTYPE_NETXRAY_1_0 */
1212         { "Cinco Networks NetXRay 2.0 or later", "netxray2", "cap", NULL,
1213           TRUE, FALSE, 0,
1214           NULL, NULL, NULL },
1215
1216         /* WTAP_FILE_TYPE_SUBTYPE_COSINE */
1217         { "CoSine IPSX L2 capture", "cosine", "txt", NULL,
1218           FALSE, FALSE, 0,
1219           NULL, NULL, NULL },
1220
1221         /* WTAP_FILE_TYPE_SUBTYPE_CSIDS */
1222         { "CSIDS IPLog", "csids", NULL, NULL,
1223           FALSE, FALSE, 0,
1224           NULL, NULL, NULL },
1225
1226         /* WTAP_FILE_TYPE_SUBTYPE_DBS_ETHERWATCH */
1227         { "DBS Etherwatch (VMS)", "etherwatch", "txt", NULL,
1228           FALSE, FALSE, 0,
1229           NULL, NULL, NULL },
1230
1231         /* WTAP_FILE_TYPE_SUBTYPE_ERF */
1232         { "Endace ERF capture", "erf", "erf", NULL,
1233           FALSE, FALSE, 0,
1234           erf_dump_can_write_encap, erf_dump_open, NULL },
1235
1236         /* WTAP_FILE_TYPE_SUBTYPE_EYESDN */
1237         { "EyeSDN USB S0/E1 ISDN trace format", "eyesdn", "trc", NULL,
1238            FALSE, FALSE, 0,
1239            eyesdn_dump_can_write_encap, eyesdn_dump_open, NULL },
1240
1241         /* WTAP_FILE_TYPE_SUBTYPE_NETTL */
1242         { "HP-UX nettl trace", "nettl", "trc0", "trc1",
1243           FALSE, FALSE, 0,
1244           nettl_dump_can_write_encap, nettl_dump_open, NULL },
1245
1246         /* WTAP_FILE_TYPE_SUBTYPE_ISERIES */
1247         { "IBM iSeries comm. trace (ASCII)", "iseries_ascii", "txt", NULL,
1248           FALSE, FALSE, 0,
1249           NULL, NULL, NULL },
1250
1251         /* WTAP_FILE_TYPE_SUBTYPE_ISERIES_UNICODE */
1252         { "IBM iSeries comm. trace (UNICODE)", "iseries_unicode", "txt", NULL,
1253           FALSE, FALSE, 0,
1254           NULL, NULL, NULL },
1255
1256         /* WTAP_FILE_TYPE_SUBTYPE_I4BTRACE */
1257         { "I4B ISDN trace", "i4btrace", NULL, NULL,
1258           FALSE, FALSE, 0,
1259           NULL, NULL, NULL },
1260
1261         /* WTAP_FILE_TYPE_SUBTYPE_ASCEND */
1262         { "Lucent/Ascend access server trace", "ascend", "txt", NULL,
1263           FALSE, FALSE, 0,
1264           NULL, NULL, NULL },
1265
1266         /* WTAP_FILE_TYPE_SUBTYPE_NETMON_1_x */
1267         { "Microsoft NetMon 1.x", "netmon1", "cap", NULL,
1268           TRUE, FALSE, 0,
1269           netmon_dump_can_write_encap_1_x, netmon_dump_open, NULL },
1270
1271         /* WTAP_FILE_TYPE_SUBTYPE_NETMON_2_x */
1272         { "Microsoft NetMon 2.x", "netmon2", "cap", NULL,
1273           TRUE, FALSE, 0,
1274           netmon_dump_can_write_encap_2_x, netmon_dump_open, NULL },
1275
1276         /* WTAP_FILE_TYPE_SUBTYPE_NGSNIFFER_UNCOMPRESSED */
1277         { "Sniffer (DOS)", "ngsniffer", "cap", "enc;trc;fdc;syc",
1278           FALSE, FALSE, 0,
1279           ngsniffer_dump_can_write_encap, ngsniffer_dump_open, NULL },
1280
1281         /* WTAP_FILE_TYPE_SUBTYPE_NGSNIFFER_COMPRESSED */
1282         { "Sniffer (DOS), compressed", "ngsniffer_comp", "cap", "enc;trc;fdc;syc",
1283           FALSE, FALSE, 0,
1284           NULL, NULL, NULL },
1285
1286         /* WTAP_FILE_TYPE_SUBTYPE_NETXRAY_1_1 */
1287         { "NetXray, Sniffer (Windows) 1.1", "ngwsniffer_1_1", "cap", NULL,
1288           TRUE, FALSE, 0,
1289           netxray_dump_can_write_encap_1_1, netxray_dump_open_1_1, NULL },
1290
1291         /* WTAP_FILE_TYPE_SUBTYPE_NETXRAY_2_00x */
1292         { "Sniffer (Windows) 2.00x", "ngwsniffer_2_0", "cap", "caz",
1293           TRUE, FALSE, 0,
1294           netxray_dump_can_write_encap_2_0, netxray_dump_open_2_0, NULL },
1295
1296         /* WTAP_FILE_TYPE_SUBTYPE_NETWORK_INSTRUMENTS */
1297         { "Network Instruments Observer", "niobserver", "bfr", NULL,
1298           FALSE, FALSE, 0,
1299           network_instruments_dump_can_write_encap, network_instruments_dump_open, NULL },
1300
1301         /* WTAP_FILE_TYPE_SUBTYPE_LANALYZER */
1302         { "Novell LANalyzer","lanalyzer", "tr1", NULL,
1303           TRUE, FALSE, 0,
1304           lanalyzer_dump_can_write_encap, lanalyzer_dump_open, NULL },
1305
1306         /* WTAP_FILE_TYPE_SUBTYPE_PPPDUMP */
1307         { "pppd log (pppdump format)", "pppd", NULL, NULL,
1308           FALSE, FALSE, 0,
1309           NULL, NULL, NULL },
1310
1311         /* WTAP_FILE_TYPE_SUBTYPE_RADCOM */
1312         { "RADCOM WAN/LAN analyzer", "radcom", NULL, NULL,
1313           FALSE, FALSE, 0,
1314           NULL, NULL, NULL },
1315
1316         /* WTAP_FILE_TYPE_SUBTYPE_SNOOP */
1317         { "Sun snoop", "snoop", "snoop", "cap",
1318           FALSE, FALSE, 0,
1319           snoop_dump_can_write_encap, snoop_dump_open, NULL },
1320
1321         /* WTAP_FILE_TYPE_SUBTYPE_SHOMITI */
1322         { "Shomiti/Finisar Surveyor", "shomiti", "cap", NULL,
1323           FALSE, FALSE, 0,
1324           NULL, NULL, NULL },
1325
1326         /* WTAP_FILE_TYPE_SUBTYPE_VMS */
1327         { "TCPIPtrace (VMS)", "tcpiptrace", "txt", NULL,
1328           FALSE, FALSE, 0,
1329           NULL, NULL, NULL },
1330
1331         /* WTAP_FILE_TYPE_SUBTYPE_K12 */
1332         { "Tektronix K12xx 32-bit .rf5 format", "rf5", "rf5", NULL,
1333            TRUE, FALSE, 0,
1334            k12_dump_can_write_encap, k12_dump_open, NULL },
1335
1336         /* WTAP_FILE_TYPE_SUBTYPE_TOSHIBA */
1337         { "Toshiba Compact ISDN Router snoop", "toshiba", "txt", NULL,
1338           FALSE, FALSE, 0,
1339           NULL, NULL, NULL },
1340
1341         /* WTAP_FILE_TYPE_SUBTYPE_VISUAL_NETWORKS */
1342         { "Visual Networks traffic capture", "visual", NULL, NULL,
1343           TRUE, FALSE, 0,
1344           visual_dump_can_write_encap, visual_dump_open, NULL },
1345
1346         /* WTAP_FILE_TYPE_SUBTYPE_PEEKCLASSIC_V56 */
1347         { "WildPackets classic (V5 and V6)", "peekclassic56", "pkt", "tpc;apc;wpz",
1348           FALSE, FALSE, 0,
1349           NULL, NULL, NULL },
1350
1351         /* WTAP_FILE_TYPE_SUBTYPE_PEEKCLASSIC_V7 */
1352         { "WildPackets classic (V7)", "peekclassic7", "pkt", "tpc;apc;wpz",
1353           FALSE, FALSE, 0,
1354           NULL, NULL, NULL },
1355
1356         /* WTAP_FILE_TYPE_SUBTYPE_PEEKTAGGED */
1357         { "WildPackets tagged", "peektagged", "pkt", "tpc;apc;wpz",
1358           FALSE, FALSE, 0,
1359           NULL, NULL, NULL },
1360
1361         /* WTAP_FILE_TYPE_SUBTYPE_MPEG */
1362         { "MPEG", "mpeg", "mpeg", "mpg;mp3",
1363           FALSE, FALSE, 0,
1364           NULL, NULL, NULL },
1365
1366         /* WTAP_FILE_TYPE_SUBTYPE_K12TEXT  */
1367         { "K12 text file", "k12text", "txt", NULL,
1368           FALSE, FALSE, 0,
1369           k12text_dump_can_write_encap, k12text_dump_open, NULL },
1370
1371         /* WTAP_FILE_TYPE_SUBTYPE_NETSCREEN */
1372         { "NetScreen snoop text file", "netscreen", "txt", NULL,
1373           FALSE, FALSE, 0,
1374           NULL, NULL, NULL },
1375
1376         /* WTAP_FILE_TYPE_SUBTYPE_COMMVIEW */
1377         { "TamoSoft CommView", "commview", "ncf", NULL,
1378           FALSE, FALSE, 0,
1379           commview_dump_can_write_encap, commview_dump_open, NULL },
1380
1381         /* WTAP_FILE_TYPE_SUBTYPE_BTSNOOP */
1382         { "Symbian OS btsnoop", "btsnoop", "log", NULL,
1383           FALSE, FALSE, 0,
1384           btsnoop_dump_can_write_encap, btsnoop_dump_open_h4, NULL },
1385
1386         /* WTAP_FILE_TYPE_SUBTYPE_TNEF */
1387         { "Transport-Neutral Encapsulation Format", "tnef", NULL, NULL,
1388           FALSE, FALSE, 0,
1389           NULL, NULL, NULL },
1390
1391         /* WTAP_FILE_TYPE_SUBTYPE_DCT3TRACE */
1392         { "Gammu DCT3 trace", "dct3trace", "xml", NULL,
1393           FALSE, FALSE, 0,
1394           NULL, NULL, NULL },
1395
1396         /* WTAP_FILE_TYPE_SUBTYPE_PACKETLOGGER */
1397         { "PacketLogger", "pklg", "pklg", NULL,
1398           FALSE, FALSE, 0,
1399           NULL, NULL, NULL },
1400
1401         /* WTAP_FILE_TYPE_SUBTYPE_DAINTREE_SNA */
1402         { "Daintree SNA", "dsna", "dcf", NULL,
1403           FALSE, FALSE, 0,
1404           NULL, NULL, NULL },
1405
1406         /* WTAP_FILE_TYPE_SUBTYPE_NETSCALER_1_0 */
1407         { "NetScaler Trace (Version 1.0)", "nstrace10", NULL, NULL,
1408           TRUE, FALSE, 0,
1409           nstrace_10_dump_can_write_encap, nstrace_dump_open, NULL },
1410
1411         /* WTAP_FILE_TYPE_SUBTYPE_NETSCALER_2_0 */
1412         { "NetScaler Trace (Version 2.0)", "nstrace20", "cap", NULL,
1413           TRUE, FALSE, 0,
1414           nstrace_20_dump_can_write_encap, nstrace_dump_open, NULL },
1415
1416         /* WTAP_FILE_TYPE_SUBTYPE_JPEG_JFIF */
1417         { "JPEG/JFIF", "jpeg", "jpg", "jpeg;jfif",
1418           FALSE, FALSE, 0,
1419           NULL, NULL, NULL },
1420
1421         /* WTAP_FILE_TYPE_SUBTYPE_IPFIX */
1422         { "IPFIX File Format", "ipfix", "pfx", "ipfix",
1423           FALSE, FALSE, 0,
1424           NULL, NULL, NULL },
1425
1426         /* WTAP_ENCAP_MIME */
1427         { "MIME File Format", "mime", NULL, NULL,
1428            FALSE, FALSE, 0,
1429            NULL, NULL, NULL },
1430
1431         /* WTAP_FILE_TYPE_SUBTYPE_AETHRA */
1432         { "Aethra .aps file", "aethra", "aps", NULL,
1433           FALSE, FALSE, 0,
1434           NULL, NULL, NULL },
1435
1436         /* WTAP_FILE_TYPE_SUBTYPE_MPEG_2_TS */
1437         { "MPEG2 transport stream", "mp2t", "mp2t", "ts;mpg",
1438           FALSE, FALSE, 0,
1439           NULL, NULL, NULL },
1440
1441         /* WTAP_FILE_TYPE_SUBTYPE_VWR_80211 */
1442         { "Ixia IxVeriWave .vwr Raw 802.11 Capture", "vwr80211", "vwr", NULL,
1443           FALSE, FALSE, 0,
1444           NULL, NULL, NULL },
1445
1446         /* WTAP_FILE_TYPE_SUBTYPE_VWR_ETH */
1447         { "Ixia IxVeriWave .vwr Raw Ethernet Capture", "vwreth", "vwr", NULL,
1448           FALSE, FALSE, 0,
1449           NULL, NULL, NULL },
1450
1451         /* WTAP_FILE_TYPE_SUBTYPE_CAMINS */
1452         { "CAM Inspector file", "camins", "camins", NULL,
1453           FALSE, FALSE, 0,
1454           NULL, NULL, NULL },
1455
1456         /* WTAP_FILE_TYPE_SUBTYPE_STANAG_4607 */
1457         { "STANAG 4607 Format", "stanag4607", NULL, NULL,
1458           FALSE, FALSE, 0,
1459           NULL, NULL, NULL },
1460
1461         /* WTAP_FILE_NETSCALER_3_0 */
1462         { "NetScaler Trace (Version 3.0)", "nstrace30", "cap", NULL,
1463           TRUE, FALSE, 0,
1464           nstrace_30_dump_can_write_encap, nstrace_dump_open, NULL },
1465
1466         /* WTAP_FILE_LOGCAT */
1467         { "Android Logcat Binary format",          "logcat",         "logcat", NULL,
1468           FALSE, FALSE, 0,
1469           logcat_dump_can_write_encap, logcat_binary_dump_open, NULL },
1470         { "Android Logcat Brief text format",      "logcat-brief",      NULL, NULL,
1471           FALSE, FALSE, 0,
1472           logcat_text_brief_dump_can_write_encap, logcat_text_brief_dump_open, NULL },
1473         { "Android Logcat Process text format",    "logcat-process",    NULL, NULL,
1474           FALSE, FALSE, 0,
1475           logcat_text_process_dump_can_write_encap, logcat_text_process_dump_open, NULL },
1476         { "Android Logcat Tag text format",        "logcat-tag",        NULL, NULL,
1477           FALSE, FALSE, 0,
1478           logcat_text_tag_dump_can_write_encap, logcat_text_tag_dump_open, NULL },
1479         { "Android Logcat Thread text format",     "logcat-thread",     NULL, NULL,
1480            FALSE, FALSE, 0,
1481            logcat_text_thread_dump_can_write_encap, logcat_text_thread_dump_open, NULL },
1482         { "Android Logcat Time text format",       "logcat-time",       NULL, NULL,
1483           FALSE, FALSE, 0,
1484           logcat_text_time_dump_can_write_encap, logcat_text_time_dump_open, NULL },
1485         { "Android Logcat Threadtime text format", "logcat-threadtime", NULL, NULL,
1486           FALSE, FALSE, 0,
1487           logcat_text_threadtime_dump_can_write_encap, logcat_text_threadtime_dump_open, NULL },
1488         { "Android Logcat Long text format",       "logcat-long",       NULL, NULL,
1489           FALSE, FALSE, 0,
1490           logcat_text_long_dump_can_write_encap, logcat_text_long_dump_open, NULL }
1491
1492 };
1493
1494 gint wtap_num_file_types_subtypes = sizeof(dump_open_table_base) / sizeof(struct file_type_subtype_info);
1495
1496 static GArray*  dump_open_table_arr = NULL;
1497 static const struct file_type_subtype_info* dump_open_table = dump_open_table_base;
1498
1499 /* initialize the file types array if it has not being initialized yet */
1500 static void
1501 init_file_types_subtypes(void)
1502 {
1503
1504         if (dump_open_table_arr) return;
1505
1506         dump_open_table_arr = g_array_new(FALSE,TRUE,sizeof(struct file_type_subtype_info));
1507
1508         g_array_append_vals(dump_open_table_arr,dump_open_table_base,wtap_num_file_types_subtypes);
1509
1510         dump_open_table = (const struct file_type_subtype_info*)(void *)dump_open_table_arr->data;
1511 }
1512
1513 /* if subtype is WTAP_FILE_TYPE_SUBTYPE_UNKNOWN, then create a new subtype as well as register it, else replace the
1514    existing entry in that spot */
1515 int
1516 wtap_register_file_type_subtypes(const struct file_type_subtype_info* fi, const int subtype)
1517 {
1518         struct file_type_subtype_info* finfo;
1519         init_file_types_subtypes();
1520
1521         if (!fi || !fi->name || !fi->short_name || subtype > wtap_num_file_types_subtypes) {
1522                 g_error("no file type info or invalid file type to register");
1523                 return subtype;
1524         }
1525
1526         /* do we want a new registration? */
1527         if (subtype == WTAP_FILE_TYPE_SUBTYPE_UNKNOWN) {
1528                 /* register a new one; first verify there isn't one named this already */
1529                 if (wtap_short_string_to_file_type_subtype(fi->short_name) > -1 ) {
1530                         g_error("file type short name already exists");
1531                         return subtype;
1532                 }
1533
1534                 g_array_append_val(dump_open_table_arr,*fi);
1535
1536                 dump_open_table = (const struct file_type_subtype_info*)(void *)dump_open_table_arr->data;
1537
1538                 return wtap_num_file_types_subtypes++;
1539         }
1540
1541         /* re-register an existing one - verify the short names do match (sanity check really) */
1542         if (!dump_open_table[subtype].short_name || strcmp(dump_open_table[subtype].short_name,fi->short_name) != 0) {
1543                 g_error("invalid file type name given to register");
1544                 return subtype;
1545         }
1546
1547         /* yes, we're going to cast to change its const-ness */
1548         finfo = (struct file_type_subtype_info*)(&dump_open_table[subtype]);
1549         /*finfo->name = fi->name;*/
1550         /*finfo->short_name = fi->short_name;*/
1551         finfo->default_file_extension     = fi->default_file_extension;
1552         finfo->additional_file_extensions = fi->additional_file_extensions;
1553         finfo->writing_must_seek          = fi->writing_must_seek;
1554         finfo->has_name_resolution        = fi->has_name_resolution;
1555         finfo->supported_comment_types    = fi->supported_comment_types;
1556         finfo->can_write_encap            = fi->can_write_encap;
1557         finfo->dump_open                  = fi->dump_open;
1558         finfo->wslua_info                 = fi->wslua_info;
1559
1560         return subtype;
1561 }
1562
1563 /* De-registers a file writer - they can never be removed from the GArray, but we can "clear" an entry.
1564  */
1565 void
1566 wtap_deregister_file_type_subtype(const int subtype)
1567 {
1568         struct file_type_subtype_info* finfo;
1569
1570         if (subtype < 0 || subtype >= wtap_num_file_types_subtypes) {
1571                 g_error("invalid file type to de-register");
1572                 return;
1573         }
1574
1575         /* yes, we're going to cast to change its const-ness */
1576         finfo = (struct file_type_subtype_info*)(&dump_open_table[subtype]);
1577         /* unfortunately, it's not safe to null-out the name or short_name; bunch of other code doesn't guard aainst that, afaict */
1578         /*finfo->name = NULL;*/
1579         /*finfo->short_name = NULL;*/
1580         finfo->default_file_extension = NULL;
1581         finfo->additional_file_extensions = NULL;
1582         finfo->writing_must_seek = FALSE;
1583         finfo->has_name_resolution = FALSE;
1584         finfo->supported_comment_types = 0;
1585         finfo->can_write_encap = NULL;
1586         finfo->dump_open = NULL;
1587         finfo->wslua_info = NULL;
1588 }
1589
1590 int
1591 wtap_get_num_file_types_subtypes(void)
1592 {
1593         return wtap_num_file_types_subtypes;
1594 }
1595
1596 /*
1597  * Given a GArray of WTAP_ENCAP_ types, return the per-file encapsulation
1598  * type that would be needed to write out a file with those types.  If
1599  * there's only one type, it's that type, otherwise it's
1600  * WTAP_ENCAP_PER_PACKET.
1601  */
1602 int
1603 wtap_dump_file_encap_type(const GArray *file_encaps)
1604 {
1605         int encap;
1606
1607         encap = WTAP_ENCAP_PER_PACKET;
1608         if (file_encaps->len == 1) {
1609                 /* OK, use the one-and-only encapsulation type. */
1610                 encap = g_array_index(file_encaps, gint, 0);
1611         }
1612         return encap;
1613 }
1614
1615 static gboolean
1616 wtap_dump_can_write_encap(int filetype, int encap)
1617 {
1618         int result = 0;
1619
1620         if (filetype < 0 || filetype >= wtap_num_file_types_subtypes
1621             || dump_open_table[filetype].can_write_encap == NULL)
1622                 return FALSE;
1623
1624         result = (*dump_open_table[filetype].can_write_encap)(encap);
1625
1626         if (result != 0) {
1627                 /* if the err said to check wslua's can_write_encap, try that */
1628                 if (result == WTAP_ERR_CHECK_WSLUA
1629                         && dump_open_table[filetype].wslua_info != NULL
1630                         && dump_open_table[filetype].wslua_info->wslua_can_write_encap != NULL) {
1631
1632                         result = (*dump_open_table[filetype].wslua_info->wslua_can_write_encap)(encap, dump_open_table[filetype].wslua_info->wslua_data);
1633
1634                 }
1635
1636                 if (result != 0)
1637                         return FALSE;
1638         }
1639
1640         return TRUE;
1641 }
1642
1643 /*
1644  * Return TRUE if a capture with a given GArray of encapsulation types
1645  * and a given bitset of comment types can be written in a specified
1646  * format, and FALSE if it can't.
1647  */
1648 static gboolean
1649 wtap_dump_can_write_format(int ft, const GArray *file_encaps,
1650     guint32 required_comment_types)
1651 {
1652         guint i;
1653
1654         /*
1655          * Can we write in this format?
1656          */
1657         if (!wtap_dump_can_open(ft)) {
1658                 /* No. */
1659                 return FALSE;
1660         }
1661
1662         /*
1663          * Yes.  Can we write out all the required comments in this
1664          * format?
1665          */
1666         if (!wtap_dump_supports_comment_types(ft, required_comment_types)) {
1667                 /* No. */
1668                 return FALSE;
1669         }
1670
1671         /*
1672          * Yes.  Is the required per-file encapsulation type supported?
1673          * This might be WTAP_ENCAP_PER_PACKET.
1674          */
1675         if (!wtap_dump_can_write_encap(ft, wtap_dump_file_encap_type(file_encaps))) {
1676                 /* No. */
1677                 return FALSE;
1678         }
1679
1680         /*
1681          * Yes.  Are all the individual encapsulation types supported?
1682          */
1683         for (i = 0; i < file_encaps->len; i++) {
1684                 if (!wtap_dump_can_write_encap(ft,
1685                     g_array_index(file_encaps, int, i))) {
1686                         /* No - one of them isn't. */
1687                         return FALSE;
1688                 }
1689         }
1690
1691         /* Yes - we're OK. */
1692         return TRUE;
1693 }
1694
1695 /**
1696  * Return TRUE if we can write a file with the given GArray of
1697  * encapsulation types and the given bitmask of comment types.
1698  */
1699 gboolean
1700 wtap_dump_can_write(const GArray *file_encaps, guint32 required_comment_types)
1701 {
1702         int ft;
1703
1704         for (ft = 0; ft < WTAP_NUM_FILE_TYPES_SUBTYPES; ft++) {
1705                 /* To save a file with Wiretap, Wiretap has to handle that format,
1706                  * and its code to handle that format must be able to write a file
1707                  * with this file's encapsulation types.
1708                  */
1709                 if (wtap_dump_can_write_format(ft, file_encaps, required_comment_types)) {
1710                         /* OK, we can write it out in this type. */
1711                         return TRUE;
1712                 }
1713         }
1714
1715         /* No, we couldn't save it in any format. */
1716         return FALSE;
1717 }
1718
1719 /**
1720  * Get a GArray of WTAP_FILE_TYPE_SUBTYPE_ values for file types/subtypes
1721  * that can be used to save a file of a given type/subtype with a given
1722  * GArray of encapsulation types and the given bitmask of comment types.
1723  */
1724 GArray *
1725 wtap_get_savable_file_types_subtypes(int file_type_subtype,
1726     const GArray *file_encaps, guint32 required_comment_types)
1727 {
1728         GArray *savable_file_types_subtypes;
1729         int ft;
1730         int default_file_type_subtype = -1;
1731         int other_file_type_subtype = -1;
1732
1733         /* Can we save this file in its own file type/subtype? */
1734         if (wtap_dump_can_write_format(file_type_subtype, file_encaps,
1735                                        required_comment_types)) {
1736                 /* Yes - make that the default file type/subtype. */
1737                 default_file_type_subtype = file_type_subtype;
1738         } else {
1739                 /* OK, find the first file type/subtype we *can* save it as. */
1740                 default_file_type_subtype = -1;
1741                 for (ft = 0; ft < WTAP_NUM_FILE_TYPES_SUBTYPES; ft++) {
1742                         if (wtap_dump_can_write_format(ft, file_encaps,
1743                                                        required_comment_types)) {
1744                                 /* OK, got it. */
1745                                 default_file_type_subtype = ft;
1746                         }
1747                 }
1748         }
1749
1750         if (default_file_type_subtype == -1) {
1751                 /* We don't support writing this file as any file type/subtype. */
1752                 return NULL;
1753         }
1754
1755         /* Allocate the array. */
1756         savable_file_types_subtypes = g_array_new(FALSE, FALSE, (guint)sizeof (int));
1757
1758         /* Put the default file type/subtype first in the list. */
1759         g_array_append_val(savable_file_types_subtypes, default_file_type_subtype);
1760
1761         /* If the default is pcap, put pcap-NG right after it if we can
1762            also write it in pcap-NG format; otherwise, if the default is
1763            pcap-NG, put pcap right after it if we can also write it in
1764            pcap format. */
1765         if (default_file_type_subtype == WTAP_FILE_TYPE_SUBTYPE_PCAP) {
1766                 if (wtap_dump_can_write_format(WTAP_FILE_TYPE_SUBTYPE_PCAPNG, file_encaps,
1767                                                required_comment_types))
1768                         other_file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_PCAPNG;
1769         } else if (default_file_type_subtype == WTAP_FILE_TYPE_SUBTYPE_PCAPNG) {
1770                 if (wtap_dump_can_write_format(WTAP_FILE_TYPE_SUBTYPE_PCAP, file_encaps,
1771                                                required_comment_types))
1772                         other_file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_PCAP;
1773         }
1774         if (other_file_type_subtype != -1)
1775                 g_array_append_val(savable_file_types_subtypes, other_file_type_subtype);
1776
1777         /* Add all the other file types/subtypes that work. */
1778         for (ft = 0; ft < WTAP_NUM_FILE_TYPES_SUBTYPES; ft++) {
1779                 if (ft == WTAP_FILE_TYPE_SUBTYPE_UNKNOWN)
1780                         continue;       /* not a real file type */
1781                 if (ft == default_file_type_subtype || ft == other_file_type_subtype)
1782                         continue;       /* we've already done this one */
1783                 if (wtap_dump_can_write_format(ft, file_encaps,
1784                                                required_comment_types)) {
1785                         /* OK, we can write it out in this type. */
1786                         g_array_append_val(savable_file_types_subtypes, ft);
1787                 }
1788         }
1789
1790         return savable_file_types_subtypes;
1791 }
1792
1793 /* Name that should be somewhat descriptive. */
1794 const char *
1795 wtap_file_type_subtype_string(int file_type_subtype)
1796 {
1797         if (file_type_subtype < 0 || file_type_subtype >= wtap_num_file_types_subtypes) {
1798                 g_error("Unknown capture file type %d", file_type_subtype);
1799                 /** g_error() does an abort() and thus never returns **/
1800                 return "";
1801         } else
1802                 return dump_open_table[file_type_subtype].name;
1803 }
1804
1805 /* Name to use in, say, a command-line flag specifying the type/subtype. */
1806 const char *
1807 wtap_file_type_subtype_short_string(int file_type_subtype)
1808 {
1809         if (file_type_subtype < 0 || file_type_subtype >= wtap_num_file_types_subtypes)
1810                 return NULL;
1811         else
1812                 return dump_open_table[file_type_subtype].short_name;
1813 }
1814
1815 /* Translate a short name to a capture file type/subtype. */
1816 int
1817 wtap_short_string_to_file_type_subtype(const char *short_name)
1818 {
1819         int file_type_subtype;
1820
1821         for (file_type_subtype = 0; file_type_subtype < wtap_num_file_types_subtypes; file_type_subtype++) {
1822                 if (dump_open_table[file_type_subtype].short_name != NULL &&
1823                     strcmp(short_name, dump_open_table[file_type_subtype].short_name) == 0)
1824                         return file_type_subtype;
1825         }
1826
1827         /*
1828          * We now call the "libpcap" file format just "pcap", but we
1829          * allow it to be specified as "libpcap" as well, for
1830          * backwards compatibility.
1831          */
1832         if (strcmp(short_name, "libpcap") == 0)
1833                 return WTAP_FILE_TYPE_SUBTYPE_PCAP;
1834
1835         return -1;      /* no such file type, or we can't write it */
1836 }
1837
1838 static GSList *
1839 add_extensions_for_file_type_subtype(int file_type_subtype, GSList *extensions,
1840     GSList *compressed_file_extensions)
1841 {
1842         gchar **extensions_set, **extensionp;
1843         gchar *extension;
1844
1845         /*
1846          * Add the default extension, and all compressed variants of
1847          * it.
1848          */
1849         extensions = add_extensions(extensions,
1850             dump_open_table[file_type_subtype].default_file_extension,
1851             compressed_file_extensions);
1852
1853         if (dump_open_table[file_type_subtype].additional_file_extensions != NULL) {
1854                 /*
1855                  * We have additional extensions; add them.
1856                  *
1857                  * First, split the extension-list string into a set of
1858                  * extensions.
1859                  */
1860                 extensions_set = g_strsplit(dump_open_table[file_type_subtype].additional_file_extensions,
1861                     ";", 0);
1862
1863                 /*
1864                  * Add each of those extensions to the list.
1865                  */
1866                 for (extensionp = extensions_set; *extensionp != NULL;
1867                     extensionp++) {
1868                         extension = *extensionp;
1869
1870                         /*
1871                          * Add the extension, and all compressed variants
1872                          * of it.
1873                          */
1874                         extensions = add_extensions(extensions, extension,
1875                             compressed_file_extensions);
1876                 }
1877
1878                 g_strfreev(extensions_set);
1879         }
1880         return extensions;
1881 }
1882
1883 /* Return a list of file extensions that are used by the specified file type.
1884
1885    If include_compressed is TRUE, the list will include compressed
1886    extensions, e.g. not just "pcap" but also "pcap.gz" if we can read
1887    gzipped files.
1888
1889    All strings in the list are allocated with g_malloc() and must be freed
1890    with g_free(). */
1891 GSList *
1892 wtap_get_file_extensions_list(int file_type_subtype, gboolean include_compressed)
1893 {
1894         GSList *compressed_file_extensions;
1895         GSList *extensions;
1896
1897         if (file_type_subtype < 0 || file_type_subtype >= wtap_num_file_types_subtypes)
1898                 return NULL;    /* not a valid file type */
1899
1900         if (dump_open_table[file_type_subtype].default_file_extension == NULL)
1901                 return NULL;    /* valid, but no extensions known */
1902
1903         extensions = NULL;      /* empty list, to start with */
1904
1905         /*
1906          * If include_compressions is true, get the list of compressed-file
1907          * extensions.
1908          */
1909         if (include_compressed)
1910                 compressed_file_extensions = wtap_get_compressed_file_extensions();
1911         else
1912                 compressed_file_extensions = NULL;
1913
1914         /*
1915          * Add all this file type's extensions, with compressed
1916          * variants.
1917          */
1918         extensions = add_extensions_for_file_type_subtype(file_type_subtype, extensions,
1919             compressed_file_extensions);
1920
1921         g_slist_free(compressed_file_extensions);
1922         return extensions;
1923 }
1924
1925 /*
1926  * Free a list returned by wtap_get_file_extension_type_extensions(),
1927  * wtap_get_all_file_extensions_list, or wtap_get_file_extensions_list().
1928  */
1929 void
1930 wtap_free_extensions_list(GSList *extensions)
1931 {
1932         GSList *extension;
1933
1934         for (extension = extensions; extension != NULL;
1935             extension = g_slist_next(extension)) {
1936                 g_free(extension->data);
1937         }
1938         g_slist_free(extensions);
1939 }
1940
1941 /* Return the default file extension to use with the specified file type;
1942    that's just the extension, without any ".". */
1943 const char *
1944 wtap_default_file_extension(int file_type_subtype)
1945 {
1946         if (file_type_subtype < 0 || file_type_subtype >= wtap_num_file_types_subtypes)
1947                 return NULL;
1948         else
1949                 return dump_open_table[file_type_subtype].default_file_extension;
1950 }
1951
1952 gboolean
1953 wtap_dump_can_open(int file_type_subtype)
1954 {
1955         if (file_type_subtype < 0 || file_type_subtype >= wtap_num_file_types_subtypes
1956             || dump_open_table[file_type_subtype].dump_open == NULL)
1957                 return FALSE;
1958
1959         return TRUE;
1960 }
1961
1962 #ifdef HAVE_LIBZ
1963 gboolean
1964 wtap_dump_can_compress(int file_type_subtype)
1965 {
1966         /*
1967          * If this is an unknown file type, or if we have to
1968          * seek when writing out a file with this file type,
1969          * return FALSE.
1970          */
1971         if (file_type_subtype < 0 || file_type_subtype >= wtap_num_file_types_subtypes
1972             || dump_open_table[file_type_subtype].writing_must_seek)
1973                 return FALSE;
1974
1975         return TRUE;
1976 }
1977 #else
1978 gboolean
1979 wtap_dump_can_compress(int file_type_subtype _U_)
1980 {
1981         return FALSE;
1982 }
1983 #endif
1984
1985 gboolean
1986 wtap_dump_has_name_resolution(int file_type_subtype)
1987 {
1988         if (file_type_subtype < 0 || file_type_subtype >= wtap_num_file_types_subtypes
1989             || dump_open_table[file_type_subtype].has_name_resolution == FALSE)
1990                 return FALSE;
1991
1992         return TRUE;
1993 }
1994
1995 gboolean
1996 wtap_dump_supports_comment_types(int file_type_subtype, guint32 comment_types)
1997 {
1998         guint32 supported_comment_types;
1999
2000         if (file_type_subtype < 0 || file_type_subtype >= wtap_num_file_types_subtypes)
2001                 return FALSE;
2002
2003         supported_comment_types = dump_open_table[file_type_subtype].supported_comment_types;
2004
2005         if ((comment_types & supported_comment_types) == comment_types)
2006                 return TRUE;
2007         return FALSE;
2008 }
2009
2010 static gboolean wtap_dump_open_check(int file_type_subtype, int encap, gboolean comressed, int *err);
2011 static wtap_dumper* wtap_dump_alloc_wdh(int file_type_subtype, int encap, int snaplen,
2012                                         gboolean compressed, int *err);
2013 static gboolean wtap_dump_open_finish(wtap_dumper *wdh, int file_type_subtype, gboolean compressed, int *err);
2014
2015 static WFILE_T wtap_dump_file_open(wtap_dumper *wdh, const char *filename);
2016 static WFILE_T wtap_dump_file_fdopen(wtap_dumper *wdh, int fd);
2017 static int wtap_dump_file_close(wtap_dumper *wdh);
2018
2019 wtap_dumper *
2020 wtap_dump_open(const char *filename, int file_type_subtype, int encap,
2021                int snaplen, gboolean compressed, int *err)
2022 {
2023         return wtap_dump_open_ng(filename, file_type_subtype, encap,snaplen, compressed, NULL, NULL, err);
2024 }
2025
2026 static wtap_dumper *
2027 wtap_dump_init_dumper(int file_type_subtype, int encap, int snaplen, gboolean compressed,
2028     wtapng_section_t *shb_hdr, wtapng_iface_descriptions_t *idb_inf, int *err)
2029 {
2030         wtap_dumper *wdh;
2031
2032         /* Allocate a data structure for the output stream. */
2033         wdh = wtap_dump_alloc_wdh(file_type_subtype, encap, snaplen, compressed, err);
2034         if (wdh == NULL)
2035                 return NULL;    /* couldn't allocate it */
2036
2037         /* Set Section Header Block data */
2038         wdh->shb_hdr = shb_hdr;
2039         /* Set Interface Description Block data */
2040         if ((idb_inf != NULL) && (idb_inf->interface_data->len > 0)) {
2041                 wdh->interface_data = idb_inf->interface_data;
2042         } else {
2043                 wtapng_if_descr_t descr;
2044
2045                 descr.wtap_encap = encap;
2046                 descr.time_units_per_second = 1000000; /* default microsecond resolution */
2047                 descr.link_type = wtap_wtap_encap_to_pcap_encap(encap);
2048                 descr.snap_len = snaplen;
2049                 descr.opt_comment = NULL;
2050                 descr.if_name = g_strdup("Unknown/not available in original file format(libpcap)");
2051                 descr.if_description = NULL;
2052                 descr.if_speed = 0;
2053                 descr.if_tsresol = 6;
2054                 descr.if_filter_str= NULL;
2055                 descr.bpf_filter_len= 0;
2056                 descr.if_filter_bpf_bytes= NULL;
2057                 descr.if_os = NULL;
2058                 descr.if_fcslen = -1;
2059                 descr.num_stat_entries = 0;          /* Number of ISB:s */
2060                 descr.interface_statistics = NULL;
2061                 wdh->interface_data = g_array_new(FALSE, FALSE, sizeof(wtapng_if_descr_t));
2062                 g_array_append_val(wdh->interface_data, descr);
2063         }
2064         return wdh;
2065 }
2066
2067 wtap_dumper *
2068 wtap_dump_open_ng(const char *filename, int file_type_subtype, int encap,
2069                   int snaplen, gboolean compressed, wtapng_section_t *shb_hdr, wtapng_iface_descriptions_t *idb_inf, int *err)
2070 {
2071         wtap_dumper *wdh;
2072         WFILE_T fh;
2073
2074         /* Check whether we can open a capture file with that file type
2075            and that encapsulation. */
2076         if (!wtap_dump_open_check(file_type_subtype, encap, compressed, err))
2077                 return NULL;
2078
2079         /* Allocate and initialize a data structure for the output stream. */
2080         wdh = wtap_dump_init_dumper(file_type_subtype, encap, snaplen, compressed,
2081             shb_hdr, idb_inf, err);
2082         if (wdh == NULL)
2083                 return NULL;
2084
2085         /* "-" means stdout */
2086         if (strcmp(filename, "-") == 0) {
2087                 if (compressed) {
2088                         *err = EINVAL;  /* XXX - return a Wiretap error code for this */
2089                         g_free(wdh);
2090                         return NULL;    /* compress won't work on stdout */
2091                 }
2092 #ifdef _WIN32
2093                 if (_setmode(fileno(stdout), O_BINARY) == -1) {
2094                         /* "Should not happen" */
2095                         *err = errno;
2096                         g_free(wdh);
2097                         return NULL;    /* couldn't put standard output in binary mode */
2098                 }
2099 #endif
2100                 wdh->fh = stdout;
2101         } else {
2102                 /* In case "fopen()" fails but doesn't set "errno", set "errno"
2103                    to a generic "the open failed" error. */
2104                 errno = WTAP_ERR_CANT_OPEN;
2105                 fh = wtap_dump_file_open(wdh, filename);
2106                 if (fh == NULL) {
2107                         *err = errno;
2108                         g_free(wdh);
2109                         return NULL;    /* can't create file */
2110                 }
2111                 wdh->fh = fh;
2112         }
2113
2114         if (!wtap_dump_open_finish(wdh, file_type_subtype, compressed, err)) {
2115                 /* Get rid of the file we created; we couldn't finish
2116                    opening it. */
2117                 if (wdh->fh != stdout) {
2118                         wtap_dump_file_close(wdh);
2119                         ws_unlink(filename);
2120                 }
2121                 g_free(wdh);
2122                 return NULL;
2123         }
2124         return wdh;
2125 }
2126
2127 wtap_dumper *
2128 wtap_dump_fdopen(int fd, int file_type_subtype, int encap, int snaplen,
2129                  gboolean compressed, int *err)
2130 {
2131         return wtap_dump_fdopen_ng(fd, file_type_subtype, encap, snaplen, compressed, NULL, NULL, err);
2132 }
2133
2134 wtap_dumper *
2135 wtap_dump_fdopen_ng(int fd, int file_type_subtype, int encap, int snaplen,
2136                     gboolean compressed, wtapng_section_t *shb_hdr, wtapng_iface_descriptions_t *idb_inf, int *err)
2137 {
2138         wtap_dumper *wdh;
2139         WFILE_T fh;
2140
2141         /* Check whether we can open a capture file with that file type
2142            and that encapsulation. */
2143         if (!wtap_dump_open_check(file_type_subtype, encap, compressed, err))
2144                 return NULL;
2145
2146         /* Allocate and initialize a data structure for the output stream. */
2147         wdh = wtap_dump_init_dumper(file_type_subtype, encap, snaplen, compressed,
2148             shb_hdr, idb_inf, err);
2149         if (wdh == NULL)
2150                 return NULL;
2151
2152 #ifdef _WIN32
2153         if (fd == 1) {
2154                 if (_setmode(fileno(stdout), O_BINARY) == -1) {
2155                         /* "Should not happen" */
2156                         *err = errno;
2157                         g_free(wdh);
2158                         return NULL;    /* couldn't put standard output in binary mode */
2159                 }
2160         }
2161 #endif
2162
2163         /* In case "fopen()" fails but doesn't set "errno", set "errno"
2164            to a generic "the open failed" error. */
2165         errno = WTAP_ERR_CANT_OPEN;
2166         fh = wtap_dump_file_fdopen(wdh, fd);
2167         if (fh == NULL) {
2168                 *err = errno;
2169                 g_free(wdh);
2170                 return NULL;    /* can't create standard I/O stream */
2171         }
2172         wdh->fh = fh;
2173
2174         if (!wtap_dump_open_finish(wdh, file_type_subtype, compressed, err)) {
2175                 wtap_dump_file_close(wdh);
2176                 g_free(wdh);
2177                 return NULL;
2178         }
2179         return wdh;
2180 }
2181
2182 static gboolean
2183 wtap_dump_open_check(int file_type_subtype, int encap, gboolean compressed, int *err)
2184 {
2185         if (!wtap_dump_can_open(file_type_subtype)) {
2186                 /* Invalid type, or type we don't know how to write. */
2187                 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
2188                 return FALSE;
2189         }
2190
2191         /* OK, we know how to write that type; can we write the specified
2192            encapsulation type? */
2193         *err = (*dump_open_table[file_type_subtype].can_write_encap)(encap);
2194         /* if the err said to check wslua's can_write_encap, try that */
2195         if (*err == WTAP_ERR_CHECK_WSLUA
2196                 && dump_open_table[file_type_subtype].wslua_info != NULL
2197                 && dump_open_table[file_type_subtype].wslua_info->wslua_can_write_encap != NULL) {
2198
2199                 *err = (*dump_open_table[file_type_subtype].wslua_info->wslua_can_write_encap)(encap, dump_open_table[file_type_subtype].wslua_info->wslua_data);
2200
2201         }
2202
2203         if (*err != 0)
2204                 return FALSE;
2205
2206         /* if compression is wanted, do we support this for this file_type_subtype? */
2207         if(compressed && !wtap_dump_can_compress(file_type_subtype)) {
2208                 *err = WTAP_ERR_COMPRESSION_NOT_SUPPORTED;
2209                 return FALSE;
2210         }
2211
2212         /* All systems go! */
2213         return TRUE;
2214 }
2215
2216 static wtap_dumper *
2217 wtap_dump_alloc_wdh(int file_type_subtype, int encap, int snaplen, gboolean compressed, int *err)
2218 {
2219         wtap_dumper *wdh;
2220
2221         wdh = (wtap_dumper *)g_malloc0(sizeof (wtap_dumper));
2222         if (wdh == NULL) {
2223                 *err = errno;
2224                 return NULL;
2225         }
2226
2227         wdh->file_type_subtype = file_type_subtype;
2228         wdh->snaplen = snaplen;
2229         wdh->encap = encap;
2230         wdh->compressed = compressed;
2231         wdh->wslua_data = NULL;
2232         return wdh;
2233 }
2234
2235 static gboolean
2236 wtap_dump_open_finish(wtap_dumper *wdh, int file_type_subtype, gboolean compressed, int *err)
2237 {
2238         int fd;
2239         gboolean cant_seek;
2240
2241         /* Can we do a seek on the file descriptor?
2242            If not, note that fact. */
2243         if(compressed) {
2244                 cant_seek = TRUE;
2245         } else {
2246                 fd = fileno((FILE *)wdh->fh);
2247                 if (ws_lseek64(fd, 1, SEEK_CUR) == (off_t) -1)
2248                         cant_seek = TRUE;
2249                 else {
2250                         /* Undo the seek. */
2251                         ws_lseek64(fd, 0, SEEK_SET);
2252                         cant_seek = FALSE;
2253                 }
2254         }
2255
2256         /* If this file type requires seeking, and we can't seek, fail. */
2257         if (dump_open_table[file_type_subtype].writing_must_seek && cant_seek) {
2258                 *err = WTAP_ERR_CANT_WRITE_TO_PIPE;
2259                 return FALSE;
2260         }
2261
2262         /* Set wdh with wslua data if any - this is how we pass the data
2263          * to the file writer.
2264          */
2265         if (dump_open_table[file_type_subtype].wslua_info)
2266                 wdh->wslua_data = dump_open_table[file_type_subtype].wslua_info->wslua_data;
2267
2268         /* Now try to open the file for writing. */
2269         if (!(*dump_open_table[file_type_subtype].dump_open)(wdh, err)) {
2270                 return FALSE;
2271         }
2272
2273         return TRUE;    /* success! */
2274 }
2275
2276 gboolean
2277 wtap_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
2278           const guint8 *pd, int *err)
2279 {
2280         return (wdh->subtype_write)(wdh, phdr, pd, err);
2281 }
2282
2283 void
2284 wtap_dump_flush(wtap_dumper *wdh)
2285 {
2286 #ifdef HAVE_LIBZ
2287         if(wdh->compressed) {
2288                 gzwfile_flush((GZWFILE_T)wdh->fh);
2289         } else
2290 #endif
2291         {
2292                 fflush((FILE *)wdh->fh);
2293         }
2294 }
2295
2296 gboolean
2297 wtap_dump_close(wtap_dumper *wdh, int *err)
2298 {
2299         gboolean ret = TRUE;
2300
2301         if (wdh->subtype_close != NULL) {
2302                 /* There's a close routine for this dump stream. */
2303                 if (!(wdh->subtype_close)(wdh, err))
2304                         ret = FALSE;
2305         }
2306         errno = WTAP_ERR_CANT_CLOSE;
2307         /* Don't close stdout */
2308         if (wdh->fh != stdout) {
2309                 if (wtap_dump_file_close(wdh) == EOF) {
2310                         if (ret) {
2311                                 /* The per-format close function succeeded,
2312                                    but the fclose didn't.  Save the reason
2313                                    why, if our caller asked for it. */
2314                                 if (err != NULL)
2315                                         *err = errno;
2316                         }
2317                         ret = FALSE;
2318                 }
2319         } else {
2320                 /* as we don't close stdout, at least try to flush it */
2321                 wtap_dump_flush(wdh);
2322         }
2323         if (wdh->priv != NULL)
2324                 g_free(wdh->priv);
2325         g_free(wdh);
2326         return ret;
2327 }
2328
2329 gint64
2330 wtap_get_bytes_dumped(wtap_dumper *wdh)
2331 {
2332         return wdh->bytes_dumped;
2333 }
2334
2335 void
2336 wtap_set_bytes_dumped(wtap_dumper *wdh, gint64 bytes_dumped)
2337 {
2338         wdh->bytes_dumped = bytes_dumped;
2339 }
2340
2341 gboolean
2342 wtap_dump_set_addrinfo_list(wtap_dumper *wdh, addrinfo_lists_t *addrinfo_lists)
2343 {
2344         if (!wdh || wdh->file_type_subtype < 0 || wdh->file_type_subtype >= wtap_num_file_types_subtypes
2345                 || dump_open_table[wdh->file_type_subtype].has_name_resolution == FALSE)
2346                         return FALSE;
2347         wdh->addrinfo_lists = addrinfo_lists;
2348         return TRUE;
2349 }
2350
2351 /* internally open a file for writing (compressed or not) */
2352 #ifdef HAVE_LIBZ
2353 static WFILE_T
2354 wtap_dump_file_open(wtap_dumper *wdh, const char *filename)
2355 {
2356         if(wdh->compressed) {
2357                 return gzwfile_open(filename);
2358         } else {
2359                 return ws_fopen(filename, "wb");
2360         }
2361 }
2362 #else
2363 static WFILE_T
2364 wtap_dump_file_open(wtap_dumper *wdh _U_, const char *filename)
2365 {
2366         return ws_fopen(filename, "wb");
2367 }
2368 #endif
2369
2370 /* internally open a file for writing (compressed or not) */
2371 #ifdef HAVE_LIBZ
2372 static WFILE_T
2373 wtap_dump_file_fdopen(wtap_dumper *wdh, int fd)
2374 {
2375         if(wdh->compressed) {
2376                 return gzwfile_fdopen(fd);
2377         } else {
2378                 return fdopen(fd, "wb");
2379         }
2380 }
2381 #else
2382 static WFILE_T
2383 wtap_dump_file_fdopen(wtap_dumper *wdh _U_, int fd)
2384 {
2385         return fdopen(fd, "wb");
2386 }
2387 #endif
2388
2389 /* internally writing raw bytes (compressed or not) */
2390 gboolean
2391 wtap_dump_file_write(wtap_dumper *wdh, const void *buf, size_t bufsize, int *err)
2392 {
2393         size_t nwritten;
2394
2395 #ifdef HAVE_LIBZ
2396         if (wdh->compressed) {
2397                 nwritten = gzwfile_write((GZWFILE_T)wdh->fh, buf, (unsigned int) bufsize);
2398                 /*
2399                  * gzwfile_write() returns 0 on error.
2400                  */
2401                 if (nwritten == 0) {
2402                         *err = gzwfile_geterr((GZWFILE_T)wdh->fh);
2403                         return FALSE;
2404                 }
2405         } else
2406 #endif
2407         {
2408                 nwritten = fwrite(buf, 1, bufsize, (FILE *)wdh->fh);
2409                 /*
2410                  * At least according to the Mac OS X man page,
2411                  * this can return a short count on an error.
2412                  */
2413                 if (nwritten != bufsize) {
2414                         if (ferror((FILE *)wdh->fh))
2415                                 *err = errno;
2416                         else
2417                                 *err = WTAP_ERR_SHORT_WRITE;
2418                         return FALSE;
2419                 }
2420         }
2421         return TRUE;
2422 }
2423
2424 /* internally close a file for writing (compressed or not) */
2425 static int
2426 wtap_dump_file_close(wtap_dumper *wdh)
2427 {
2428 #ifdef HAVE_LIBZ
2429         if(wdh->compressed) {
2430                 return gzwfile_close((GZWFILE_T)wdh->fh);
2431         } else
2432 #endif
2433         {
2434                 return fclose((FILE *)wdh->fh);
2435         }
2436 }
2437
2438 gint64
2439 wtap_dump_file_seek(wtap_dumper *wdh, gint64 offset, int whence, int *err)
2440 {
2441 #ifdef HAVE_LIBZ
2442         if(wdh->compressed) {
2443                 *err = WTAP_ERR_CANT_SEEK_COMPRESSED;
2444                 return -1;
2445         } else
2446 #endif
2447         {
2448                 if (-1 == fseek((FILE *)wdh->fh, (long)offset, whence)) {
2449                         *err = errno;
2450                         return -1;
2451                 } else
2452                 {
2453                         return 0;
2454                 }
2455         }
2456 }
2457
2458 gint64
2459 wtap_dump_file_tell(wtap_dumper *wdh, int *err)
2460 {
2461         gint64 rval;
2462 #ifdef HAVE_LIBZ
2463         if(wdh->compressed) {
2464                 *err = WTAP_ERR_CANT_SEEK_COMPRESSED;
2465                 return -1;
2466         } else
2467 #endif
2468         {
2469                 if (-1 == (rval = ftell((FILE *)wdh->fh))) {
2470                         *err = errno;
2471                         return -1;
2472                 } else
2473                 {
2474                         return rval;
2475                 }
2476         }
2477 }