In Windows, in the Save As and Export Selected Packets dialog, append
[metze/wireshark/wip.git] / wiretap / file_access.c
1 /* file_access.c
2  *
3  * $Id$
4  *
5  * Wiretap Library
6  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdlib.h>
30
31 #ifdef HAVE_FCNTL_H
32 #include <fcntl.h>
33 #endif
34
35 #ifdef HAVE_UNISTD_H
36 #include <unistd.h>
37 #endif
38
39 #include <errno.h>
40
41 #include <wsutil/file_util.h>
42
43 #include "wtap-int.h"
44 #include "file_wrappers.h"
45 #include "buffer.h"
46 #include "lanalyzer.h"
47 #include "airopeek9.h"
48 #include "ngsniffer.h"
49 #include "radcom.h"
50 #include "ascendtext.h"
51 #include "nettl.h"
52 #include "libpcap.h"
53 #include "snoop.h"
54 #include "iptrace.h"
55 #include "iseries.h"
56 #include "netmon.h"
57 #include "netxray.h"
58 #include "toshiba.h"
59 #include "eyesdn.h"
60 #include "i4btrace.h"
61 #include "csids.h"
62 #include "pppdump.h"
63 #include "etherpeek.h"
64 #include "vms.h"
65 #include "dbs-etherwatch.h"
66 #include "visual.h"
67 #include "cosine.h"
68 #include "5views.h"
69 #include "erf.h"
70 #include "hcidump.h"
71 #include "network_instruments.h"
72 #include "k12.h"
73 #include "ber.h"
74 #include "catapult_dct2000.h"
75 #include "mp2t.h"
76 #include "mpeg.h"
77 #include "netscreen.h"
78 #include "commview.h"
79 #include "pcapng.h"
80 #include "aethra.h"
81 #include "btsnoop.h"
82 #include "tnef.h"
83 #include "dct3trace.h"
84 #include "packetlogger.h"
85 #include "daintree-sna.h"
86 #include "netscaler.h"
87 #include "mime_file.h"
88 #include "ipfix.h"
89 #include "vwr.h"
90 #include "pcap-encap.h"
91
92 /* The open_file_* routines should return:
93  *
94  *      -1 on an I/O error;
95  *
96  *      1 if the file they're reading is one of the types it handles;
97  *
98  *      0 if the file they're reading isn't the type they're checking for.
99  *
100  * If the routine handles this type of file, it should set the "file_type"
101  * field in the "struct wtap" to the type of the file.
102  *
103  * Put the trace files that are merely saved telnet-sessions last, since it's
104  * possible that you could have captured someone a router telnet-session
105  * using another tool. So, a libpcap trace of an toshiba "snoop" session
106  * should be discovered as a libpcap file, not a toshiba file.
107  */
108
109
110 static wtap_open_routine_t open_routines_base[] = {
111         /* Files that have magic bytes in fixed locations. These
112          * are easy to identify.
113          */
114         libpcap_open,
115         pcapng_open,
116         lanalyzer_open,
117         ngsniffer_open,
118         snoop_open,
119         iptrace_open,
120         netmon_open,
121         netxray_open,
122         radcom_open,
123         nettl_open,
124         visual_open,
125         _5views_open,
126         network_instruments_open,
127         airopeek9_open,
128         dbs_etherwatch_open,
129         k12_open,
130         catapult_dct2000_open,
131         ber_open,
132         aethra_open,
133         btsnoop_open,
134         eyesdn_open,
135         vwr_open,
136         packetlogger_open, /* This type does not have a magic number, but its
137                             * files are sometimes grabbed by mpeg_open. */
138         mpeg_open,
139         mp2t_open,
140         tnef_open,
141         dct3trace_open,
142         daintree_sna_open,
143         mime_file_open,
144         /* Files that don't have magic bytes at a fixed location,
145          * but that instead require a heuristic of some sort to
146          * identify them.  This includes the ASCII trace files that
147          * would be, for example, saved copies of a Telnet session
148          * to some box.
149          */
150
151         /* I put NetScreen *before* erf, because there were some
152          * false positives with my test-files (Sake Blok, July 2007)
153          */
154         netscreen_open,
155         erf_open,
156         ipfix_open,
157         k12text_open,
158         etherpeek_open,
159         pppdump_open,
160         iseries_open,
161         ascend_open,
162         toshiba_open,
163         i4btrace_open,
164         csids_open,
165         vms_open,
166         cosine_open,
167         hcidump_open,
168         commview_open,
169         nstrace_open
170 };
171
172 #define N_FILE_TYPES    (sizeof open_routines_base / sizeof open_routines_base[0])
173
174 static wtap_open_routine_t* open_routines = NULL;
175
176 static GArray* open_routines_arr = NULL;
177
178
179 /* initialize the open routines array if it has not been initialized yet */
180 static void init_open_routines(void) {
181
182         if (open_routines_arr) return;
183
184         open_routines_arr = g_array_new(FALSE,TRUE,sizeof(wtap_open_routine_t));
185
186         g_array_append_vals(open_routines_arr,open_routines_base,N_FILE_TYPES);
187
188         open_routines = (wtap_open_routine_t*)(void *)open_routines_arr->data;
189 }
190
191 void wtap_register_open_routine(wtap_open_routine_t open_routine, gboolean has_magic) {
192         init_open_routines();
193
194         if (has_magic)
195                 g_array_prepend_val(open_routines_arr,open_routine);
196         else
197                 g_array_append_val(open_routines_arr,open_routine);
198
199         open_routines = (wtap_open_routine_t*)(void *)open_routines_arr->data;
200 }
201
202 /*
203  * Visual C++ on Win32 systems doesn't define these.  (Old UNIX systems don't
204  * define them either.)
205  *
206  * Visual C++ on Win32 systems doesn't define S_IFIFO, it defines _S_IFIFO.
207  */
208 #ifndef S_ISREG
209 #define S_ISREG(mode)   (((mode) & S_IFMT) == S_IFREG)
210 #endif
211 #ifndef S_IFIFO
212 #define S_IFIFO _S_IFIFO
213 #endif
214 #ifndef S_ISFIFO
215 #define S_ISFIFO(mode)  (((mode) & S_IFMT) == S_IFIFO)
216 #endif
217 #ifndef S_ISDIR
218 #define S_ISDIR(mode)   (((mode) & S_IFMT) == S_IFDIR)
219 #endif
220
221 /* Opens a file and prepares a wtap struct.
222    If "do_random" is TRUE, it opens the file twice; the second open
223    allows the application to do random-access I/O without moving
224    the seek offset for sequential I/O, which is used by Wireshark
225    so that it can do sequential I/O to a capture file that's being
226    written to as new packets arrive independently of random I/O done
227    to display protocol trees for packets when they're selected. */
228 wtap* wtap_open_offline(const char *filename, int *err, char **err_info,
229                         gboolean do_random)
230 {
231         int     fd;
232         ws_statb64 statb;
233         wtap    *wth;
234         unsigned int    i;
235         gboolean use_stdin = FALSE;
236
237         /* open standard input if filename is '-' */
238         if (strcmp(filename, "-") == 0)
239                 use_stdin = TRUE;
240
241         /* First, make sure the file is valid */
242         if (use_stdin) {
243                 if (ws_fstat64(0, &statb) < 0) {
244                         *err = errno;
245                         return NULL;
246                 }
247         } else {
248                 if (ws_stat64(filename, &statb) < 0) {
249                         *err = errno;
250                         return NULL;
251                 }
252         }
253         if (S_ISFIFO(statb.st_mode)) {
254                 /*
255                  * Opens of FIFOs are allowed only when not opening
256                  * for random access.
257                  *
258                  * XXX - currently, we do seeking when trying to find
259                  * out the file type, so we don't actually support
260                  * opening FIFOs.  However, we may eventually
261                  * do buffering that allows us to do at least some
262                  * file type determination even on pipes, so we
263                  * allow FIFO opens and let things fail later when
264                  * we try to seek.
265                  */
266                 if (do_random) {
267                         *err = WTAP_ERR_RANDOM_OPEN_PIPE;
268                         return NULL;
269                 }
270         } else if (S_ISDIR(statb.st_mode)) {
271                 /*
272                  * Return different errors for "this is a directory"
273                  * and "this is some random special file type", so
274                  * the user can get a potentially more helpful error.
275                  */
276                 *err = EISDIR;
277                 return NULL;
278         } else if (! S_ISREG(statb.st_mode)) {
279                 *err = WTAP_ERR_NOT_REGULAR_FILE;
280                 return NULL;
281         }
282
283         /*
284          * We need two independent descriptors for random access, so
285          * they have different file positions.  If we're opening the
286          * standard input, we can only dup it to get additional
287          * descriptors, so we can't have two independent descriptors,
288          * and thus can't do random access.
289          */
290         if (use_stdin && do_random) {
291                 *err = WTAP_ERR_RANDOM_OPEN_STDIN;
292                 return NULL;
293         }
294
295         errno = ENOMEM;
296         wth = (wtap *)g_malloc0(sizeof(wtap));
297
298         /* Open the file */
299         errno = WTAP_ERR_CANT_OPEN;
300         if (use_stdin) {
301                 /*
302                  * We dup FD 0, so that we don't have to worry about
303                  * a file_close of wth->fh closing the standard
304                  * input of the process.
305                  */
306                 fd = ws_dup(0);
307                 if (fd < 0) {
308                         *err = errno;
309                         g_free(wth);
310                         return NULL;
311                 }
312 #ifdef _WIN32
313                 if (_setmode(fd, O_BINARY) == -1) {
314                         /* "Shouldn't happen" */
315                         *err = errno;
316                         g_free(wth);
317                         return NULL;
318                 }
319 #endif
320                 if (!(wth->fh = filed_open(fd))) {
321                         *err = errno;
322                         ws_close(fd);
323                         g_free(wth);
324                         return NULL;
325                 }
326         } else {
327                 if (!(wth->fh = file_open(filename))) {
328                         *err = errno;
329                         g_free(wth);
330                         return NULL;
331                 }
332         }
333
334         if (do_random) {
335                 if (!(wth->random_fh = file_open(filename))) {
336                         *err = errno;
337                         file_close(wth->fh);
338                         g_free(wth);
339                         return NULL;
340                 }
341         } else
342                 wth->random_fh = NULL;
343
344         /* initialization */
345         wth->file_encap = WTAP_ENCAP_UNKNOWN;
346         wth->subtype_sequential_close = NULL;
347         wth->subtype_close = NULL;
348         wth->tsprecision = WTAP_FILE_TSPREC_USEC;
349         wth->priv = NULL;
350
351         init_open_routines();
352         if (wth->random_fh) {
353                 wth->fast_seek = g_ptr_array_new();
354
355                 file_set_random_access(wth->fh, FALSE, wth->fast_seek);
356                 file_set_random_access(wth->random_fh, TRUE, wth->fast_seek);
357         }
358
359         /* Try all file types */
360         for (i = 0; i < open_routines_arr->len; i++) {
361                 /* Seek back to the beginning of the file; the open routine
362                    for the previous file type may have left the file
363                    position somewhere other than the beginning, and the
364                    open routine for this file type will probably want
365                    to start reading at the beginning.
366
367                    Initialize the data offset while we're at it. */
368                 if (file_seek(wth->fh, 0, SEEK_SET, err) == -1) {
369                         /* I/O error - give up */
370                         if (wth->random_fh != NULL)
371                                 file_close(wth->random_fh);
372                         file_close(wth->fh);
373                         g_free(wth);
374                         return NULL;
375                 }
376
377                 switch ((*open_routines[i])(wth, err, err_info)) {
378
379                 case -1:
380                         /* I/O error - give up */
381                         if (wth->random_fh != NULL)
382                                 file_close(wth->random_fh);
383                         file_close(wth->fh);
384                         g_free(wth);
385                         return NULL;
386
387                 case 0:
388                         /* No I/O error, but not that type of file */
389                         break;
390
391                 case 1:
392                         /* We found the file type */
393                         goto success;
394                 }
395         }
396
397         /* Well, it's not one of the types of file we know about. */
398         wtap_close(wth);
399         *err = WTAP_ERR_FILE_UNKNOWN_FORMAT;
400         return NULL;
401
402 success:
403         wth->frame_buffer = (struct Buffer *)g_malloc(sizeof(struct Buffer));
404         buffer_init(wth->frame_buffer, 1500);
405         return wth;
406 }
407
408 /* Table of the file types we know about.
409    Entries must be sorted by WTAP_FILE_xxx values in ascending order */
410 static const struct file_type_info dump_open_table_base[] = {
411         /* WTAP_FILE_UNKNOWN (only used internally for initialization) */
412         { NULL, NULL, NULL, NULL, FALSE, FALSE,
413           NULL, NULL },
414
415         /* WTAP_FILE_PCAP */
416         /* Gianluca Varenni suggests that we add "deprecated" to the description. */
417         { "Wireshark/tcpdump/... - libpcap", "libpcap", "pcap", "cap;dmp", FALSE, FALSE,
418           libpcap_dump_can_write_encap, libpcap_dump_open },
419
420         /* WTAP_FILE_PCAPNG */
421         { "Wireshark - pcapng", "pcapng", "pcapng", "ntar", FALSE, TRUE,
422           pcapng_dump_can_write_encap, pcapng_dump_open },
423
424         /* WTAP_FILE_PCAP_NSEC */
425         { "Wireshark - nanosecond libpcap", "nseclibpcap", "pcap", "cap;dmp", FALSE, FALSE,
426           libpcap_dump_can_write_encap, libpcap_dump_open },
427
428         /* WTAP_FILE_PCAP_AIX */
429         { "AIX tcpdump - libpcap", "aixlibpcap", "pcap", "cap;dmp", FALSE, FALSE,
430           NULL, NULL },
431
432         /* WTAP_FILE_PCAP_SS991029 */
433         { "Modified tcpdump - libpcap", "modlibpcap", "pcap", "cap;dmp", FALSE, FALSE,
434           libpcap_dump_can_write_encap, libpcap_dump_open },
435
436         /* WTAP_FILE_PCAP_NOKIA */
437         { "Nokia tcpdump - libpcap ", "nokialibpcap", "pcap", "cap;dmp", FALSE, FALSE,
438           libpcap_dump_can_write_encap, libpcap_dump_open },
439
440         /* WTAP_FILE_PCAP_SS990417 */
441         { "RedHat 6.1 tcpdump - libpcap", "rh6_1libpcap", "pcap", "cap;dmp", FALSE, FALSE,
442           libpcap_dump_can_write_encap, libpcap_dump_open },
443
444         /* WTAP_FILE_PCAP_SS990915 */
445         { "SuSE 6.3 tcpdump - libpcap", "suse6_3libpcap", "pcap", "cap;dmp", FALSE, FALSE,
446           libpcap_dump_can_write_encap, libpcap_dump_open },
447
448         /* WTAP_FILE_5VIEWS */
449         { "InfoVista 5View capture", "5views", "5vw", NULL, TRUE, FALSE,
450           _5views_dump_can_write_encap, _5views_dump_open },
451
452         /* WTAP_FILE_IPTRACE_1_0 */
453         { "AIX iptrace 1.0", "iptrace_1", NULL, NULL, FALSE, FALSE,
454           NULL, NULL },
455
456         /* WTAP_FILE_IPTRACE_2_0 */
457         { "AIX iptrace 2.0", "iptrace_2", NULL, NULL, FALSE, FALSE,
458           NULL, NULL },
459
460         /* WTAP_FILE_BER */
461         { "ASN.1 Basic Encoding Rules", "ber", NULL, NULL, FALSE, FALSE,
462                 NULL, NULL },
463
464         /* WTAP_FILE_HCIDUMP */
465         { "Bluetooth HCI dump", "hcidump", NULL, NULL, FALSE, FALSE,
466           NULL, NULL },
467
468         /* WTAP_FILE_CATAPULT_DCT2000 */
469         { "Catapult DCT2000 trace (.out format)", "dct2000", "out", NULL, FALSE, FALSE,
470           catapult_dct2000_dump_can_write_encap, catapult_dct2000_dump_open },
471
472         /* WTAP_FILE_NETXRAY_OLD */
473         { "Cinco Networks NetXRay 1.x", "netxray1", "cap", NULL, TRUE, FALSE,
474           NULL, NULL },
475
476         /* WTAP_FILE_NETXRAY_1_0 */
477         { "Cinco Networks NetXRay 2.0 or later", "netxray2", "cap", NULL, TRUE, FALSE,
478           NULL, NULL },
479
480         /* WTAP_FILE_COSINE */
481         { "CoSine IPSX L2 capture", "cosine", "txt", NULL, FALSE, FALSE,
482           NULL, NULL },
483
484         /* WTAP_FILE_CSIDS */
485         { "CSIDS IPLog", "csids", NULL, NULL, FALSE, FALSE,
486           NULL, NULL },
487
488         /* WTAP_FILE_DBS_ETHERWATCH */
489         { "DBS Etherwatch (VMS)", "etherwatch", "txt", NULL, FALSE, FALSE,
490           NULL, NULL},
491
492         /* WTAP_FILE_ERF */
493         { "Endace ERF capture", "erf", "erf", NULL, FALSE, FALSE,
494           erf_dump_can_write_encap, erf_dump_open },
495
496         /* WTAP_FILE_EYESDN */
497         { "EyeSDN USB S0/E1 ISDN trace format", "eyesdn", "trc", NULL, FALSE, FALSE,
498            eyesdn_dump_can_write_encap, eyesdn_dump_open },
499
500         /* WTAP_FILE_NETTL */
501         { "HP-UX nettl trace", "nettl", "trc0", "trc1", FALSE, FALSE,
502           nettl_dump_can_write_encap, nettl_dump_open },
503
504         /* WTAP_FILE_ISERIES */
505         { "IBM iSeries comm. trace (ASCII)", "iseries_ascii", "txt", NULL, FALSE, FALSE,
506           NULL, NULL },
507
508         /* WTAP_FILE_ISERIES_UNICODE */
509         { "IBM iSeries comm. trace (UNICODE)", "iseries_unicode", "txt", NULL, FALSE, FALSE,
510           NULL, NULL },
511
512         /* WTAP_FILE_I4BTRACE */
513         { "I4B ISDN trace", "i4btrace", NULL, NULL, FALSE, FALSE,
514           NULL, NULL },
515
516         /* WTAP_FILE_ASCEND */
517         { "Lucent/Ascend access server trace", "ascend", "txt", NULL, FALSE, FALSE,
518           NULL, NULL },
519
520         /* WTAP_FILE_NETMON_1_x */
521         { "Microsoft NetMon 1.x", "netmon1", "cap", NULL, TRUE, FALSE,
522           netmon_dump_can_write_encap_1_x, netmon_dump_open },
523
524         /* WTAP_FILE_NETMON_2_x */
525         { "Microsoft NetMon 2.x", "netmon2", "cap", NULL, TRUE, FALSE,
526           netmon_dump_can_write_encap_2_x, netmon_dump_open },
527
528         /* WTAP_FILE_NGSNIFFER_UNCOMPRESSED */
529         { "NA Sniffer (DOS)", "ngsniffer", "cap", "enc;trc;fdc;syc", FALSE, FALSE,
530           ngsniffer_dump_can_write_encap, ngsniffer_dump_open },
531
532         /* WTAP_FILE_NGSNIFFER_COMPRESSED */
533         { "NA Sniffer (DOS), compressed", "ngsniffer_comp", "caz", NULL, FALSE, FALSE,
534           NULL, NULL },
535
536         /* WTAP_FILE_NETXRAY_1_1 */
537         { "NA Sniffer (Windows) 1.1", "ngwsniffer_1_1", "cap", NULL, TRUE, FALSE,
538           netxray_dump_can_write_encap_1_1, netxray_dump_open_1_1 },
539
540         /* WTAP_FILE_NETXRAY_2_00x */
541         { "NA Sniffer (Windows) 2.00x", "ngwsniffer_2_0", "cap", NULL, TRUE, FALSE,
542           netxray_dump_can_write_encap_2_0, netxray_dump_open_2_0 },
543
544         /* WTAP_FILE_NETWORK_INSTRUMENTS */
545         { "Network Instruments Observer", "niobserver", "bfr", NULL, FALSE, FALSE,
546           network_instruments_dump_can_write_encap, network_instruments_dump_open },
547
548         /* WTAP_FILE_LANALYZER */
549         { "Novell LANalyzer","lanalyzer", "tr1", NULL, TRUE, FALSE,
550           lanalyzer_dump_can_write_encap, lanalyzer_dump_open },
551
552         /* WTAP_FILE_PPPDUMP */
553         { "pppd log (pppdump format)", "pppd", NULL, NULL, FALSE, FALSE,
554           NULL, NULL },
555
556         /* WTAP_FILE_RADCOM */
557         { "RADCOM WAN/LAN analyzer", "radcom", NULL, NULL, FALSE, FALSE,
558           NULL, NULL },
559
560         /* WTAP_FILE_SNOOP */
561         { "Sun snoop", "snoop", "snoop", "cap", FALSE, FALSE,
562           snoop_dump_can_write_encap, snoop_dump_open },
563
564         /* WTAP_FILE_SHOMITI */
565         { "Shomiti/Finisar Surveyor", "shomiti", "cap", NULL, FALSE, FALSE,
566           NULL, NULL },
567
568         /* WTAP_FILE_VMS */
569         { "TCPIPtrace (VMS)", "tcpiptrace", "txt", NULL, FALSE, FALSE,
570           NULL, NULL},
571
572         /* WTAP_FILE_K12 */
573         { "Tektronix K12xx 32-bit .rf5 format", "rf5", "rf5", NULL, TRUE, FALSE,
574                 k12_dump_can_write_encap, k12_dump_open },
575
576         /* WTAP_FILE_TOSHIBA */
577         { "Toshiba Compact ISDN Router snoop", "toshiba", "txt", NULL, FALSE, FALSE,
578           NULL, NULL },
579
580         /* WTAP_FILE_VISUAL_NETWORKS */
581         { "Visual Networks traffic capture", "visual", NULL, NULL, TRUE, FALSE,
582           visual_dump_can_write_encap, visual_dump_open },
583
584         /* WTAP_FILE_ETHERPEEK_V56 */
585         { "WildPackets Ether/TokenPeek (V5 & V6)", "peek56", "pkt", "tpc;apc;wpz", FALSE, FALSE,
586           NULL, NULL },
587
588         /* WTAP_FILE_ETHERPEEK_V7 */
589         { "WildPackets Ether/Token/AiroPeek (V7)", "peek7", "pkt", "tpc;apc;wpz", FALSE, FALSE,
590           NULL, NULL },
591
592         /* WTAP_FILE_AIROPEEK_V9 */
593         { "WildPackets Ether/AiroPeek (V9)", "peek9", "pkt", "tpc;apc;wpz", FALSE, FALSE,
594           NULL, NULL },
595
596         /* WTAP_FILE_MPEG */
597         { "MPEG", "mpeg", "mpeg", "mpg;mp3", FALSE, FALSE,
598           NULL, NULL },
599
600         /* WTAP_FILE_K12TEXT  */
601         { "K12 text file", "k12text", "txt", NULL, FALSE, FALSE,
602           k12text_dump_can_write_encap, k12text_dump_open },
603
604         /* WTAP_FILE_NETSCREEN */
605         { "NetScreen snoop text file", "netscreen", "txt", NULL, FALSE, FALSE,
606           NULL, NULL },
607
608         /* WTAP_FILE_COMMVIEW */
609         { "TamoSoft CommView", "commview", "ncf", NULL, FALSE, FALSE,
610           commview_dump_can_write_encap, commview_dump_open },
611
612         /* WTAP_FILE_BTSNOOP */
613         { "Symbian OS btsnoop", "btsnoop", "log", NULL, FALSE, FALSE,
614           btsnoop_dump_can_write_encap, btsnoop_dump_open_h4 },
615
616         /* WTAP_FILE_TNEF */
617         { "Transport-Neutral Encapsulation Format", "tnef", NULL, NULL, FALSE, FALSE,
618           NULL, NULL },
619
620         /* WTAP_FILE_DCT3TRACE */
621         { "Gammu DCT3 trace", "dct3trace", "xml", NULL, FALSE, FALSE,
622           NULL, NULL },
623
624         /* WTAP_FILE_PACKETLOGGER */
625         { "PacketLogger", "pklg", "pklg", NULL, FALSE, FALSE,
626           NULL, NULL },
627
628         /* WTAP_FILE_DAINTREE_SNA */
629         { "Daintree SNA", "dsna", "dcf", NULL, FALSE, FALSE,
630           NULL, NULL },
631
632         /* WTAP_FILE_NETSCALER_1_0 */
633         { "NetScaler Trace (Version 1.0)", "nstrace10", NULL, NULL, TRUE, FALSE,
634           nstrace_10_dump_can_write_encap, nstrace_dump_open },
635
636         /* WTAP_FILE_NETSCALER_2_0 */
637         { "NetScaler Trace (Version 2.0)", "nstrace20", "cap", NULL, TRUE, FALSE,
638           nstrace_20_dump_can_write_encap, nstrace_dump_open },
639
640         /* WTAP_FILE_JPEG_JFIF */
641         { "JPEG/JFIF", "jpeg", "jpg", "jpeg;jfif", FALSE, FALSE,
642           NULL, NULL },
643
644         /* WTAP_FILE_IPFIX */
645         { "IPFIX File Format", "ipfix", "pfx", "ipfix", FALSE, FALSE,
646           NULL, NULL },
647
648         /* WTAP_ENCAP_MIME */
649         { "MIME File Format", "mime", NULL, NULL, FALSE, FALSE,
650            NULL, NULL },
651
652         /* WTAP_FILE_AETHRA */
653         { "Aethra .aps file", "aethra", "aps", NULL, FALSE, FALSE,
654           NULL, NULL },
655
656         /* WTAP_FILE_MPEG_2_TS */
657         { "MPEG2 transport stream", "mp2t", "mp2t", "ts;mpg", FALSE, FALSE,
658           NULL, NULL },
659   
660         /* WTAP_FILE_VWR_80211 */
661         { "Ixia IxVeriWave .vwr Raw 802.11 Capture", "vwr80211", "*.vwr", ".vwr", FALSE, FALSE,
662           NULL, NULL },
663  
664         /* WTAP_FILE_VWR_ETH */
665         { "Ixia IxVeriWave .vwr Raw Ethernet Capture", "vwreth", "*.vwr", ".vwr", FALSE, FALSE,
666           NULL, NULL }
667
668 };
669
670 gint wtap_num_file_types = sizeof(dump_open_table_base) / sizeof(struct file_type_info);
671
672 static GArray*  dump_open_table_arr = NULL;
673 static const struct file_type_info* dump_open_table = dump_open_table_base;
674
675 /* initialize the open routines array if it has not being initialized yet */
676 static void init_file_types(void) {
677
678         if (dump_open_table_arr) return;
679
680         dump_open_table_arr = g_array_new(FALSE,TRUE,sizeof(struct file_type_info));
681
682         g_array_append_vals(dump_open_table_arr,dump_open_table_base,wtap_num_file_types);
683
684         dump_open_table = (const struct file_type_info*)(void *)dump_open_table_arr->data;
685 }
686
687 int wtap_register_file_type(const struct file_type_info* fi) {
688         init_file_types();
689
690         g_array_append_val(dump_open_table_arr,*fi);
691
692         dump_open_table = (const struct file_type_info*)(void *)dump_open_table_arr->data;
693
694         return wtap_num_file_types++;
695 }
696
697 int wtap_get_num_file_types(void)
698 {
699         return wtap_num_file_types;
700 }
701
702 /*
703  * Get a GArray of WTAP_FILE_ values for file types that can be used
704  * to save a file of a given type with a given WTAP_ENCAP_ type.
705  */
706 static gboolean
707 can_save_with_wiretap(int ft, int encap)
708 {
709         /*
710          * To save a file in a given file format, we have to handle that
711          * format, and the code to handle that format must be able to
712          * write a file with that file's encapsulation type.
713          */
714         return wtap_dump_can_open(ft) &&
715             wtap_dump_can_write_encap(ft, encap);
716 }
717
718 GArray *
719 wtap_get_savable_file_types(int file_type, int file_encap)
720 {
721         GArray *savable_file_types;
722         int ft;
723         int default_file_type = -1;
724         int other_file_type = -1;
725
726         /* Can we save this file in its own file type? */
727         if (can_save_with_wiretap(file_type, file_encap)) {
728                 /* Yes - make that the default file type. */
729                 default_file_type = file_type;
730         } else {
731                 /* No - can we save it as a pcap-NG file? */
732                 if (can_save_with_wiretap(WTAP_FILE_PCAPNG, file_encap)) {
733                         /* Yes - default to pcap-NG, instead. */
734                         default_file_type = WTAP_FILE_PCAPNG;
735                 } else {
736                         /* OK, find the first file type we *can* save it as. */
737                         default_file_type = -1;
738                         for (ft = 0; ft < WTAP_NUM_FILE_TYPES; ft++) {
739                                 if (can_save_with_wiretap(ft, file_encap)) {
740                                         /* OK, got it. */
741                                         default_file_type = ft;
742                                 }
743                         }
744                 }
745         }
746
747         if (default_file_type == -1) {
748                 /* We don't support writing this file as any file type. */
749                 return NULL;
750         }
751
752         /* Allocate the array. */
753         savable_file_types = g_array_new(FALSE, FALSE, (guint)sizeof (int));
754
755         /* Put the default file format first in the list. */
756         g_array_append_val(savable_file_types, default_file_type);
757
758         /* If it's pcap, put pcap-NG right after it; otherwise, if it's
759            pcap-NG, put pcap right after it. */
760         if (default_file_type == WTAP_FILE_PCAP) {
761                 if (can_save_with_wiretap(WTAP_FILE_PCAPNG, file_encap))
762                         other_file_type = WTAP_FILE_PCAPNG;
763         } else if (default_file_type == WTAP_FILE_PCAPNG) {
764                 if (can_save_with_wiretap(WTAP_FILE_PCAP, file_encap))
765                         other_file_type = WTAP_FILE_PCAP;
766         }
767         if (other_file_type != -1)
768                 g_array_append_val(savable_file_types, other_file_type);
769
770         /* Add all the other file types that work. */
771         for (ft = 0; ft < WTAP_NUM_FILE_TYPES; ft++) {
772                 if (ft == WTAP_FILE_UNKNOWN)
773                         continue;       /* not a real file type */
774                 if (ft == default_file_type || ft == other_file_type)
775                         continue;       /* we've already done this one */
776                 if (can_save_with_wiretap(ft, file_encap)) {
777                         /* OK, we can write it out in this type. */
778                         g_array_append_val(savable_file_types, ft);
779                 }
780         }
781
782         return savable_file_types;
783 }
784
785 /* Name that should be somewhat descriptive. */
786 const char *wtap_file_type_string(int filetype)
787 {
788         if (filetype < 0 || filetype >= wtap_num_file_types) {
789                 g_error("Unknown capture file type %d", filetype);
790                 /** g_error() does an abort() and thus never returns **/
791                 return "";
792         } else
793                 return dump_open_table[filetype].name;
794 }
795
796 /* Name to use in, say, a command-line flag specifying the type. */
797 const char *wtap_file_type_short_string(int filetype)
798 {
799         if (filetype < 0 || filetype >= wtap_num_file_types)
800                 return NULL;
801         else
802                 return dump_open_table[filetype].short_name;
803 }
804
805 /* Translate a short name to a capture file type. */
806 int wtap_short_string_to_file_type(const char *short_name)
807 {
808         int filetype;
809
810         for (filetype = 0; filetype < wtap_num_file_types; filetype++) {
811                 if (dump_open_table[filetype].short_name != NULL &&
812                     strcmp(short_name, dump_open_table[filetype].short_name) == 0)
813                         return filetype;
814         }
815         return -1;      /* no such file type, or we can't write it */
816 }
817
818 static GSList *add_extensions(GSList *extensions, const gchar *extension,
819     GSList *compressed_file_extensions)
820 {
821         GSList *compressed_file_extension;
822
823         /*
824          * Add the specified extension.
825          */
826         extensions = g_slist_append(extensions, g_strdup(extension));
827
828         /*
829          * Now add the extensions for compressed-file versions of
830          * that extension.
831          */
832         for (compressed_file_extension = compressed_file_extensions;
833             compressed_file_extension != NULL;
834             compressed_file_extension = g_slist_next(compressed_file_extension)) {
835                 extensions = g_slist_append(extensions,
836                     g_strdup_printf("%s.%s", extension,
837                       (gchar *)compressed_file_extension->data));
838         }
839
840         return extensions;
841 }
842
843 /* Return a list of file extensions that are used by the specified file type.
844
845    If include_compressed is TRUE, the list will include compressed
846    extensions, e.g. not just "pcap" but also "pcap.gz" if we can read
847    gzipped files.
848
849    All strings in the list are allocated with g_malloc() and must be freed
850    with g_free(). */
851 GSList *wtap_get_file_extensions_list(int filetype, gboolean include_compressed)
852 {
853         gchar **extensions_set, **extensionp;
854         gchar *extension;
855         GSList *compressed_file_extensions;
856         GSList *extensions;
857
858         if (filetype < 0 || filetype >= wtap_num_file_types)
859                 return NULL;    /* not a valid file type */
860
861         if (dump_open_table[filetype].default_file_extension == NULL)
862                 return NULL;    /* valid, but no extensions known */
863
864         extensions = NULL;      /* empty list, to start with */
865
866         /*
867          * If include_compressions is true, get the list of compressed-file
868          * extensions.
869          */
870         if (include_compressed)
871                 compressed_file_extensions = wtap_get_compressed_file_extensions();
872         else
873                 compressed_file_extensions = NULL;
874
875         /*
876          * Add the default extension, and all compressed variants of
877          * it.
878          */
879         extensions = add_extensions(extensions,
880             dump_open_table[filetype].default_file_extension,
881             compressed_file_extensions);
882
883         if (dump_open_table[filetype].additional_file_extensions != NULL) {
884                 /*
885                  * We have additional extensions; add them.
886                  *
887                  * First, split the extension-list string into a set of
888                  * extensions.
889                  */
890                 extensions_set = g_strsplit(dump_open_table[filetype].additional_file_extensions,
891                     ";", 0);
892
893                 /*
894                  * Add each of those extensions to the list.
895                  */
896                 for (extensionp = extensions_set; *extensionp != NULL;
897                     extensionp++) {
898                         extension = *extensionp;
899
900                         /*
901                          * Add the extension, and all compressed variants
902                          * of it.
903                          */
904                         extensions = add_extensions(extensions, extension,
905                             compressed_file_extensions);
906                 }
907
908                 g_strfreev(extensions_set);
909         }
910         g_slist_free(compressed_file_extensions);
911         return extensions;
912 }
913
914 /*
915  * Free a list returned by wtap_file_extensions_list().
916  */
917 void wtap_free_file_extensions_list(GSList *extensions)
918 {
919         GSList *extension;
920
921         for (extension = extensions; extension != NULL;
922             extension = g_slist_next(extension)) {
923                 g_free(extension->data);
924         }
925         g_slist_free(extensions);
926 }
927
928 /* Return the default file extension to use with the specified file type;
929    that's just the extension, without any ".". */
930 const char *wtap_default_file_extension(int filetype)
931 {
932         if (filetype < 0 || filetype >= wtap_num_file_types)
933                 return NULL;
934         else
935                 return dump_open_table[filetype].default_file_extension;
936 }
937
938 gboolean wtap_dump_can_open(int filetype)
939 {
940         if (filetype < 0 || filetype >= wtap_num_file_types
941             || dump_open_table[filetype].dump_open == NULL)
942                 return FALSE;
943
944         return TRUE;
945 }
946
947 gboolean wtap_dump_can_write_encap(int filetype, int encap)
948 {
949         if (filetype < 0 || filetype >= wtap_num_file_types
950             || dump_open_table[filetype].can_write_encap == NULL)
951                 return FALSE;
952
953         if ((*dump_open_table[filetype].can_write_encap)(encap) != 0)
954                 return FALSE;
955
956         return TRUE;
957 }
958
959 #ifdef HAVE_LIBZ
960 gboolean wtap_dump_can_compress(int filetype)
961 {
962         /*
963          * If this is an unknown file type, or if we have to
964          * seek when writing out a file with this file type,
965          * return FALSE.
966          */
967         if (filetype < 0 || filetype >= wtap_num_file_types
968             || dump_open_table[filetype].writing_must_seek)
969                 return FALSE;
970
971         return TRUE;
972 }
973 #else
974 gboolean wtap_dump_can_compress(int filetype _U_)
975 {
976         return FALSE;
977 }
978 #endif
979
980 gboolean wtap_dump_has_name_resolution(int filetype)
981 {
982         if (filetype < 0 || filetype >= wtap_num_file_types
983             || dump_open_table[filetype].has_name_resolution == FALSE)
984                 return FALSE;
985
986         return TRUE;
987 }
988
989 static gboolean wtap_dump_open_check(int filetype, int encap, gboolean comressed, int *err);
990 static wtap_dumper* wtap_dump_alloc_wdh(int filetype, int encap, int snaplen,
991                                         gboolean compressed, int *err);
992 static gboolean wtap_dump_open_finish(wtap_dumper *wdh, int filetype, gboolean compressed, int *err);
993
994 static WFILE_T wtap_dump_file_open(wtap_dumper *wdh, const char *filename);
995 static WFILE_T wtap_dump_file_fdopen(wtap_dumper *wdh, int fd);
996 static int wtap_dump_file_close(wtap_dumper *wdh);
997
998 wtap_dumper* wtap_dump_open(const char *filename, int filetype, int encap,
999                                 int snaplen, gboolean compressed, int *err)
1000 {
1001         return wtap_dump_open_ng(filename, filetype, encap,snaplen, compressed, NULL, NULL, err);
1002 }
1003
1004 wtap_dumper* wtap_dump_open_ng(const char *filename, int filetype, int encap,
1005                                 int snaplen, gboolean compressed, wtapng_section_t *shb_hdr, wtapng_iface_descriptions_t *idb_inf, int *err)
1006 {
1007         wtap_dumper *wdh;
1008         WFILE_T fh;
1009
1010         /* Check whether we can open a capture file with that file type
1011            and that encapsulation. */
1012         if (!wtap_dump_open_check(filetype, encap, compressed, err))
1013                 return NULL;
1014
1015         /* Allocate a data structure for the output stream. */
1016         wdh = wtap_dump_alloc_wdh(filetype, encap, snaplen, compressed, err);
1017         if (wdh == NULL)
1018                 return NULL;    /* couldn't allocate it */
1019
1020         /* Set Section Header Block data */
1021         wdh->shb_hdr = shb_hdr;
1022         /* Set Interface Description Block data */
1023         if ((idb_inf != NULL) && (idb_inf->number_of_interfaces > 0)) {
1024                 wdh->number_of_interfaces = idb_inf->number_of_interfaces;
1025                 wdh->interface_data = idb_inf->interface_data;
1026         } else {
1027                 wtapng_if_descr_t descr;
1028
1029                 descr.wtap_encap = encap;
1030                 descr.time_units_per_second = 0;
1031                 descr.link_type = wtap_wtap_encap_to_pcap_encap(encap);
1032                 descr.snap_len = snaplen;
1033                 descr.opt_comment = NULL;
1034                 descr.if_name = NULL;
1035                 descr.if_description = NULL;
1036                 descr.if_speed = 0;
1037                 descr.if_tsresol = 6;
1038                 descr.if_filter_str= NULL;
1039                 descr.bpf_filter_len= 0;
1040                 descr.if_filter_bpf_bytes= NULL;
1041                 descr.if_os = NULL;
1042                 descr.if_fcslen = -1;
1043                 descr.num_stat_entries = 0;          /* Number of ISB:s */
1044                 descr.interface_statistics = NULL;
1045                 wdh->number_of_interfaces= 1;
1046                 wdh->interface_data= g_array_new(FALSE, FALSE, sizeof(wtapng_if_descr_t));
1047                 g_array_append_val(wdh->interface_data, descr);
1048         }
1049
1050         /* "-" means stdout */
1051         if (strcmp(filename, "-") == 0) {
1052                 if (compressed) {
1053                         *err = EINVAL;  /* XXX - return a Wiretap error code for this */
1054                         g_free(wdh);
1055                         return NULL;    /* compress won't work on stdout */
1056                 }
1057 #ifdef _WIN32
1058                 if (_setmode(fileno(stdout), O_BINARY) == -1) {
1059                         /* "Should not happen" */
1060                         *err = errno;
1061                         g_free(wdh);
1062                         return NULL;    /* couldn't put standard output in binary mode */
1063                 }
1064 #endif
1065                 wdh->fh = stdout;
1066         } else {
1067                 /* In case "fopen()" fails but doesn't set "errno", set "errno"
1068                    to a generic "the open failed" error. */
1069                 errno = WTAP_ERR_CANT_OPEN;
1070                 fh = wtap_dump_file_open(wdh, filename);
1071                 if (fh == NULL) {
1072                         *err = errno;
1073                         g_free(wdh);
1074                         return NULL;    /* can't create file */
1075                 }
1076                 wdh->fh = fh;
1077         }
1078
1079         if (!wtap_dump_open_finish(wdh, filetype, compressed, err)) {
1080                 /* Get rid of the file we created; we couldn't finish
1081                    opening it. */
1082                 if (wdh->fh != stdout) {
1083                         wtap_dump_file_close(wdh);
1084                         ws_unlink(filename);
1085                 }
1086                 g_free(wdh);
1087                 return NULL;
1088         }
1089         return wdh;
1090 }
1091
1092 wtap_dumper* wtap_dump_fdopen(int fd, int filetype, int encap, int snaplen,
1093                                 gboolean compressed, int *err)
1094 {
1095         return wtap_dump_fdopen_ng(fd, filetype, encap, snaplen, compressed, NULL, NULL, err);
1096 }
1097
1098 wtap_dumper* wtap_dump_fdopen_ng(int fd, int filetype, int encap, int snaplen,
1099                                 gboolean compressed, wtapng_section_t *shb_hdr, wtapng_iface_descriptions_t *idb_inf, int *err)
1100 {
1101         wtap_dumper *wdh;
1102         WFILE_T fh;
1103
1104         /* Check whether we can open a capture file with that file type
1105            and that encapsulation. */
1106         if (!wtap_dump_open_check(filetype, encap, compressed, err))
1107                 return NULL;
1108
1109         /* Allocate a data structure for the output stream. */
1110         wdh = wtap_dump_alloc_wdh(filetype, encap, snaplen, compressed, err);
1111         if (wdh == NULL)
1112                 return NULL;    /* couldn't allocate it */
1113
1114 #ifdef _WIN32
1115         if (fd == 1) {
1116                 if (_setmode(fileno(stdout), O_BINARY) == -1) {
1117                         /* "Should not happen" */
1118                         *err = errno;
1119                         g_free(wdh);
1120                         return NULL;    /* couldn't put standard output in binary mode */
1121                 }
1122         }
1123 #endif
1124
1125         /* Set Section Header Block data */
1126         wdh->shb_hdr = shb_hdr;
1127         /* Set Interface Description Block data */
1128         if ((idb_inf != NULL) && (idb_inf->number_of_interfaces > 0)) {
1129                 wdh->number_of_interfaces = idb_inf->number_of_interfaces;
1130                 wdh->interface_data = idb_inf->interface_data;
1131         } else {
1132                 wtapng_if_descr_t descr;
1133
1134                 descr.wtap_encap = encap;
1135                 descr.time_units_per_second = 0;
1136                 descr.link_type = wtap_wtap_encap_to_pcap_encap(encap);
1137                 descr.snap_len = snaplen;
1138                 descr.opt_comment = NULL;
1139                 descr.if_name = NULL;
1140                 descr.if_description = NULL;
1141                 descr.if_speed = 0;
1142                 descr.if_tsresol = 6;
1143                 descr.if_filter_str= NULL;
1144                 descr.bpf_filter_len= 0;
1145                 descr.if_filter_bpf_bytes= NULL;
1146                 descr.if_os = NULL;
1147                 descr.if_fcslen = -1;
1148                 descr.num_stat_entries = 0;          /* Number of ISB:s */
1149                 descr.interface_statistics = NULL;
1150                 wdh->number_of_interfaces= 1;
1151                 wdh->interface_data= g_array_new(FALSE, FALSE, sizeof(wtapng_if_descr_t));
1152                 g_array_append_val(wdh->interface_data, descr);
1153         }
1154
1155         /* In case "fopen()" fails but doesn't set "errno", set "errno"
1156            to a generic "the open failed" error. */
1157         errno = WTAP_ERR_CANT_OPEN;
1158         fh = wtap_dump_file_fdopen(wdh, fd);
1159         if (fh == NULL) {
1160                 *err = errno;
1161                 g_free(wdh);
1162                 return NULL;    /* can't create standard I/O stream */
1163         }
1164         wdh->fh = fh;
1165
1166         if (!wtap_dump_open_finish(wdh, filetype, compressed, err)) {
1167                 wtap_dump_file_close(wdh);
1168                 g_free(wdh);
1169                 return NULL;
1170         }
1171         return wdh;
1172 }
1173
1174 static gboolean wtap_dump_open_check(int filetype, int encap, gboolean compressed, int *err)
1175 {
1176         if (!wtap_dump_can_open(filetype)) {
1177                 /* Invalid type, or type we don't know how to write. */
1178                 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
1179                 return FALSE;
1180         }
1181
1182         /* OK, we know how to write that type; can we write the specified
1183            encapsulation type? */
1184         *err = (*dump_open_table[filetype].can_write_encap)(encap);
1185         if (*err != 0)
1186                 return FALSE;
1187
1188         /* if compression is wanted, do we support this for this filetype? */
1189         if(compressed && !wtap_dump_can_compress(filetype)) {
1190                 *err = WTAP_ERR_COMPRESSION_NOT_SUPPORTED;
1191                 return FALSE;
1192         }
1193
1194         *err = (*dump_open_table[filetype].can_write_encap)(encap);
1195         if (*err != 0)
1196                 return FALSE;
1197
1198         /* All systems go! */
1199         return TRUE;
1200 }
1201
1202 static wtap_dumper* wtap_dump_alloc_wdh(int filetype, int encap, int snaplen,
1203                                         gboolean compressed, int *err)
1204 {
1205         wtap_dumper *wdh;
1206
1207         wdh = (wtap_dumper *)g_malloc0(sizeof (wtap_dumper));
1208         if (wdh == NULL) {
1209                 *err = errno;
1210                 return NULL;
1211         }
1212
1213         wdh->file_type = filetype;
1214         wdh->snaplen = snaplen;
1215         wdh->encap = encap;
1216         wdh->compressed = compressed;
1217         return wdh;
1218 }
1219
1220 static gboolean wtap_dump_open_finish(wtap_dumper *wdh, int filetype, gboolean compressed, int *err)
1221 {
1222         int fd;
1223         gboolean cant_seek;
1224
1225         /* Can we do a seek on the file descriptor?
1226            If not, note that fact. */
1227         if(compressed) {
1228                 cant_seek = TRUE;
1229         } else {
1230                 fd = fileno((FILE *)wdh->fh);
1231                 if (lseek(fd, 1, SEEK_CUR) == -1)
1232                         cant_seek = TRUE;
1233                 else {
1234                         /* Undo the seek. */
1235                         lseek(fd, 0, SEEK_SET);
1236                         cant_seek = FALSE;
1237                 }
1238         }
1239
1240         /* If this file type requires seeking, and we can't seek, fail. */
1241         if (dump_open_table[filetype].writing_must_seek && cant_seek) {
1242                 *err = WTAP_ERR_CANT_WRITE_TO_PIPE;
1243                 return FALSE;
1244         }
1245
1246         /* Now try to open the file for writing. */
1247         if (!(*dump_open_table[filetype].dump_open)(wdh, err)) {
1248                 return FALSE;
1249         }
1250
1251         return TRUE;    /* success! */
1252 }
1253
1254 gboolean wtap_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
1255                    const union wtap_pseudo_header *pseudo_header, const guint8 *pd, int *err)
1256 {
1257         return (wdh->subtype_write)(wdh, phdr, pseudo_header, pd, err);
1258 }
1259
1260 void wtap_dump_flush(wtap_dumper *wdh)
1261 {
1262 #ifdef HAVE_LIBZ
1263         if(wdh->compressed) {
1264                 gzwfile_flush((GZWFILE_T)wdh->fh);
1265         } else
1266 #endif
1267         {
1268                 fflush((FILE *)wdh->fh);
1269         }
1270 }
1271
1272 gboolean wtap_dump_close(wtap_dumper *wdh, int *err)
1273 {
1274         gboolean ret = TRUE;
1275
1276         if (wdh->subtype_close != NULL) {
1277                 /* There's a close routine for this dump stream. */
1278                 if (!(wdh->subtype_close)(wdh, err))
1279                         ret = FALSE;
1280         }
1281         errno = WTAP_ERR_CANT_CLOSE;
1282         /* Don't close stdout */
1283         if (wdh->fh != stdout) {
1284                 if (wtap_dump_file_close(wdh) == EOF) {
1285                         if (ret) {
1286                                 /* The per-format close function succeeded,
1287                                    but the fclose didn't.  Save the reason
1288                                    why, if our caller asked for it. */
1289                                 if (err != NULL)
1290                                         *err = errno;
1291                         }
1292                         ret = FALSE;
1293                 }
1294         } else {
1295                 /* as we don't close stdout, at least try to flush it */
1296                 wtap_dump_flush(wdh);
1297         }
1298         if (wdh->priv != NULL)
1299                 g_free(wdh->priv);
1300         g_free(wdh);
1301         return ret;
1302 }
1303
1304 gint64 wtap_get_bytes_dumped(wtap_dumper *wdh)
1305 {
1306         return wdh->bytes_dumped;
1307 }
1308
1309 void wtap_set_bytes_dumped(wtap_dumper *wdh, gint64 bytes_dumped)
1310 {
1311         wdh->bytes_dumped = bytes_dumped;
1312 }
1313
1314 gboolean wtap_dump_set_addrinfo_list(wtap_dumper *wdh, struct addrinfo *addrinfo_list)
1315 {
1316         if (!wdh || wdh->file_type < 0 || wdh->file_type >= wtap_num_file_types
1317                 || dump_open_table[wdh->file_type].has_name_resolution == FALSE)
1318                         return FALSE;
1319         wdh->addrinfo_list = addrinfo_list;
1320         return TRUE;
1321 }
1322
1323 /* internally open a file for writing (compressed or not) */
1324 #ifdef HAVE_LIBZ
1325 static WFILE_T wtap_dump_file_open(wtap_dumper *wdh, const char *filename)
1326 {
1327         if(wdh->compressed) {
1328                 return gzwfile_open(filename);
1329         } else {
1330                 return ws_fopen(filename, "wb");
1331         }
1332 }
1333 #else
1334 static WFILE_T wtap_dump_file_open(wtap_dumper *wdh _U_, const char *filename)
1335 {
1336         return ws_fopen(filename, "wb");
1337 }
1338 #endif
1339
1340 /* internally open a file for writing (compressed or not) */
1341 #ifdef HAVE_LIBZ
1342 static WFILE_T wtap_dump_file_fdopen(wtap_dumper *wdh, int fd)
1343 {
1344         if(wdh->compressed) {
1345                 return gzwfile_fdopen(fd);
1346         } else {
1347                 return fdopen(fd, "wb");
1348         }
1349 }
1350 #else
1351 static WFILE_T wtap_dump_file_fdopen(wtap_dumper *wdh _U_, int fd)
1352 {
1353         return fdopen(fd, "wb");
1354 }
1355 #endif
1356
1357 /* internally writing raw bytes (compressed or not) */
1358 gboolean wtap_dump_file_write(wtap_dumper *wdh, const void *buf, size_t bufsize,
1359                      int *err)
1360 {
1361         size_t nwritten;
1362
1363 #ifdef HAVE_LIBZ
1364         if (wdh->compressed) {
1365                 nwritten = gzwfile_write((GZWFILE_T)wdh->fh, buf, (unsigned) bufsize);
1366                 /*
1367                  * gzwfile_write() returns 0 on error.
1368                  */
1369                 if (nwritten == 0) {
1370                         *err = gzwfile_geterr((GZWFILE_T)wdh->fh);
1371                         return FALSE;
1372                 }
1373         } else
1374 #endif
1375         {
1376                 nwritten = fwrite(buf, 1, bufsize, (FILE *)wdh->fh);
1377                 /*
1378                  * At least according to the Mac OS X man page,
1379                  * this can return a short count on an error.
1380                  */
1381                 if (nwritten != bufsize) {
1382                         if (ferror((FILE *)wdh->fh))
1383                                 *err = errno;
1384                         else
1385                                 *err = WTAP_ERR_SHORT_WRITE;
1386                         return FALSE;
1387                 }
1388         }
1389         return TRUE;
1390 }
1391
1392 /* internally close a file for writing (compressed or not) */
1393 static int wtap_dump_file_close(wtap_dumper *wdh)
1394 {
1395 #ifdef HAVE_LIBZ
1396         if(wdh->compressed) {
1397                 return gzwfile_close((GZWFILE_T)wdh->fh);
1398         } else
1399 #endif
1400         {
1401                 return fclose((FILE *)wdh->fh);
1402         }
1403 }