mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-01-26 05:56:14 +01:00
gfileutils: Factor out fsync calculation
This introduces no functional changes, just makes the code a bit more modular and reusable. Signed-off-by: Philip Withnall <withnall@endlessm.com> Helps: #1302
This commit is contained in:
parent
00c17de72e
commit
e4e618c604
@ -1050,13 +1050,48 @@ rename_file (const char *old_name,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fd_should_be_fsynced (int fd,
|
||||
const gchar *test_file,
|
||||
GFileSetContentsFlags flags)
|
||||
{
|
||||
#ifdef HAVE_FSYNC
|
||||
struct stat statbuf;
|
||||
|
||||
#ifdef BTRFS_SUPER_MAGIC
|
||||
{
|
||||
struct statfs buf;
|
||||
|
||||
/* On Linux, on btrfs, skip the fsync since rename-over-existing is
|
||||
* guaranteed to be atomic and this is the only case in which we
|
||||
* would fsync() anyway.
|
||||
*/
|
||||
|
||||
if (fstatfs (fd, &buf) == 0 && buf.f_type == BTRFS_SUPER_MAGIC)
|
||||
return FALSE;
|
||||
}
|
||||
#endif /* BTRFS_SUPER_MAGIC */
|
||||
|
||||
errno = 0;
|
||||
/* If the final destination exists and is > 0 bytes, we want to sync the
|
||||
* newly written file to ensure the data is on disk when we rename over
|
||||
* the destination. Otherwise if we get a system crash we can lose both
|
||||
* the new and the old file on some filesystems. (I.E. those that don't
|
||||
* guarantee the data is written to the disk before the metadata.)
|
||||
*/
|
||||
return (g_lstat (test_file, &statbuf) == 0 && statbuf.st_size > 0);
|
||||
#else /* if !HAVE_FSYNC */
|
||||
return FALSE;
|
||||
#endif /* !HAVE_FSYNC */
|
||||
}
|
||||
|
||||
/* closes @fd once it’s finished (on success or error) */
|
||||
static gboolean
|
||||
write_to_file (const gchar *contents,
|
||||
gssize length,
|
||||
int fd,
|
||||
const gchar *dest_file,
|
||||
const gchar *test_file,
|
||||
gboolean do_fsync,
|
||||
GError **err)
|
||||
{
|
||||
#ifdef HAVE_FALLOCATE
|
||||
@ -1094,46 +1129,19 @@ write_to_file (const gchar *contents,
|
||||
length -= s;
|
||||
}
|
||||
|
||||
#ifdef BTRFS_SUPER_MAGIC
|
||||
{
|
||||
struct statfs buf;
|
||||
|
||||
/* On Linux, on btrfs, skip the fsync since rename-over-existing is
|
||||
* guaranteed to be atomic and this is the only case in which we
|
||||
* would fsync() anyway.
|
||||
*/
|
||||
|
||||
if (fstatfs (fd, &buf) == 0 && buf.f_type == BTRFS_SUPER_MAGIC)
|
||||
goto no_fsync;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_FSYNC
|
||||
{
|
||||
struct stat statbuf;
|
||||
errno = 0;
|
||||
if (do_fsync && fsync (fd) != 0)
|
||||
{
|
||||
int saved_errno = errno;
|
||||
set_file_error (err,
|
||||
dest_file, _("Failed to write file “%s”: fsync() failed: %s"),
|
||||
saved_errno);
|
||||
close (fd);
|
||||
|
||||
errno = 0;
|
||||
/* If the final destination exists and is > 0 bytes, we want to sync the
|
||||
* newly written file to ensure the data is on disk when we rename over
|
||||
* the destination. Otherwise if we get a system crash we can lose both
|
||||
* the new and the old file on some filesystems. (I.E. those that don't
|
||||
* guarantee the data is written to the disk before the metadata.)
|
||||
*/
|
||||
if (g_lstat (dest_file, &statbuf) == 0 && statbuf.st_size > 0 && fsync (fd) != 0)
|
||||
{
|
||||
int saved_errno = errno;
|
||||
set_file_error (err,
|
||||
dest_file, _("Failed to write file “%s”: fsync() failed: %s"),
|
||||
saved_errno);
|
||||
close (fd);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BTRFS_SUPER_MAGIC
|
||||
no_fsync:
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
errno = 0;
|
||||
@ -1159,6 +1167,7 @@ write_to_temp_file (const gchar *contents,
|
||||
{
|
||||
gchar *tmp_name = NULL;
|
||||
int fd;
|
||||
gboolean do_fsync;
|
||||
|
||||
tmp_name = g_strdup_printf ("%s.XXXXXX", dest_file);
|
||||
|
||||
@ -1175,7 +1184,8 @@ write_to_temp_file (const gchar *contents,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!write_to_file (contents, length, steal_fd (&fd), tmp_name, dest_file, err))
|
||||
do_fsync = fd_should_be_fsynced (fd, dest_file, flags);
|
||||
if (!write_to_file (contents, length, steal_fd (&fd), tmp_name, do_fsync, err))
|
||||
{
|
||||
g_unlink (tmp_name);
|
||||
g_free (tmp_name);
|
||||
|
Loading…
Reference in New Issue
Block a user