Skip only the actual file descriptor close when writing to stdout.

Have a "this is stdout" flag for a wtap_dumper, and have "open the
standard output for dumping" routines that set that flag.  When closing
a wtap_dumper, do most of the work regardless of whether we're writing
to the standard output or not (so that everything gets written out) and
only skip the closing of the underlying file descriptor.

Change-Id: I9f7e4d142b3bd598055d806b7ded1cb4c378de8e
Reviewed-on: https://code.wireshark.org/review/11673
Reviewed-by: Guy Harris <guy@alum.mit.edu>
This commit is contained in:
Guy Harris 2015-11-10 02:01:43 -08:00
parent 630ccbe2d7
commit 827b7dd756
9 changed files with 134 additions and 45 deletions

View File

@ -898,10 +898,10 @@ editcap_dump_open(const char *filename, guint32 snaplen,
if (strcmp(filename, "-") == 0) {
/* Write to the standard output. */
pdh = wtap_dump_fdopen_ng(1, out_file_type_subtype, out_frame_type,
snaplen, FALSE /* compressed */,
shb_hdr, idb_inf, nrb_hdr,
write_err);
pdh = wtap_dump_open_stdout_ng(out_file_type_subtype, out_frame_type,
snaplen, FALSE /* compressed */,
shb_hdr, idb_inf, nrb_hdr,
write_err);
} else {
pdh = wtap_dump_open_ng(filename, out_file_type_subtype, out_frame_type,
snaplen, FALSE /* compressed */,

View File

@ -636,7 +636,7 @@ static void randpkt_example_init(randpkt_example* example, char* produce_filenam
if (strcmp(produce_filename, "-") == 0) {
/* Write to the standard output. */
example->dump = wtap_dump_fdopen(1, WTAP_FILE_TYPE_SUBTYPE_PCAP,
example->dump = wtap_dump_open_stdout(WTAP_FILE_TYPE_SUBTYPE_PCAP,
example->sample_wtap_encap, produce_max_bytes, FALSE /* compressed */, &err);
example->filename = "the standard output";
} else {

View File

@ -276,8 +276,8 @@ DIAG_ON(cast-qual)
/* Open outfile (same filetype/encap as input file) */
if (strcmp(outfile, "-") == 0) {
pdh = wtap_dump_fdopen_ng(1, wtap_file_type_subtype(wth), wtap_file_encap(wth),
65535, FALSE, shb_hdr, idb_inf, nrb_hdr, &err);
pdh = wtap_dump_open_stdout_ng(wtap_file_type_subtype(wth), wtap_file_encap(wth),
65535, FALSE, shb_hdr, idb_inf, nrb_hdr, &err);
outfile = "standard output";
} else {
pdh = wtap_dump_open_ng(outfile, wtap_file_type_subtype(wth), wtap_file_encap(wth),

View File

@ -3201,7 +3201,7 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type,
tshark_debug("tshark: writing PCAP format to %s", save_file);
if (strcmp(save_file, "-")) {
/* Write to the standard output. */
pdh = wtap_dump_fdopen(1, out_file_type, linktype,
pdh = wtap_dump_open_stdout(out_file_type, linktype,
snapshot_length, FALSE /* compressed */, &err);
} else {
pdh = wtap_dump_open(save_file, out_file_type, linktype,
@ -3212,7 +3212,7 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type,
tshark_debug("tshark: writing format type %d, to %s", out_file_type, save_file);
if (strcmp(save_file, "-")) {
/* Write to the standard output. */
pdh = wtap_dump_fdopen_ng(1, out_file_type, linktype,
pdh = wtap_dump_open_stdout_ng(out_file_type, linktype,
snapshot_length, FALSE /* compressed */, shb_hdr, idb_inf, nrb_hdr, &err);
} else {
pdh = wtap_dump_open_ng(save_file, out_file_type, linktype,

View File

@ -2231,10 +2231,8 @@ wtap_dump_open_ng(const char *filename, int file_type_subtype, int encap,
if (!wtap_dump_open_finish(wdh, file_type_subtype, compressed, err)) {
/* Get rid of the file we created; we couldn't finish
opening it. */
if (wdh->fh != stdout) {
wtap_dump_file_close(wdh);
ws_unlink(filename);
}
wtap_dump_file_close(wdh);
ws_unlink(filename);
g_free(wdh);
return NULL;
}
@ -2267,17 +2265,6 @@ wtap_dump_fdopen_ng(int fd, int file_type_subtype, int encap, int snaplen,
if (wdh == NULL)
return NULL;
#ifdef _WIN32
if (fd == 1) {
if (_setmode(fileno(stdout), O_BINARY) == -1) {
/* "Should not happen" */
*err = errno;
g_free(wdh);
return NULL; /* couldn't put standard output in binary mode */
}
}
#endif
/* In case "fopen()" fails but doesn't set "errno", set "errno"
to a generic "the open failed" error. */
errno = WTAP_ERR_CANT_OPEN;
@ -2297,6 +2284,68 @@ wtap_dump_fdopen_ng(int fd, int file_type_subtype, int encap, int snaplen,
return wdh;
}
wtap_dumper *
wtap_dump_open_stdout(int file_type_subtype, int encap, int snaplen,
gboolean compressed, int *err)
{
return wtap_dump_open_stdout_ng(file_type_subtype, encap, snaplen, compressed, NULL, NULL, NULL, err);
}
wtap_dumper *
wtap_dump_open_stdout_ng(int file_type_subtype, int encap, int snaplen,
gboolean compressed, wtapng_section_t *shb_hdr,
wtapng_iface_descriptions_t *idb_inf,
wtapng_name_res_t *nrb_hdr, int *err)
{
wtap_dumper *wdh;
WFILE_T fh;
/* Check whether we can open a capture file with that file type
and that encapsulation. */
if (!wtap_dump_open_check(file_type_subtype, encap, compressed, err))
return NULL;
/* Allocate and initialize a data structure for the output stream. */
wdh = wtap_dump_init_dumper(file_type_subtype, encap, snaplen, compressed,
shb_hdr, idb_inf, nrb_hdr, err);
if (wdh == NULL)
return NULL;
#ifdef _WIN32
/*
* Put the standard output into binary mode.
*
* XXX - even if the file format we're writing is a text
* format?
*/
if (_setmode(1, O_BINARY) == -1) {
/* "Should not happen" */
*err = errno;
g_free(wdh);
return NULL; /* couldn't put standard output in binary mode */
}
#endif
/* In case "fopen()" fails but doesn't set "errno", set "errno"
to a generic "the open failed" error. */
errno = WTAP_ERR_CANT_OPEN;
fh = wtap_dump_file_fdopen(wdh, 1);
if (fh == NULL) {
*err = errno;
g_free(wdh);
return NULL; /* can't create standard I/O stream */
}
wdh->fh = fh;
wdh->is_stdout = TRUE;
if (!wtap_dump_open_finish(wdh, file_type_subtype, compressed, err)) {
wtap_dump_file_close(wdh);
g_free(wdh);
return NULL;
}
return wdh;
}
static gboolean
wtap_dump_open_check(int file_type_subtype, int encap, gboolean compressed, int *err)
{
@ -2424,21 +2473,15 @@ wtap_dump_close(wtap_dumper *wdh, int *err)
ret = FALSE;
}
errno = WTAP_ERR_CANT_CLOSE;
/* Don't close stdout */
if (wdh->fh != stdout) {
if (wtap_dump_file_close(wdh) == EOF) {
if (ret) {
/* The per-format close function succeeded,
but the fclose didn't. Save the reason
why, if our caller asked for it. */
if (err != NULL)
*err = errno;
}
ret = FALSE;
if (wtap_dump_file_close(wdh) == EOF) {
if (ret) {
/* The per-format finish function succeeded,
but the stream close didn't. Save the
reason why, if our caller asked for it. */
if (err != NULL)
*err = errno;
}
} else {
/* as we don't close stdout, at least try to flush it */
wtap_dump_flush(wdh);
ret = FALSE;
}
if (wdh->priv != NULL)
g_free(wdh->priv);
@ -2548,11 +2591,22 @@ wtap_dump_file_close(wtap_dumper *wdh)
{
#ifdef HAVE_LIBZ
if(wdh->compressed) {
return gzwfile_close((GZWFILE_T)wdh->fh);
/*
* Tell gzwfile_close() whether to close the descriptor
* or not.
*/
return gzwfile_close((GZWFILE_T)wdh->fh, wdh->is_stdout);
} else
#endif
{
return fclose((FILE *)wdh->fh);
/*
* Don't close the standard output.
*
* XXX - this really should do everything fclose() does,
* including freeing all allocated data structures,
* *except* for actually closing the file descriptor.
*/
return wdh->is_stdout ? fflush((FILE *)wdh->fh) : fclose((FILE *)wdh->fh);
}
}

View File

@ -1719,9 +1719,15 @@ gzwfile_flush(GZWFILE_T state)
}
/* 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;
@ -1732,8 +1738,10 @@ gzwfile_close(GZWFILE_T state)
g_free(state->out);
g_free(state->in);
state->err = Z_OK;
if (ws_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;
}

View File

@ -53,7 +53,7 @@ extern GZWFILE_T gzwfile_open(const char *path);
extern GZWFILE_T gzwfile_fdopen(int fd);
extern guint gzwfile_write(GZWFILE_T state, const void *buf, guint len);
extern int gzwfile_flush(GZWFILE_T state);
extern int gzwfile_close(GZWFILE_T state);
extern int gzwfile_close(GZWFILE_T state, gboolean is_stdout);
extern int gzwfile_geterr(GZWFILE_T state);
#endif /* HAVE_LIBZ */

View File

@ -95,6 +95,7 @@ typedef gboolean (*subtype_finish_func)(struct wtap_dumper*, int*);
struct wtap_dumper {
WFILE_T fh;
gboolean is_stdout;
int file_type_subtype;
int snaplen;
int encap;

View File

@ -1936,6 +1936,7 @@ wtap_dumper* wtap_dump_fdopen(int fd, int file_type_subtype, int encap, int snap
* wtap_dump_close() is called, but will not be free'd by the dumper. If
* you created them, you must free them yourself after wtap_dump_close().
*
* @param fd The file descriptor for which the dumper should be created.
* @param file_type_subtype The WTAP_FILE_TYPE_SUBTYPE_XXX file type.
* @param encap The WTAP_ENCAP_XXX encapsulation type (WTAP_ENCAP_PER_PACKET for multi)
* @param snaplen The maximum packet capture length.
@ -1951,6 +1952,31 @@ wtap_dumper* wtap_dump_fdopen_ng(int fd, int file_type_subtype, int encap, int s
gboolean compressed, wtapng_section_t *shb_hdr, wtapng_iface_descriptions_t *idb_inf,
wtapng_name_res_t *nrb_hdr, int *err);
WS_DLL_PUBLIC
wtap_dumper* wtap_dump_open_stdout(int file_type_subtype, int encap, int snaplen,
gboolean compressed, int *err);
/**
* @brief Creates a dumper for the standard output.
*
* @note The shb_hdr, idb_inf, and nrb_hdr arguments will be used until
* wtap_dump_close() is called, but will not be free'd by the dumper. If
* you created them, you must free them yourself after wtap_dump_close().
*
* @param file_type_subtype The WTAP_FILE_TYPE_SUBTYPE_XXX file type.
* @param encap The WTAP_ENCAP_XXX encapsulation type (WTAP_ENCAP_PER_PACKET for multi)
* @param snaplen The maximum packet capture length.
* @param compressed True if file should be compressed.
* @param shb_hdr The section header block information, or NULL.
* @param idb_inf The interface description information, or NULL.
* @param nrb_hdr The name resolution comment/custom_opts information, or NULL.
* @param[out] err Will be set to an error code on failure.
* @return The newly created dumper object, or NULL on failure.
*/
WS_DLL_PUBLIC
wtap_dumper* wtap_dump_open_stdout_ng(int file_type_subtype, int encap, int snaplen,
gboolean compressed, wtapng_section_t *shb_hdr, wtapng_iface_descriptions_t *idb_inf,
wtapng_name_res_t *nrb_hdr, int *err);
WS_DLL_PUBLIC
gboolean wtap_dump(wtap_dumper *, const struct wtap_pkthdr *, const guint8 *,