Merge branch '3144-file-set-contents-truncation' into 'main'

gfileutils: Add a missing ftruncate() call when writing files

Closes #3144

See merge request GNOME/glib!3650
This commit is contained in:
Michael Catanzaro 2023-10-22 22:41:56 +00:00
commit ceca2dc5bc
2 changed files with 36 additions and 2 deletions

View File

@ -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 its 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;

View File

@ -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);
}