mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-02-04 18:26:19 +01:00
gfileutils: Add a missing ftruncate() call when writing files
When calling `g_file_set_contents_full()` without `G_FILE_SET_CONTENTS_CONSISTENT`, the file is written by opening it, `write()`ing to it, then closing it. This is fine as long as the file is not longer than the new content you want to set its contents to. If it is, the last bit of the old content remains, because `g_file_set_contents_full()` was missing an `ftruncate()` call. Fix that, and change the tests to catch truncation failures in future. Signed-off-by: Philip Withnall <pwithnall@endlessos.org> Fixes: #3144
This commit is contained in:
parent
6ad6180b3c
commit
3f705ffa12
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user