EVERYTHING IN THE BUILDBOT IS GOING TO BE RED!!! Sorry!
[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         wth->tsprecision = WTAP_FILE_TSPREC_USEC;
283
284         /* Try all file types */
285         for (i = 0; i < N_FILE_TYPES; i++) {
286                 /* Seek back to the beginning of the file; the open routine
287                    for the previous file type may have left the file
288                    position somewhere other than the beginning, and the
289                    open routine for this file type will probably want
290                    to start reading at the beginning.
291
292                    Initialize the data offset while we're at it. */
293                 if (file_seek(wth->fh, 0, SEEK_SET, err) == -1) {
294                         /* I/O error - give up */
295                         if (wth->random_fh != NULL)
296                                 file_close(wth->random_fh);
297                         file_close(wth->fh);
298                         g_free(wth);
299                         return NULL;
300                 }
301                 wth->data_offset = 0;
302                 
303                 switch ((*open_routines[i])(wth, err, err_info)) {
304
305                 case -1:
306                         /* I/O error - give up */
307                         if (wth->random_fh != NULL)
308                                 file_close(wth->random_fh);
309                         file_close(wth->fh);
310                         g_free(wth);
311                         return NULL;
312
313                 case 0:
314                         /* No I/O error, but not that type of file */
315                         break;
316
317                 case 1:
318                         /* We found the file type */
319                         goto success;
320                 }
321         }
322
323         /* Well, it's not one of the types of file we know about. */
324         if (wth->random_fh != NULL)
325                 file_close(wth->random_fh);
326         file_close(wth->fh);
327         g_free(wth);
328         *err = WTAP_ERR_FILE_UNKNOWN_FORMAT;
329         return NULL;
330
331 success:
332         wth->frame_buffer = g_malloc(sizeof(struct Buffer));
333         buffer_init(wth->frame_buffer, 1500);
334         return wth;
335 }
336
337 /* Table of the file types we know about. */
338 static const struct file_type_info {
339         const char *name;
340         const char *short_name;
341         int     (*can_write_encap)(int);
342         int     (*dump_open)(wtap_dumper *, gboolean, int *);
343 } dump_open_table[WTAP_NUM_FILE_TYPES] = {
344         /* WTAP_FILE_UNKNOWN */
345         { NULL, NULL,
346           NULL, NULL },
347
348         /* WTAP_FILE_WTAP */
349         { "Wiretap (Ethereal)", NULL,
350           NULL, NULL },
351
352         /* WTAP_FILE_PCAP */
353         { "libpcap (tcpdump, Ethereal, etc.)", "libpcap",
354           libpcap_dump_can_write_encap, libpcap_dump_open },
355
356         /* WTAP_FILE_PCAP_SS990417 */
357         { "RedHat Linux 6.1 libpcap (tcpdump)", "rh6_1libpcap",
358           libpcap_dump_can_write_encap, libpcap_dump_open },
359
360         /* WTAP_FILE_PCAP_SS990915 */
361         { "SuSE Linux 6.3 libpcap (tcpdump)", "suse6_3libpcap",
362           libpcap_dump_can_write_encap, libpcap_dump_open },
363
364         /* WTAP_FILE_PCAP_SS991029 */
365         { "modified libpcap (tcpdump)", "modlibpcap",
366           libpcap_dump_can_write_encap, libpcap_dump_open },
367
368         /* WTAP_FILE_PCAP_NOKIA */
369         { "Nokia libpcap (tcpdump)", "nokialibpcap",
370           libpcap_dump_can_write_encap, libpcap_dump_open },
371
372         /* WTAP_FILE_PCAP_AIX */
373         { "AIX libpcap (tcpdump)", NULL,
374           NULL, NULL },
375
376         /* WTAP_FILE_LANALYZER */
377         { "Novell LANalyzer","lanalyzer",
378           lanalyzer_dump_can_write_encap, lanalyzer_dump_open },
379
380         /* WTAP_FILE_NGSNIFFER_UNCOMPRESSED */
381         { "Network Associates Sniffer (DOS-based)", "ngsniffer",
382           ngsniffer_dump_can_write_encap, ngsniffer_dump_open },
383
384         /* WTAP_FILE_NGSNIFFER_COMPRESSED */
385         { "Network Associates Sniffer (DOS-based), compressed", "ngsniffer_comp",
386           NULL, NULL },
387
388         /* WTAP_FILE_SNOOP */
389         { "Sun snoop", "snoop",
390           snoop_dump_can_write_encap, snoop_dump_open },
391
392         /* WTAP_FILE_SHOMITI */
393         { "Shomiti/Finisar Surveyor", "shomiti",
394           NULL, NULL },
395
396         /* WTAP_FILE_IPTRACE_1_0 */
397         { "AIX iptrace 1.0", NULL,
398           NULL, NULL },
399
400         /* WTAP_FILE_IPTRACE_2_0 */
401         { "AIX iptrace 2.0", NULL,
402           NULL, NULL },
403
404         /* WTAP_FILE_NETMON_1_x */
405         { "Microsoft Network Monitor 1.x", "netmon1",
406           netmon_dump_can_write_encap, netmon_dump_open },
407
408         /* WTAP_FILE_NETMON_2_x */
409         { "Microsoft Network Monitor 2.x", "netmon2",
410           netmon_dump_can_write_encap, netmon_dump_open },
411
412         /* WTAP_FILE_NETXRAY_OLD */
413         { "Cinco Networks NetXRay 1.x", NULL,
414           NULL, NULL },
415
416         /* WTAP_FILE_NETXRAY_1_0 */
417         { "Cinco Networks NetXRay 2.0 or later", NULL,
418           NULL, NULL },
419
420         /* WTAP_FILE_NETXRAY_1_1 */
421         { "Network Associates Sniffer (Windows-based) 1.1", "ngwsniffer_1_1",
422           netxray_dump_can_write_encap_1_1, netxray_dump_open_1_1 },
423
424         /* WTAP_FILE_NETXRAY_2_00x */
425         { "Network Associates Sniffer (Windows-based) 2.00x", "ngwsniffer_2_0",
426           netxray_dump_can_write_encap_2_0, netxray_dump_open_2_0 },
427
428         /* WTAP_FILE_RADCOM */
429         { "RADCOM WAN/LAN analyzer", NULL,
430           NULL, NULL },
431
432         /* WTAP_FILE_ASCEND */
433         { "Lucent/Ascend access server trace", NULL,
434           NULL, NULL },
435
436         /* WTAP_FILE_NETTL */
437         { "HP-UX nettl trace", "nettl",
438           nettl_dump_can_write_encap, nettl_dump_open },
439
440         /* WTAP_FILE_TOSHIBA */
441         { "Toshiba Compact ISDN Router snoop trace", NULL,
442           NULL, NULL },
443
444         /* WTAP_FILE_I4BTRACE */
445         { "I4B ISDN trace", NULL,
446           NULL, NULL },
447
448         /* WTAP_FILE_CSIDS */
449         { "CSIDS IPLog", NULL,
450           NULL, NULL },
451
452         /* WTAP_FILE_PPPDUMP */
453         { "pppd log (pppdump format)", NULL,
454           NULL, NULL },
455
456         /* WTAP_FILE_ETHERPEEK_V56 */
457         { "EtherPeek/TokenPeek trace (V5 & V6 file format)", NULL,
458           NULL, NULL },
459
460         /* WTAP_FILE_ETHERPEEK_V7 */
461         { "EtherPeek/TokenPeek/AiroPeek trace (V7 file format)", NULL,
462           NULL, NULL },
463
464         /* WTAP_FILE_VMS */
465         { "TCPIPtrace (VMS)", NULL,
466           NULL, NULL},
467
468         /* WTAP_FILE_DBS_ETHERWATCH */
469         { "DBS Etherwatch (VMS)", NULL,
470           NULL, NULL},
471
472         /* WTAP_FILE_VISUAL_NETWORKS */
473         { "Visual Networks traffic capture", "visual",
474           visual_dump_can_write_encap, visual_dump_open },
475
476         /* WTAP_FILE_COSINE */
477         { "CoSine IPSX L2 capture", "cosine",
478           NULL, NULL },
479
480         /* WTAP_FILE_5VIEWS */
481         { "Accellent 5Views capture", "5views",
482           _5views_dump_can_write_encap, _5views_dump_open },
483
484         /* WTAP_FILE_ERF */
485         { "Endace DAG capture", "erf",
486           NULL, NULL },
487
488         /* WTAP_FILE_HCIDUMP */
489         { "Bluetooth HCI dump", "hcidump",
490           NULL, NULL },
491
492         /* WTAP_FILE_NETWORK_INSTRUMENTS_V9 */
493         { "Network Instruments Observer version 9", "niobserverv9",
494           network_instruments_dump_can_write_encap, network_instruments_dump_open },
495
496         /* WTAP_FILE_AIROPEEK_V9 */
497         { "EtherPeek/AiroPeek trace (V9 file format)", NULL,
498           NULL, NULL },
499     
500         /* WTAP_FILE_EYESDN */
501         { "EyeSDN USB S0/E1 ISDN trace format", NULL,
502                 NULL, NULL },
503     
504         /* WTAP_FILE_K12 */
505         { "Tektronix K12xx 32-bit .rf5 format", "rf5",
506                 k12_dump_can_write_encap, k12_dump_open },
507 };
508
509 /* Name that should be somewhat descriptive. */
510 const char *wtap_file_type_string(int filetype)
511 {
512         if (filetype < 0 || filetype >= WTAP_NUM_FILE_TYPES) {
513                 g_error("Unknown capture file type %d", filetype);
514                 return NULL;
515         } else
516                 return dump_open_table[filetype].name;
517 }
518
519 /* Name to use in, say, a command-line flag specifying the type. */
520 const char *wtap_file_type_short_string(int filetype)
521 {
522         if (filetype < 0 || filetype >= WTAP_NUM_FILE_TYPES)
523                 return NULL;
524         else
525                 return dump_open_table[filetype].short_name;
526 }
527
528 /* Translate a short name to a capture file type. */
529 int wtap_short_string_to_file_type(const char *short_name)
530 {
531         int filetype;
532
533         for (filetype = 0; filetype < WTAP_NUM_FILE_TYPES; filetype++) {
534                 if (dump_open_table[filetype].short_name != NULL &&
535                     strcmp(short_name, dump_open_table[filetype].short_name) == 0)
536                         return filetype;
537         }
538         return -1;      /* no such file type, or we can't write it */
539 }
540
541 gboolean wtap_dump_can_open(int filetype)
542 {
543         if (filetype < 0 || filetype >= WTAP_NUM_FILE_TYPES
544             || dump_open_table[filetype].dump_open == NULL)
545                 return FALSE;
546
547         return TRUE;
548 }
549
550 gboolean wtap_dump_can_write_encap(int filetype, int encap)
551 {
552         if (filetype < 0 || filetype >= WTAP_NUM_FILE_TYPES
553             || dump_open_table[filetype].can_write_encap == NULL)
554                 return FALSE;
555
556         if ((*dump_open_table[filetype].can_write_encap)(encap) != 0)
557                 return FALSE;
558
559         return TRUE;
560 }
561
562 static gboolean wtap_dump_open_check(int filetype, int encap, int *err);
563 static wtap_dumper* wtap_dump_alloc_wdh(int filetype, int encap, int snaplen,
564     int *err);
565 static gboolean wtap_dump_open_finish(wtap_dumper *wdh, int filetype, int *err);
566
567 wtap_dumper* wtap_dump_open(const char *filename, int filetype, int encap,
568                                 int snaplen, int *err)
569 {
570         wtap_dumper *wdh;
571         FILE *fh;
572
573         /* Check whether we can open a capture file with that file type
574            and that encapsulation. */
575         if (!wtap_dump_open_check(filetype, encap, err))
576                 return NULL;
577
578         /* Allocate a data structure for the output stream. */
579         wdh = wtap_dump_alloc_wdh(filetype, encap, snaplen, err);
580         if (wdh == NULL)
581                 return NULL;    /* couldn't allocate it */
582
583         /* Empty filename means stdout */
584         if (*filename == '\0') {
585 #ifdef _WIN32
586                 setmode(fileno(stdout), O_BINARY);
587 #endif
588                 wdh->fh = stdout;
589         } else {
590                 /* In case "fopen()" fails but doesn't set "errno", set "errno"
591                    to a generic "the open failed" error. */
592                 errno = WTAP_ERR_CANT_OPEN;
593                 fh = fopen(filename, "wb");
594                 if (fh == NULL) {
595                         *err = errno;
596                         return NULL;    /* can't create file */
597                 }
598                 wdh->fh = fh;
599         }
600
601         if (!wtap_dump_open_finish(wdh, filetype, err)) {
602                 /* Get rid of the file we created; we couldn't finish
603                    opening it. */
604                 if (wdh->fh != stdout)
605                         unlink(filename);
606                 return NULL;
607         }
608         return wdh;
609 }
610
611 wtap_dumper* wtap_dump_fdopen(int fd, int filetype, int encap, int snaplen,
612                                 int *err)
613 {
614         wtap_dumper *wdh;
615         FILE *fh;
616
617         /* Check whether we can open a capture file with that file type
618            and that encapsulation. */
619         if (!wtap_dump_open_check(filetype, encap, err))
620                 return NULL;
621
622         /* Allocate a data structure for the output stream. */
623         wdh = wtap_dump_alloc_wdh(filetype, encap, snaplen, err);
624         if (wdh == NULL)
625                 return NULL;    /* couldn't allocate it */
626
627         /* In case "fopen()" fails but doesn't set "errno", set "errno"
628            to a generic "the open failed" error. */
629         errno = WTAP_ERR_CANT_OPEN;
630         fh = fdopen(fd, "wb");
631         if (fh == NULL) {
632                 *err = errno;
633                 return NULL;    /* can't create standard I/O stream */
634         }
635         wdh->fh = fh;
636
637         if (!wtap_dump_open_finish(wdh, filetype, err))
638                 return NULL;
639         return wdh;
640 }
641
642 static gboolean wtap_dump_open_check(int filetype, int encap, int *err)
643 {
644         if (!wtap_dump_can_open(filetype)) {
645                 /* Invalid type, or type we don't know how to write. */
646                 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
647                 return FALSE;
648         }
649
650         /* OK, we know how to write that type; can we write the specified
651            encapsulation type? */
652         *err = (*dump_open_table[filetype].can_write_encap)(encap);
653         if (*err != 0)
654                 return FALSE;
655
656         /* All systems go! */
657         return TRUE;
658 }
659
660 static wtap_dumper* wtap_dump_alloc_wdh(int filetype, int encap, int snaplen,
661                                         int *err)
662 {
663         wtap_dumper *wdh;
664
665         wdh = g_malloc(sizeof (wtap_dumper));
666         if (wdh == NULL) {
667                 *err = errno;
668                 return NULL;
669         }
670         wdh->fh = NULL;
671         wdh->file_type = filetype;
672         wdh->snaplen = snaplen;
673         wdh->encap = encap;
674         wdh->bytes_dumped = 0;
675         wdh->dump.opaque = NULL;
676         wdh->subtype_write = NULL;
677         wdh->subtype_close = NULL;
678         return wdh;
679 }
680
681 static gboolean wtap_dump_open_finish(wtap_dumper *wdh, int filetype, int *err)
682 {
683         int fd;
684         gboolean cant_seek;
685
686         /* Can we do a seek on the file descriptor?
687            If not, note that fact. */
688         fd = fileno(wdh->fh);
689         if (lseek(fd, 1, SEEK_CUR) == -1)
690           cant_seek = TRUE;
691         else {
692           /* Undo the seek. */
693           lseek(fd, 0, SEEK_SET);
694           cant_seek = FALSE;
695         }
696
697         /* Now try to open the file for writing. */
698         if (!(*dump_open_table[filetype].dump_open)(wdh, cant_seek, err)) {
699                 /* The attempt failed.  Close the stream for the file.
700                    NOTE: this means the FD handed to "wtap_dump_fdopen()"
701                    will be closed if the open fails. */
702                 if (wdh->fh != stdout)
703                         fclose(wdh->fh);
704
705                 /* Now free up the dumper handle. */
706                 g_free(wdh);
707                 return FALSE;
708         }
709
710         return TRUE;    /* success! */
711 }
712
713 FILE* wtap_dump_file(wtap_dumper *wdh)
714 {
715         return wdh->fh;
716 }
717
718 gboolean wtap_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
719     const union wtap_pseudo_header *pseudo_header, const guchar *pd, int *err)
720 {
721         return (wdh->subtype_write)(wdh, phdr, pseudo_header, pd, err);
722 }
723
724 gboolean wtap_dump_close(wtap_dumper *wdh, int *err)
725 {
726         gboolean ret = TRUE;
727
728         if (wdh->subtype_close != NULL) {
729                 /* There's a close routine for this dump stream. */
730                 if (!(wdh->subtype_close)(wdh, err))
731                         ret = FALSE;
732         }
733         errno = WTAP_ERR_CANT_CLOSE;
734         /* Don't close stdout */
735         if (wdh->fh != stdout) {
736                 if (fclose(wdh->fh) == EOF) {
737                         if (ret) {
738                                 /* The per-format close function succeeded,
739                                    but the fclose didn't.  Save the reason
740                                    why, if our caller asked for it. */
741                                 if (err != NULL)
742                                         *err = errno;
743                         }
744                         ret = FALSE;
745                 }
746         }
747         if (wdh->dump.opaque != NULL)
748                 g_free(wdh->dump.opaque);
749         g_free(wdh);
750         return ret;
751 }
752
753 long wtap_get_bytes_dumped(wtap_dumper *wdh)
754 {
755         return wdh->bytes_dumped;
756 }
757
758 void wtap_set_bytes_dumped(wtap_dumper *wdh, long bytes_dumped)
759 {
760         wdh->bytes_dumped = bytes_dumped;
761 }
762