diff --git a/glib/gfileutils.c b/glib/gfileutils.c index bd3cc179a..378b334d8 100644 --- a/glib/gfileutils.c +++ b/glib/gfileutils.c @@ -1139,6 +1139,36 @@ fd_should_be_fsynced (int fd, #endif /* !HAVE_FSYNC */ } +static gboolean +truncate_file (int fd, + off_t length, + const char *dest_file, + GError **error) +{ + while ( +#ifdef G_OS_WIN32 + g_win32_ftruncate (fd, length) < 0 +#else + ftruncate (fd, length) < 0 +#endif + ) + { + int saved_errno = errno; + + if (saved_errno == EINTR) + continue; + + if (error != NULL) + set_file_error (error, + dest_file, + _("Failed to write file “%s”: ftruncate() failed: %s"), + saved_errno); + return FALSE; + } + + return TRUE; +} + /* closes @fd once it’s finished (on success or error) */ static gboolean write_to_file (const gchar *contents, @@ -1475,6 +1505,8 @@ consistent_out: } do_fsync = fd_should_be_fsynced (direct_fd, filename, flags); + if (!truncate_file (direct_fd, 0, filename, error)) + return FALSE; if (!write_to_file (contents, length, g_steal_fd (&direct_fd), filename, do_fsync, error)) return FALSE; diff --git a/glib/tests/fileutils.c b/glib/tests/fileutils.c index 1b45e83c2..8d8aaa21e 100644 --- a/glib/tests/fileutils.c +++ b/glib/tests/fileutils.c @@ -1603,6 +1603,8 @@ test_set_contents_full (void) gsize len; gboolean ret; GStatBuf statbuf; + const gchar *original_contents = "a string which is longer than what will be overwritten on it"; + size_t original_contents_len = strlen (original_contents); g_test_message ("Flags %d and test %" G_GSIZE_FORMAT, flags, i); @@ -1617,7 +1619,7 @@ test_set_contents_full (void) fd = g_file_open_tmp (NULL, &file_name, &error); g_assert_no_error (error); - g_assert_cmpint (write (fd, "a", 1), ==, 1); + g_assert_cmpint (write (fd, original_contents, original_contents_len), ==, original_contents_len); g_assert_no_errno (g_fsync (fd)); close (fd); @@ -1713,7 +1715,7 @@ test_set_contents_full (void) g_file_get_contents (file_name, &target_contents, NULL, &error); g_assert_no_error (error); - g_assert_cmpstr (target_contents, ==, "a"); + g_assert_cmpstr (target_contents, ==, original_contents); g_free (target_contents); }