Don't free idb_inf in wtap_dump_open_ng(): free it in the callers. This fixes the...
[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 "pcap-encap.h"
90
91 /* The open_file_* routines should return:
92  *
93  *      -1 on an I/O error;
94  *
95  *      1 if the file they're reading is one of the types it handles;
96  *
97  *      0 if the file they're reading isn't the type they're checking for.
98  *
99  * If the routine handles this type of file, it should set the "file_type"
100  * field in the "struct wtap" to the type of the file.
101  *
102  * Put the trace files that are merely saved telnet-sessions last, since it's
103  * possible that you could have captured someone a router telnet-session
104  * using another tool. So, a libpcap trace of an toshiba "snoop" session
105  * should be discovered as a libpcap file, not a toshiba file.
106  */
107
108
109 static wtap_open_routine_t open_routines_base[] = {
110         /* Files that have magic bytes in fixed locations. These
111          * are easy to identify.
112          */
113         libpcap_open,
114         lanalyzer_open,
115         ngsniffer_open,
116         snoop_open,
117         iptrace_open,
118         netmon_open,
119         netxray_open,
120         radcom_open,
121         nettl_open,
122         visual_open,
123         _5views_open,
124         network_instruments_open,
125         airopeek9_open,
126         dbs_etherwatch_open,
127         k12_open,
128         catapult_dct2000_open,
129         ber_open,
130         pcapng_open,
131         aethra_open,
132         btsnoop_open,
133         packetlogger_open, /* This type does not have a magic number, but its
134                             * files are sometimes grabbed by mpeg_open. */
135         mpeg_open,
136         mp2t_open,
137         tnef_open,
138         dct3trace_open,
139         daintree_sna_open,
140         mime_file_open,
141         /* Files that don't have magic bytes at a fixed location,
142          * but that instead require a heuristic of some sort to
143          * identify them.  This includes the ASCII trace files that
144          * would be, for example, saved copies of a Telnet session
145          * to some box.
146          */
147
148         /* I put NetScreen *before* erf, because there were some
149          * false positives with my test-files (Sake Blok, July 2007)
150          */
151         netscreen_open,
152         erf_open,
153         ipfix_open,
154         k12text_open,
155         etherpeek_open,
156         pppdump_open,
157         iseries_open,
158         ascend_open,
159         eyesdn_open,
160         toshiba_open,
161         i4btrace_open,
162         csids_open,
163         vms_open,
164         cosine_open,
165         hcidump_open,
166         commview_open,
167         nstrace_open
168 };
169
170 #define N_FILE_TYPES    (sizeof open_routines_base / sizeof open_routines_base[0])
171
172 static wtap_open_routine_t* open_routines = NULL;
173
174 static GArray* open_routines_arr = NULL;
175
176
177 /* initialize the open routines array if it has not been initialized yet */
178 static void init_open_routines(void) {
179
180         if (open_routines_arr) return;
181
182         open_routines_arr = g_array_new(FALSE,TRUE,sizeof(wtap_open_routine_t));
183
184         g_array_append_vals(open_routines_arr,open_routines_base,N_FILE_TYPES);
185
186         open_routines = (wtap_open_routine_t*)(void *)open_routines_arr->data;
187 }
188
189 void wtap_register_open_routine(wtap_open_routine_t open_routine, gboolean has_magic) {
190         init_open_routines();
191
192         if (has_magic)
193                 g_array_prepend_val(open_routines_arr,open_routine);
194         else
195                 g_array_append_val(open_routines_arr,open_routine);
196
197         open_routines = (wtap_open_routine_t*)(void *)open_routines_arr->data;
198 }
199
200 /*
201  * Visual C++ on Win32 systems doesn't define these.  (Old UNIX systems don't
202  * define them either.)
203  *
204  * Visual C++ on Win32 systems doesn't define S_IFIFO, it defines _S_IFIFO.
205  */
206 #ifndef S_ISREG
207 #define S_ISREG(mode)   (((mode) & S_IFMT) == S_IFREG)
208 #endif
209 #ifndef S_IFIFO
210 #define S_IFIFO _S_IFIFO
211 #endif
212 #ifndef S_ISFIFO
213 #define S_ISFIFO(mode)  (((mode) & S_IFMT) == S_IFIFO)
214 #endif
215 #ifndef S_ISDIR
216 #define S_ISDIR(mode)   (((mode) & S_IFMT) == S_IFDIR)
217 #endif
218
219 /* Opens a file and prepares a wtap struct.
220    If "do_random" is TRUE, it opens the file twice; the second open
221    allows the application to do random-access I/O without moving
222    the seek offset for sequential I/O, which is used by Wireshark
223    so that it can do sequential I/O to a capture file that's being
224    written to as new packets arrive independently of random I/O done
225    to display protocol trees for packets when they're selected. */
226 wtap* wtap_open_offline(const char *filename, int *err, char **err_info,
227                         gboolean do_random)
228 {
229         int     fd;
230         ws_statb64 statb;
231         wtap    *wth;
232         unsigned int    i;
233         gboolean use_stdin = FALSE;
234
235         /* open standard input if filename is '-' */
236         if (strcmp(filename, "-") == 0)
237                 use_stdin = TRUE;
238
239         /* First, make sure the file is valid */
240         if (use_stdin) {
241                 if (ws_fstat64(0, &statb) < 0) {
242                         *err = errno;
243                         return NULL;
244                 }
245         } else {
246                 if (ws_stat64(filename, &statb) < 0) {
247                         *err = errno;
248                         return NULL;
249                 }
250         }
251         if (S_ISFIFO(statb.st_mode)) {
252                 /*
253                  * Opens of FIFOs are allowed only when not opening
254                  * for random access.
255                  *
256                  * XXX - currently, we do seeking when trying to find
257                  * out the file type, so we don't actually support
258                  * opening FIFOs.  However, we may eventually
259                  * do buffering that allows us to do at least some
260                  * file type determination even on pipes, so we
261                  * allow FIFO opens and let things fail later when
262                  * we try to seek.
263                  */
264                 if (do_random) {
265                         *err = WTAP_ERR_RANDOM_OPEN_PIPE;
266                         return NULL;
267                 }
268         } else if (S_ISDIR(statb.st_mode)) {
269                 /*
270                  * Return different errors for "this is a directory"
271                  * and "this is some random special file type", so
272                  * the user can get a potentially more helpful error.
273                  */
274                 *err = EISDIR;
275                 return NULL;
276         } else if (! S_ISREG(statb.st_mode)) {
277                 *err = WTAP_ERR_NOT_REGULAR_FILE;
278                 return NULL;
279         }
280
281         /*
282          * We need two independent descriptors for random access, so
283          * they have different file positions.  If we're opening the
284          * standard input, we can only dup it to get additional
285          * descriptors, so we can't have two independent descriptors,
286          * and thus can't do random access.
287          */
288         if (use_stdin && do_random) {
289                 *err = WTAP_ERR_RANDOM_OPEN_STDIN;
290                 return NULL;
291         }
292
293         errno = ENOMEM;
294         wth = (wtap *)g_malloc0(sizeof(wtap));
295
296         /* Open the file */
297         errno = WTAP_ERR_CANT_OPEN;
298         if (use_stdin) {
299                 /*
300                  * We dup FD 0, so that we don't have to worry about
301                  * a file_close of wth->fh closing the standard
302                  * input of the process.
303                  */
304                 fd = ws_dup(0);
305                 if (fd < 0) {
306                         *err = errno;
307                         g_free(wth);
308                         return NULL;
309                 }
310 #ifdef _WIN32
311                 if (_setmode(fd, O_BINARY) == -1) {
312                         /* "Shouldn't happen" */
313                         *err = errno;
314                         g_free(wth);
315                         return NULL;
316                 }
317 #endif
318                 if (!(wth->fh = filed_open(fd))) {
319                         *err = errno;
320                         ws_close(fd);
321                         g_free(wth);
322                         return NULL;
323                 }
324         } else {
325                 if (!(wth->fh = file_open(filename))) {
326                         *err = errno;
327                         g_free(wth);
328                         return NULL;
329                 }
330         }
331
332         if (do_random) {
333                 if (!(wth->random_fh = file_open(filename))) {
334                         *err = errno;
335                         file_close(wth->fh);
336                         g_free(wth);
337                         return NULL;
338                 }
339         } else
340                 wth->random_fh = NULL;
341
342         /* initialization */
343         wth->file_encap = WTAP_ENCAP_UNKNOWN;
344         wth->data_offset = 0;
345         wth->subtype_sequential_close = NULL;
346         wth->subtype_close = NULL;
347         wth->tsprecision = WTAP_FILE_TSPREC_USEC;
348         wth->priv = NULL;
349
350         init_open_routines();
351         if (wth->random_fh) {
352                 wth->fast_seek = g_ptr_array_new();
353
354                 file_set_random_access(wth->fh, FALSE, wth->fast_seek);
355                 file_set_random_access(wth->random_fh, TRUE, wth->fast_seek);
356         }
357
358         /* Try all file types */
359         for (i = 0; i < open_routines_arr->len; i++) {
360                 /* Seek back to the beginning of the file; the open routine
361                    for the previous file type may have left the file
362                    position somewhere other than the beginning, and the
363                    open routine for this file type will probably want
364                    to start reading at the beginning.
365
366                    Initialize the data offset while we're at it. */
367                 if (file_seek(wth->fh, 0, SEEK_SET, err) == -1) {
368                         /* I/O error - give up */
369                         if (wth->random_fh != NULL)
370                                 file_close(wth->random_fh);
371                         file_close(wth->fh);
372                         g_free(wth);
373                         return NULL;
374                 }
375                 wth->data_offset = 0;
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", FALSE, FALSE,
418           libpcap_dump_can_write_encap, libpcap_dump_open },
419
420         /* WTAP_FILE_PCAPNG */
421         { "Wireshark - pcapng", "pcapng", "pcapng", NULL, FALSE, TRUE,
422           pcapng_dump_can_write_encap, pcapng_dump_open },
423
424         /* WTAP_FILE_PCAP_NSEC */
425         { "Wireshark - nanosecond libpcap", "nseclibpcap", "pcap", "cap", FALSE, FALSE,
426           libpcap_dump_can_write_encap, libpcap_dump_open },
427
428         /* WTAP_FILE_PCAP_AIX */
429         { "AIX tcpdump - libpcap", "aixlibpcap", "pcap", "cap", FALSE, FALSE,
430           NULL, NULL },
431
432         /* WTAP_FILE_PCAP_SS991029 */
433         { "Modified tcpdump - libpcap", "modlibpcap", "pcap", "cap", FALSE, FALSE,
434           libpcap_dump_can_write_encap, libpcap_dump_open },
435
436         /* WTAP_FILE_PCAP_NOKIA */
437         { "Nokia tcpdump - libpcap ", "nokialibpcap", "pcap", "cap", 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", 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", FALSE, FALSE,
446           libpcap_dump_can_write_encap, libpcap_dump_open },
447
448         /* WTAP_FILE_5VIEWS */
449         { "Accellent 5Views 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 };
661
662 gint wtap_num_file_types = sizeof(dump_open_table_base) / sizeof(struct file_type_info);
663
664 static GArray*  dump_open_table_arr = NULL;
665 static const struct file_type_info* dump_open_table = dump_open_table_base;
666
667 /* initialize the open routines array if it has not being initialized yet */
668 static void init_file_types(void) {
669
670         if (dump_open_table_arr) return;
671
672         dump_open_table_arr = g_array_new(FALSE,TRUE,sizeof(struct file_type_info));
673
674         g_array_append_vals(dump_open_table_arr,dump_open_table_base,wtap_num_file_types);
675
676         dump_open_table = (const struct file_type_info*)(void *)dump_open_table_arr->data;
677 }
678
679 int wtap_register_file_type(const struct file_type_info* fi) {
680         init_file_types();
681
682         g_array_append_val(dump_open_table_arr,*fi);
683
684         dump_open_table = (const struct file_type_info*)(void *)dump_open_table_arr->data;
685
686         return wtap_num_file_types++;
687 }
688
689 int wtap_get_num_file_types(void)
690 {
691         return wtap_num_file_types;
692 }
693
694 /*
695  * Get a GArray of WTAP_FILE_ values for file types that can be used
696  * to save a file of a given type with a given WTAP_ENCAP_ type.
697  */
698 static gboolean
699 can_save_with_wiretap(int ft, int encap)
700 {
701         /*
702          * To save a file in a given file format, we have to handle that
703          * format, and the code to handle that format must be able to
704          * write a file with that file's encapsulation type.
705          */
706         return wtap_dump_can_open(ft) &&
707             wtap_dump_can_write_encap(ft, encap);
708 }
709
710 GArray *
711 wtap_get_savable_file_types(int file_type, int file_encap)
712 {
713         GArray *savable_file_types;
714         int ft;
715         int default_file_type = -1;
716         int other_file_type = -1;
717
718         /* Can we save this file in its own file type? */
719         if (can_save_with_wiretap(file_type, file_encap)) {
720                 /* Yes - make that the default file type. */
721                 default_file_type = file_type;
722         } else {
723                 /* No - can we save it as a pcap-NG file? */
724                 if (can_save_with_wiretap(WTAP_FILE_PCAPNG, file_encap)) {
725                         /* Yes - default to pcap-NG, instead. */
726                         default_file_type = WTAP_FILE_PCAPNG;
727                 } else {
728                         /* OK, find the first file type we *can* save it as. */
729                         default_file_type = -1;
730                         for (ft = 0; ft < WTAP_NUM_FILE_TYPES; ft++) {
731                                 if (can_save_with_wiretap(ft, file_encap)) {
732                                         /* OK, got it. */
733                                         default_file_type = ft;
734                                 }
735                         }
736                 }
737         }
738
739         if (default_file_type == -1) {
740                 /* We don't support writing this file as any file type. */
741                 return NULL;
742         }
743
744         /* Allocate the array. */
745         savable_file_types = g_array_new(FALSE, FALSE, (guint)sizeof (int));
746
747         /* Put the default file format first in the list. */
748         g_array_append_val(savable_file_types, default_file_type);
749
750         /* If it's pcap, put pcap-NG right after it; otherwise, if it's
751            pcap-NG, put pcap right after it. */
752         if (default_file_type == WTAP_FILE_PCAP) {
753                 if (can_save_with_wiretap(WTAP_FILE_PCAPNG, file_encap))
754                         other_file_type = WTAP_FILE_PCAPNG;
755         } else if (default_file_type == WTAP_FILE_PCAPNG) {
756                 if (can_save_with_wiretap(WTAP_FILE_PCAP, file_encap))
757                         other_file_type = WTAP_FILE_PCAP;
758         }
759         if (other_file_type != -1)
760                 g_array_append_val(savable_file_types, other_file_type);
761
762         /* Add all the other file types that work. */
763         for (ft = 0; ft < WTAP_NUM_FILE_TYPES; ft++) {
764                 if (ft == WTAP_FILE_UNKNOWN)
765                         continue;       /* not a real file type */
766                 if (ft == default_file_type || ft == other_file_type)
767                         continue;       /* we've already done this one */
768                 if (can_save_with_wiretap(ft, file_encap)) {
769                         /* OK, we can write it out in this type. */
770                         g_array_append_val(savable_file_types, ft);
771                 }
772         }
773
774         return savable_file_types;
775 }
776
777 /* Name that should be somewhat descriptive. */
778 const char *wtap_file_type_string(int filetype)
779 {
780         if (filetype < 0 || filetype >= wtap_num_file_types) {
781                 g_error("Unknown capture file type %d", filetype);
782                 /** g_error() does an abort() and thus never returns **/
783                 return "";
784         } else
785                 return dump_open_table[filetype].name;
786 }
787
788 /* Name to use in, say, a command-line flag specifying the type. */
789 const char *wtap_file_type_short_string(int filetype)
790 {
791         if (filetype < 0 || filetype >= wtap_num_file_types)
792                 return NULL;
793         else
794                 return dump_open_table[filetype].short_name;
795 }
796
797 /* Translate a short name to a capture file type. */
798 int wtap_short_string_to_file_type(const char *short_name)
799 {
800         int filetype;
801
802         for (filetype = 0; filetype < wtap_num_file_types; filetype++) {
803                 if (dump_open_table[filetype].short_name != NULL &&
804                     strcmp(short_name, dump_open_table[filetype].short_name) == 0)
805                         return filetype;
806         }
807         return -1;      /* no such file type, or we can't write it */
808 }
809
810 static GSList *add_extensions(GSList *extensions, const gchar *extension,
811     GSList *compressed_file_extensions)
812 {
813         GSList *compressed_file_extension;
814
815         /*
816          * Add the specified extension.
817          */
818         extensions = g_slist_append(extensions, g_strdup(extension));
819
820         /*
821          * Now add the extensions for compressed-file versions of
822          * that extension.
823          */
824         for (compressed_file_extension = compressed_file_extensions;
825             compressed_file_extension != NULL;
826             compressed_file_extension = g_slist_next(compressed_file_extension)) {
827                 extensions = g_slist_append(extensions,
828                     g_strdup_printf("%s.%s", extension,
829                       (gchar *)compressed_file_extension->data));
830         }
831
832         return extensions;
833 }
834
835 /* Return a list of file extensions that are used by the specified file type.
836    This includes compressed extensions, e.g. not just "pcap" but also
837    "pcap.gz" if we can read gzipped files.
838
839    All strings in the list are allocated with g_malloc() and must be freed
840    with g_free(). */
841 GSList *wtap_get_file_extensions_list(int filetype)
842 {
843         gchar **extensions_set, **extensionp;
844         gchar *extension;
845         GSList *compressed_file_extensions;
846         GSList *extensions;
847
848         if (filetype < 0 || filetype >= wtap_num_file_types)
849                 return NULL;    /* not a valid file type */
850
851         if (dump_open_table[filetype].default_file_extension == NULL)
852                 return NULL;    /* valid, but no extensions known */
853
854         extensions = NULL;      /* empty list, to start with */
855
856         /*
857          * Get the list of compressed-file extensions.
858          */
859         compressed_file_extensions = wtap_get_compressed_file_extensions();
860
861         /*
862          * Add the default extension, and all compressed variants of
863          * it.
864          */
865         extensions = add_extensions(extensions,
866             dump_open_table[filetype].default_file_extension,
867             compressed_file_extensions);
868
869         if (dump_open_table[filetype].additional_file_extensions != NULL) {
870                 /*
871                  * We have additional extensions; add them.
872                  *
873                  * First, split the extension-list string into a set of
874                  * extensions.
875                  */
876                 extensions_set = g_strsplit(dump_open_table[filetype].additional_file_extensions,
877                     ";", 0);
878
879                 /*
880                  * Add each of those extensions to the list.
881                  */
882                 for (extensionp = extensions_set; *extensionp != NULL;
883                     extensionp++) {
884                         extension = *extensionp;
885
886                         /*
887                          * Add the extension, and all compressed variants
888                          * of it.
889                          */
890                         extensions = add_extensions(extensions, extension,
891                             compressed_file_extensions);
892                 }
893
894                 g_strfreev(extensions_set);
895         }
896         g_slist_free(compressed_file_extensions);
897         return extensions;
898 }
899
900 /*
901  * Free a list returned by wtap_file_extensions_list().
902  */
903 void wtap_free_file_extensions_list(GSList *extensions)
904 {
905         GSList *extension;
906
907         for (extension = extensions; extension != NULL;
908             extension = g_slist_next(extension)) {
909                 g_free(extension->data);
910         }
911         g_slist_free(extensions);
912 }
913
914 /* Return the default file extension to use with the specified file type;
915    that's just the extension, without any ".". */
916 const char *wtap_default_file_extension(int filetype)
917 {
918         if (filetype < 0 || filetype >= wtap_num_file_types)
919                 return NULL;
920         else
921                 return dump_open_table[filetype].default_file_extension;
922 }
923
924 gboolean wtap_dump_can_open(int filetype)
925 {
926         if (filetype < 0 || filetype >= wtap_num_file_types
927             || dump_open_table[filetype].dump_open == NULL)
928                 return FALSE;
929
930         return TRUE;
931 }
932
933 gboolean wtap_dump_can_write_encap(int filetype, int encap)
934 {
935         if (filetype < 0 || filetype >= wtap_num_file_types
936             || dump_open_table[filetype].can_write_encap == NULL)
937                 return FALSE;
938
939         if ((*dump_open_table[filetype].can_write_encap)(encap) != 0)
940                 return FALSE;
941
942         return TRUE;
943 }
944
945 #ifdef HAVE_LIBZ
946 gboolean wtap_dump_can_compress(int filetype)
947 {
948         /*
949          * If this is an unknown file type, or if we have to
950          * seek when writing out a file with this file type,
951          * return FALSE.
952          */
953         if (filetype < 0 || filetype >= wtap_num_file_types
954             || dump_open_table[filetype].writing_must_seek)
955                 return FALSE;
956
957         return TRUE;
958 }
959 #else
960 gboolean wtap_dump_can_compress(int filetype _U_)
961 {
962         return FALSE;
963 }
964 #endif
965
966 gboolean wtap_dump_has_name_resolution(int filetype)
967 {
968         if (filetype < 0 || filetype >= wtap_num_file_types
969             || dump_open_table[filetype].has_name_resolution == FALSE)
970                 return FALSE;
971
972         return TRUE;
973 }
974
975 static gboolean wtap_dump_open_check(int filetype, int encap, gboolean comressed, int *err);
976 static wtap_dumper* wtap_dump_alloc_wdh(int filetype, int encap, int snaplen,
977                                         gboolean compressed, int *err);
978 static gboolean wtap_dump_open_finish(wtap_dumper *wdh, int filetype, gboolean compressed, int *err);
979
980 static WFILE_T wtap_dump_file_open(wtap_dumper *wdh, const char *filename);
981 static WFILE_T wtap_dump_file_fdopen(wtap_dumper *wdh, int fd);
982 static int wtap_dump_file_close(wtap_dumper *wdh);
983
984 wtap_dumper* wtap_dump_open(const char *filename, int filetype, int encap,
985                                 int snaplen, gboolean compressed, int *err)
986 {
987         return wtap_dump_open_ng(filename, filetype, encap,snaplen, compressed, NULL, NULL, err);
988 }
989
990 wtap_dumper* wtap_dump_open_ng(const char *filename, int filetype, int encap,
991                                 int snaplen, gboolean compressed, wtapng_section_t *shb_hdr, wtapng_iface_descriptions_t *idb_inf, int *err)
992 {
993         wtap_dumper *wdh;
994         WFILE_T fh;
995
996         /* Check whether we can open a capture file with that file type
997            and that encapsulation. */
998         if (!wtap_dump_open_check(filetype, encap, compressed, err))
999                 return NULL;
1000
1001         /* Allocate a data structure for the output stream. */
1002         wdh = wtap_dump_alloc_wdh(filetype, encap, snaplen, compressed, err);
1003         if (wdh == NULL)
1004                 return NULL;    /* couldn't allocate it */
1005
1006         /* Set Section Header Block data */
1007         wdh->shb_hdr = shb_hdr;
1008         /* Set Interface Description Block data */
1009         if ((idb_inf != NULL) && (idb_inf->number_of_interfaces > 0)) {
1010                 wdh->number_of_interfaces = idb_inf->number_of_interfaces;
1011                 wdh->interface_data = idb_inf->interface_data;
1012         } else {
1013                 wtapng_if_descr_t descr;
1014
1015                 descr.wtap_encap = encap;
1016                 descr.time_units_per_second = 0;
1017                 descr.link_type = wtap_wtap_encap_to_pcap_encap(encap);
1018                 descr.snap_len = snaplen;
1019                 descr.opt_comment = NULL;
1020                 descr.if_name = NULL;
1021                 descr.if_description = NULL;
1022                 descr.if_speed = 0;
1023                 descr.if_tsresol = 6;
1024                 descr.if_filter_str= NULL;
1025                 descr.bpf_filter_len= 0;
1026                 descr.if_filter_bpf_bytes= NULL;
1027                 descr.if_os = NULL;
1028                 descr.if_fcslen = -1;
1029                 descr.num_stat_entries = 0;          /* Number of ISB:s */
1030                 descr.interface_statistics = NULL;
1031                 wdh->number_of_interfaces= 1;
1032                 wdh->interface_data= g_array_new(FALSE, FALSE, sizeof(wtapng_if_descr_t));
1033                 g_array_append_val(wdh->interface_data, descr);
1034         }
1035
1036         /* "-" means stdout */
1037         if (strcmp(filename, "-") == 0) {
1038                 if (compressed) {
1039                         *err = EINVAL;  /* XXX - return a Wiretap error code for this */
1040                         g_free(wdh);
1041                         return NULL;    /* compress won't work on stdout */
1042                 }
1043 #ifdef _WIN32
1044                 if (_setmode(fileno(stdout), O_BINARY) == -1) {
1045                         /* "Should not happen" */
1046                         *err = errno;
1047                         g_free(wdh);
1048                         return NULL;    /* couldn't put standard output in binary mode */
1049                 }
1050 #endif
1051                 wdh->fh = stdout;
1052         } else {
1053                 /* In case "fopen()" fails but doesn't set "errno", set "errno"
1054                    to a generic "the open failed" error. */
1055                 errno = WTAP_ERR_CANT_OPEN;
1056                 fh = wtap_dump_file_open(wdh, filename);
1057                 if (fh == NULL) {
1058                         *err = errno;
1059                         g_free(wdh);
1060                         return NULL;    /* can't create file */
1061                 }
1062                 wdh->fh = fh;
1063         }
1064
1065         if (!wtap_dump_open_finish(wdh, filetype, compressed, err)) {
1066                 /* Get rid of the file we created; we couldn't finish
1067                    opening it. */
1068                 if (wdh->fh != stdout) {
1069                         wtap_dump_file_close(wdh);
1070                         ws_unlink(filename);
1071                 }
1072                 g_free(wdh);
1073                 return NULL;
1074         }
1075         return wdh;
1076 }
1077
1078 wtap_dumper* wtap_dump_fdopen(int fd, int filetype, int encap, int snaplen,
1079                                 gboolean compressed, int *err)
1080 {
1081         wtap_dumper *wdh;
1082         WFILE_T fh;
1083
1084         /* Check whether we can open a capture file with that file type
1085            and that encapsulation. */
1086         if (!wtap_dump_open_check(filetype, encap, compressed, err))
1087                 return NULL;
1088
1089         /* Allocate a data structure for the output stream. */
1090         wdh = wtap_dump_alloc_wdh(filetype, encap, snaplen, compressed, err);
1091         if (wdh == NULL)
1092                 return NULL;    /* couldn't allocate it */
1093
1094 #ifdef _WIN32
1095         if (fd == 1) {
1096                 if (_setmode(fileno(stdout), O_BINARY) == -1) {
1097                         /* "Should not happen" */
1098                         *err = errno;
1099                         g_free(wdh);
1100                         return NULL;    /* couldn't put standard output in binary mode */
1101                 }
1102         }
1103 #endif
1104
1105         /* In case "fopen()" fails but doesn't set "errno", set "errno"
1106            to a generic "the open failed" error. */
1107         errno = WTAP_ERR_CANT_OPEN;
1108         fh = wtap_dump_file_fdopen(wdh, fd);
1109         if (fh == NULL) {
1110                 *err = errno;
1111                 g_free(wdh);
1112                 return NULL;    /* can't create standard I/O stream */
1113         }
1114         wdh->fh = fh;
1115
1116         if (!wtap_dump_open_finish(wdh, filetype, compressed, err)) {
1117                 wtap_dump_file_close(wdh);
1118                 g_free(wdh);
1119                 return NULL;
1120         }
1121         return wdh;
1122 }
1123
1124 static gboolean wtap_dump_open_check(int filetype, int encap, gboolean compressed, int *err)
1125 {
1126         if (!wtap_dump_can_open(filetype)) {
1127                 /* Invalid type, or type we don't know how to write. */
1128                 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
1129                 return FALSE;
1130         }
1131
1132         /* OK, we know how to write that type; can we write the specified
1133            encapsulation type? */
1134         *err = (*dump_open_table[filetype].can_write_encap)(encap);
1135         if (*err != 0)
1136                 return FALSE;
1137
1138         /* if compression is wanted, do we support this for this filetype? */
1139         if(compressed && !wtap_dump_can_compress(filetype)) {
1140                 *err = WTAP_ERR_COMPRESSION_NOT_SUPPORTED;
1141                 return FALSE;
1142         }
1143
1144         *err = (*dump_open_table[filetype].can_write_encap)(encap);
1145         if (*err != 0)
1146                 return FALSE;
1147
1148         /* All systems go! */
1149         return TRUE;
1150 }
1151
1152 static wtap_dumper* wtap_dump_alloc_wdh(int filetype, int encap, int snaplen,
1153                                         gboolean compressed, int *err)
1154 {
1155         wtap_dumper *wdh;
1156
1157         wdh = (wtap_dumper *)g_malloc0(sizeof (wtap_dumper));
1158         if (wdh == NULL) {
1159                 *err = errno;
1160                 return NULL;
1161         }
1162
1163         wdh->file_type = filetype;
1164         wdh->snaplen = snaplen;
1165         wdh->encap = encap;
1166         wdh->compressed = compressed;
1167         return wdh;
1168 }
1169
1170 static gboolean wtap_dump_open_finish(wtap_dumper *wdh, int filetype, gboolean compressed, int *err)
1171 {
1172         int fd;
1173         gboolean cant_seek;
1174
1175         /* Can we do a seek on the file descriptor?
1176            If not, note that fact. */
1177         if(compressed) {
1178                 cant_seek = TRUE;
1179         } else {
1180                 fd = fileno((FILE *)wdh->fh);
1181                 if (lseek(fd, 1, SEEK_CUR) == -1)
1182                         cant_seek = TRUE;
1183                 else {
1184                         /* Undo the seek. */
1185                         lseek(fd, 0, SEEK_SET);
1186                         cant_seek = FALSE;
1187                 }
1188         }
1189
1190         /* If this file type requires seeking, and we can't seek, fail. */
1191         if (dump_open_table[filetype].writing_must_seek && cant_seek) {
1192                 *err = WTAP_ERR_CANT_WRITE_TO_PIPE;
1193                 return FALSE;
1194         }
1195
1196         /* Now try to open the file for writing. */
1197         if (!(*dump_open_table[filetype].dump_open)(wdh, err)) {
1198                 return FALSE;
1199         }
1200
1201         return TRUE;    /* success! */
1202 }
1203
1204 gboolean wtap_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
1205                    const union wtap_pseudo_header *pseudo_header, const guint8 *pd, int *err)
1206 {
1207         return (wdh->subtype_write)(wdh, phdr, pseudo_header, pd, err);
1208 }
1209
1210 void wtap_dump_flush(wtap_dumper *wdh)
1211 {
1212 #ifdef HAVE_LIBZ
1213         if(wdh->compressed) {
1214                 gzwfile_flush((GZWFILE_T)wdh->fh);
1215         } else
1216 #endif
1217         {
1218                 fflush((FILE *)wdh->fh);
1219         }
1220 }
1221
1222 gboolean wtap_dump_close(wtap_dumper *wdh, int *err)
1223 {
1224         gboolean ret = TRUE;
1225
1226         if (wdh->subtype_close != NULL) {
1227                 /* There's a close routine for this dump stream. */
1228                 if (!(wdh->subtype_close)(wdh, err))
1229                         ret = FALSE;
1230         }
1231         errno = WTAP_ERR_CANT_CLOSE;
1232         /* Don't close stdout */
1233         if (wdh->fh != stdout) {
1234                 if (wtap_dump_file_close(wdh) == EOF) {
1235                         if (ret) {
1236                                 /* The per-format close function succeeded,
1237                                    but the fclose didn't.  Save the reason
1238                                    why, if our caller asked for it. */
1239                                 if (err != NULL)
1240                                         *err = errno;
1241                         }
1242                         ret = FALSE;
1243                 }
1244         } else {
1245                 /* as we don't close stdout, at least try to flush it */
1246                 wtap_dump_flush(wdh);
1247         }
1248         if (wdh->priv != NULL)
1249                 g_free(wdh->priv);
1250         g_free(wdh);
1251         return ret;
1252 }
1253
1254 gint64 wtap_get_bytes_dumped(wtap_dumper *wdh)
1255 {
1256         return wdh->bytes_dumped;
1257 }
1258
1259 void wtap_set_bytes_dumped(wtap_dumper *wdh, gint64 bytes_dumped)
1260 {
1261         wdh->bytes_dumped = bytes_dumped;
1262 }
1263
1264 gboolean wtap_dump_set_addrinfo_list(wtap_dumper *wdh, struct addrinfo *addrinfo_list)
1265 {
1266         if (!wdh || wdh->file_type < 0 || wdh->file_type >= wtap_num_file_types
1267                 || dump_open_table[wdh->file_type].has_name_resolution == FALSE)
1268                         return FALSE;
1269         wdh->addrinfo_list = addrinfo_list;
1270         return TRUE;
1271 }
1272
1273 /* internally open a file for writing (compressed or not) */
1274 #ifdef HAVE_LIBZ
1275 static WFILE_T wtap_dump_file_open(wtap_dumper *wdh, const char *filename)
1276 {
1277         if(wdh->compressed) {
1278                 return gzwfile_open(filename);
1279         } else {
1280                 return ws_fopen(filename, "wb");
1281         }
1282 }
1283 #else
1284 static WFILE_T wtap_dump_file_open(wtap_dumper *wdh _U_, const char *filename)
1285 {
1286         return ws_fopen(filename, "wb");
1287 }
1288 #endif
1289
1290 /* internally open a file for writing (compressed or not) */
1291 #ifdef HAVE_LIBZ
1292 static WFILE_T wtap_dump_file_fdopen(wtap_dumper *wdh, int fd)
1293 {
1294         if(wdh->compressed) {
1295                 return gzwfile_fdopen(fd);
1296         } else {
1297                 return fdopen(fd, "wb");
1298         }
1299 }
1300 #else
1301 static WFILE_T wtap_dump_file_fdopen(wtap_dumper *wdh _U_, int fd)
1302 {
1303         return fdopen(fd, "wb");
1304 }
1305 #endif
1306
1307 /* internally writing raw bytes (compressed or not) */
1308 gboolean wtap_dump_file_write(wtap_dumper *wdh, const void *buf, size_t bufsize,
1309                      int *err)
1310 {
1311         size_t nwritten;
1312
1313 #ifdef HAVE_LIBZ
1314         if (wdh->compressed) {
1315                 nwritten = gzwfile_write((GZWFILE_T)wdh->fh, buf, (unsigned) bufsize);
1316                 /*
1317                  * gzwfile_write() returns 0 on error.
1318                  */
1319                 if (nwritten == 0) {
1320                         *err = gzwfile_geterr((GZWFILE_T)wdh->fh);
1321                         return FALSE;
1322                 }
1323         } else
1324 #endif
1325         {
1326                 nwritten = fwrite(buf, 1, bufsize, (FILE *)wdh->fh);
1327                 /*
1328                  * At least according to the Mac OS X man page,
1329                  * this can return a short count on an error.
1330                  */
1331                 if (nwritten != bufsize) {
1332                         if (ferror((FILE *)wdh->fh))
1333                                 *err = errno;
1334                         else
1335                                 *err = WTAP_ERR_SHORT_WRITE;
1336                         return FALSE;
1337                 }
1338         }
1339         return TRUE;
1340 }
1341
1342 /* internally close a file for writing (compressed or not) */
1343 static int wtap_dump_file_close(wtap_dumper *wdh)
1344 {
1345 #ifdef HAVE_LIBZ
1346         if(wdh->compressed) {
1347                 return gzwfile_close((GZWFILE_T)wdh->fh);
1348         } else
1349 #endif
1350         {
1351                 return fclose((FILE *)wdh->fh);
1352         }
1353 }