diff --git a/apidoc/ostree-sections.txt b/apidoc/ostree-sections.txt index df9767d4..90bec167 100644 --- a/apidoc/ostree-sections.txt +++ b/apidoc/ostree-sections.txt @@ -271,6 +271,7 @@ ostree_mutable_tree_get_type OstreeRepo OstreeRepoMode ostree_repo_mode_from_string +ostree_repo_open_at ostree_repo_new ostree_repo_new_for_sysroot_path ostree_repo_new_default @@ -279,6 +280,7 @@ ostree_repo_set_disable_fsync ostree_repo_get_disable_fsync ostree_repo_is_system ostree_repo_is_writable +ostree_repo_create_at ostree_repo_create ostree_repo_get_path ostree_repo_get_mode diff --git a/src/libostree/libostree-devel.sym b/src/libostree/libostree-devel.sym index 49111b4a..82b18667 100644 --- a/src/libostree/libostree-devel.sym +++ b/src/libostree/libostree-devel.sym @@ -21,6 +21,8 @@ LIBOSTREE_2017.10 { ostree_gpg_error_quark; 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 diff --git a/src/libostree/ostree-repo-finder-mount.c b/src/libostree/ostree-repo-finder-mount.c index 1eb3d31d..7f257f68 100644 --- a/src/libostree/ostree-repo-finder-mount.c +++ b/src/libostree/ostree-repo-finder-mount.c @@ -31,6 +31,7 @@ #include "ostree-autocleanups.h" #include "ostree-remote-private.h" +#include "ostree-repo-private.h" #include "ostree-repo-finder.h" #include "ostree-repo-finder-mount.h" @@ -257,19 +258,16 @@ ostree_repo_finder_mount_resolve_async (OstreeRepoFinder *finde { struct stat stbuf; g_autofree gchar *collection_and_ref = NULL; - g_autofree gchar *repo_dir_path = NULL; g_autofree gchar *resolved_repo_uri = NULL; g_autofree gchar *keyring = NULL; g_autoptr(UriAndKeyring) resolved_repo = 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)) { 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); continue; } @@ -277,7 +275,7 @@ ostree_repo_finder_mount_resolve_async (OstreeRepoFinder *finde 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.", - 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); continue; } @@ -294,27 +292,19 @@ ostree_repo_finder_mount_resolve_async (OstreeRepoFinder *finde } /* Exclude repositories which resolve to @parent_repo. */ - g_autofree char *canonical_repo_dir_path = realpath (repo_dir_path, NULL); - g_autofree gchar *parent_repo_path = g_file_get_path (ostree_repo_get_path (parent_repo)); - g_autofree char *canonical_parent_repo_path = realpath (parent_repo_path, NULL); - - if (g_strcmp0 (canonical_repo_dir_path, canonical_parent_repo_path) == 0) + if (stbuf.st_dev == parent_repo->device && + stbuf.st_ino == parent_repo->inode) { - g_debug ("Ignoring ref (%s, %s) on mount ‘%s’ as its repository was the one we are resolving for: %s", - refs[i]->collection_id, refs[i]->ref_name, mount_name, canonical_parent_repo_path); + 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); g_clear_error (&local_error); continue; } - /* Grab the given ref and a checksum for it from the repo. - * FIXME: Ideally, there would be some ostree_repo_open_at() which we - * could use to keep the openat() chain going. See - * https://github.com/ostreedev/ostree/pull/820. */ - 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)) + /* Grab the given ref and a checksum for it from the repo, if it appears to be a valid repo */ + g_autoptr(OstreeRepo) repo = ostree_repo_open_at (repos_dfd, collection_and_ref, + cancellable, &local_error); + if (!repo) { 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); @@ -358,6 +348,11 @@ ostree_repo_finder_mount_resolve_async (OstreeRepoFinder *finde * $mount_root/.ostree/repos/$refs[i]->collection_id/$refs[i]->ref_name. * Add it to the results, keyed by the canonicalised repository URI * 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); 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); diff --git a/src/libostree/ostree-repo-private.h b/src/libostree/ostree-repo-private.h index d2c41316..e38e48bc 100644 --- a/src/libostree/ostree-repo-private.h +++ b/src/libostree/ostree-repo-private.h @@ -96,7 +96,11 @@ struct OstreeRepo { char *commit_stagedir_name; 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 tmp_dir_fd; int cache_dir_fd; @@ -132,10 +136,13 @@ struct OstreeRepo { GHashTable *updated_uncompressed_dirs; GHashTable *object_sizes; - uid_t owner_uid; - uid_t target_owner_uid; + /* Cache the repo's device/inode to use for comparisons elsewhere */ + 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; - guint min_free_space_percent; + guint min_free_space_percent; /* See the min-free-space-percent config option */ guint test_error_flags; /* OstreeRepoTestErrorFlags */ diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c index df019dd6..795016ce 100644 --- a/src/libostree/ostree-repo.c +++ b/src/libostree/ostree-repo.c @@ -456,6 +456,7 @@ ostree_repo_finalize (GObject *object) g_clear_object (&self->parent_repo); g_free (self->stagedir_prefix); + g_clear_object (&self->repodir_fdrel); g_clear_object (&self->repodir); if (self->repo_dir_fd != -1) (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 ostree_repo_class_init (OstreeRepoClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - object_class->constructed = ostree_repo_constructed; object_class->get_property = ostree_repo_get_property; object_class->set_property = ostree_repo_set_property; object_class->finalize = ostree_repo_finalize; @@ -581,6 +571,7 @@ ostree_repo_class_init (OstreeRepoClass *klass) "", G_TYPE_FILE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (object_class, PROP_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); } +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 * get_default_repo_path (GFile *sysroot_path) { @@ -744,8 +772,16 @@ ostree_repo_is_system (OstreeRepo *repo) if (!repo->sysroot_dir) return FALSE; - g_autoptr(GFile) default_repo_path = get_default_repo_path (repo->sysroot_dir); - return g_file_equal (repo->repodir, default_repo_path); + /* 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); + return g_file_equal (repo->repodir, default_repo_path); + } + /* Otherwise, not a system repo */ + return FALSE; } /** @@ -1670,6 +1706,104 @@ ostree_repo_mode_from_string (const char *mode, #define DEFAULT_CONFIG_CONTENTS ("[core]\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: * @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 * 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 ostree_repo_create (OstreeRepo *self, @@ -1693,76 +1832,64 @@ ostree_repo_create (OstreeRepo *self, GCancellable *cancellable, GError **error) { + g_return_val_if_fail (self->repodir, FALSE); const char *repopath = gs_file_get_path_cached (self->repodir); - glnx_fd_close int dfd = -1; - struct stat stbuf; - const char *state_dirs[] = { "objects", "tmp", "extensions", "state", - "refs", "refs/heads", "refs/mirrors", - "refs/remotes" }; + g_autoptr(GVariantBuilder) builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); + if (self->collection_id) + g_variant_builder_add (builder, "{s@v}", "collection-id", + g_variant_new_variant (g_variant_new_string (self->collection_id))); - if (mkdir (repopath, 0755) != 0) - { - if (G_UNLIKELY (errno != EEXIST)) - return glnx_throw_errno (error); - } - - if (!glnx_opendirat (AT_FDCWD, repopath, TRUE, &dfd, error)) + glnx_fd_close int repo_dir_fd = -1; + if (!repo_create_at_internal (AT_FDCWD, repopath, mode, + g_variant_builder_end (builder), + &repo_dir_fd, + cancellable, error)) return FALSE; - - 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; - } - + self->repo_dir_fd = glnx_steal_fd (&repo_dir_fd); if (!ostree_repo_open (self, cancellable, error)) return FALSE; - 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 enumerate_directory_allow_noent (GFile *dirpath, const char *queryargs, @@ -2132,7 +2259,6 @@ ostree_repo_open (OstreeRepo *self, GCancellable *cancellable, GError **error) { - struct stat self_stbuf; struct stat stbuf; 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); } - if (!glnx_opendirat (AT_FDCWD, gs_file_get_path_cached (self->repodir), TRUE, - &self->repo_dir_fd, error)) + if (self->repo_dir_fd == -1) { - g_prefix_error (error, "%s: ", gs_file_get_path_cached (self->repodir)); - return FALSE; + g_assert (self->repodir); + if (!glnx_opendirat (AT_FDCWD, gs_file_get_path_cached (self->repodir), TRUE, + &self->repo_dir_fd, error)) + { + g_prefix_error (error, "%s: ", gs_file_get_path_cached (self->repodir)); + return FALSE; + } } - if (!glnx_fstat (self->repo_dir_fd, &self_stbuf, error)) + if (!glnx_fstat (self->repo_dir_fd, &stbuf, error)) return FALSE; + self->device = stbuf.st_dev; + self->inode = stbuf.st_ino; if (!glnx_opendirat (self->repo_dir_fd, "objects", TRUE, &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; if (!self->writable) @@ -2238,8 +2367,8 @@ ostree_repo_open (OstreeRepo *self, if (fstatat (AT_FDCWD, "/ostree/repo", &system_stbuf, 0) == 0) { /* Are we the same as /ostree/repo? */ - if (self_stbuf.st_dev == system_stbuf.st_dev && - self_stbuf.st_ino == system_stbuf.st_ino) + if (self->device == system_stbuf.st_dev && + self->inode == system_stbuf.st_ino) self->sysroot_kind = OSTREE_REPO_SYSROOT_KIND_IS_SYSROOT_OSTREE; else self->sysroot_kind = OSTREE_REPO_SYSROOT_KIND_NO; @@ -2349,14 +2478,24 @@ _ostree_repo_file_replace_contents (OstreeRepo *self, /** * 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 */ GFile * ostree_repo_get_path (OstreeRepo *self) { - return self->repodir; + /* Did we have an abspath? Return it */ + if (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; } /** diff --git a/src/libostree/ostree-repo.h b/src/libostree/ostree-repo.h index f01fee2a..8766e6df 100644 --- a/src/libostree/ostree-repo.h +++ b/src/libostree/ostree-repo.h @@ -63,6 +63,13 @@ gboolean ostree_repo_open (OstreeRepo *self, GCancellable *cancellable, GError **error); +_OSTREE_PUBLIC +OstreeRepo* +ostree_repo_open_at (int dfd, + const char *path, + GCancellable *cancellable, + GError **error); + _OSTREE_PUBLIC void ostree_repo_set_disable_fsync (OstreeRepo *self, gboolean disable_fsync); @@ -89,6 +96,13 @@ gboolean ostree_repo_create (OstreeRepo *self, OstreeRepoMode mode, GCancellable *cancellable, 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 diff --git a/src/libostree/ostree-sysroot-private.h b/src/libostree/ostree-sysroot-private.h index 4c6cb328..8c4de9e0 100644 --- a/src/libostree/ostree-sysroot-private.h +++ b/src/libostree/ostree-sysroot-private.h @@ -57,9 +57,8 @@ struct OstreeSysroot { OstreeDeployment *booted_deployment; struct timespec loaded_ts; - /* Only access through ostree_sysroot_get_repo() */ + /* Only access through ostree_sysroot_[_get]repo() */ OstreeRepo *repo; - gboolean repo_opened; OstreeSysrootDebugFlags debug_flags; }; diff --git a/src/libostree/ostree-sysroot.c b/src/libostree/ostree-sysroot.c index 5bdfe116..8d91cde6 100644 --- a/src/libostree/ostree-sysroot.c +++ b/src/libostree/ostree-sysroot.c @@ -137,18 +137,11 @@ static void ostree_sysroot_constructed (GObject *object) { OstreeSysroot *self = OSTREE_SYSROOT (object); - g_autoptr(GFile) repo_path = NULL; /* Ensure the system root path is set. */ if (self->path == NULL) 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); } @@ -332,21 +325,12 @@ ostree_sysroot_ensure_initialized (OstreeSysroot *self, cancellable, error)) return FALSE; - struct stat stbuf; - if (fstatat (self->sysroot_fd, "ostree/repo/objects", &stbuf, 0) != 0) - { - if (errno != ENOENT) - return glnx_throw_errno_prefix (error, "stat(ostree/repo/objects)"); - 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; - } - } - + g_autoptr(OstreeRepo) repo = + ostree_repo_create_at (self->sysroot_fd, "ostree/repo", + OSTREE_REPO_MODE_BARE, NULL, + cancellable, error); + if (!repo) + return FALSE; return TRUE; } @@ -772,14 +756,22 @@ ostree_sysroot_load (OstreeSysroot *self, } static gboolean -ensure_repo_opened (OstreeSysroot *self, - GError **error) +ensure_repo (OstreeSysroot *self, + GError **error) { - if (self->repo_opened) + if (self->repo != NULL) return TRUE; - if (!ostree_repo_open (self->repo, NULL, error)) + if (!ensure_sysroot_fd (self, error)) 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; } @@ -796,7 +788,7 @@ ostree_sysroot_load_if_changed (OstreeSysroot *self, * previous to v2017.6, but we do now to support the error-free * ostree_sysroot_repo() API. */ - if (!ensure_repo_opened (self, error)) + if (!ensure_repo (self, error)) return FALSE; int bootversion = 0; @@ -999,9 +991,8 @@ ostree_sysroot_get_repo (OstreeSysroot *self, GCancellable *cancellable, GError **error) { - if (!ensure_repo_opened (self, error)) + if (!ensure_repo (self, error)) return FALSE; - if (out_repo != NULL) *out_repo = g_object_ref (self->repo); return TRUE; diff --git a/tests/test-repo-finder-config.c b/tests/test-repo-finder-config.c index dc083754..ba7191ec 100644 --- a/tests/test-repo-finder-config.c +++ b/tests/test-repo-finder-config.c @@ -70,7 +70,6 @@ static void teardown (Fixture *fixture, gconstpointer test_data) { - glnx_fd_close int parent_repo_dfd = -1; g_autoptr(GError) error = NULL; /* 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 * of setup_test_repository() in libtest.sh. */ - g_autofree gchar *parent_repo_path = g_file_get_path (ostree_repo_get_path (fixture->parent_repo)); - glnx_opendirat (-1, parent_repo_path, TRUE, &parent_repo_dfd, &error); - g_assert_no_error (error); - + int parent_repo_dfd = ostree_repo_get_dfd (fixture->parent_repo); glnx_shutil_rm_rf_at (parent_repo_dfd, "../files", NULL, NULL); glnx_shutil_rm_rf_at (parent_repo_dfd, "../repo", NULL, NULL); diff --git a/tests/test-repo-finder-mount.c b/tests/test-repo-finder-mount.c index c84feb52..f51fb3bb 100644 --- a/tests/test-repo-finder-mount.c +++ b/tests/test-repo-finder-mount.c @@ -73,7 +73,6 @@ static void teardown (Fixture *fixture, gconstpointer test_data) { - glnx_fd_close int parent_repo_dfd = -1; g_autoptr(GError) error = NULL; /* 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 * of setup_test_repository() in libtest.sh. */ - g_autofree gchar *parent_repo_path = g_file_get_path (ostree_repo_get_path (fixture->parent_repo)); - glnx_opendirat (-1, parent_repo_path, TRUE, &parent_repo_dfd, &error); - g_assert_no_error (error); - + int parent_repo_dfd = ostree_repo_get_dfd (fixture->parent_repo); glnx_shutil_rm_rf_at (parent_repo_dfd, "../files", NULL, NULL); glnx_shutil_rm_rf_at (parent_repo_dfd, "../repo", NULL, NULL);