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