repo: Introduce ostree_repo_open_at() and ostree_repo_create_at()
This essentially completes our fd-relative conversion. While here, I cleaned up the semantics of `ostree_repo_create()` and `ostree_repo_create_at()` to be more atomic - basically various scripts were testing for the `objects` subdirectory, so let's formalize that. Closes: #820 Approved by: jlebon
This commit is contained in:
parent
64b7c42025
commit
fd98bda3c7
|
|
@ -271,6 +271,7 @@ ostree_mutable_tree_get_type
|
||||||
OstreeRepo
|
OstreeRepo
|
||||||
OstreeRepoMode
|
OstreeRepoMode
|
||||||
ostree_repo_mode_from_string
|
ostree_repo_mode_from_string
|
||||||
|
ostree_repo_open_at
|
||||||
ostree_repo_new
|
ostree_repo_new
|
||||||
ostree_repo_new_for_sysroot_path
|
ostree_repo_new_for_sysroot_path
|
||||||
ostree_repo_new_default
|
ostree_repo_new_default
|
||||||
|
|
@ -279,6 +280,7 @@ ostree_repo_set_disable_fsync
|
||||||
ostree_repo_get_disable_fsync
|
ostree_repo_get_disable_fsync
|
||||||
ostree_repo_is_system
|
ostree_repo_is_system
|
||||||
ostree_repo_is_writable
|
ostree_repo_is_writable
|
||||||
|
ostree_repo_create_at
|
||||||
ostree_repo_create
|
ostree_repo_create
|
||||||
ostree_repo_get_path
|
ostree_repo_get_path
|
||||||
ostree_repo_get_mode
|
ostree_repo_get_mode
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,8 @@
|
||||||
LIBOSTREE_2017.10 {
|
LIBOSTREE_2017.10 {
|
||||||
ostree_gpg_error_quark;
|
ostree_gpg_error_quark;
|
||||||
ostree_repo_set_alias_ref_immediate;
|
ostree_repo_set_alias_ref_immediate;
|
||||||
|
ostree_repo_open_at;
|
||||||
|
ostree_repo_create_at;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Stub section for the stable release *after* this development one; don't
|
/* Stub section for the stable release *after* this development one; don't
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@
|
||||||
|
|
||||||
#include "ostree-autocleanups.h"
|
#include "ostree-autocleanups.h"
|
||||||
#include "ostree-remote-private.h"
|
#include "ostree-remote-private.h"
|
||||||
|
#include "ostree-repo-private.h"
|
||||||
#include "ostree-repo-finder.h"
|
#include "ostree-repo-finder.h"
|
||||||
#include "ostree-repo-finder-mount.h"
|
#include "ostree-repo-finder-mount.h"
|
||||||
|
|
||||||
|
|
@ -257,19 +258,16 @@ ostree_repo_finder_mount_resolve_async (OstreeRepoFinder *finde
|
||||||
{
|
{
|
||||||
struct stat stbuf;
|
struct stat stbuf;
|
||||||
g_autofree gchar *collection_and_ref = NULL;
|
g_autofree gchar *collection_and_ref = NULL;
|
||||||
g_autofree gchar *repo_dir_path = NULL;
|
|
||||||
g_autofree gchar *resolved_repo_uri = NULL;
|
g_autofree gchar *resolved_repo_uri = NULL;
|
||||||
g_autofree gchar *keyring = NULL;
|
g_autofree gchar *keyring = NULL;
|
||||||
g_autoptr(UriAndKeyring) resolved_repo = NULL;
|
g_autoptr(UriAndKeyring) resolved_repo = NULL;
|
||||||
|
|
||||||
collection_and_ref = g_build_filename (refs[i]->collection_id, refs[i]->ref_name, NULL);
|
collection_and_ref = g_build_filename (refs[i]->collection_id, refs[i]->ref_name, NULL);
|
||||||
repo_dir_path = g_build_filename (mount_root_path, ".ostree", "repos",
|
|
||||||
collection_and_ref, NULL);
|
|
||||||
|
|
||||||
if (!glnx_fstatat (repos_dfd, collection_and_ref, &stbuf, AT_NO_AUTOMOUNT, &local_error))
|
if (!glnx_fstatat (repos_dfd, collection_and_ref, &stbuf, AT_NO_AUTOMOUNT, &local_error))
|
||||||
{
|
{
|
||||||
g_debug ("Ignoring ref (%s, %s) on mount ‘%s’ as querying info of ‘%s’ failed: %s",
|
g_debug ("Ignoring ref (%s, %s) on mount ‘%s’ as querying info of ‘%s’ failed: %s",
|
||||||
refs[i]->collection_id, refs[i]->ref_name, mount_name, repo_dir_path, local_error->message);
|
refs[i]->collection_id, refs[i]->ref_name, mount_name, collection_and_ref, local_error->message);
|
||||||
g_clear_error (&local_error);
|
g_clear_error (&local_error);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -277,7 +275,7 @@ ostree_repo_finder_mount_resolve_async (OstreeRepoFinder *finde
|
||||||
if ((stbuf.st_mode & S_IFMT) != S_IFDIR)
|
if ((stbuf.st_mode & S_IFMT) != S_IFDIR)
|
||||||
{
|
{
|
||||||
g_debug ("Ignoring ref (%s, %s) on mount ‘%s’ as ‘%s’ is of type %u, not a directory.",
|
g_debug ("Ignoring ref (%s, %s) on mount ‘%s’ as ‘%s’ is of type %u, not a directory.",
|
||||||
refs[i]->collection_id, refs[i]->ref_name, mount_name, repo_dir_path, (stbuf.st_mode & S_IFMT));
|
refs[i]->collection_id, refs[i]->ref_name, mount_name, collection_and_ref, (stbuf.st_mode & S_IFMT));
|
||||||
g_clear_error (&local_error);
|
g_clear_error (&local_error);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -294,27 +292,19 @@ ostree_repo_finder_mount_resolve_async (OstreeRepoFinder *finde
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Exclude repositories which resolve to @parent_repo. */
|
/* Exclude repositories which resolve to @parent_repo. */
|
||||||
g_autofree char *canonical_repo_dir_path = realpath (repo_dir_path, NULL);
|
if (stbuf.st_dev == parent_repo->device &&
|
||||||
g_autofree gchar *parent_repo_path = g_file_get_path (ostree_repo_get_path (parent_repo));
|
stbuf.st_ino == parent_repo->inode)
|
||||||
g_autofree char *canonical_parent_repo_path = realpath (parent_repo_path, NULL);
|
|
||||||
|
|
||||||
if (g_strcmp0 (canonical_repo_dir_path, canonical_parent_repo_path) == 0)
|
|
||||||
{
|
{
|
||||||
g_debug ("Ignoring ref (%s, %s) on mount ‘%s’ as its repository was the one we are resolving for: %s",
|
g_debug ("Ignoring ref (%s, %s) on mount ‘%s’ as it is the same as the one we are resolving",
|
||||||
refs[i]->collection_id, refs[i]->ref_name, mount_name, canonical_parent_repo_path);
|
refs[i]->collection_id, refs[i]->ref_name, mount_name);
|
||||||
g_clear_error (&local_error);
|
g_clear_error (&local_error);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Grab the given ref and a checksum for it from the repo.
|
/* Grab the given ref and a checksum for it from the repo, if it appears to be a valid repo */
|
||||||
* FIXME: Ideally, there would be some ostree_repo_open_at() which we
|
g_autoptr(OstreeRepo) repo = ostree_repo_open_at (repos_dfd, collection_and_ref,
|
||||||
* could use to keep the openat() chain going. See
|
cancellable, &local_error);
|
||||||
* https://github.com/ostreedev/ostree/pull/820. */
|
if (!repo)
|
||||||
g_autoptr(OstreeRepo) repo = NULL;
|
|
||||||
g_autoptr(GFile) repo_dir_file = g_file_new_for_path (repo_dir_path);
|
|
||||||
repo = ostree_repo_new (repo_dir_file);
|
|
||||||
|
|
||||||
if (!ostree_repo_open (repo, cancellable, &local_error))
|
|
||||||
{
|
{
|
||||||
g_debug ("Ignoring ref (%s, %s) on mount ‘%s’ as its repository could not be opened: %s",
|
g_debug ("Ignoring ref (%s, %s) on mount ‘%s’ as its repository could not be opened: %s",
|
||||||
refs[i]->collection_id, refs[i]->ref_name, mount_name, local_error->message);
|
refs[i]->collection_id, refs[i]->ref_name, mount_name, local_error->message);
|
||||||
|
|
@ -358,6 +348,11 @@ ostree_repo_finder_mount_resolve_async (OstreeRepoFinder *finde
|
||||||
* $mount_root/.ostree/repos/$refs[i]->collection_id/$refs[i]->ref_name.
|
* $mount_root/.ostree/repos/$refs[i]->collection_id/$refs[i]->ref_name.
|
||||||
* Add it to the results, keyed by the canonicalised repository URI
|
* Add it to the results, keyed by the canonicalised repository URI
|
||||||
* to deduplicate the results. */
|
* to deduplicate the results. */
|
||||||
|
|
||||||
|
g_autofree char *repo_abspath = g_build_filename (mount_root_path, ".ostree/repos",
|
||||||
|
collection_and_ref, NULL);
|
||||||
|
/* FIXME - why are we using realpath here? */
|
||||||
|
g_autofree char *canonical_repo_dir_path = realpath (repo_abspath, NULL);
|
||||||
resolved_repo_uri = g_strconcat ("file://", canonical_repo_dir_path, NULL);
|
resolved_repo_uri = g_strconcat ("file://", canonical_repo_dir_path, NULL);
|
||||||
g_debug ("Resolved ref (%s, %s) on mount ‘%s’ to repo URI ‘%s’ with keyring ‘%s’.",
|
g_debug ("Resolved ref (%s, %s) on mount ‘%s’ to repo URI ‘%s’ with keyring ‘%s’.",
|
||||||
refs[i]->collection_id, refs[i]->ref_name, mount_name, resolved_repo_uri, keyring);
|
refs[i]->collection_id, refs[i]->ref_name, mount_name, resolved_repo_uri, keyring);
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,11 @@ struct OstreeRepo {
|
||||||
char *commit_stagedir_name;
|
char *commit_stagedir_name;
|
||||||
GLnxLockFile commit_stagedir_lock;
|
GLnxLockFile commit_stagedir_lock;
|
||||||
|
|
||||||
GFile *repodir;
|
/* A cached fd-relative version, distinct from the case where we may have a
|
||||||
|
* user-provided absolute path.
|
||||||
|
*/
|
||||||
|
GFile *repodir_fdrel;
|
||||||
|
GFile *repodir; /* May be %NULL if we were opened via ostree_repo_open_at() */
|
||||||
int repo_dir_fd;
|
int repo_dir_fd;
|
||||||
int tmp_dir_fd;
|
int tmp_dir_fd;
|
||||||
int cache_dir_fd;
|
int cache_dir_fd;
|
||||||
|
|
@ -132,10 +136,13 @@ struct OstreeRepo {
|
||||||
GHashTable *updated_uncompressed_dirs;
|
GHashTable *updated_uncompressed_dirs;
|
||||||
GHashTable *object_sizes;
|
GHashTable *object_sizes;
|
||||||
|
|
||||||
uid_t owner_uid;
|
/* Cache the repo's device/inode to use for comparisons elsewhere */
|
||||||
uid_t target_owner_uid;
|
dev_t device;
|
||||||
|
ino_t inode;
|
||||||
|
uid_t owner_uid; /* Cache of repo's owner uid */
|
||||||
|
uid_t target_owner_uid; /* Ensure files are chowned to this uid/gid */
|
||||||
gid_t target_owner_gid;
|
gid_t target_owner_gid;
|
||||||
guint min_free_space_percent;
|
guint min_free_space_percent; /* See the min-free-space-percent config option */
|
||||||
|
|
||||||
guint test_error_flags; /* OstreeRepoTestErrorFlags */
|
guint test_error_flags; /* OstreeRepoTestErrorFlags */
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -456,6 +456,7 @@ ostree_repo_finalize (GObject *object)
|
||||||
g_clear_object (&self->parent_repo);
|
g_clear_object (&self->parent_repo);
|
||||||
|
|
||||||
g_free (self->stagedir_prefix);
|
g_free (self->stagedir_prefix);
|
||||||
|
g_clear_object (&self->repodir_fdrel);
|
||||||
g_clear_object (&self->repodir);
|
g_clear_object (&self->repodir);
|
||||||
if (self->repo_dir_fd != -1)
|
if (self->repo_dir_fd != -1)
|
||||||
(void) close (self->repo_dir_fd);
|
(void) close (self->repo_dir_fd);
|
||||||
|
|
@ -546,22 +547,11 @@ ostree_repo_get_property(GObject *object,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
ostree_repo_constructed (GObject *object)
|
|
||||||
{
|
|
||||||
OstreeRepo *self = OSTREE_REPO (object);
|
|
||||||
|
|
||||||
g_assert (self->repodir != NULL);
|
|
||||||
|
|
||||||
G_OBJECT_CLASS (ostree_repo_parent_class)->constructed (object);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ostree_repo_class_init (OstreeRepoClass *klass)
|
ostree_repo_class_init (OstreeRepoClass *klass)
|
||||||
{
|
{
|
||||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
|
|
||||||
object_class->constructed = ostree_repo_constructed;
|
|
||||||
object_class->get_property = ostree_repo_get_property;
|
object_class->get_property = ostree_repo_get_property;
|
||||||
object_class->set_property = ostree_repo_set_property;
|
object_class->set_property = ostree_repo_set_property;
|
||||||
object_class->finalize = ostree_repo_finalize;
|
object_class->finalize = ostree_repo_finalize;
|
||||||
|
|
@ -581,6 +571,7 @@ ostree_repo_class_init (OstreeRepoClass *klass)
|
||||||
"",
|
"",
|
||||||
G_TYPE_FILE,
|
G_TYPE_FILE,
|
||||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
|
||||||
|
|
||||||
g_object_class_install_property (object_class,
|
g_object_class_install_property (object_class,
|
||||||
PROP_REMOTES_CONFIG_DIR,
|
PROP_REMOTES_CONFIG_DIR,
|
||||||
g_param_spec_string ("remotes-config-dir",
|
g_param_spec_string ("remotes-config-dir",
|
||||||
|
|
@ -662,6 +653,43 @@ ostree_repo_new (GFile *path)
|
||||||
return g_object_new (OSTREE_TYPE_REPO, "path", path, NULL);
|
return g_object_new (OSTREE_TYPE_REPO, "path", path, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static OstreeRepo *
|
||||||
|
repo_open_at_take_fd (int *dfd,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
g_autoptr(OstreeRepo) repo = g_object_new (OSTREE_TYPE_REPO, NULL);
|
||||||
|
repo->repo_dir_fd = glnx_steal_fd (dfd);
|
||||||
|
|
||||||
|
if (!ostree_repo_open (repo, cancellable, error))
|
||||||
|
return NULL;
|
||||||
|
return g_steal_pointer (&repo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ostree_repo_open_at:
|
||||||
|
* @dfd: Directory fd
|
||||||
|
* @path: Path
|
||||||
|
*
|
||||||
|
* This combines ostree_repo_new() (but using fd-relative access) with
|
||||||
|
* ostree_repo_open(). Use this when you know you should be operating on an
|
||||||
|
* already extant repository. If you want to create one, use ostree_repo_create_at().
|
||||||
|
*
|
||||||
|
* Returns: (transfer full): An accessor object for an OSTree repository located at @dfd + @path
|
||||||
|
*/
|
||||||
|
OstreeRepo*
|
||||||
|
ostree_repo_open_at (int dfd,
|
||||||
|
const char *path,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
glnx_fd_close int repo_dfd = -1;
|
||||||
|
if (!glnx_opendirat (dfd, path, TRUE, &repo_dfd, error))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return repo_open_at_take_fd (&repo_dfd, cancellable, error);
|
||||||
|
}
|
||||||
|
|
||||||
static GFile *
|
static GFile *
|
||||||
get_default_repo_path (GFile *sysroot_path)
|
get_default_repo_path (GFile *sysroot_path)
|
||||||
{
|
{
|
||||||
|
|
@ -744,9 +772,17 @@ ostree_repo_is_system (OstreeRepo *repo)
|
||||||
if (!repo->sysroot_dir)
|
if (!repo->sysroot_dir)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
/* If we created via ostree_repo_new(), we'll have a repo path. Compare
|
||||||
|
* it to the sysroot path in that case.
|
||||||
|
*/
|
||||||
|
if (repo->repodir)
|
||||||
|
{
|
||||||
g_autoptr(GFile) default_repo_path = get_default_repo_path (repo->sysroot_dir);
|
g_autoptr(GFile) default_repo_path = get_default_repo_path (repo->sysroot_dir);
|
||||||
return g_file_equal (repo->repodir, default_repo_path);
|
return g_file_equal (repo->repodir, default_repo_path);
|
||||||
}
|
}
|
||||||
|
/* Otherwise, not a system repo */
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ostree_repo_is_writable:
|
* ostree_repo_is_writable:
|
||||||
|
|
@ -1670,6 +1706,104 @@ ostree_repo_mode_from_string (const char *mode,
|
||||||
#define DEFAULT_CONFIG_CONTENTS ("[core]\n" \
|
#define DEFAULT_CONFIG_CONTENTS ("[core]\n" \
|
||||||
"repo_version=1\n")
|
"repo_version=1\n")
|
||||||
|
|
||||||
|
/* Just write the dirs to disk, return a dfd */
|
||||||
|
static gboolean
|
||||||
|
repo_create_at_internal (int dfd,
|
||||||
|
const char *path,
|
||||||
|
OstreeRepoMode mode,
|
||||||
|
GVariant *options,
|
||||||
|
int *out_dfd,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
struct stat stbuf;
|
||||||
|
/* We do objects/ last - if it exists we do nothing and exit successfully */
|
||||||
|
const char *state_dirs[] = { "tmp", "extensions", "state",
|
||||||
|
"refs", "refs/heads", "refs/mirrors",
|
||||||
|
"refs/remotes", "objects" };
|
||||||
|
|
||||||
|
/* Early return if we have an existing repo */
|
||||||
|
{ g_autofree char *objects_path = g_build_filename (path, "objects", NULL);
|
||||||
|
|
||||||
|
if (fstatat (dfd, objects_path, &stbuf, 0) == 0)
|
||||||
|
{
|
||||||
|
glnx_fd_close int repo_dfd = -1;
|
||||||
|
if (!glnx_opendirat (dfd, path, TRUE, &repo_dfd, error))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* Note early return */
|
||||||
|
*out_dfd = glnx_steal_fd (&repo_dfd);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
else if (errno != ENOENT)
|
||||||
|
return glnx_throw_errno_prefix (error, "fstatat");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mkdirat (dfd, path, 0755) != 0)
|
||||||
|
{
|
||||||
|
if (G_UNLIKELY (errno != EEXIST))
|
||||||
|
return glnx_throw_errno_prefix (error, "mkdirat");
|
||||||
|
}
|
||||||
|
|
||||||
|
glnx_fd_close int repo_dfd = -1;
|
||||||
|
if (!glnx_opendirat (dfd, path, TRUE, &repo_dfd, error))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (fstatat (repo_dfd, "config", &stbuf, 0) < 0)
|
||||||
|
{
|
||||||
|
if (errno == ENOENT)
|
||||||
|
{
|
||||||
|
const char *mode_str = NULL;
|
||||||
|
g_autoptr(GString) config_data = g_string_new (DEFAULT_CONFIG_CONTENTS);
|
||||||
|
|
||||||
|
if (!ostree_repo_mode_to_string (mode, &mode_str, error))
|
||||||
|
return FALSE;
|
||||||
|
g_assert (mode_str);
|
||||||
|
|
||||||
|
g_string_append_printf (config_data, "mode=%s\n", mode_str);
|
||||||
|
|
||||||
|
const char *collection_id = NULL;
|
||||||
|
if (options)
|
||||||
|
g_variant_lookup (options, "collection-id", "&s", &collection_id);
|
||||||
|
if (collection_id != NULL)
|
||||||
|
g_string_append_printf (config_data, "collection-id=%s\n", collection_id);
|
||||||
|
|
||||||
|
if (!glnx_file_replace_contents_at (repo_dfd, "config",
|
||||||
|
(guint8*)config_data->str, config_data->len,
|
||||||
|
0, cancellable, error))
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return glnx_throw_errno_prefix (error, "fstatat");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (guint i = 0; i < G_N_ELEMENTS (state_dirs); i++)
|
||||||
|
{
|
||||||
|
const char *elt = state_dirs[i];
|
||||||
|
if (mkdirat (repo_dfd, elt, 0755) == -1)
|
||||||
|
{
|
||||||
|
if (G_UNLIKELY (errno != EEXIST))
|
||||||
|
return glnx_throw_errno_prefix (error, "mkdirat");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test that the fs supports user xattrs now, so we get an error early rather
|
||||||
|
* than during an object write later.
|
||||||
|
*/
|
||||||
|
if (mode == OSTREE_REPO_MODE_BARE_USER)
|
||||||
|
{
|
||||||
|
g_auto(GLnxTmpfile) tmpf = { 0, };
|
||||||
|
|
||||||
|
if (!glnx_open_tmpfile_linkable_at (repo_dfd, ".", O_RDWR|O_CLOEXEC, &tmpf, error))
|
||||||
|
return FALSE;
|
||||||
|
if (!_ostree_write_bareuser_metadata (tmpf.fd, 0, 0, 644, NULL, error))
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out_dfd = glnx_steal_fd (&repo_dfd);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ostree_repo_create:
|
* ostree_repo_create:
|
||||||
* @self: An #OstreeRepo
|
* @self: An #OstreeRepo
|
||||||
|
|
@ -1686,6 +1820,11 @@ ostree_repo_mode_from_string (const char *mode,
|
||||||
* of an existing repository, and will silently ignore an attempt to
|
* of an existing repository, and will silently ignore an attempt to
|
||||||
* do so.
|
* do so.
|
||||||
*
|
*
|
||||||
|
* Since 2017.9, "existing repository" is defined by the existence of an
|
||||||
|
* `objects` subdirectory.
|
||||||
|
*
|
||||||
|
* This function predates ostree_repo_create_at(). It is an error to call
|
||||||
|
* this function on a repository initialized via ostree_repo_open_at().
|
||||||
*/
|
*/
|
||||||
gboolean
|
gboolean
|
||||||
ostree_repo_create (OstreeRepo *self,
|
ostree_repo_create (OstreeRepo *self,
|
||||||
|
|
@ -1693,76 +1832,64 @@ ostree_repo_create (OstreeRepo *self,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
|
g_return_val_if_fail (self->repodir, FALSE);
|
||||||
const char *repopath = gs_file_get_path_cached (self->repodir);
|
const char *repopath = gs_file_get_path_cached (self->repodir);
|
||||||
glnx_fd_close int dfd = -1;
|
g_autoptr(GVariantBuilder) builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
|
||||||
struct stat stbuf;
|
if (self->collection_id)
|
||||||
const char *state_dirs[] = { "objects", "tmp", "extensions", "state",
|
g_variant_builder_add (builder, "{s@v}", "collection-id",
|
||||||
"refs", "refs/heads", "refs/mirrors",
|
g_variant_new_variant (g_variant_new_string (self->collection_id)));
|
||||||
"refs/remotes" };
|
|
||||||
|
|
||||||
if (mkdir (repopath, 0755) != 0)
|
glnx_fd_close int repo_dir_fd = -1;
|
||||||
{
|
if (!repo_create_at_internal (AT_FDCWD, repopath, mode,
|
||||||
if (G_UNLIKELY (errno != EEXIST))
|
g_variant_builder_end (builder),
|
||||||
return glnx_throw_errno (error);
|
&repo_dir_fd,
|
||||||
}
|
cancellable, error))
|
||||||
|
|
||||||
if (!glnx_opendirat (AT_FDCWD, repopath, TRUE, &dfd, error))
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
self->repo_dir_fd = glnx_steal_fd (&repo_dir_fd);
|
||||||
if (fstatat (dfd, "config", &stbuf, 0) < 0)
|
|
||||||
{
|
|
||||||
if (errno == ENOENT)
|
|
||||||
{
|
|
||||||
const char *mode_str = NULL;
|
|
||||||
g_autoptr(GString) config_data = g_string_new (DEFAULT_CONFIG_CONTENTS);
|
|
||||||
|
|
||||||
if (!ostree_repo_mode_to_string (mode, &mode_str, error))
|
|
||||||
return FALSE;
|
|
||||||
g_assert (mode_str);
|
|
||||||
|
|
||||||
g_string_append_printf (config_data, "mode=%s\n", mode_str);
|
|
||||||
|
|
||||||
if (self->collection_id != NULL)
|
|
||||||
g_string_append_printf (config_data, "collection-id=%s\n", self->collection_id);
|
|
||||||
|
|
||||||
if (!glnx_file_replace_contents_at (dfd, "config",
|
|
||||||
(guint8*)config_data->str, config_data->len,
|
|
||||||
0, cancellable, error))
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return glnx_throw_errno (error);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (guint i = 0; i < G_N_ELEMENTS (state_dirs); i++)
|
|
||||||
{
|
|
||||||
const char *elt = state_dirs[i];
|
|
||||||
if (mkdirat (dfd, elt, 0755) == -1)
|
|
||||||
{
|
|
||||||
if (G_UNLIKELY (errno != EEXIST))
|
|
||||||
return glnx_throw_errno (error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Test that the fs supports user xattrs now, so we get an error early rather
|
|
||||||
* than during an object write later.
|
|
||||||
*/
|
|
||||||
if (mode == OSTREE_REPO_MODE_BARE_USER)
|
|
||||||
{
|
|
||||||
g_auto(GLnxTmpfile) tmpf = { 0, };
|
|
||||||
|
|
||||||
if (!glnx_open_tmpfile_linkable_at (dfd, ".", O_RDWR|O_CLOEXEC, &tmpf, error))
|
|
||||||
return FALSE;
|
|
||||||
if (!_ostree_write_bareuser_metadata (tmpf.fd, 0, 0, 644, NULL, error))
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ostree_repo_open (self, cancellable, error))
|
if (!ostree_repo_open (self, cancellable, error))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ostree_repo_create_at:
|
||||||
|
* @dfd: Directory fd
|
||||||
|
* @path: Path
|
||||||
|
* @mode: The mode to store the repository in
|
||||||
|
* @options: a{sv}: See below for accepted keys
|
||||||
|
* @cancellable: Cancellable
|
||||||
|
* @error: Error
|
||||||
|
*
|
||||||
|
* This is a file-descriptor relative version of ostree_repo_create().
|
||||||
|
* Create the underlying structure on disk for the repository, and call
|
||||||
|
* ostree_repo_open_at() on the result, preparing it for use.
|
||||||
|
*
|
||||||
|
* If a repository already exists at @dfd + @path (defined by an `objects/`
|
||||||
|
* subdirectory existing), then this function will simply call
|
||||||
|
* ostree_repo_open_at(). In other words, this function cannot be used to change
|
||||||
|
* the mode or configuration (`repo/config`) of an existing repo.
|
||||||
|
*
|
||||||
|
* The @options dict may contain:
|
||||||
|
*
|
||||||
|
* - collection-id: s: Set as collection ID in repo/config (Since 2017.9)
|
||||||
|
*
|
||||||
|
* Returns: (transfer full): A new OSTree repository reference
|
||||||
|
*/
|
||||||
|
OstreeRepo *
|
||||||
|
ostree_repo_create_at (int dfd,
|
||||||
|
const char *path,
|
||||||
|
OstreeRepoMode mode,
|
||||||
|
GVariant *options,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
glnx_fd_close int repo_dfd = -1;
|
||||||
|
if (!repo_create_at_internal (dfd, path, mode, options, &repo_dfd,
|
||||||
|
cancellable, error))
|
||||||
|
return NULL;
|
||||||
|
return repo_open_at_take_fd (&repo_dfd, cancellable, error);
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
enumerate_directory_allow_noent (GFile *dirpath,
|
enumerate_directory_allow_noent (GFile *dirpath,
|
||||||
const char *queryargs,
|
const char *queryargs,
|
||||||
|
|
@ -2132,7 +2259,6 @@ ostree_repo_open (OstreeRepo *self,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
struct stat self_stbuf;
|
|
||||||
struct stat stbuf;
|
struct stat stbuf;
|
||||||
|
|
||||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||||
|
|
@ -2162,22 +2288,25 @@ ostree_repo_open (OstreeRepo *self,
|
||||||
self->stagedir_prefix = g_strconcat (OSTREE_REPO_TMPDIR_STAGING, boot_id, "-", NULL);
|
self->stagedir_prefix = g_strconcat (OSTREE_REPO_TMPDIR_STAGING, boot_id, "-", NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (self->repo_dir_fd == -1)
|
||||||
|
{
|
||||||
|
g_assert (self->repodir);
|
||||||
if (!glnx_opendirat (AT_FDCWD, gs_file_get_path_cached (self->repodir), TRUE,
|
if (!glnx_opendirat (AT_FDCWD, gs_file_get_path_cached (self->repodir), TRUE,
|
||||||
&self->repo_dir_fd, error))
|
&self->repo_dir_fd, error))
|
||||||
{
|
{
|
||||||
g_prefix_error (error, "%s: ", gs_file_get_path_cached (self->repodir));
|
g_prefix_error (error, "%s: ", gs_file_get_path_cached (self->repodir));
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!glnx_fstat (self->repo_dir_fd, &self_stbuf, error))
|
if (!glnx_fstat (self->repo_dir_fd, &stbuf, error))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
self->device = stbuf.st_dev;
|
||||||
|
self->inode = stbuf.st_ino;
|
||||||
|
|
||||||
if (!glnx_opendirat (self->repo_dir_fd, "objects", TRUE,
|
if (!glnx_opendirat (self->repo_dir_fd, "objects", TRUE,
|
||||||
&self->objects_dir_fd, error))
|
&self->objects_dir_fd, error))
|
||||||
{
|
|
||||||
g_prefix_error (error, "Opening objects/ directory: ");
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
|
||||||
|
|
||||||
self->writable = faccessat (self->objects_dir_fd, ".", W_OK, 0) == 0;
|
self->writable = faccessat (self->objects_dir_fd, ".", W_OK, 0) == 0;
|
||||||
if (!self->writable)
|
if (!self->writable)
|
||||||
|
|
@ -2238,8 +2367,8 @@ ostree_repo_open (OstreeRepo *self,
|
||||||
if (fstatat (AT_FDCWD, "/ostree/repo", &system_stbuf, 0) == 0)
|
if (fstatat (AT_FDCWD, "/ostree/repo", &system_stbuf, 0) == 0)
|
||||||
{
|
{
|
||||||
/* Are we the same as /ostree/repo? */
|
/* Are we the same as /ostree/repo? */
|
||||||
if (self_stbuf.st_dev == system_stbuf.st_dev &&
|
if (self->device == system_stbuf.st_dev &&
|
||||||
self_stbuf.st_ino == system_stbuf.st_ino)
|
self->inode == system_stbuf.st_ino)
|
||||||
self->sysroot_kind = OSTREE_REPO_SYSROOT_KIND_IS_SYSROOT_OSTREE;
|
self->sysroot_kind = OSTREE_REPO_SYSROOT_KIND_IS_SYSROOT_OSTREE;
|
||||||
else
|
else
|
||||||
self->sysroot_kind = OSTREE_REPO_SYSROOT_KIND_NO;
|
self->sysroot_kind = OSTREE_REPO_SYSROOT_KIND_NO;
|
||||||
|
|
@ -2349,14 +2478,24 @@ _ostree_repo_file_replace_contents (OstreeRepo *self,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ostree_repo_get_path:
|
* ostree_repo_get_path:
|
||||||
* @self:
|
* @self: Repo
|
||||||
|
*
|
||||||
|
* Note that since the introduction of ostree_repo_open_at(), this function may
|
||||||
|
* return a process-specific path in `/proc` if the repository was created using
|
||||||
|
* that API. In general, you should avoid use of this API.
|
||||||
*
|
*
|
||||||
* Returns: (transfer none): Path to repo
|
* Returns: (transfer none): Path to repo
|
||||||
*/
|
*/
|
||||||
GFile *
|
GFile *
|
||||||
ostree_repo_get_path (OstreeRepo *self)
|
ostree_repo_get_path (OstreeRepo *self)
|
||||||
{
|
{
|
||||||
|
/* Did we have an abspath? Return it */
|
||||||
|
if (self->repodir)
|
||||||
return self->repodir;
|
return self->repodir;
|
||||||
|
/* Lazily create a fd-relative path */
|
||||||
|
if (!self->repodir_fdrel)
|
||||||
|
self->repodir_fdrel = ot_fdrel_to_gfile (self->repo_dir_fd, ".");
|
||||||
|
return self->repodir_fdrel;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,13 @@ gboolean ostree_repo_open (OstreeRepo *self,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
|
||||||
|
_OSTREE_PUBLIC
|
||||||
|
OstreeRepo*
|
||||||
|
ostree_repo_open_at (int dfd,
|
||||||
|
const char *path,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
_OSTREE_PUBLIC
|
_OSTREE_PUBLIC
|
||||||
void ostree_repo_set_disable_fsync (OstreeRepo *self,
|
void ostree_repo_set_disable_fsync (OstreeRepo *self,
|
||||||
gboolean disable_fsync);
|
gboolean disable_fsync);
|
||||||
|
|
@ -89,6 +96,13 @@ gboolean ostree_repo_create (OstreeRepo *self,
|
||||||
OstreeRepoMode mode,
|
OstreeRepoMode mode,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
_OSTREE_PUBLIC
|
||||||
|
OstreeRepo * ostree_repo_create_at (int dfd,
|
||||||
|
const char *path,
|
||||||
|
OstreeRepoMode mode,
|
||||||
|
GVariant *options,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
#ifdef OSTREE_ENABLE_EXPERIMENTAL_API
|
#ifdef OSTREE_ENABLE_EXPERIMENTAL_API
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -57,9 +57,8 @@ struct OstreeSysroot {
|
||||||
OstreeDeployment *booted_deployment;
|
OstreeDeployment *booted_deployment;
|
||||||
struct timespec loaded_ts;
|
struct timespec loaded_ts;
|
||||||
|
|
||||||
/* Only access through ostree_sysroot_get_repo() */
|
/* Only access through ostree_sysroot_[_get]repo() */
|
||||||
OstreeRepo *repo;
|
OstreeRepo *repo;
|
||||||
gboolean repo_opened;
|
|
||||||
|
|
||||||
OstreeSysrootDebugFlags debug_flags;
|
OstreeSysrootDebugFlags debug_flags;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -137,18 +137,11 @@ static void
|
||||||
ostree_sysroot_constructed (GObject *object)
|
ostree_sysroot_constructed (GObject *object)
|
||||||
{
|
{
|
||||||
OstreeSysroot *self = OSTREE_SYSROOT (object);
|
OstreeSysroot *self = OSTREE_SYSROOT (object);
|
||||||
g_autoptr(GFile) repo_path = NULL;
|
|
||||||
|
|
||||||
/* Ensure the system root path is set. */
|
/* Ensure the system root path is set. */
|
||||||
if (self->path == NULL)
|
if (self->path == NULL)
|
||||||
self->path = g_object_ref (_ostree_get_default_sysroot_path ());
|
self->path = g_object_ref (_ostree_get_default_sysroot_path ());
|
||||||
|
|
||||||
repo_path = g_file_resolve_relative_path (self->path, "ostree/repo");
|
|
||||||
self->repo = ostree_repo_new_for_sysroot_path (repo_path, self->path);
|
|
||||||
self->repo->sysroot_kind = OSTREE_REPO_SYSROOT_KIND_VIA_SYSROOT;
|
|
||||||
/* Hold a weak ref for the remote-add handling */
|
|
||||||
g_weak_ref_init (&self->repo->sysroot, object);
|
|
||||||
|
|
||||||
G_OBJECT_CLASS (ostree_sysroot_parent_class)->constructed (object);
|
G_OBJECT_CLASS (ostree_sysroot_parent_class)->constructed (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -332,21 +325,12 @@ ostree_sysroot_ensure_initialized (OstreeSysroot *self,
|
||||||
cancellable, error))
|
cancellable, error))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
struct stat stbuf;
|
g_autoptr(OstreeRepo) repo =
|
||||||
if (fstatat (self->sysroot_fd, "ostree/repo/objects", &stbuf, 0) != 0)
|
ostree_repo_create_at (self->sysroot_fd, "ostree/repo",
|
||||||
{
|
OSTREE_REPO_MODE_BARE, NULL,
|
||||||
if (errno != ENOENT)
|
cancellable, error);
|
||||||
return glnx_throw_errno_prefix (error, "stat(ostree/repo/objects)");
|
if (!repo)
|
||||||
else
|
|
||||||
{
|
|
||||||
g_autoptr(GFile) repo_dir = g_file_resolve_relative_path (self->path, "ostree/repo");
|
|
||||||
g_autoptr(OstreeRepo) repo = ostree_repo_new (repo_dir);
|
|
||||||
if (!ostree_repo_create (repo, OSTREE_REPO_MODE_BARE,
|
|
||||||
cancellable, error))
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -772,14 +756,22 @@ ostree_sysroot_load (OstreeSysroot *self,
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
ensure_repo_opened (OstreeSysroot *self,
|
ensure_repo (OstreeSysroot *self,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
if (self->repo_opened)
|
if (self->repo != NULL)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
if (!ostree_repo_open (self->repo, NULL, error))
|
if (!ensure_sysroot_fd (self, error))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
self->repo_opened = TRUE;
|
self->repo = ostree_repo_open_at (self->sysroot_fd, "ostree/repo", NULL, error);
|
||||||
|
if (!self->repo)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* Flag it as having been created via ostree_sysroot_get_repo(), and hold a
|
||||||
|
* weak ref for the remote-add handling.
|
||||||
|
*/
|
||||||
|
g_weak_ref_init (&self->repo->sysroot, self);
|
||||||
|
self->repo->sysroot_kind = OSTREE_REPO_SYSROOT_KIND_VIA_SYSROOT;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -796,7 +788,7 @@ ostree_sysroot_load_if_changed (OstreeSysroot *self,
|
||||||
* previous to v2017.6, but we do now to support the error-free
|
* previous to v2017.6, but we do now to support the error-free
|
||||||
* ostree_sysroot_repo() API.
|
* ostree_sysroot_repo() API.
|
||||||
*/
|
*/
|
||||||
if (!ensure_repo_opened (self, error))
|
if (!ensure_repo (self, error))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
int bootversion = 0;
|
int bootversion = 0;
|
||||||
|
|
@ -999,9 +991,8 @@ ostree_sysroot_get_repo (OstreeSysroot *self,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
if (!ensure_repo_opened (self, error))
|
if (!ensure_repo (self, error))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
if (out_repo != NULL)
|
if (out_repo != NULL)
|
||||||
*out_repo = g_object_ref (self->repo);
|
*out_repo = g_object_ref (self->repo);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,6 @@ static void
|
||||||
teardown (Fixture *fixture,
|
teardown (Fixture *fixture,
|
||||||
gconstpointer test_data)
|
gconstpointer test_data)
|
||||||
{
|
{
|
||||||
glnx_fd_close int parent_repo_dfd = -1;
|
|
||||||
g_autoptr(GError) error = NULL;
|
g_autoptr(GError) error = NULL;
|
||||||
|
|
||||||
/* Recursively remove the temporary directory. */
|
/* Recursively remove the temporary directory. */
|
||||||
|
|
@ -81,10 +80,7 @@ teardown (Fixture *fixture,
|
||||||
|
|
||||||
/* The repo also needs its source files to be removed. This is the inverse
|
/* The repo also needs its source files to be removed. This is the inverse
|
||||||
* of setup_test_repository() in libtest.sh. */
|
* of setup_test_repository() in libtest.sh. */
|
||||||
g_autofree gchar *parent_repo_path = g_file_get_path (ostree_repo_get_path (fixture->parent_repo));
|
int parent_repo_dfd = ostree_repo_get_dfd (fixture->parent_repo);
|
||||||
glnx_opendirat (-1, parent_repo_path, TRUE, &parent_repo_dfd, &error);
|
|
||||||
g_assert_no_error (error);
|
|
||||||
|
|
||||||
glnx_shutil_rm_rf_at (parent_repo_dfd, "../files", NULL, NULL);
|
glnx_shutil_rm_rf_at (parent_repo_dfd, "../files", NULL, NULL);
|
||||||
glnx_shutil_rm_rf_at (parent_repo_dfd, "../repo", NULL, NULL);
|
glnx_shutil_rm_rf_at (parent_repo_dfd, "../repo", NULL, NULL);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,6 @@ static void
|
||||||
teardown (Fixture *fixture,
|
teardown (Fixture *fixture,
|
||||||
gconstpointer test_data)
|
gconstpointer test_data)
|
||||||
{
|
{
|
||||||
glnx_fd_close int parent_repo_dfd = -1;
|
|
||||||
g_autoptr(GError) error = NULL;
|
g_autoptr(GError) error = NULL;
|
||||||
|
|
||||||
/* Recursively remove the temporary directory. */
|
/* Recursively remove the temporary directory. */
|
||||||
|
|
@ -84,10 +83,7 @@ teardown (Fixture *fixture,
|
||||||
|
|
||||||
/* The repo also needs its source files to be removed. This is the inverse
|
/* The repo also needs its source files to be removed. This is the inverse
|
||||||
* of setup_test_repository() in libtest.sh. */
|
* of setup_test_repository() in libtest.sh. */
|
||||||
g_autofree gchar *parent_repo_path = g_file_get_path (ostree_repo_get_path (fixture->parent_repo));
|
int parent_repo_dfd = ostree_repo_get_dfd (fixture->parent_repo);
|
||||||
glnx_opendirat (-1, parent_repo_path, TRUE, &parent_repo_dfd, &error);
|
|
||||||
g_assert_no_error (error);
|
|
||||||
|
|
||||||
glnx_shutil_rm_rf_at (parent_repo_dfd, "../files", NULL, NULL);
|
glnx_shutil_rm_rf_at (parent_repo_dfd, "../files", NULL, NULL);
|
||||||
glnx_shutil_rm_rf_at (parent_repo_dfd, "../repo", NULL, NULL);
|
glnx_shutil_rm_rf_at (parent_repo_dfd, "../repo", NULL, NULL);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue