refs: Use *at for writes, honor repo fsync flag
I was looking at https://bugzilla.gnome.org/show_bug.cgi?id=738954 which wants us to ensure we chown() the refs. As part of that, I did a generic conversion to use `*at()` (which naturally gives us more low level control so we can call `fchown` etc. This patch also sneaks in a change to respect the repo's `disable_fsync` flag - if fsync is not set, then we never `fdatasync()` (unlike the `g_file_replace_contents()` default. Also unlike it, if fsync is enabled, we *always* sync even if the file didn't exist.
This commit is contained in:
parent
c648fada30
commit
1892a6fe13
2
libglnx
2
libglnx
|
|
@ -1 +1 @@
|
||||||
Subproject commit d59a63e3e650aa75a055e4ede523790d60645435
|
Subproject commit 376219a9c276237f21c2c5aa1f0b7875a89586b6
|
||||||
|
|
@ -60,19 +60,15 @@ add_ref_to_set (const char *remote,
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
write_checksum_file (GFile *parentdir,
|
write_checksum_file_at (OstreeRepo *self,
|
||||||
const char *name,
|
int dfd,
|
||||||
const char *sha256,
|
const char *name,
|
||||||
GCancellable *cancellable,
|
const char *sha256,
|
||||||
GError **error)
|
GCancellable *cancellable,
|
||||||
|
GError **error)
|
||||||
{
|
{
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
gsize bytes_written;
|
const char *lastslash;
|
||||||
int i;
|
|
||||||
gs_unref_object GFile *parent = NULL;
|
|
||||||
gs_unref_object GFile *child = NULL;
|
|
||||||
gs_unref_object GOutputStream *out = NULL;
|
|
||||||
gs_unref_ptrarray GPtrArray *components = NULL;
|
|
||||||
|
|
||||||
if (!ostree_validate_checksum_string (sha256, error))
|
if (!ostree_validate_checksum_string (sha256, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
@ -84,38 +80,37 @@ write_checksum_file (GFile *parentdir,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ot_util_path_split_validate (name, &components, error))
|
if (!*name)
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (components->len == 0)
|
|
||||||
{
|
{
|
||||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
"Invalid empty ref name");
|
"Invalid empty ref name");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
parent = g_object_ref (parentdir);
|
lastslash = strrchr (name, '/');
|
||||||
for (i = 0; i+1 < components->len; i++)
|
|
||||||
|
if (lastslash)
|
||||||
{
|
{
|
||||||
child = g_file_get_child (parent, (char*)components->pdata[i]);
|
char *parent = strdupa (name);
|
||||||
|
parent[lastslash - name] = '\0';
|
||||||
|
|
||||||
if (!gs_file_ensure_directory (child, FALSE, cancellable, error))
|
if (!glnx_shutil_mkdir_p_at (dfd, parent, 0777, cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
g_clear_object (&parent);
|
|
||||||
parent = child;
|
|
||||||
child = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
child = g_file_get_child (parent, components->pdata[components->len - 1]);
|
{
|
||||||
if ((out = (GOutputStream*)g_file_replace (child, NULL, FALSE, 0, cancellable, error)) == NULL)
|
size_t l = strlen (sha256);
|
||||||
goto out;
|
char *bufnl = alloca (l + 2);
|
||||||
if (!g_output_stream_write_all (out, sha256, strlen (sha256), &bytes_written, cancellable, error))
|
|
||||||
goto out;
|
memcpy (bufnl, sha256, l);
|
||||||
if (!g_output_stream_write_all (out, "\n", 1, &bytes_written, cancellable, error))
|
bufnl[l] = '\n';
|
||||||
goto out;
|
bufnl[l+1] = '\0';
|
||||||
if (!g_output_stream_close (out, cancellable, error))
|
|
||||||
goto out;
|
if (!glnx_file_replace_contents_at (dfd, name, (guint8*)bufnl, l + 1,
|
||||||
|
self->disable_fsync ? GLNX_FILE_REPLACE_NODATASYNC : GLNX_FILE_REPLACE_DATASYNC_NEW,
|
||||||
|
cancellable, error))
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
out:
|
out:
|
||||||
|
|
@ -593,34 +588,47 @@ _ostree_repo_write_ref (OstreeRepo *self,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
gs_unref_object GFile *dir = NULL;
|
glnx_fd_close int dfd = -1;
|
||||||
|
|
||||||
if (remote == NULL)
|
if (remote == NULL)
|
||||||
dir = g_object_ref (self->local_heads_dir);
|
{
|
||||||
|
if (!glnx_opendirat (self->repo_dir_fd, "refs/heads", TRUE,
|
||||||
|
&dfd, error))
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dir = g_file_get_child (self->remote_heads_dir, remote);
|
glnx_fd_close int refs_remotes_dfd = -1;
|
||||||
|
|
||||||
|
if (!glnx_opendirat (self->repo_dir_fd, "refs/remotes", TRUE,
|
||||||
|
&refs_remotes_dfd, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
if (rev != NULL)
|
if (rev != NULL)
|
||||||
{
|
{
|
||||||
if (!gs_file_ensure_directory (dir, FALSE, cancellable, error))
|
/* Ensure we have a dir for the remote */
|
||||||
|
if (!glnx_shutil_mkdir_p_at (refs_remotes_dfd, remote, 0777, cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!glnx_opendirat (refs_remotes_dfd, remote, TRUE, &dfd, error))
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rev == NULL)
|
if (rev == NULL)
|
||||||
{
|
{
|
||||||
gs_unref_object GFile *child = g_file_resolve_relative_path (dir, ref);
|
if (unlinkat (dfd, ref, 0) != 0)
|
||||||
|
|
||||||
if (g_file_query_exists (child, cancellable))
|
|
||||||
{
|
{
|
||||||
if (!gs_file_unlink (child, cancellable, error))
|
if (errno != ENOENT)
|
||||||
goto out;
|
{
|
||||||
|
glnx_set_error_from_errno (error);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!write_checksum_file (dir, ref, rev, cancellable, error))
|
if (!write_checksum_file_at (self, dfd, ref, rev, cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue