08b4d72384c5b09ed8423ef7d075f0c8348c0ffe
[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         gboolean        can_compress;
342         int     (*can_write_encap)(int);
343         int     (*dump_open)(wtap_dumper *, gboolean, int *);
344 } dump_open_table[WTAP_NUM_FILE_TYPES] = {
345         /* WTAP_FILE_UNKNOWN */
346         { NULL, NULL, FALSE,
347           NULL, NULL },
348
349         /* WTAP_FILE_WTAP */
350         { "Wiretap (Ethereal)", NULL, FALSE,
351           NULL, NULL },
352
353         /* WTAP_FILE_PCAP */
354         { "libpcap (tcpdump, Ethereal, etc.)", "libpcap", TRUE,
355           libpcap_dump_can_write_encap, libpcap_dump_open },
356
357         /* WTAP_FILE_PCAP_SS990417 */
358         { "RedHat Linux 6.1 libpcap (tcpdump)", "rh6_1libpcap", TRUE,
359           libpcap_dump_can_write_encap, libpcap_dump_open },
360
361         /* WTAP_FILE_PCAP_SS990915 */
362         { "SuSE Linux 6.3 libpcap (tcpdump)", "suse6_3libpcap", TRUE,
363           libpcap_dump_can_write_encap, libpcap_dump_open },
364
365         /* WTAP_FILE_PCAP_SS991029 */
366         { "modified libpcap (tcpdump)", "modlibpcap", TRUE,
367           libpcap_dump_can_write_encap, libpcap_dump_open },
368
369         /* WTAP_FILE_PCAP_NOKIA */
370         { "Nokia libpcap (tcpdump)", "nokialibpcap", TRUE,
371           libpcap_dump_can_write_encap, libpcap_dump_open },
372
373         /* WTAP_FILE_PCAP_AIX */
374         { "AIX libpcap (tcpdump)", NULL, TRUE,
375           NULL, NULL },
376
377         /* WTAP_FILE_PCAP_NSEC */
378         { "Nanosecond libpcap (Ethereal)", "nseclibpcap", TRUE,
379           libpcap_dump_can_write_encap, libpcap_dump_open },
380
381         /* WTAP_FILE_LANALYZER */
382         { "Novell LANalyzer","lanalyzer", FALSE,
383           lanalyzer_dump_can_write_encap, lanalyzer_dump_open },
384
385         /* WTAP_FILE_NGSNIFFER_UNCOMPRESSED */
386         { "Network Associates Sniffer (DOS-based)", "ngsniffer", FALSE,
387           ngsniffer_dump_can_write_encap, ngsniffer_dump_open },
388
389         /* WTAP_FILE_NGSNIFFER_COMPRESSED */
390         { "Network Associates Sniffer (DOS-based), compressed", "ngsniffer_comp", FALSE,
391           NULL, NULL },
392
393         /* WTAP_FILE_SNOOP */
394         { "Sun snoop", "snoop", FALSE,
395           snoop_dump_can_write_encap, snoop_dump_open },
396
397         /* WTAP_FILE_SHOMITI */
398         { "Shomiti/Finisar Surveyor", "shomiti", FALSE,
399           NULL, NULL },
400
401         /* WTAP_FILE_IPTRACE_1_0 */
402         { "AIX iptrace 1.0", NULL, FALSE,
403           NULL, NULL },
404
405         /* WTAP_FILE_IPTRACE_2_0 */
406         { "AIX iptrace 2.0", NULL, FALSE,
407           NULL, NULL },
408
409         /* WTAP_FILE_NETMON_1_x */
410         { "Microsoft Network Monitor 1.x", "netmon1", FALSE,
411           netmon_dump_can_write_encap, netmon_dump_open },
412
413         /* WTAP_FILE_NETMON_2_x */
414         { "Microsoft Network Monitor 2.x", "netmon2", FALSE,
415           netmon_dump_can_write_encap, netmon_dump_open },
416
417         /* WTAP_FILE_NETXRAY_OLD */
418         { "Cinco Networks NetXRay 1.x", NULL, FALSE,
419           NULL, NULL },
420
421         /* WTAP_FILE_NETXRAY_1_0 */
422         { "Cinco Networks NetXRay 2.0 or later", NULL, FALSE,
423           NULL, NULL },
424
425         /* WTAP_FILE_NETXRAY_1_1 */
426         { "Network Associates Sniffer (Windows-based) 1.1", "ngwsniffer_1_1", FALSE,
427           netxray_dump_can_write_encap_1_1, netxray_dump_open_1_1 },
428
429         /* WTAP_FILE_NETXRAY_2_00x */
430         { "Network Associates Sniffer (Windows-based) 2.00x", "ngwsniffer_2_0", FALSE,
431           netxray_dump_can_write_encap_2_0, netxray_dump_open_2_0 },
432
433         /* WTAP_FILE_RADCOM */
434         { "RADCOM WAN/LAN analyzer", NULL, FALSE,
435           NULL, NULL },
436
437         /* WTAP_FILE_ASCEND */
438         { "Lucent/Ascend access server trace", NULL, FALSE,
439           NULL, NULL },
440
441         /* WTAP_FILE_NETTL */
442         { "HP-UX nettl trace", "nettl", FALSE,
443           nettl_dump_can_write_encap, nettl_dump_open },
444
445         /* WTAP_FILE_TOSHIBA */
446         { "Toshiba Compact ISDN Router snoop trace", NULL, FALSE,
447           NULL, NULL },
448
449         /* WTAP_FILE_I4BTRACE */
450         { "I4B ISDN trace", NULL, FALSE,
451           NULL, NULL },
452
453         /* WTAP_FILE_CSIDS */
454         { "CSIDS IPLog", NULL, FALSE,
455           NULL, NULL },
456
457         /* WTAP_FILE_PPPDUMP */
458         { "pppd log (pppdump format)", NULL, FALSE,
459           NULL, NULL },
460
461         /* WTAP_FILE_ETHERPEEK_V56 */
462         { "EtherPeek/TokenPeek trace (V5 & V6 file format)", NULL, FALSE,
463           NULL, NULL },
464
465         /* WTAP_FILE_ETHERPEEK_V7 */
466         { "EtherPeek/TokenPeek/AiroPeek trace (V7 file format)", NULL, FALSE,
467           NULL, NULL },
468
469         /* WTAP_FILE_VMS */
470         { "TCPIPtrace (VMS)", NULL, FALSE,
471           NULL, NULL},
472
473         /* WTAP_FILE_DBS_ETHERWATCH */
474         { "DBS Etherwatch (VMS)", NULL, FALSE,
475           NULL, NULL},
476
477         /* WTAP_FILE_VISUAL_NETWORKS */
478         { "Visual Networks traffic capture", "visual", FALSE,
479           visual_dump_can_write_encap, visual_dump_open },
480
481         /* WTAP_FILE_COSINE */
482         { "CoSine IPSX L2 capture", "cosine", FALSE,
483           NULL, NULL },
484
485         /* WTAP_FILE_5VIEWS */
486         { "Accellent 5Views capture", "5views", FALSE,
487           _5views_dump_can_write_encap, _5views_dump_open },
488
489         /* WTAP_FILE_ERF */
490         { "Endace DAG capture", "erf", FALSE,
491           NULL, NULL },
492
493         /* WTAP_FILE_HCIDUMP */
494         { "Bluetooth HCI dump", "hcidump", FALSE,
495           NULL, NULL },
496
497         /* WTAP_FILE_NETWORK_INSTRUMENTS_V9 */
498         { "Network Instruments Observer version 9", "niobserverv9", FALSE,
499           network_instruments_dump_can_write_encap, network_instruments_dump_open },
500
501         /* WTAP_FILE_AIROPEEK_V9 */
502         { "EtherPeek/AiroPeek trace (V9 file format)", NULL, FALSE,
503           NULL, NULL },
504     
505         /* WTAP_FILE_EYESDN */
506         { "EyeSDN USB S0/E1 ISDN trace format", NULL, FALSE,
507                 NULL, NULL },
508     
509         /* WTAP_FILE_K12 */
510         { "Tektronix K12xx 32-bit .rf5 format", "rf5", FALSE,
511                 k12_dump_can_write_encap, k12_dump_open },
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         /* Empty filename means stdout */
607         if (*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                         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         /* In case "fopen()" fails but doesn't set "errno", set "errno"
659            to a generic "the open failed" error. */
660         errno = WTAP_ERR_CANT_OPEN;
661         fh = wtap_dump_file_fdopen(wdh, fd);
662         if (fh == NULL) {
663                 *err = errno;
664                 g_free(wdh);
665                 return NULL;    /* can't create standard I/O stream */
666         }
667         wdh->fh = fh;
668
669         if (!wtap_dump_open_finish(wdh, filetype, compressed, err)) {
670                 wtap_dump_file_close(wdh);
671                 g_free(wdh);
672                 return NULL;
673         }
674         return wdh;
675 }
676
677 static gboolean wtap_dump_open_check(int filetype, int encap, gboolean compressed, int *err)
678 {
679         if (!wtap_dump_can_open(filetype)) {
680                 /* Invalid type, or type we don't know how to write. */
681                 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
682                 return FALSE;
683         }
684
685         /* OK, we know how to write that type; can we write the specified
686            encapsulation type? */
687         *err = (*dump_open_table[filetype].can_write_encap)(encap);
688         if (*err != 0)
689                 return FALSE;
690
691         /* if compression is wanted, do we support this for this filetype? */
692         if(compressed && !wtap_dump_can_compress(filetype)) {
693                 *err = WTAP_ERR_COMPRESSION_NOT_SUPPORTED;
694                 return FALSE;
695         }
696
697         *err = (*dump_open_table[filetype].can_write_encap)(encap);
698         if (*err != 0)
699                 return FALSE;
700
701
702         /* All systems go! */
703         return TRUE;
704 }
705
706 static wtap_dumper* wtap_dump_alloc_wdh(int filetype, int encap, int snaplen,
707                                         gboolean compressed, int *err)
708 {
709         wtap_dumper *wdh;
710
711         wdh = g_malloc(sizeof (wtap_dumper));
712         if (wdh == NULL) {
713                 *err = errno;
714                 return NULL;
715         }
716         wdh->fh = NULL;
717         wdh->file_type = filetype;
718         wdh->snaplen = snaplen;
719         wdh->encap = encap;
720         wdh->compressed = compressed;
721         wdh->bytes_dumped = 0;
722         wdh->dump.opaque = NULL;
723         wdh->subtype_write = NULL;
724         wdh->subtype_close = NULL;
725         return wdh;
726 }
727
728 static gboolean wtap_dump_open_finish(wtap_dumper *wdh, int filetype, gboolean compressed, int *err)
729 {
730         int fd;
731         gboolean cant_seek;
732
733         /* Can we do a seek on the file descriptor?
734            If not, note that fact. */
735         if(compressed) {
736                 cant_seek = TRUE;
737         } else {
738                 fd = fileno(wdh->fh);
739                 if (lseek(fd, 1, SEEK_CUR) == -1)
740                   cant_seek = TRUE;
741                 else {
742                   /* Undo the seek. */
743                   lseek(fd, 0, SEEK_SET);
744                   cant_seek = FALSE;
745                 }
746         }
747
748         /* Now try to open the file for writing. */
749         if (!(*dump_open_table[filetype].dump_open)(wdh, cant_seek, err)) {
750                 return FALSE;
751         }
752
753         return TRUE;    /* success! */
754 }
755
756 gboolean wtap_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
757     const union wtap_pseudo_header *pseudo_header, const guchar *pd, int *err)
758 {
759         return (wdh->subtype_write)(wdh, phdr, pseudo_header, pd, err);
760 }
761
762 void wtap_dump_flush(wtap_dumper *wdh)
763 {
764 #ifdef HAVE_LIBZ
765         if(wdh->compressed) {
766                 gzflush(wdh->fh, Z_SYNC_FLUSH); /* XXX - is Z_SYNC_FLUSH the right one? */
767         } else 
768 #endif
769         {
770                 fflush(wdh->fh);
771         }
772 }
773
774 gboolean wtap_dump_close(wtap_dumper *wdh, int *err)
775 {
776         gboolean ret = TRUE;
777
778         if (wdh->subtype_close != NULL) {
779                 /* There's a close routine for this dump stream. */
780                 if (!(wdh->subtype_close)(wdh, err))
781                         ret = FALSE;
782         }
783         errno = WTAP_ERR_CANT_CLOSE;
784         /* Don't close stdout */
785         if (wdh->fh != stdout) {
786                 if (wtap_dump_file_close(wdh) == EOF) {
787                         if (ret) {
788                                 /* The per-format close function succeeded,
789                                    but the fclose didn't.  Save the reason
790                                    why, if our caller asked for it. */
791                                 if (err != NULL)
792                                         *err = errno;
793                         }
794                         ret = FALSE;
795                 }
796         }
797         if (wdh->dump.opaque != NULL)
798                 g_free(wdh->dump.opaque);
799         g_free(wdh);
800         return ret;
801 }
802
803 long wtap_get_bytes_dumped(wtap_dumper *wdh)
804 {
805         return wdh->bytes_dumped;
806 }
807
808 void wtap_set_bytes_dumped(wtap_dumper *wdh, long bytes_dumped)
809 {
810         wdh->bytes_dumped = bytes_dumped;
811 }
812
813
814 /* internally open a file for writing (compressed or not) */
815 static FILE *wtap_dump_file_open(wtap_dumper *wdh, const char *filename)
816 {
817 #ifdef HAVE_LIBZ
818         if(wdh->compressed) {
819                 return gzopen(filename, "wb");
820         } else 
821 #endif
822         {
823                 return fopen(filename, "wb");
824         }
825 }
826
827 /* internally open a file for writing (compressed or not) */
828 static FILE *wtap_dump_file_fdopen(wtap_dumper *wdh, int fd)
829 {
830 #ifdef HAVE_LIBZ
831         if(wdh->compressed) {
832                 return gzdopen(fd, "wb");
833         } else 
834 #endif
835         {
836                 return fdopen(fd, "wb");
837         }
838 }
839
840 /* internally writing raw bytes (compressed or not) */
841 size_t wtap_dump_file_write(wtap_dumper *wdh, const void *buf, unsigned bufsize)
842 {
843 #ifdef HAVE_LIBZ
844         if(wdh->compressed) {
845                 return gzwrite(wdh->fh, buf, bufsize);
846         } else 
847 #endif
848         {
849                 return fwrite(buf, 1, bufsize, wdh->fh);
850         }
851 }
852
853 /* internally close a file for writing (compressed or not) */
854 static int wtap_dump_file_close(wtap_dumper *wdh)
855 {
856 #ifdef HAVE_LIBZ
857         if(wdh->compressed) {
858                 return gzclose(wdh->fh);
859         } else 
860 #endif
861         {
862                 return fclose(wdh->fh);
863         }
864 }
865
866 int wtap_dump_file_ferror(wtap_dumper *wdh)
867 {
868 #ifdef HAVE_LIBZ
869         int errnum;
870
871         if(wdh->compressed) {
872                 gzerror(wdh->fh, &errnum);
873
874                 if(errnum == Z_ERRNO) {
875                         return errno;
876                 } else {
877                         /* XXX - what to do with this zlib specific number? */
878                         return errnum;
879                 }
880         } else 
881 #endif
882         {
883                 return ferror(wdh->fh);
884         }
885 }
886