* 3. This notice may not be removed or altered from any source distribution.
*/
-#include "config.h"
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif /* HAVE_UNISTD_H */
+#include <config.h>
#include <errno.h>
-#include <stdio.h>
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif /* HAVE_FCNTL_H */
#include <string.h>
#include "wtap-int.h"
#include "file_wrappers.h"
#include <wsutil/file_util.h>
-#ifdef HAVE_LIBZ
+#ifdef HAVE_ZLIB
+#define ZLIB_CONST
#include <zlib.h>
-#endif /* HAVE_LIBZ */
+#endif /* HAVE_ZLIB */
/*
* See RFC 1952 for a description of the gzip file format.
* might be expanded to include routines to handle the various
* compression types.
*/
-static const char *compressed_file_extensions[] = {
-#ifdef HAVE_LIBZ
+const char *compressed_file_extension_table[] = {
+#ifdef HAVE_ZLIB
"gz",
#endif
NULL
};
-/*
- * Return a GSList of all the compressed file extensions.
- * The data pointers all point to items in compressed_file_extensions[],
- * so the GSList can just be freed with g_slist_free().
- */
-GSList *
-wtap_get_compressed_file_extensions(void)
-{
- const char **extension;
- GSList *extensions;
-
- extensions = NULL;
- for (extension = &compressed_file_extensions[0]; *extension != NULL;
- extension++)
- extensions = g_slist_append(extensions, (gpointer)(*extension));
- return extensions;
-}
-
/* #define GZBUFSIZE 8192 */
#define GZBUFSIZE 4096
typedef enum {
UNKNOWN, /* unknown - look for a gzip header */
UNCOMPRESSED, /* uncompressed - copy input directly */
-#ifdef HAVE_LIBZ
+#ifdef HAVE_ZLIB
ZLIB, /* decompress a zlib stream */
GZIP_AFTER_HEADER
#endif
guint avail_in; /* number of bytes available at next_in */
unsigned char *next_in; /* next input byte */
-#ifdef HAVE_LIBZ
+#ifdef HAVE_ZLIB
/* zlib inflate stream */
z_stream strm; /* stream structure in-place (not a pointer) */
gboolean dont_check_crc; /* TRUE if we aren't supposed to check the CRC */
*have = 0;
do {
- ret = read(state->fd, buf + *have, count - *have);
+ ret = ws_read(state->fd, buf + *have, count - *have);
if (ret <= 0)
break;
*have += (unsigned)ret;
}
static void
-fast_seek_reset(FILE_T state _U_)
+fast_seek_reset(
+#ifdef HAVE_ZLIB
+ FILE_T state)
+#else
+ FILE_T state _U_)
+#endif
{
-#ifdef HAVE_LIBZ
+#ifdef HAVE_ZLIB
if (state->compression == ZLIB && state->fast_seek_cur) {
struct zlib_cur_seek_point *cur = (struct zlib_cur_seek_point *) state->fast_seek_cur;
#endif
}
-#ifdef HAVE_LIBZ
+#ifdef HAVE_ZLIB
/* Get next byte from input, or -1 if end or error.
*
ret = inflate(strm, Z_NO_FLUSH);
#endif
state->avail_in = strm->avail_in;
+#ifdef z_const
+DIAG_OFF(cast-qual)
+ state->next_in = (unsigned char *)strm->next_in;
+DIAG_ON(cast-qual)
+#else
state->next_in = strm->next_in;
+#endif
if (ret == Z_STREAM_ERROR) {
state->err = WTAP_ERR_DECOMPRESS;
state->err_info = strm->msg;
if (crc != strm->adler && !state->dont_check_crc) {
state->err = WTAP_ERR_DECOMPRESS;
state->err_info = "bad CRC";
- } else if (len != (strm->total_out & 0xffffffffL)) {
+ } else if (len != (strm->total_out & 0xffffffffUL)) {
state->err = WTAP_ERR_DECOMPRESS;
state->err_info = "length field wrong";
}
}
/* look for the gzip magic header bytes 31 and 139 */
-#ifdef HAVE_LIBZ
+#ifdef HAVE_ZLIB
if (state->next_in[0] == 31) {
state->avail_in--;
state->next_in++;
return -1;
state->next = state->out;
}
-#ifdef HAVE_LIBZ
+#ifdef HAVE_ZLIB
else if (state->compression == ZLIB) { /* decompress */
zlib_read(state, state->out, state->size << 1);
}
return NULL;
}
-#ifdef HAVE_LIBZ
+#ifdef HAVE_ZLIB
/* allocate inflate memory */
state->strm.zalloc = Z_NULL;
state->strm.zfree = Z_NULL;
{
int fd;
FILE_T ft;
-#ifdef HAVE_LIBZ
+#ifdef HAVE_ZLIB
const char *suffixp;
#endif
return NULL;
}
-#ifdef HAVE_LIBZ
+#ifdef HAVE_ZLIB
/*
* If this file's name ends in ".caz", it's probably a compressed
* Windows Sniffer file. The compression is gzip, but if we
struct fast_seek_point *here;
guint n;
- /* can only seek from start or relative to current position */
- if (whence != SEEK_SET && whence != SEEK_CUR) {
+ if (whence != SEEK_SET && whence != SEEK_CUR && whence != SEEK_END) {
g_assert_not_reached();
/*
*err = EINVAL;
*/
}
- /* normalize offset to a SEEK_CUR specification */
- if (whence == SEEK_SET)
+ /* Normalize offset to a SEEK_CUR specification */
+ if (whence == SEEK_END) {
+ /* Try skip until end-of-file */
+ if (gz_skip(file, G_MAXINT64) == -1) {
+ *err = file->err;
+ return -1;
+ }
+ if (offset == 0) {
+ /* We are done */
+ return file->pos;
+ }
+ } else if (whence == SEEK_SET)
offset -= file->pos;
else if (file->seek_pending)
offset += file->skip;
file->seek_pending = FALSE;
+ /*
+ * Are we seeking backwards and, if so, do we have data in the buffer?
+ */
if (offset < 0 && file->next) {
/*
+ * Yes.
+ *
* This is guaranteed to fit in an unsigned int.
* To squelch compiler warnings, we cast the
* result.
*/
guint had = (unsigned)(file->next - file->out);
+
+ /*
+ * Do we have enough data before the current position in
+ * the buffer that we can seek backwards within the buffer?
+ */
if (-offset <= had) {
/*
+ * Yes.
+ *
* Offset is negative, so -offset is
* non-negative, and -offset is
* <= an unsigned and thus fits in an
}
}
- /* XXX, profile */
+ /*
+ * No. Do we have "fast seek" data for the location to which we
+ * will be seeking?
+ *
+ * XXX, profile
+ */
if ((here = fast_seek_find(file, file->pos + offset)) && (offset < 0 || offset > SPAN || here->compression == UNCOMPRESSED)) {
gint64 off, off2;
-#ifdef HAVE_LIBZ
+ /*
+ * Yes. Use that data to do the seek.
+ * Note that this will be true only if file_set_random_access()
+ * has been called on this file, which should never be the case
+ * for a pipe.
+ */
+#ifdef HAVE_ZLIB
if (here->compression == ZLIB) {
#ifdef HAVE_INFLATEPRIME
off = here->in - (here->data.zlib.bits ? 1 : 0);
file->err_info = NULL;
file->avail_in = 0;
-#ifdef HAVE_LIBZ
+#ifdef HAVE_ZLIB
if (here->compression == ZLIB) {
z_stream *strm = &file->strm;
return file->pos + offset;
}
- /* if within raw area while reading, just go there */
+ /*
+ * Is this an uncompressed file, are we within the raw area,
+ * are we either seeking backwards or seeking past the end
+ * of the buffer, and are we set up for random access with
+ * file_set_random_access()?
+ *
+ * Again, note that this will never be true on a pipe, as
+ * file_set_random_access() should never be called if we're
+ * reading from a pipe.
+ */
if (file->compression == UNCOMPRESSED && file->pos + offset >= file->raw
- && (offset < 0 || offset >= file->have) /* seek only when we don't have that offset in buffer */
- && (file->fast_seek) /* seek only when random access is supported */)
+ && (offset < 0 || offset >= file->have)
+ && (file->fast_seek))
{
+ /*
+ * Yes. Just seek there within the file.
+ */
if (ws_lseek64(file->fd, offset - file->have, SEEK_CUR) == -1) {
*err = errno;
return -1;
return file->pos;
}
- /* calculate skip amount, rewinding if needed for back seek when reading */
+ /*
+ * Are we seeking backwards?
+ */
if (offset < 0) {
+ /*
+ * Yes.
+ *
+ * Calculate the amount to skip forward after rewinding.
+ */
offset += file->pos;
if (offset < 0) { /* before start of file! */
*err = EINVAL;
gz_reset(file);
}
- /* skip what's in output buffer (one less gzgetc() check) */
+ /*
+ * No, we're skipping forwards.
+ *
+ * Skip what's in output buffer (one less gzgetc() check).
+ */
n = (gint64)file->have > offset ? (unsigned)offset : file->have;
file->have -= n;
file->next += n;
/* free memory and close file */
if (file->size) {
-#ifdef HAVE_LIBZ
+#ifdef HAVE_ZLIB
inflateEnd(&(file->strm));
#endif
g_free(file->out);
ws_close(fd);
}
-#ifdef HAVE_LIBZ
+#ifdef HAVE_ZLIB
/* internal gzip file state data structure for writing */
struct wtap_writer {
int fd; /* file descriptor */
state = gzwfile_fdopen(fd);
if (state == NULL) {
save_errno = errno;
- close(fd);
+ ws_close(fd);
errno = save_errno;
}
return state;
(flush != Z_FINISH || ret == Z_STREAM_END))) {
have = strm->next_out - state->next;
if (have) {
- got = write(state->fd, state->next, (unsigned int)have);
+ got = ws_write(state->fd, state->next, (unsigned int)have);
if (got < 0) {
state->err = errno;
return -1;
n = state->size - strm->avail_in;
if (n > len)
n = len;
+#ifdef z_const
+DIAG_OFF(cast-qual)
+ memcpy((Bytef *)strm->next_in + strm->avail_in, buf, n);
+DIAG_ON(cast-qual)
+#else
memcpy(strm->next_in + strm->avail_in, buf, n);
+#endif
strm->avail_in += n;
state->pos += n;
buf = (const char *)buf + n;
/* directly compress user buffer to file */
strm->avail_in = len;
+#ifdef z_const
+ strm->next_in = (z_const Bytef *)buf;
+#else
+DIAG_OFF(cast-qual)
strm->next_in = (Bytef *)buf;
+DIAG_ON(cast-qual)
+#endif
state->pos += len;
if (gz_comp(state, Z_NO_FLUSH) == -1)
return 0;
}
/* Flush out all data written, and close the file. Returns a Wiretap
- error on failure; returns 0 on success. */
+ error on failure; returns 0 on success.
+
+ If is_stdout is true, do all of that except for closing the file
+ descriptor, as we don't want to close the standard output file
+ descriptor out from under the program (even though, if the program
+ is writing a capture file to the standard output, it shouldn't be
+ doing anything *else* on the standard output). */
int
-gzwfile_close(GZWFILE_T state)
+gzwfile_close(GZWFILE_T state, gboolean is_stdout)
{
int ret = 0;
g_free(state->out);
g_free(state->in);
state->err = Z_OK;
- if (close(state->fd) == -1 && ret == 0)
- ret = errno;
+ if (!is_stdout) {
+ if (ws_close(state->fd) == -1 && ret == 0)
+ ret = errno;
+ }
g_free(state);
return ret;
}