Initial checkin of the 32 bit tektronix k12 binary format (rf5)
[obnox/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_SYS_STAT_H
36 #include <sys/stat.h>
37 #endif
38
39 #ifdef HAVE_UNISTD_H
40 #include <unistd.h>
41 #endif
42
43 #include <errno.h>
44
45 #ifdef HAVE_IO_H
46 #include <io.h> /* open/close on win32 */
47 #endif
48
49 #include "wtap-int.h"
50 #include "file_wrappers.h"
51 #include "buffer.h"
52 #include "lanalyzer.h"
53 #include "airopeek9.h"
54 #include "ngsniffer.h"
55 #include "radcom.h"
56 #include "ascend.h"
57 #include "nettl.h"
58 #include "libpcap.h"
59 #include "snoop.h"
60 #include "iptrace.h"
61 #include "netmon.h"
62 #include "netxray.h"
63 #include "toshiba.h"
64 #include "eyesdn.h"
65 #include "i4btrace.h"
66 #include "csids.h"
67 #include "pppdump.h"
68 #include "etherpeek.h"
69 #include "vms.h"
70 #include "dbs-etherwatch.h"
71 #include "visual.h"
72 #include "cosine.h"
73 #include "5views.h"
74 #include "erf.h"
75 #include "hcidump.h"
76 #include "network_instruments.h"
77 #include "k12.h"
78
79 /* The open_file_* routines should return:
80  *
81  *      -1 on an I/O error;
82  *
83  *      1 if the file they're reading is one of the types it handles;
84  *
85  *      0 if the file they're reading isn't the type they're checking for.
86  *
87  * If the routine handles this type of file, it should set the "file_type"
88  * field in the "struct wtap" to the type of the file.
89  *
90  * Put the trace files that are merely saved telnet-sessions last, since it's
91  * possible that you could have captured someone a router telnet-session
92  * using another tool. So, a libpcap trace of an toshiba "snoop" session
93  * should be discovered as a libpcap file, not a toshiba file.
94  */
95
96 static int (*const open_routines[])(wtap *, int *, char **) = {
97         /* Files that have magic bytes in fixed locations. These
98          * are easy to identify.
99          */
100         libpcap_open,
101         lanalyzer_open,
102         ngsniffer_open,
103         snoop_open,
104         iptrace_open,
105         netmon_open,
106         netxray_open,
107         radcom_open,
108         nettl_open,
109         visual_open,
110         _5views_open,
111         network_instruments_open,
112         airopeek9_open,
113         dbs_etherwatch_open,
114         k12_open,
115         
116         /* Files that don't have magic bytes at a fixed location,
117          * but that instead require a heuristic of some sort to
118          * identify them.  This includes the ASCII trace files that
119          * would be, for example, saved copies of a Telnet session
120          * to some box.
121          */
122         etherpeek_open,
123         pppdump_open,
124         ascend_open,
125         eyesdn_open,
126         toshiba_open,
127         i4btrace_open,
128         csids_open,
129         vms_open,
130         cosine_open,
131         erf_open,
132         hcidump_open,
133 };
134
135 #define N_FILE_TYPES    (sizeof open_routines / sizeof open_routines[0])
136
137 /*
138  * Visual C++ on Win32 systems doesn't define these.  (Old UNIX systems don't
139  * define them either.)
140  *
141  * Visual C++ on Win32 systems doesn't define S_IFIFO, it defines _S_IFIFO.
142  */
143 #ifndef S_ISREG
144 #define S_ISREG(mode)   (((mode) & S_IFMT) == S_IFREG)
145 #endif
146 #ifndef S_IFIFO
147 #define S_IFIFO _S_IFIFO
148 #endif
149 #ifndef S_ISFIFO
150 #define S_ISFIFO(mode)  (((mode) & S_IFMT) == S_IFIFO)
151 #endif
152 #ifndef S_ISDIR
153 #define S_ISDIR(mode)   (((mode) & S_IFMT) == S_IFDIR)
154 #endif
155
156 /* Opens a file and prepares a wtap struct.
157    If "do_random" is TRUE, it opens the file twice; the second open
158    allows the application to do random-access I/O without moving
159    the seek offset for sequential I/O, which is used by Ethereal
160    so that it can do sequential I/O to a capture file that's being
161    written to as new packets arrive independently of random I/O done
162    to display protocol trees for packets when they're selected. */
163 wtap* wtap_open_offline(const char *filename, int *err, char **err_info,
164     gboolean do_random)
165 {
166         struct stat statb;
167         wtap    *wth;
168         unsigned int    i;
169         gboolean use_stdin = FALSE;
170
171         /* open standard input if filename is '-' */
172         if (strcmp(filename, "-") == 0)
173                 use_stdin = TRUE;
174
175         /* First, make sure the file is valid */
176         if (use_stdin) {
177                 if (fstat(0, &statb) < 0) {
178                         *err = errno;
179                         return NULL;
180                 }
181         } else {
182                 if (stat(filename, &statb) < 0) {
183                         *err = errno;
184                         return NULL;
185                 }
186         }
187         if (S_ISFIFO(statb.st_mode)) {
188                 /*
189                  * Opens of FIFOs are allowed only when not opening
190                  * for random access.
191                  *
192                  * XXX - currently, we do seeking when trying to find
193                  * out the file type, so we don't actually support
194                  * opening FIFOs.  However, we may eventually
195                  * do buffering that allows us to do at least some
196                  * file type determination even on pipes, so we
197                  * allow FIFO opens and let things fail later when
198                  * we try to seek.
199                  */
200                 if (do_random) {
201                         *err = WTAP_ERR_RANDOM_OPEN_PIPE;
202                         return NULL;
203                 }
204         } else if (S_ISDIR(statb.st_mode)) {
205                 /*
206                  * Return different errors for "this is a directory"
207                  * and "this is some random special file type", so
208                  * the user can get a potentially more helpful error.
209                  */
210                 *err = EISDIR;
211                 return NULL;
212         } else if (! S_ISREG(statb.st_mode)) {
213                 *err = WTAP_ERR_NOT_REGULAR_FILE;
214                 return NULL;
215         }
216
217         /*
218          * We need two independent descriptors for random access, so
219          * they have different file positions.  If we're opening the
220          * standard input, we can only dup it to get additional
221          * descriptors, so we can't have two independent descriptors,
222          * and thus can't do random access.
223          */
224         if (use_stdin && do_random) {
225                 *err = WTAP_ERR_RANDOM_OPEN_STDIN;
226                 return NULL;
227         }
228
229         errno = ENOMEM;
230         wth = g_malloc(sizeof(wtap));
231         if (wth == NULL) {
232                 *err = errno;
233                 return NULL;
234         }
235
236 /* Win32 needs the O_BINARY flag for open() */
237 #ifndef O_BINARY
238 #define O_BINARY        0
239 #endif
240
241         /* Open the file */
242         errno = WTAP_ERR_CANT_OPEN;
243         if (use_stdin) {
244                 /*
245                  * We dup FD 0, so that we don't have to worry about
246                  * an fclose or gzclose of wth->fh closing the standard
247                  * input of the process.
248                  */
249                 wth->fd = dup(0);
250 #ifdef _WIN32
251                 _setmode(wth->fd, O_BINARY);
252 #endif
253         } else
254                 wth->fd = open(filename, O_RDONLY|O_BINARY);
255         if (wth->fd < 0) {
256                 *err = errno;
257                 g_free(wth);
258                 return NULL;
259         }
260         if (!(wth->fh = filed_open(wth->fd, "rb"))) {
261                 *err = errno;
262                 close(wth->fd);
263                 g_free(wth);
264                 return NULL;
265         }
266
267         if (do_random) {
268                 if (!(wth->random_fh = file_open(filename, "rb"))) {
269                         *err = errno;
270                         file_close(wth->fh);
271                         g_free(wth);
272                         return NULL;
273                 }
274         } else
275                 wth->random_fh = NULL;
276
277         /* initialization */
278         wth->file_encap = WTAP_ENCAP_UNKNOWN;
279         wth->data_offset = 0;
280         wth->subtype_sequential_close = NULL;
281         wth->subtype_close = NULL;
282
283         /* Try all file types */
284         for (i = 0; i < N_FILE_TYPES; i++) {
285                 /* Seek back to the beginning of the file; the open routine
286                    for the previous file type may have left the file
287                    position somewhere other than the beginning, and the
288                    open routine for this file type will probably want
289                    to start reading at the beginning.
290
291                    Initialize the data offset while we're at it. */
292                 if (file_seek(wth->fh, 0, SEEK_SET, err) == -1) {
293                         /* I/O error - give up */
294                         if (wth->random_fh != NULL)
295                                 file_close(wth->random_fh);
296                         file_close(wth->fh);
297                         g_free(wth);
298                         return NULL;
299                 }
300                 wth->data_offset = 0;
301                 
302                 switch ((*open_routines[i])(wth, err, err_info)) {
303
304                 case -1:
305                         /* I/O error - give up */
306                         if (wth->random_fh != NULL)
307                                 file_close(wth->random_fh);
308                         file_close(wth->fh);
309                         g_free(wth);
310                         return NULL;
311
312                 case 0:
313                         /* No I/O error, but not that type of file */
314                         break;
315
316                 case 1:
317                         /* We found the file type */
318                         goto success;
319                 }
320         }
321
322         /* Well, it's not one of the types of file we know about. */
323         if (wth->random_fh != NULL)
324                 file_close(wth->random_fh);
325         file_close(wth->fh);
326         g_free(wth);
327         *err = WTAP_ERR_FILE_UNKNOWN_FORMAT;
328         return NULL;
329
330 success:
331         wth->frame_buffer = g_malloc(sizeof(struct Buffer));
332         buffer_init(wth->frame_buffer, 1500);
333         return wth;
334 }
335
336 /* Table of the file types we know about. */
337 static const struct file_type_info {
338         const char *name;
339         const char *short_name;
340         int     (*can_write_encap)(int);
341         int     (*dump_open)(wtap_dumper *, gboolean, int *);
342 } dump_open_table[WTAP_NUM_FILE_TYPES] = {
343         /* WTAP_FILE_UNKNOWN */
344         { NULL, NULL,
345           NULL, NULL },
346
347         /* WTAP_FILE_WTAP */
348         { "Wiretap (Ethereal)", NULL,
349           NULL, NULL },
350
351         /* WTAP_FILE_PCAP */
352         { "libpcap (tcpdump, Ethereal, etc.)", "libpcap",
353           libpcap_dump_can_write_encap, libpcap_dump_open },
354
355         /* WTAP_FILE_PCAP_SS990417 */
356         { "RedHat Linux 6.1 libpcap (tcpdump)", "rh6_1libpcap",
357           libpcap_dump_can_write_encap, libpcap_dump_open },
358
359         /* WTAP_FILE_PCAP_SS990915 */
360         { "SuSE Linux 6.3 libpcap (tcpdump)", "suse6_3libpcap",
361           libpcap_dump_can_write_encap, libpcap_dump_open },
362
363         /* WTAP_FILE_PCAP_SS991029 */
364         { "modified libpcap (tcpdump)", "modlibpcap",
365           libpcap_dump_can_write_encap, libpcap_dump_open },
366
367         /* WTAP_FILE_PCAP_NOKIA */
368         { "Nokia libpcap (tcpdump)", "nokialibpcap",
369           libpcap_dump_can_write_encap, libpcap_dump_open },
370
371         /* WTAP_FILE_PCAP_AIX */
372         { "AIX libpcap (tcpdump)", NULL,
373           NULL, NULL },
374
375         /* WTAP_FILE_LANALYZER */
376         { "Novell LANalyzer","lanalyzer",
377           lanalyzer_dump_can_write_encap, lanalyzer_dump_open },
378
379         /* WTAP_FILE_NGSNIFFER_UNCOMPRESSED */
380         { "Network Associates Sniffer (DOS-based)", "ngsniffer",
381           ngsniffer_dump_can_write_encap, ngsniffer_dump_open },
382
383         /* WTAP_FILE_NGSNIFFER_COMPRESSED */
384         { "Network Associates Sniffer (DOS-based), compressed", "ngsniffer_comp",
385           NULL, NULL },
386
387         /* WTAP_FILE_SNOOP */
388         { "Sun snoop", "snoop",
389           snoop_dump_can_write_encap, snoop_dump_open },
390
391         /* WTAP_FILE_SHOMITI */
392         { "Shomiti/Finisar Surveyor", "shomiti",
393           NULL, NULL },
394
395         /* WTAP_FILE_IPTRACE_1_0 */
396         { "AIX iptrace 1.0", NULL,
397           NULL, NULL },
398
399         /* WTAP_FILE_IPTRACE_2_0 */
400         { "AIX iptrace 2.0", NULL,
401           NULL, NULL },
402
403         /* WTAP_FILE_NETMON_1_x */
404         { "Microsoft Network Monitor 1.x", "netmon1",
405           netmon_dump_can_write_encap, netmon_dump_open },
406
407         /* WTAP_FILE_NETMON_2_x */
408         { "Microsoft Network Monitor 2.x", "netmon2",
409           netmon_dump_can_write_encap, netmon_dump_open },
410
411         /* WTAP_FILE_NETXRAY_OLD */
412         { "Cinco Networks NetXRay 1.x", NULL,
413           NULL, NULL },
414
415         /* WTAP_FILE_NETXRAY_1_0 */
416         { "Cinco Networks NetXRay 2.0 or later", NULL,
417           NULL, NULL },
418
419         /* WTAP_FILE_NETXRAY_1_1 */
420         { "Network Associates Sniffer (Windows-based) 1.1", "ngwsniffer_1_1",
421           netxray_dump_can_write_encap_1_1, netxray_dump_open_1_1 },
422
423         /* WTAP_FILE_NETXRAY_2_00x */
424         { "Network Associates Sniffer (Windows-based) 2.00x", "ngwsniffer_2_0",
425           netxray_dump_can_write_encap_2_0, netxray_dump_open_2_0 },
426
427         /* WTAP_FILE_RADCOM */
428         { "RADCOM WAN/LAN analyzer", NULL,
429           NULL, NULL },
430
431         /* WTAP_FILE_ASCEND */
432         { "Lucent/Ascend access server trace", NULL,
433           NULL, NULL },
434
435         /* WTAP_FILE_NETTL */
436         { "HP-UX nettl trace", "nettl",
437           nettl_dump_can_write_encap, nettl_dump_open },
438
439         /* WTAP_FILE_TOSHIBA */
440         { "Toshiba Compact ISDN Router snoop trace", NULL,
441           NULL, NULL },
442
443         /* WTAP_FILE_I4BTRACE */
444         { "I4B ISDN trace", NULL,
445           NULL, NULL },
446
447         /* WTAP_FILE_CSIDS */
448         { "CSIDS IPLog", NULL,
449           NULL, NULL },
450
451         /* WTAP_FILE_PPPDUMP */
452         { "pppd log (pppdump format)", NULL,
453           NULL, NULL },
454
455         /* WTAP_FILE_ETHERPEEK_V56 */
456         { "EtherPeek/TokenPeek trace (V5 & V6 file format)", NULL,
457           NULL, NULL },
458
459         /* WTAP_FILE_ETHERPEEK_V7 */
460         { "EtherPeek/TokenPeek/AiroPeek trace (V7 file format)", NULL,
461           NULL, NULL },
462
463         /* WTAP_FILE_VMS */
464         { "TCPIPtrace (VMS)", NULL,
465           NULL, NULL},
466
467         /* WTAP_FILE_DBS_ETHERWATCH */
468         { "DBS Etherwatch (VMS)", NULL,
469           NULL, NULL},
470
471         /* WTAP_FILE_VISUAL_NETWORKS */
472         { "Visual Networks traffic capture", "visual",
473           visual_dump_can_write_encap, visual_dump_open },
474
475         /* WTAP_FILE_COSINE */
476         { "CoSine IPSX L2 capture", "cosine",
477           NULL, NULL },
478
479         /* WTAP_FILE_5VIEWS */
480         { "Accellent 5Views capture", "5views",
481           _5views_dump_can_write_encap, _5views_dump_open },
482
483         /* WTAP_FILE_ERF */
484         { "Endace DAG capture", "erf",
485           NULL, NULL },
486
487         /* WTAP_FILE_HCIDUMP */
488         { "Bluetooth HCI dump", "hcidump",
489           NULL, NULL },
490
491         /* WTAP_FILE_NETWORK_INSTRUMENTS_V9 */
492         { "Network Instruments Observer version 9", "niobserverv9",
493           network_instruments_dump_can_write_encap, network_instruments_dump_open },
494
495         /* WTAP_FILE_AIROPEEK_V9 */
496         { "EtherPeek/AiroPeek trace (V9 file format)", NULL,
497           NULL, NULL },
498     
499         /* WTAP_FILE_EYESDN */
500         { "EyeSDN USB S0/E1 ISDN trace format", NULL,
501                 NULL, NULL },
502     
503         /* WTAP_FILE_K12 */
504         { "Tektronix K12xx 32-bit .rf5 format", "rf5",
505                 NULL, NULL },
506 };
507
508 /* Name that should be somewhat descriptive. */
509 const char *wtap_file_type_string(int filetype)
510 {
511         if (filetype < 0 || filetype >= WTAP_NUM_FILE_TYPES) {
512                 g_error("Unknown capture file type %d", filetype);
513                 return NULL;
514         } else
515                 return dump_open_table[filetype].name;
516 }
517
518 /* Name to use in, say, a command-line flag specifying the type. */
519 const char *wtap_file_type_short_string(int filetype)
520 {
521         if (filetype < 0 || filetype >= WTAP_NUM_FILE_TYPES)
522                 return NULL;
523         else
524                 return dump_open_table[filetype].short_name;
525 }
526
527 /* Translate a short name to a capture file type. */
528 int wtap_short_string_to_file_type(const char *short_name)
529 {
530         int filetype;
531
532         for (filetype = 0; filetype < WTAP_NUM_FILE_TYPES; filetype++) {
533                 if (dump_open_table[filetype].short_name != NULL &&
534                     strcmp(short_name, dump_open_table[filetype].short_name) == 0)
535                         return filetype;
536         }
537         return -1;      /* no such file type, or we can't write it */
538 }
539
540 gboolean wtap_dump_can_open(int filetype)
541 {
542         if (filetype < 0 || filetype >= WTAP_NUM_FILE_TYPES
543             || dump_open_table[filetype].dump_open == NULL)
544                 return FALSE;
545
546         return TRUE;
547 }
548
549 gboolean wtap_dump_can_write_encap(int filetype, int encap)
550 {
551         if (filetype < 0 || filetype >= WTAP_NUM_FILE_TYPES
552             || dump_open_table[filetype].can_write_encap == NULL)
553                 return FALSE;
554
555         if ((*dump_open_table[filetype].can_write_encap)(encap) != 0)
556                 return FALSE;
557
558         return TRUE;
559 }
560
561 static gboolean wtap_dump_open_check(int filetype, int encap, int *err);
562 static wtap_dumper* wtap_dump_alloc_wdh(int filetype, int encap, int snaplen,
563     int *err);
564 static gboolean wtap_dump_open_finish(wtap_dumper *wdh, int filetype, int *err);
565
566 wtap_dumper* wtap_dump_open(const char *filename, int filetype, int encap,
567                                 int snaplen, int *err)
568 {
569         wtap_dumper *wdh;
570         FILE *fh;
571
572         /* Check whether we can open a capture file with that file type
573            and that encapsulation. */
574         if (!wtap_dump_open_check(filetype, encap, err))
575                 return NULL;
576
577         /* Allocate a data structure for the output stream. */
578         wdh = wtap_dump_alloc_wdh(filetype, encap, snaplen, err);
579         if (wdh == NULL)
580                 return NULL;    /* couldn't allocate it */
581
582         /* Empty filename means stdout */
583         if (*filename == '\0') {
584 #ifdef _WIN32
585                 setmode(fileno(stdout), O_BINARY);
586 #endif
587                 wdh->fh = stdout;
588         } else {
589                 /* In case "fopen()" fails but doesn't set "errno", set "errno"
590                    to a generic "the open failed" error. */
591                 errno = WTAP_ERR_CANT_OPEN;
592                 fh = fopen(filename, "wb");
593                 if (fh == NULL) {
594                         *err = errno;
595                         return NULL;    /* can't create file */
596                 }
597                 wdh->fh = fh;
598         }
599
600         if (!wtap_dump_open_finish(wdh, filetype, err)) {
601                 /* Get rid of the file we created; we couldn't finish
602                    opening it. */
603                 if (wdh->fh != stdout)
604                         unlink(filename);
605                 return NULL;
606         }
607         return wdh;
608 }
609
610 wtap_dumper* wtap_dump_fdopen(int fd, int filetype, int encap, int snaplen,
611                                 int *err)
612 {
613         wtap_dumper *wdh;
614         FILE *fh;
615
616         /* Check whether we can open a capture file with that file type
617            and that encapsulation. */
618         if (!wtap_dump_open_check(filetype, encap, err))
619                 return NULL;
620
621         /* Allocate a data structure for the output stream. */
622         wdh = wtap_dump_alloc_wdh(filetype, encap, snaplen, err);
623         if (wdh == NULL)
624                 return NULL;    /* couldn't allocate it */
625
626         /* In case "fopen()" fails but doesn't set "errno", set "errno"
627            to a generic "the open failed" error. */
628         errno = WTAP_ERR_CANT_OPEN;
629         fh = fdopen(fd, "wb");
630         if (fh == NULL) {
631                 *err = errno;
632                 return NULL;    /* can't create standard I/O stream */
633         }
634         wdh->fh = fh;
635
636         if (!wtap_dump_open_finish(wdh, filetype, err))
637                 return NULL;
638         return wdh;
639 }
640
641 static gboolean wtap_dump_open_check(int filetype, int encap, int *err)
642 {
643         if (!wtap_dump_can_open(filetype)) {
644                 /* Invalid type, or type we don't know how to write. */
645                 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
646                 return FALSE;
647         }
648
649         /* OK, we know how to write that type; can we write the specified
650            encapsulation type? */
651         *err = (*dump_open_table[filetype].can_write_encap)(encap);
652         if (*err != 0)
653                 return FALSE;
654
655         /* All systems go! */
656         return TRUE;
657 }
658
659 static wtap_dumper* wtap_dump_alloc_wdh(int filetype, int encap, int snaplen,
660                                         int *err)
661 {
662         wtap_dumper *wdh;
663
664         wdh = g_malloc(sizeof (wtap_dumper));
665         if (wdh == NULL) {
666                 *err = errno;
667                 return NULL;
668         }
669         wdh->fh = NULL;
670         wdh->file_type = filetype;
671         wdh->snaplen = snaplen;
672         wdh->encap = encap;
673         wdh->bytes_dumped = 0;
674         wdh->dump.opaque = NULL;
675         wdh->subtype_write = NULL;
676         wdh->subtype_close = NULL;
677         return wdh;
678 }
679
680 static gboolean wtap_dump_open_finish(wtap_dumper *wdh, int filetype, int *err)
681 {
682         int fd;
683         gboolean cant_seek;
684
685         /* Can we do a seek on the file descriptor?
686            If not, note that fact. */
687         fd = fileno(wdh->fh);
688         if (lseek(fd, 1, SEEK_CUR) == -1)
689           cant_seek = TRUE;
690         else {
691           /* Undo the seek. */
692           lseek(fd, 0, SEEK_SET);
693           cant_seek = FALSE;
694         }
695
696         /* Now try to open the file for writing. */
697         if (!(*dump_open_table[filetype].dump_open)(wdh, cant_seek, err)) {
698                 /* The attempt failed.  Close the stream for the file.
699                    NOTE: this means the FD handed to "wtap_dump_fdopen()"
700                    will be closed if the open fails. */
701                 if (wdh->fh != stdout)
702                         fclose(wdh->fh);
703
704                 /* Now free up the dumper handle. */
705                 g_free(wdh);
706                 return FALSE;
707         }
708
709         return TRUE;    /* success! */
710 }
711
712 FILE* wtap_dump_file(wtap_dumper *wdh)
713 {
714         return wdh->fh;
715 }
716
717 gboolean wtap_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
718     const union wtap_pseudo_header *pseudo_header, const guchar *pd, int *err)
719 {
720         return (wdh->subtype_write)(wdh, phdr, pseudo_header, pd, err);
721 }
722
723 gboolean wtap_dump_close(wtap_dumper *wdh, int *err)
724 {
725         gboolean ret = TRUE;
726
727         if (wdh->subtype_close != NULL) {
728                 /* There's a close routine for this dump stream. */
729                 if (!(wdh->subtype_close)(wdh, err))
730                         ret = FALSE;
731         }
732         errno = WTAP_ERR_CANT_CLOSE;
733         /* Don't close stdout */
734         if (wdh->fh != stdout) {
735                 if (fclose(wdh->fh) == EOF) {
736                         if (ret) {
737                                 /* The per-format close function succeeded,
738                                    but the fclose didn't.  Save the reason
739                                    why, if our caller asked for it. */
740                                 if (err != NULL)
741                                         *err = errno;
742                         }
743                         ret = FALSE;
744                 }
745         }
746         if (wdh->dump.opaque != NULL)
747                 g_free(wdh->dump.opaque);
748         g_free(wdh);
749         return ret;
750 }
751
752 long wtap_get_bytes_dumped(wtap_dumper *wdh)
753 {
754         return wdh->bytes_dumped;
755 }
756
757 void wtap_set_bytes_dumped(wtap_dumper *wdh, long bytes_dumped)
758 {
759         wdh->bytes_dumped = bytes_dumped;
760 }
761