sysroot: Write symlinks before calling fsync(), then rename after

There might be a race here in that we create new symlink files *after*
calling `syncfs`, and they are not guaranteed to end up on disk.

Rework the code so that we create symlinks before, and then only
rename them after (and `fsync()` the directory for good measure).

Additional-fixes-by: Giuseppe Scrivano <gscrivan@redhat.com>
Tested-by: Giuseppe Scrivano <gscrivan@redhat.com>

This still needs verification that we're fixing a real bug; but I'm
fairly confident this won't make the fsync situation worse.

https://bugzilla.gnome.org/show_bug.cgi?id=755595
This commit is contained in:
Colin Walters committed 2015-10-25 11:46:41 -04:00
1 parent 70c07a6338
commit 723705b803
3 files changed
+211 -110

No files matched your search

-56
View File
@@ -508,59 +508,3 @@ ot_util_ensure_directory_and_fsync (GFile *dir,
(void) close (parentfd);
return ret;
}
/**
* ot_gfile_atomic_symlink_swap:
* @path: Replace the contents of this symbolic link
* @target: New symbolic link target
* @cancellable:
* @error
*
* Create a new temporary symbolic link, then use the Unix rename()
* function to atomically replace @path with the new symbolic link.
* Do not use this function inside directories such as /tmp as it uses
* a predicatable file name.
*/
gboolean
ot_gfile_atomic_symlink_swap (GFile *path,
const char *target,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
g_autoptr(GFile) parent = g_file_get_parent (path);
g_autofree char *tmpname = g_strconcat (gs_file_get_basename_cached (path), ".tmp", NULL);
g_autoptr(GFile) tmppath = g_file_get_child (parent, tmpname);
int parent_dfd = -1;
if (!ot_gfile_ensure_unlinked (tmppath, cancellable, error))
goto out;
if (!g_file_make_symbolic_link (tmppath, target, cancellable, error))
goto out;
if (!gs_file_open_dir_fd (parent, &parent_dfd, cancellable, error))
goto out;
/* Ensure the link has hit disk */
if (fsync (parent_dfd) != 0)
{
gs_set_error_from_errno (error, errno);
goto out;
}
if (!gs_file_rename (tmppath, path, cancellable, error))
goto out;
/* And sync again for good measure */
if (fsync (parent_dfd) != 0)
{
gs_set_error_from_errno (error, errno);
goto out;
}
ret = TRUE;
out:
if (parent_dfd != -1) (void) close (parent_dfd);
return ret;
}
-5
View File
@@ -85,11 +85,6 @@ gboolean ot_gfile_ensure_unlinked (GFile *path,
GCancellable *cancellable,
GError **error);
gboolean ot_gfile_atomic_symlink_swap (GFile *path,
const char *target,
GCancellable *cancellable,
GError **error);
gboolean ot_util_ensure_directory_and_fsync (GFile *dir,
GCancellable *cancellable,
GError **error);