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