3 * $Id: file.c,v 1.94 2002/07/16 07:15:08 guy Exp $
6 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
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.
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.
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.
35 #ifdef HAVE_SYS_STAT_H
46 #include <io.h> /* open/close on win32 */
50 #include "file_wrappers.h"
52 #include "lanalyzer.h"
53 #include "ngsniffer.h"
66 #include "etherpeek.h"
68 #include "dbs-etherwatch.h"
71 /* The open_file_* routines should return:
75 * 1 if the file they're reading is one of the types it handles;
77 * 0 if the file they're reading isn't the type they're checking for.
79 * If the routine handles this type of file, it should set the "file_type"
80 * field in the "struct wtap" to the type of the file.
82 * XXX - I need to drag my damn ANSI C spec in to figure out how to
83 * declare a "const" array of pointers to functions; putting "const"
84 * right after "static" isn't the right answer, at least according
85 * to GCC, which whines if I do that.
87 * Put the trace files that are merely saved telnet-sessions last, since it's
88 * possible that you could have captured someone a router telnet-session
89 * using another tool. So, a libpcap trace of an toshiba "snoop" session
90 * should be discovered as a libpcap file, not a toshiba file.
93 static int (*open_routines[])(wtap *, int *) = {
94 /* Files that have magic bytes in fixed locations. These
95 * are easy to identify.
108 /* Files that don't have magic bytes at a fixed location,
109 * but that instead require a heuristic of some sort to
110 * identify them. This includes the ASCII trace files that
111 * would be, for example, saved copies of a Telnet session
124 #define N_FILE_TYPES (sizeof open_routines / sizeof open_routines[0])
126 gboolean wtap_def_seek_read(wtap *wth, long seek_off,
127 union wtap_pseudo_header *pseudo_header _U_,
128 guint8 *pd, int len, int *err)
132 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
135 bytes_read = file_read(pd, sizeof(guint8), len, wth->random_fh);
136 if (bytes_read != len) {
137 *err = file_error(wth->random_fh);
139 *err = WTAP_ERR_SHORT_READ;
146 * Visual C++ on Win32 systems doesn't define these. (Old UNIX systems don't
147 * define them either.)
149 * Visual C++ on Win32 systems doesn't define S_IFIFO, it defines _S_IFIFO.
152 #define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
155 #define S_IFIFO _S_IFIFO
158 #define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)
161 #define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
164 /* Opens a file and prepares a wtap struct.
165 If "do_random" is TRUE, it opens the file twice; the second open
166 allows the application to do random-access I/O without moving
167 the seek offset for sequential I/O, which is used by Ethereal
168 so that it can do sequential I/O to a capture file that's being
169 written to as new packets arrive independently of random I/O done
170 to display protocol trees for packets when they're selected. */
171 wtap* wtap_open_offline(const char *filename, int *err, gboolean do_random)
177 /* First, make sure the file is valid */
178 if (stat(filename, &statb) < 0) {
182 if (S_ISFIFO(statb.st_mode)) {
184 * Opens of FIFOs are allowed only when not opening
187 * XXX - currently, we do seeking when trying to find
188 * out the file type, so we don't actually support
189 * opening FIFOs. However, we may eventually
190 * do buffering that allows us to do at least some
191 * file type determination even on pipes, so we
192 * allow FIFO opens and let things fail later when
196 *err = WTAP_ERR_RANDOM_OPEN_PIPE;
199 } else if (S_ISDIR(statb.st_mode)) {
201 * Return different errors for "this is a directory"
202 * and "this is some random special file type", so
203 * the user can get a potentially more helpful error.
207 } else if (! S_ISREG(statb.st_mode)) {
208 *err = WTAP_ERR_NOT_REGULAR_FILE;
213 wth = g_malloc(sizeof(wtap));
219 /* Win32 needs the O_BINARY flag for open() */
225 errno = WTAP_ERR_CANT_OPEN;
226 wth->fd = open(filename, O_RDONLY|O_BINARY);
232 if (!(wth->fh = filed_open(wth->fd, "rb"))) {
239 if (!(wth->random_fh = file_open(filename, "rb"))) {
246 wth->random_fh = NULL;
249 wth->file_encap = WTAP_ENCAP_UNKNOWN;
250 wth->data_offset = 0;
251 wth->subtype_sequential_close = NULL;
252 wth->subtype_close = NULL;
254 /* Try all file types */
255 for (i = 0; i < N_FILE_TYPES; i++) {
256 /* Seek back to the beginning of the file; the open routine
257 for the previous file type may have left the file
258 position somewhere other than the beginning, and the
259 open routine for this file type will probably want
260 to start reading at the beginning.
262 Initialize the data offset while we're at it. */
263 if (file_seek(wth->fh, 0, SEEK_SET, err) == -1) {
264 /* I/O error - give up */
265 if (wth->random_fh != NULL)
266 file_close(wth->random_fh);
271 wth->data_offset = 0;
272 switch ((*open_routines[i])(wth, err)) {
275 /* I/O error - give up */
276 if (wth->random_fh != NULL)
277 file_close(wth->random_fh);
283 /* No I/O error, but not that type of file */
287 /* We found the file type */
292 /* Well, it's not one of the types of file we know about. */
293 if (wth->random_fh != NULL)
294 file_close(wth->random_fh);
297 *err = WTAP_ERR_FILE_UNKNOWN_FORMAT;
301 wth->frame_buffer = g_malloc(sizeof(struct Buffer));
302 buffer_init(wth->frame_buffer, 1500);
306 /* Table of the file types we know about. */
307 static const struct file_type_info {
309 const char *short_name;
310 int (*can_write_encap)(int);
311 int (*dump_open)(wtap_dumper *, gboolean, int *);
312 } dump_open_table[WTAP_NUM_FILE_TYPES] = {
313 /* WTAP_FILE_UNKNOWN */
318 { "Wiretap (Ethereal)", NULL,
322 { "libpcap (tcpdump, Ethereal, etc.)", "libpcap",
323 libpcap_dump_can_write_encap, libpcap_dump_open },
325 /* WTAP_FILE_PCAP_SS990417 */
326 { "Red Hat Linux 6.1 libpcap (tcpdump)", "rh6_1libpcap",
327 libpcap_dump_can_write_encap, libpcap_dump_open },
329 /* WTAP_FILE_PCAP_SS990915 */
330 { "SuSE Linux 6.3 libpcap (tcpdump)", "suse6_3libpcap",
331 libpcap_dump_can_write_encap, libpcap_dump_open },
333 /* WTAP_FILE_PCAP_SS991029 */
334 { "modified libpcap (tcpdump)", "modlibpcap",
335 libpcap_dump_can_write_encap, libpcap_dump_open },
337 /* WTAP_FILE_PCAP_NOKIA */
338 { "Nokia libpcap (tcpdump)", "nokialibpcap",
339 libpcap_dump_can_write_encap, libpcap_dump_open },
341 /* WTAP_FILE_PCAP_AIX */
342 { "AIX libpcap (tcpdump)", NULL,
345 /* WTAP_FILE_LANALYZER */
346 { "Novell LANalyzer","lanalyzer",
347 lanalyzer_dump_can_write_encap, lanalyzer_dump_open },
349 /* WTAP_FILE_NGSNIFFER_UNCOMPRESSED */
350 { "Network Associates Sniffer (DOS-based)", "ngsniffer",
351 ngsniffer_dump_can_write_encap, ngsniffer_dump_open },
353 /* WTAP_FILE_NGSNIFFER_COMPRESSED */
354 { "Network Associates Sniffer (DOS-based), compressed", "ngsniffer_comp",
357 /* WTAP_FILE_SNOOP */
358 { "Sun snoop", "snoop",
359 snoop_dump_can_write_encap, snoop_dump_open },
361 /* WTAP_FILE_IPTRACE_1_0 */
362 { "AIX iptrace 1.0", NULL,
365 /* WTAP_FILE_IPTRACE_2_0 */
366 { "AIX iptrace 2.0", NULL,
369 /* WTAP_FILE_NETMON_1_x */
370 { "Microsoft Network Monitor 1.x", "netmon1",
371 netmon_dump_can_write_encap, netmon_dump_open },
373 /* WTAP_FILE_NETMON_2_x */
374 { "Microsoft Network Monitor 2.x", "netmon2",
375 netmon_dump_can_write_encap, netmon_dump_open },
377 /* WTAP_FILE_NETXRAY_OLD */
378 { "Cinco Networks NetXRay 1.x", NULL,
381 /* WTAP_FILE_NETXRAY_1_0 */
382 { "Cinco Networks NetXRay 2.0 or later", NULL,
385 /* WTAP_FILE_NETXRAY_1_1 */
386 { "Network Associates Sniffer (Windows-based) 1.1", "ngwsniffer_1_1",
387 netxray_dump_can_write_encap, netxray_dump_open_1_1 },
389 /* WTAP_FILE_NETXRAY_2_00x */
390 { "Network Associates Sniffer (Windows-based) 2.00x", "ngwsniffer_2_0",
391 netxray_dump_can_write_encap, netxray_dump_open_2_0 },
393 /* WTAP_FILE_RADCOM */
394 { "RADCOM WAN/LAN analyzer", NULL,
397 /* WTAP_FILE_ASCEND */
398 { "Lucent/Ascend access server trace", NULL,
401 /* WTAP_FILE_NETTL */
402 { "HP-UX nettl trace", NULL,
405 /* WTAP_FILE_TOSHIBA */
406 { "Toshiba Compact ISDN Router snoop trace", NULL,
409 /* WTAP_FILE_I4BTRACE */
410 { "I4B ISDN trace", NULL,
413 /* WTAP_FILE_CSIDS */
414 { "CSIDS IPLog", NULL,
417 /* WTAP_FILE_PPPDUMP */
418 { "pppd log (pppdump format)", NULL,
421 /* WTAP_FILE_ETHERPEEK_V56 */
422 { "EtherPeek/TokenPeek trace (V5 & V6 file format)", NULL,
425 /* WTAP_FILE_ETHERPEEK_V7 */
426 { "EtherPeek/TokenPeek/AiroPeek trace (V7 file format)", NULL,
430 { "TCPIPtrace (VMS)", NULL,
433 /* WTAP_FILE_DBS_ETHERWATCH */
434 { "DBS Etherwatch (VMS)", NULL,
437 /* WTAP_FILE_VISUAL_NETWORKS */
438 { "Visual Networks traffic capture", "visual",
439 visual_dump_can_write_encap, visual_dump_open },
442 /* Name that should be somewhat descriptive. */
443 const char *wtap_file_type_string(int filetype)
445 if (filetype < 0 || filetype >= WTAP_NUM_FILE_TYPES) {
446 g_error("Unknown capture file type %d", filetype);
449 return dump_open_table[filetype].name;
452 /* Name to use in, say, a command-line flag specifying the type. */
453 const char *wtap_file_type_short_string(int filetype)
455 if (filetype < 0 || filetype >= WTAP_NUM_FILE_TYPES)
458 return dump_open_table[filetype].short_name;
461 /* Translate a short name to a capture file type. */
462 int wtap_short_string_to_file_type(const char *short_name)
466 for (filetype = 0; filetype < WTAP_NUM_FILE_TYPES; filetype++) {
467 if (dump_open_table[filetype].short_name != NULL &&
468 strcmp(short_name, dump_open_table[filetype].short_name) == 0)
471 return -1; /* no such file type, or we can't write it */
474 gboolean wtap_dump_can_open(int filetype)
476 if (filetype < 0 || filetype >= WTAP_NUM_FILE_TYPES
477 || dump_open_table[filetype].dump_open == NULL)
483 gboolean wtap_dump_can_write_encap(int filetype, int encap)
485 if (filetype < 0 || filetype >= WTAP_NUM_FILE_TYPES
486 || dump_open_table[filetype].can_write_encap == NULL)
489 if ((*dump_open_table[filetype].can_write_encap)(encap) != 0)
495 static gboolean wtap_dump_open_check(int filetype, int encap, int *err);
496 static wtap_dumper* wtap_dump_alloc_wdh(int filetype, int encap, int snaplen,
498 static gboolean wtap_dump_open_finish(wtap_dumper *wdh, int filetype, int *err);
500 wtap_dumper* wtap_dump_open(const char *filename, int filetype, int encap,
501 int snaplen, int *err)
506 /* Check whether we can open a capture file with that file type
507 and that encapsulation. */
508 if (!wtap_dump_open_check(filetype, encap, err))
511 /* Allocate a data structure for the output stream. */
512 wdh = wtap_dump_alloc_wdh(filetype, encap, snaplen, err);
514 return NULL; /* couldn't allocate it */
516 /* Empty filename means stdout */
517 if (*filename == '\0')
520 /* In case "fopen()" fails but doesn't set "errno", set "errno"
521 to a generic "the open failed" error. */
522 errno = WTAP_ERR_CANT_OPEN;
523 fh = fopen(filename, "wb");
526 return NULL; /* can't create file */
531 if (!wtap_dump_open_finish(wdh, filetype, err)) {
532 /* Get rid of the file we created; we couldn't finish
534 if (wdh->fh != stdout)
541 wtap_dumper* wtap_dump_fdopen(int fd, int filetype, int encap, int snaplen,
547 /* Check whether we can open a capture file with that file type
548 and that encapsulation. */
549 if (!wtap_dump_open_check(filetype, encap, err))
552 /* Allocate a data structure for the output stream. */
553 wdh = wtap_dump_alloc_wdh(filetype, encap, snaplen, err);
555 return NULL; /* couldn't allocate it */
557 /* In case "fopen()" fails but doesn't set "errno", set "errno"
558 to a generic "the open failed" error. */
559 errno = WTAP_ERR_CANT_OPEN;
560 fh = fdopen(fd, "wb");
563 return NULL; /* can't create standard I/O stream */
567 if (!wtap_dump_open_finish(wdh, filetype, err))
572 static gboolean wtap_dump_open_check(int filetype, int encap, int *err)
574 if (!wtap_dump_can_open(filetype)) {
575 /* Invalid type, or type we don't know how to write. */
576 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
580 /* OK, we know how to write that type; can we write the specified
581 encapsulation type? */
582 *err = (*dump_open_table[filetype].can_write_encap)(encap);
586 /* All systems go! */
590 static wtap_dumper* wtap_dump_alloc_wdh(int filetype, int encap, int snaplen,
595 wdh = g_malloc(sizeof (wtap_dumper));
601 wdh->file_type = filetype;
602 wdh->snaplen = snaplen;
604 wdh->bytes_dumped = 0;
605 wdh->dump.opaque = NULL;
606 wdh->subtype_write = NULL;
607 wdh->subtype_close = NULL;
611 static gboolean wtap_dump_open_finish(wtap_dumper *wdh, int filetype, int *err)
616 /* Can we do a seek on the file descriptor?
617 If not, note that fact. */
618 fd = fileno(wdh->fh);
619 if (lseek(fd, 1, SEEK_CUR) == -1)
623 lseek(fd, 0, SEEK_SET);
627 /* Now try to open the file for writing. */
628 if (!(*dump_open_table[filetype].dump_open)(wdh, cant_seek, err)) {
629 /* The attempt failed. Close the stream for the file.
630 NOTE: this means the FD handed to "wtap_dump_fdopen()"
631 will be closed if the open fails. */
632 if (wdh->fh != stdout)
635 /* Now free up the dumper handle. */
640 return TRUE; /* success! */
643 FILE* wtap_dump_file(wtap_dumper *wdh)
648 gboolean wtap_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
649 const union wtap_pseudo_header *pseudo_header, const u_char *pd, int *err)
651 return (wdh->subtype_write)(wdh, phdr, pseudo_header, pd, err);
654 gboolean wtap_dump_close(wtap_dumper *wdh, int *err)
658 if (wdh->subtype_close != NULL) {
659 /* There's a close routine for this dump stream. */
660 if (!(wdh->subtype_close)(wdh, err))
663 errno = WTAP_ERR_CANT_CLOSE;
664 /* Don't close stdout */
665 if (wdh->fh != stdout) {
666 if (fclose(wdh->fh) == EOF) {
668 /* The per-format close function succeeded,
669 but the fclose didn't. Save the reason
670 why, if our caller asked for it. */
677 if (wdh->dump.opaque != NULL)
678 g_free(wdh->dump.opaque);
683 long wtap_get_bytes_dumped(wtap_dumper *wdh)
685 return wdh->bytes_dumped;
688 void wtap_set_bytes_dumped(wtap_dumper *wdh, long bytes_dumped)
690 wdh->bytes_dumped = bytes_dumped;