Bug 548988 - g_file_replace fails on Windows when the target file exists

2008-08-23  Tor Lillqvist  <tml@novell.com>

	Bug 548988 - g_file_replace fails on Windows when the target file
	exists already

	* glocalfileoutputstream.c (g_local_file_output_stream_close): On
	Windows, close the file before renaming it (in case we have been
	writing to a file with a temporary name).

	(g_local_file_output_stream_close, handle_overwrite_open): Use
	GLocalFileStat instead of plain struct stat, for passing to
	_g_local_file_info_create_etag(). Thus also use _fstati64()
	instead of plain fstat() on Windows.


svn path=/trunk/; revision=7388
This commit is contained in:
Tor Lillqvist 2008-08-23 01:09:08 +00:00 committed by Tor Lillqvist
parent 886c0e0d81
commit 02d9af3562
2 changed files with 59 additions and 3 deletions

View File

@ -1,3 +1,17 @@
2008-08-23 Tor Lillqvist <tml@novell.com>
Bug 548988 - g_file_replace fails on Windows when the target file
exists already
* glocalfileoutputstream.c (g_local_file_output_stream_close): On
Windows, close the file before renaming it (in case we have been
writing to a file with a temporary name).
(g_local_file_output_stream_close, handle_overwrite_open): Use
GLocalFileStat instead of plain struct stat, for passing to
_g_local_file_info_create_etag(). Thus also use _fstati64()
instead of plain fstat() on Windows.
2008-08-18 Matthias Clasen <mclasen@redhat.com> 2008-08-18 Matthias Clasen <mclasen@redhat.com>
* === Released 2.17.7 === * === Released 2.17.7 ===

View File

@ -185,11 +185,33 @@ g_local_file_output_stream_close (GOutputStream *stream,
GError **error) GError **error)
{ {
GLocalFileOutputStream *file; GLocalFileOutputStream *file;
struct stat final_stat; GLocalFileStat final_stat;
int res; int res;
file = G_LOCAL_FILE_OUTPUT_STREAM (stream); file = G_LOCAL_FILE_OUTPUT_STREAM (stream);
#ifdef G_OS_WIN32
/* Must close before renaming on Windows, so just do the close first
* in all cases for now.
*/
if (_fstati64 (file->priv->fd, &final_stat) == 0)
file->priv->etag = _g_local_file_info_create_etag (&final_stat);
res = close (file->priv->fd);
if (res == -1)
{
int errsv = errno;
g_set_error (error, G_IO_ERROR,
g_io_error_from_errno (errsv),
_("Error closing file: %s"),
g_strerror (errsv));
return FALSE;
}
#endif
if (file->priv->tmp_filename) if (file->priv->tmp_filename)
{ {
/* We need to move the temp file to its final place, /* We need to move the temp file to its final place,
@ -264,6 +286,8 @@ g_local_file_output_stream_close (GOutputStream *stream,
if (g_cancellable_set_error_if_cancelled (cancellable, error)) if (g_cancellable_set_error_if_cancelled (cancellable, error))
goto err_out; goto err_out;
#ifndef G_OS_WIN32 /* Already did the fstat() and close() above on Win32 */
if (fstat (file->priv->fd, &final_stat) == 0) if (fstat (file->priv->fd, &final_stat) == 0)
file->priv->etag = _g_local_file_info_create_etag (&final_stat); file->priv->etag = _g_local_file_info_create_etag (&final_stat);
@ -284,9 +308,18 @@ g_local_file_output_stream_close (GOutputStream *stream,
return res != -1; return res != -1;
#else
return TRUE;
#endif
err_out: err_out:
#ifndef G_OS_WIN32
/* A simple try to close the fd in case we fail before the actual close */ /* A simple try to close the fd in case we fail before the actual close */
close (file->priv->fd); close (file->priv->fd);
#endif
return FALSE; return FALSE;
} }
@ -615,10 +648,11 @@ handle_overwrite_open (const char *filename,
GError **error) GError **error)
{ {
int fd = -1; int fd = -1;
struct stat original_stat; GLocalFileStat original_stat;
char *current_etag; char *current_etag;
gboolean is_symlink; gboolean is_symlink;
int open_flags; int open_flags;
int res;
/* We only need read access to the original file if we are creating a backup. /* We only need read access to the original file if we are creating a backup.
* We also add O_CREATE to avoid a race if the file was just removed */ * We also add O_CREATE to avoid a race if the file was just removed */
@ -657,7 +691,13 @@ handle_overwrite_open (const char *filename,
return -1; return -1;
} }
if (fstat (fd, &original_stat) != 0) #ifdef G_OS_WIN32
res = _fstati64 (fd, &original_stat);
#else
res = fstat (fd, &original_stat);
#endif
if (res != 0)
{ {
int errsv = errno; int errsv = errno;
char *display_name = g_filename_display_name (filename); char *display_name = g_filename_display_name (filename);
@ -763,7 +803,9 @@ handle_overwrite_open (const char *filename,
if (create_backup) if (create_backup)
{ {
#if defined(HAVE_FCHOWN) && defined(HAVE_FCHMOD)
struct stat tmp_statbuf; struct stat tmp_statbuf;
#endif
char *backup_filename; char *backup_filename;
int bfd; int bfd;