Sigh. There appears to be no way to get Windows to allow us to rename a
file that we ourselves have open. In the "safe save" code path for capture files, on Windows temporarily close the file descriptors for the currently-open capture before doing the rename and then, if the rename failed, reopen them, leaving the rest of the wtap and capture_file structures intact. Rename filed_open() to file_fdopen(), to make its name match what it does a bit better (it's an fdopen()-style routine, i.e. do the equivalent of an open with an already-open file descriptor rather than a pathname, in the file_wrappers.c set of routines). Remove the file_ routines from the .def file for Wiretap - they should only be called by code inside Wiretap. Closing a descriptor open for input has no reason to fail (closing a descriptor open for *writing* could fail if the file is on a server and dirty pages are pushed asynchronously to the server and synchronously on a close), so just have file_close() return void. svn path=/trunk/; revision=42961
This commit is contained in:
parent
86c69b01e7
commit
129c881fcf
27
file.c
27
file.c
@ -3850,13 +3850,9 @@ cf_save_packets(capture_file *cf, const char *fname, guint save_format,
|
|||||||
convert it to a file descriptor with _open_osfhandle(),
|
convert it to a file descriptor with _open_osfhandle(),
|
||||||
that would allow the file to be renamed out from under us.
|
that would allow the file to be renamed out from under us.
|
||||||
|
|
||||||
It would also allow it to be deleted out from under us; according
|
However, that doesn't work in practice. Perhaps the problem
|
||||||
to the MSDN documentation on DeleteFile(), "The DeleteFile function
|
is that the process doing the rename is the process that
|
||||||
marks a file for deletion on close. Therefore, the file deletion
|
has the file open. */
|
||||||
does not occur until the last handle to the file is closed.
|
|
||||||
Subsequent calls to CreateFile to open the file fail with
|
|
||||||
ERROR_ACCESS_DENIED.", so it sounds as if deleting it out from
|
|
||||||
under us would be safe. */
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
if (ws_rename(cf->filename, fname) == 0) {
|
if (ws_rename(cf->filename, fname) == 0) {
|
||||||
/* That succeeded - there's no need to copy the source file. */
|
/* That succeeded - there's no need to copy the source file. */
|
||||||
@ -3975,12 +3971,25 @@ cf_save_packets(capture_file *cf, const char *fname, guint save_format,
|
|||||||
|
|
||||||
if (fname_new != NULL) {
|
if (fname_new != NULL) {
|
||||||
/* We wrote out to fname_new, and should rename it on top of
|
/* We wrote out to fname_new, and should rename it on top of
|
||||||
fname; fname is now closed, so that should be possible even
|
fname. fname_new is now closed, so that should be possible even
|
||||||
on Windows. Do the rename. */
|
on Windows. However, on Windows, we first need to close whatever
|
||||||
|
file descriptors we have open for fname. */
|
||||||
|
#ifdef _WIN32
|
||||||
|
wtap_fdclose(cf->wth);
|
||||||
|
#endif
|
||||||
|
/* Now do the rename. */
|
||||||
if (ws_rename(fname_new, fname) == -1) {
|
if (ws_rename(fname_new, fname) == -1) {
|
||||||
/* Well, the rename failed. */
|
/* Well, the rename failed. */
|
||||||
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
|
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
|
||||||
file_rename_error_message(errno), fname);
|
file_rename_error_message(errno), fname);
|
||||||
|
#ifdef _WIN32
|
||||||
|
/* Attempt to reopen the file descriptors using fname. */
|
||||||
|
if (!wtap_fdreopen(cf->wth, fname, &err)) {
|
||||||
|
/* Oh, well, we're screwed. */
|
||||||
|
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
|
||||||
|
file_open_error_message(err, FALSE), fname);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -317,7 +317,7 @@ wtap* wtap_open_offline(const char *filename, int *err, char **err_info,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (!(wth->fh = filed_open(fd))) {
|
if (!(wth->fh = file_fdopen(fd))) {
|
||||||
*err = errno;
|
*err = errno;
|
||||||
ws_close(fd);
|
ws_close(fd);
|
||||||
g_free(wth);
|
g_free(wth);
|
||||||
|
@ -766,7 +766,7 @@ gz_reset(FILE_T state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
FILE_T
|
FILE_T
|
||||||
filed_open(int fd)
|
file_fdopen(int fd)
|
||||||
{
|
{
|
||||||
#ifdef _STATBUF_ST_BLKSIZE /* XXX, _STATBUF_ST_BLKSIZE portable? */
|
#ifdef _STATBUF_ST_BLKSIZE /* XXX, _STATBUF_ST_BLKSIZE portable? */
|
||||||
struct stat st;
|
struct stat st;
|
||||||
@ -862,7 +862,7 @@ file_open(const char *path)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* open file handle */
|
/* open file handle */
|
||||||
ft = filed_open(fd);
|
ft = file_fdopen(fd);
|
||||||
if (ft == NULL) {
|
if (ft == NULL) {
|
||||||
ws_close(fd);
|
ws_close(fd);
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -1274,7 +1274,25 @@ file_clearerr(FILE_T stream)
|
|||||||
stream->eof = 0;
|
stream->eof = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
void
|
||||||
|
file_fdclose(FILE_T file)
|
||||||
|
{
|
||||||
|
ws_close(file->fd);
|
||||||
|
file->fd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
file_fdreopen(FILE_T file, const char *path)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
if ((fd = ws_open(path, O_RDONLY|O_BINARY, 0000)) == -1)
|
||||||
|
return FALSE;
|
||||||
|
file->fd = fd;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
file_close(FILE_T file)
|
file_close(FILE_T file)
|
||||||
{
|
{
|
||||||
int fd = file->fd;
|
int fd = file->fd;
|
||||||
@ -1291,7 +1309,13 @@ file_close(FILE_T file)
|
|||||||
file->err = 0;
|
file->err = 0;
|
||||||
file->err_info = NULL;
|
file->err_info = NULL;
|
||||||
g_free(file);
|
g_free(file);
|
||||||
return ws_close(fd);
|
/*
|
||||||
|
* If fd is -1, somebody's done a file_closefd() on us, so
|
||||||
|
* we don't need to close the FD itself, and shouldn't do
|
||||||
|
* so.
|
||||||
|
*/
|
||||||
|
if (fd != -1)
|
||||||
|
ws_close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_LIBZ
|
#ifdef HAVE_LIBZ
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
#include <wsutil/file_util.h>
|
#include <wsutil/file_util.h>
|
||||||
|
|
||||||
extern FILE_T file_open(const char *path);
|
extern FILE_T file_open(const char *path);
|
||||||
extern FILE_T filed_open(int fildes);
|
extern FILE_T file_fdopen(int fildes);
|
||||||
extern void file_set_random_access(FILE_T stream, gboolean random, GPtrArray *seek);
|
extern void file_set_random_access(FILE_T stream, gboolean random, GPtrArray *seek);
|
||||||
extern gint64 file_seek(FILE_T stream, gint64 offset, int whence, int *err);
|
extern gint64 file_seek(FILE_T stream, gint64 offset, int whence, int *err);
|
||||||
extern gint64 file_skip(FILE_T file, gint64 delta, int *err);
|
extern gint64 file_skip(FILE_T file, gint64 delta, int *err);
|
||||||
@ -42,7 +42,9 @@ extern char *file_gets(char *buf, int len, FILE_T stream);
|
|||||||
extern int file_eof(FILE_T stream);
|
extern int file_eof(FILE_T stream);
|
||||||
extern int file_error(FILE_T fh, gchar **err_info);
|
extern int file_error(FILE_T fh, gchar **err_info);
|
||||||
extern void file_clearerr(FILE_T stream);
|
extern void file_clearerr(FILE_T stream);
|
||||||
extern int file_close(FILE_T file);
|
extern void file_fdclose(FILE_T file);
|
||||||
|
extern int file_fdreopen(FILE_T file, const char *path);
|
||||||
|
extern void file_close(FILE_T file);
|
||||||
|
|
||||||
#ifdef HAVE_LIBZ
|
#ifdef HAVE_LIBZ
|
||||||
typedef struct wtap_writer *GZWFILE_T;
|
typedef struct wtap_writer *GZWFILE_T;
|
||||||
|
129
wiretap/wtap.c
129
wiretap/wtap.c
@ -739,6 +739,135 @@ g_fast_seek_item_free(gpointer data, gpointer user_data _U_)
|
|||||||
g_free(data);
|
g_free(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Close the file descriptors for the sequential and random streams, but
|
||||||
|
* don't discard any information about those streams. Used on Windows if
|
||||||
|
* we need to rename a file that we have open or if we need to rename on
|
||||||
|
* top of a file we have open.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
wtap_fdclose(wtap *wth)
|
||||||
|
{
|
||||||
|
if (wth->fh != NULL)
|
||||||
|
file_fdclose(wth->fh);
|
||||||
|
if (wth->random_fh != NULL)
|
||||||
|
file_fdclose(wth->random_fh);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Given the pathname of the file we just closed with wtap_fdclose(), attempt
|
||||||
|
* to reopen that file and assign the new file descriptor(s) to the sequential
|
||||||
|
* stream and, if do_random is TRUE, to the random stream. Used on Windows
|
||||||
|
* after the rename of a file we had open was done or if the rename of a
|
||||||
|
* file on top of a file we had open failed.
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
wtap_fdreopen(wtap *wth, const char *filename, int *err, gboolean do_random)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
ws_statb64 statb;
|
||||||
|
gboolean use_stdin = FALSE;
|
||||||
|
|
||||||
|
/* open standard input if filename is '-' */
|
||||||
|
if (strcmp(filename, "-") == 0)
|
||||||
|
use_stdin = TRUE;
|
||||||
|
|
||||||
|
/* First, make sure the file is valid */
|
||||||
|
if (use_stdin) {
|
||||||
|
if (ws_fstat64(0, &statb) < 0) {
|
||||||
|
*err = errno;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (ws_stat64(filename, &statb) < 0) {
|
||||||
|
*err = errno;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (S_ISFIFO(statb.st_mode)) {
|
||||||
|
/*
|
||||||
|
* Opens of FIFOs are allowed only when not opening
|
||||||
|
* for random access.
|
||||||
|
*
|
||||||
|
* XXX - currently, we do seeking when trying to find
|
||||||
|
* out the file type, so we don't actually support
|
||||||
|
* opening FIFOs. However, we may eventually
|
||||||
|
* do buffering that allows us to do at least some
|
||||||
|
* file type determination even on pipes, so we
|
||||||
|
* allow FIFO opens and let things fail later when
|
||||||
|
* we try to seek.
|
||||||
|
*/
|
||||||
|
if (do_random) {
|
||||||
|
*err = WTAP_ERR_RANDOM_OPEN_PIPE;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
} else if (S_ISDIR(statb.st_mode)) {
|
||||||
|
/*
|
||||||
|
* Return different errors for "this is a directory"
|
||||||
|
* and "this is some random special file type", so
|
||||||
|
* the user can get a potentially more helpful error.
|
||||||
|
*/
|
||||||
|
*err = EISDIR;
|
||||||
|
return FALSE;
|
||||||
|
} else if (! S_ISREG(statb.st_mode)) {
|
||||||
|
*err = WTAP_ERR_NOT_REGULAR_FILE;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need two independent descriptors for random access, so
|
||||||
|
* they have different file positions. If we're opening the
|
||||||
|
* standard input, we can only dup it to get additional
|
||||||
|
* descriptors, so we can't have two independent descriptors,
|
||||||
|
* and thus can't do random access.
|
||||||
|
*/
|
||||||
|
if (use_stdin && do_random) {
|
||||||
|
*err = WTAP_ERR_RANDOM_OPEN_STDIN;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Open the file */
|
||||||
|
errno = WTAP_ERR_CANT_OPEN;
|
||||||
|
if (use_stdin) {
|
||||||
|
/*
|
||||||
|
* We dup FD 0, so that we don't have to worry about
|
||||||
|
* a file_close of wth->fh closing the standard
|
||||||
|
* input of the process.
|
||||||
|
*/
|
||||||
|
fd = ws_dup(0);
|
||||||
|
if (fd < 0) {
|
||||||
|
*err = errno;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
#ifdef _WIN32
|
||||||
|
if (_setmode(fd, O_BINARY) == -1) {
|
||||||
|
/* "Shouldn't happen" */
|
||||||
|
*err = errno;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (!(wth->fh = file_fdopen(fd))) {
|
||||||
|
*err = errno;
|
||||||
|
ws_close(fd);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!file_fdreopen(wth->fh, filename)) {
|
||||||
|
*err = errno;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (do_random) {
|
||||||
|
if (!file_fdreopen(wth->random_fh, filename)) {
|
||||||
|
*err = errno;
|
||||||
|
file_fdclose(wth->fh);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
wtap_close(wtap *wth)
|
wtap_close(wtap *wth)
|
||||||
{
|
{
|
||||||
|
@ -15,20 +15,6 @@ buffer_free
|
|||||||
buffer_init
|
buffer_init
|
||||||
buffer_remove_start
|
buffer_remove_start
|
||||||
|
|
||||||
file_seek
|
|
||||||
file_tell
|
|
||||||
file_error
|
|
||||||
file_gets
|
|
||||||
file_open
|
|
||||||
filed_open
|
|
||||||
file_read
|
|
||||||
file_close
|
|
||||||
file_getc
|
|
||||||
file_gets
|
|
||||||
file_eof
|
|
||||||
file_clearerr
|
|
||||||
file_set_random_access
|
|
||||||
|
|
||||||
wtap_buf_ptr
|
wtap_buf_ptr
|
||||||
wtap_cleareof
|
wtap_cleareof
|
||||||
wtap_close
|
wtap_close
|
||||||
@ -46,6 +32,8 @@ wtap_dump_open_ng
|
|||||||
wtap_dump_set_addrinfo_list
|
wtap_dump_set_addrinfo_list
|
||||||
wtap_encap_short_string
|
wtap_encap_short_string
|
||||||
wtap_encap_string
|
wtap_encap_string
|
||||||
|
wtap_fdclose
|
||||||
|
wtap_fdreopen
|
||||||
wtap_file_encap
|
wtap_file_encap
|
||||||
wtap_get_savable_file_types
|
wtap_get_savable_file_types
|
||||||
wtap_get_file_extensions_list
|
wtap_get_file_extensions_list
|
||||||
|
@ -1083,6 +1083,13 @@ wtapng_section_t* wtap_file_get_shb_info(wtap *wth);
|
|||||||
wtapng_iface_descriptions_t *wtap_file_get_idb_info(wtap *wth);
|
wtapng_iface_descriptions_t *wtap_file_get_idb_info(wtap *wth);
|
||||||
void wtap_write_shb_comment(wtap *wth, gchar *comment);
|
void wtap_write_shb_comment(wtap *wth, gchar *comment);
|
||||||
|
|
||||||
|
/*** close the file descriptors for the current file ***/
|
||||||
|
void wtap_fdclose(wtap *wth);
|
||||||
|
|
||||||
|
/*** reopen the file descriptors for the current file ***/
|
||||||
|
gboolean wtap_fdreopen(wtap *wth, const char *filename, int *err,
|
||||||
|
gboolean do_random);
|
||||||
|
|
||||||
/*** close the current file ***/
|
/*** close the current file ***/
|
||||||
void wtap_sequential_close(wtap *wth);
|
void wtap_sequential_close(wtap *wth);
|
||||||
void wtap_close(wtap *wth);
|
void wtap_close(wtap *wth);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user