[ostree] core: Add internal GFile implementation for reading commits
- From: Colin Walters <walters src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [ostree] core: Add internal GFile implementation for reading commits
- Date: Wed, 9 Nov 2011 11:33:05 +0000 (UTC)
commit 8b43c539cf54a20fceeed94bad63b32d659991c4
Author: Colin Walters <walters verbum org>
Date: Mon Nov 7 11:25:49 2011 -0500
core: Add internal GFile implementation for reading commits
The data structures we use for reading already-written commits versus
building them don't need to be the same. It's cleaner if we can have
generic code which operates on a GFile implementation for reads,
because then we can share more generic code for walking and operating
on filesystem trees via GIO.
Makefile-libostree.am | 4 +
libostree/ostree-core.c | 4 +-
libostree/ostree-core.h | 5 +-
libostree/ostree-repo-file-enumerator.c | 142 +++
libostree/ostree-repo-file-enumerator.h | 54 ++
libostree/ostree-repo-file.c | 1427 +++++++++++++++++++++++++++++++
libostree/ostree-repo-file.h | 114 +++
libostree/ostree-repo.c | 280 ++-----
libostree/ostree-repo.h | 8 +-
ostree/ot-builtin-checkout.c | 2 +-
ostree/ot-builtin-compose.c | 2 +-
11 files changed, 1839 insertions(+), 203 deletions(-)
---
diff --git a/Makefile-libostree.am b/Makefile-libostree.am
index 7b8790b..f1357cc 100644
--- a/Makefile-libostree.am
+++ b/Makefile-libostree.am
@@ -25,6 +25,10 @@ libostree_la_SOURCES = libostree/ostree.h \
libostree/ostree-core.h \
libostree/ostree-repo.c \
libostree/ostree-repo.h \
+ libostree/ostree-repo-file.c \
+ libostree/ostree-repo-file.h \
+ libostree/ostree-repo-file-enumerator.c \
+ libostree/ostree-repo-file-enumerator.h \
libostree/ostree-checkout.c \
libostree/ostree-checkout.h \
$(NULL)
diff --git a/libostree/ostree-core.c b/libostree/ostree-core.c
index a3fc34c..9a05e91 100644
--- a/libostree/ostree-core.c
+++ b/libostree/ostree-core.c
@@ -296,7 +296,7 @@ ostree_stat_and_checksum_file (int dir_fd, const char *path,
}
gboolean
-ostree_set_xattrs (const char *path, GVariant *xattrs, GError **error)
+ostree_set_xattrs (const char *path, GVariant *xattrs, GCancellable *cancellable, GError **error)
{
gboolean ret = FALSE;
int i, n;
@@ -790,7 +790,7 @@ unpack_file (const char *path,
}
}
- if (!ostree_set_xattrs (dest_path, xattrs, error))
+ if (!ostree_set_xattrs (dest_path, xattrs, NULL, error))
goto out;
if (ret_checksum)
diff --git a/libostree/ostree-core.h b/libostree/ostree-core.h
index 3dc70b4..2b39f3f 100644
--- a/libostree/ostree-core.h
+++ b/libostree/ostree-core.h
@@ -28,7 +28,7 @@ G_BEGIN_DECLS
#define OSTREE_MAX_METADATA_SIZE (1 << 26)
-#define OSTREE_GIO_FAST_QUERYINFO "standard::name,standard::type,standard::is-symlink,standard::symlink-target,unix::*"
+#define OSTREE_GIO_FAST_QUERYINFO "standard::name,standard::type,standard::is-symlink,standard::symlink-target,standard::is-hidden,unix::*"
#define OSTREE_EMPTY_STRING_SHA256 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
@@ -98,7 +98,8 @@ char *ostree_get_relative_object_path (const char *checksum,
GVariant *ostree_get_xattrs_for_path (const char *path,
GError **error);
-gboolean ostree_set_xattrs (const char *path, GVariant *xattrs, GError **error);
+gboolean ostree_set_xattrs (const char *path, GVariant *xattrs,
+ GCancellable *cancellable, GError **error);
gboolean ostree_parse_metadata_file (const char *path,
OstreeSerializedVariantType *out_type,
diff --git a/libostree/ostree-repo-file-enumerator.c b/libostree/ostree-repo-file-enumerator.c
new file mode 100644
index 0000000..3a40281
--- /dev/null
+++ b/libostree/ostree-repo-file-enumerator.c
@@ -0,0 +1,142 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2011 Colin Walters <walters verbum org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Author: Colin Walters <walters verbum org>
+ */
+
+#include "config.h"
+
+#include "ostree-repo-file-enumerator.h"
+#include <string.h>
+
+struct _OstreeRepoFileEnumerator
+{
+ GFileEnumerator parent;
+
+ OstreeRepoFile *dir;
+ char *attributes;
+ GFileQueryInfoFlags flags;
+
+ int index;
+};
+
+#define ostree_repo_file_enumerator_get_type _ostree_repo_file_enumerator_get_type
+G_DEFINE_TYPE (OstreeRepoFileEnumerator, ostree_repo_file_enumerator, G_TYPE_FILE_ENUMERATOR);
+
+static GFileInfo *ostree_repo_file_enumerator_next_file (GFileEnumerator *enumerator,
+ GCancellable *cancellable,
+ GError **error);
+static gboolean ostree_repo_file_enumerator_close (GFileEnumerator *enumerator,
+ GCancellable *cancellable,
+ GError **error);
+
+
+static void
+ostree_repo_file_enumerator_dispose (GObject *object)
+{
+ OstreeRepoFileEnumerator *self;
+
+ self = OSTREE_REPO_FILE_ENUMERATOR (object);
+
+ g_clear_object (&self->dir);
+ g_free (self->attributes);
+
+ if (G_OBJECT_CLASS (ostree_repo_file_enumerator_parent_class)->dispose)
+ G_OBJECT_CLASS (ostree_repo_file_enumerator_parent_class)->dispose (object);
+}
+
+static void
+ostree_repo_file_enumerator_finalize (GObject *object)
+{
+ OstreeRepoFileEnumerator *self;
+
+ self = OSTREE_REPO_FILE_ENUMERATOR (object);
+ (void)self;
+
+ G_OBJECT_CLASS (ostree_repo_file_enumerator_parent_class)->finalize (object);
+}
+
+
+static void
+ostree_repo_file_enumerator_class_init (OstreeRepoFileEnumeratorClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GFileEnumeratorClass *enumerator_class = G_FILE_ENUMERATOR_CLASS (klass);
+
+ gobject_class->finalize = ostree_repo_file_enumerator_finalize;
+ gobject_class->dispose = ostree_repo_file_enumerator_dispose;
+
+ enumerator_class->next_file = ostree_repo_file_enumerator_next_file;
+ enumerator_class->close_fn = ostree_repo_file_enumerator_close;
+}
+
+static void
+ostree_repo_file_enumerator_init (OstreeRepoFileEnumerator *self)
+{
+}
+
+GFileEnumerator *
+_ostree_repo_file_enumerator_new (OstreeRepoFile *dir,
+ const char *attributes,
+ GFileQueryInfoFlags flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ OstreeRepoFileEnumerator *self;
+
+ self = g_object_new (OSTREE_TYPE_REPO_FILE_ENUMERATOR,
+ "container", dir,
+ NULL);
+
+ self->dir = g_object_ref (dir);
+ self->attributes = g_strdup (attributes);
+ self->flags = flags;
+
+ return G_FILE_ENUMERATOR (self);
+}
+
+static GFileInfo *
+ostree_repo_file_enumerator_next_file (GFileEnumerator *enumerator,
+ GCancellable *cancellable,
+ GError **error)
+{
+ OstreeRepoFileEnumerator *self = OSTREE_REPO_FILE_ENUMERATOR (enumerator);
+ gboolean ret = FALSE;
+ GFileInfo *info = NULL;
+
+ if (!_ostree_repo_file_tree_query_child (self->dir, self->index,
+ self->attributes, self->flags,
+ &info, cancellable, error))
+ goto out;
+
+ self->index++;
+
+ ret = TRUE;
+ out:
+ if (!ret)
+ g_clear_object (&info);
+ return info;
+}
+
+static gboolean
+ostree_repo_file_enumerator_close (GFileEnumerator *enumerator,
+ GCancellable *cancellable,
+ GError **error)
+{
+ return TRUE;
+}
diff --git a/libostree/ostree-repo-file-enumerator.h b/libostree/ostree-repo-file-enumerator.h
new file mode 100644
index 0000000..04c8e21
--- /dev/null
+++ b/libostree/ostree-repo-file-enumerator.h
@@ -0,0 +1,54 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2011 Colin Walters <walters verbum org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Author: Colin Walters <walters verbum org>
+ */
+
+#ifndef _OSTREE_REPO_FILE_ENUMERATOR
+#define _OSTREE_REPO_FILE_ENUMERATOR
+
+#include "ostree-repo-file.h"
+
+G_BEGIN_DECLS
+
+#define OSTREE_TYPE_REPO_FILE_ENUMERATOR (_ostree_repo_file_enumerator_get_type ())
+#define OSTREE_REPO_FILE_ENUMERATOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), OSTREE_TYPE_REPO_FILE_ENUMERATOR, OstreeRepoFileEnumerator))
+#define OSTREE_REPO_FILE_ENUMERATOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), OSTREE_TYPE_REPO_FILE_ENUMERATOR, OstreeRepoFileEnumeratorClass))
+#define OSTREE_IS_REPO_FILE_ENUMERATOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), OSTREE_TYPE_REPO_FILE_ENUMERATOR))
+#define OSTREE_IS_REPO_FILE_ENUMERATOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), OSTREE_TYPE_REPO_FILE_ENUMERATOR))
+#define OSTREE_REPO_FILE_ENUMERATOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), OSTREE_TYPE_REPO_FILE_ENUMERATOR, OstreeRepoFileEnumeratorClass))
+
+typedef struct _OstreeRepoFileEnumerator OstreeRepoFileEnumerator;
+typedef struct _OstreeRepoFileEnumeratorClass OstreeRepoFileEnumeratorClass;
+
+struct _OstreeRepoFileEnumeratorClass
+{
+ GFileEnumeratorClass parent_class;
+};
+
+GType _ostree_repo_file_enumerator_get_type (void) G_GNUC_CONST;
+
+GFileEnumerator * _ostree_repo_file_enumerator_new (OstreeRepoFile *dir,
+ const char *attributes,
+ GFileQueryInfoFlags flags,
+ GCancellable *cancellable,
+ GError **error);
+
+G_END_DECLS
+
+#endif
diff --git a/libostree/ostree-repo-file.c b/libostree/ostree-repo-file.c
new file mode 100644
index 0000000..6626872
--- /dev/null
+++ b/libostree/ostree-repo-file.c
@@ -0,0 +1,1427 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2011 Colin Walters <walters verbum org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Author: Colin Walters <walters verbum org>
+ */
+
+#include "config.h"
+
+#include "ostree-repo-file-enumerator.h"
+
+static void ostree_repo_file_file_iface_init (GFileIface *iface);
+
+static void
+tree_replace_contents (OstreeRepoFile *self,
+ GVariant *new_files,
+ GVariant *new_dirs);
+
+struct _OstreeRepoFile
+{
+ GObject parent_instance;
+
+ OstreeRepo *repo;
+
+ char *commit;
+ GError *commit_resolve_error;
+
+ OstreeRepoFile *parent;
+ int index;
+ char *name;
+
+ char *tree_contents_checksum;
+ GVariant *tree_contents;
+ char *tree_metadata_checksum;
+ GVariant *tree_metadata;
+};
+
+#define ostree_repo_file_get_type _ostree_repo_file_get_type
+G_DEFINE_TYPE_WITH_CODE (OstreeRepoFile, ostree_repo_file, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (G_TYPE_FILE,
+ ostree_repo_file_file_iface_init))
+
+static void
+ostree_repo_file_finalize (GObject *object)
+{
+ OstreeRepoFile *self;
+
+ self = OSTREE_REPO_FILE (object);
+
+ if (self->tree_contents)
+ g_variant_unref (self->tree_contents);
+ if (self->tree_metadata)
+ g_variant_unref (self->tree_metadata);
+ g_free (self->tree_contents_checksum);
+ g_free (self->tree_metadata_checksum);
+ g_free (self->commit);
+ g_free (self->name);
+
+ G_OBJECT_CLASS (ostree_repo_file_parent_class)->finalize (object);
+}
+
+static void
+ostree_repo_file_dispose (GObject *object)
+{
+ OstreeRepoFile *self;
+
+ self = OSTREE_REPO_FILE (object);
+
+ g_clear_object (&self->repo);
+ g_clear_object (&self->parent);
+
+ if (G_OBJECT_CLASS (ostree_repo_file_parent_class)->dispose)
+ G_OBJECT_CLASS (ostree_repo_file_parent_class)->dispose (object);
+}
+
+static void
+ostree_repo_file_class_init (OstreeRepoFileClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->finalize = ostree_repo_file_finalize;
+ gobject_class->dispose = ostree_repo_file_dispose;
+}
+
+static void
+ostree_repo_file_init (OstreeRepoFile *self)
+{
+ self->index = -1;
+}
+
+static gboolean
+set_error_noent (GFile *self, GError **error)
+{
+ char *path = g_file_get_path (self);
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
+ "No such file or directory: %s", path);
+ g_free (path);
+ return FALSE;
+}
+
+GFile *
+_ostree_repo_file_new_root (OstreeRepo *repo,
+ const char *commit)
+{
+ OstreeRepoFile *self;
+
+ g_return_val_if_fail (repo != NULL, NULL);
+ g_return_val_if_fail (commit != NULL, NULL);
+ g_return_val_if_fail (strlen (commit) == 64, NULL);
+
+ self = g_object_new (OSTREE_TYPE_REPO_FILE, NULL);
+ self->repo = g_object_ref (repo);
+ self->commit = g_strdup (commit);
+
+ return G_FILE (self);
+}
+
+
+GFile *
+_ostree_repo_file_new_child (OstreeRepoFile *parent,
+ const char *name)
+{
+ OstreeRepoFile *self;
+
+ self = g_object_new (OSTREE_TYPE_REPO_FILE, NULL);
+ self->repo = g_object_ref (parent->repo);
+ self->parent = g_object_ref (parent);
+ self->name = g_strdup (name);
+
+ return G_FILE (self);
+}
+
+OstreeRepoFile *
+_ostree_repo_file_new_empty_tree (OstreeRepo *repo)
+{
+ OstreeRepoFile *self;
+
+ self = g_object_new (OSTREE_TYPE_REPO_FILE, NULL);
+ self->repo = g_object_ref (repo);
+
+ tree_replace_contents (self, NULL, NULL);
+
+ return self;
+}
+
+static gboolean
+do_resolve_commit (OstreeRepoFile *self,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ GVariant *commit = NULL;
+ GVariant *root_contents = NULL;
+ GVariant *root_metadata = NULL;
+ const char *tree_contents_checksum;
+ const char *tree_meta_checksum;
+
+ g_assert (self->parent == NULL);
+
+ if (!ostree_repo_load_variant_checked (self->repo, OSTREE_SERIALIZED_COMMIT_VARIANT,
+ self->commit, &commit, error))
+ goto out;
+
+ /* PARSE OSTREE_SERIALIZED_COMMIT_VARIANT */
+ g_variant_get_child (commit, 6, "&s", &tree_contents_checksum);
+ g_variant_get_child (commit, 7, "&s", &tree_meta_checksum);
+
+ if (!ostree_repo_load_variant_checked (self->repo, OSTREE_SERIALIZED_TREE_VARIANT,
+ tree_contents_checksum, &root_contents,
+ error))
+ goto out;
+
+ if (!ostree_repo_load_variant_checked (self->repo, OSTREE_SERIALIZED_DIRMETA_VARIANT,
+ tree_meta_checksum, &root_metadata,
+ error))
+ goto out;
+
+ self->tree_metadata = root_metadata;
+ root_metadata = NULL;
+ self->tree_contents = root_contents;
+ root_contents = NULL;
+
+ out:
+ if (commit)
+ g_variant_unref (commit);
+ if (root_metadata)
+ g_variant_unref (root_metadata);
+ if (root_contents)
+ g_variant_unref (root_contents);
+ return ret;
+}
+
+static gboolean
+do_resolve_nonroot (OstreeRepoFile *self,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ GVariant *container = NULL;
+ GVariant *tree_contents = NULL;
+ GVariant *tree_metadata = NULL;
+ gboolean is_dir;
+ int i;
+
+ i = _ostree_repo_file_tree_find_child (self->parent, self->name, &is_dir, &container);
+
+ if (i < 0)
+ {
+ set_error_noent ((GFile*)self, error);
+ goto out;
+ }
+
+ if (is_dir)
+ {
+ const char *name;
+ const char *content_checksum;
+ const char *metadata_checksum;
+ GVariant *files_variant;
+
+ files_variant = g_variant_get_child_value (self->parent->tree_contents, 2);
+ self->index = g_variant_n_children (files_variant) + i;
+ g_variant_unref (files_variant);
+
+ g_variant_get_child (container, i, "(&s&s&s)",
+ &name, &content_checksum, &metadata_checksum);
+
+ if (!ostree_repo_load_variant_checked (self->repo, OSTREE_SERIALIZED_TREE_VARIANT,
+ content_checksum, &tree_contents,
+ error))
+ goto out;
+
+ if (!ostree_repo_load_variant_checked (self->repo, OSTREE_SERIALIZED_DIRMETA_VARIANT,
+ metadata_checksum, &tree_metadata,
+ error))
+ goto out;
+
+ self->tree_contents = tree_contents;
+ tree_contents = NULL;
+ self->tree_metadata = tree_metadata;
+ tree_metadata = NULL;
+ }
+ else
+ self->index = i;
+
+ ret = TRUE;
+ out:
+ if (container)
+ g_variant_unref (container);
+ if (tree_metadata)
+ g_variant_unref (tree_metadata);
+ if (tree_contents)
+ g_variant_unref (tree_contents);
+ return ret;
+}
+
+gboolean
+_ostree_repo_file_ensure_resolved (OstreeRepoFile *self,
+ GError **error)
+{
+ if (self->commit_resolve_error != NULL)
+ goto out;
+
+ if (self->parent == NULL)
+ {
+ if (self->tree_contents == NULL)
+ (void)do_resolve_commit (self, &(self->commit_resolve_error));
+ }
+ else if (self->index == -1)
+ {
+ (void)do_resolve_nonroot (self, &(self->commit_resolve_error));
+ }
+
+ out:
+ if (self->commit_resolve_error)
+ {
+ if (error)
+ *error = g_error_copy (self->commit_resolve_error);
+ return FALSE;
+ }
+ else
+ return TRUE;
+}
+
+gboolean
+_ostree_repo_file_get_xattrs (OstreeRepoFile *self,
+ GVariant **out_xattrs,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ GVariant *ret_xattrs = NULL;
+ GVariant *metadata = NULL;
+ GInputStream *input = NULL;
+ GFile *local_file = NULL;
+
+ if (!_ostree_repo_file_ensure_resolved (self, error))
+ goto out;
+
+ if (self->tree_metadata)
+ ret_xattrs = g_variant_get_child_value (self->tree_metadata, 4);
+ else if (ostree_repo_is_archive (self->repo))
+ {
+ local_file = _ostree_repo_file_nontree_get_local (self);
+ if (!ostree_parse_packed_file (local_file, &metadata, &input, cancellable, error))
+ goto out;
+ ret_xattrs = g_variant_get_child_value (metadata, 4);
+ }
+ else
+ {
+ local_file = _ostree_repo_file_nontree_get_local (self);
+ ret_xattrs = ostree_get_xattrs_for_path (ot_gfile_get_path_cached (local_file), error);
+ }
+
+ ret = TRUE;
+ *out_xattrs = ret_xattrs;
+ ret_xattrs = NULL;
+ out:
+ if (ret_xattrs)
+ g_variant_unref (ret_xattrs);
+ if (metadata)
+ g_variant_unref (metadata);
+ g_clear_object (&input);
+ g_clear_object (&local_file);
+ return ret;
+}
+
+GVariant *
+_ostree_repo_file_tree_get_contents (OstreeRepoFile *self)
+{
+ return self->tree_contents;
+}
+
+GVariant *
+_ostree_repo_file_tree_get_metadata (OstreeRepoFile *self)
+{
+ return self->tree_metadata;
+}
+
+void
+_ostree_repo_file_tree_set_metadata (OstreeRepoFile *self,
+ const char *checksum,
+ GVariant *metadata)
+{
+ if (self->tree_metadata)
+ g_variant_unref (self->tree_metadata);
+ self->tree_metadata = g_variant_ref (metadata);
+ g_free (self->tree_metadata_checksum);
+ self->tree_metadata_checksum = g_strdup (checksum);
+}
+
+void
+_ostree_repo_file_make_empty_tree (OstreeRepoFile *self)
+{
+ tree_replace_contents (self, NULL, NULL);
+}
+
+void
+_ostree_repo_file_tree_set_content_checksum (OstreeRepoFile *self,
+ const char *checksum)
+{
+ g_assert (self->parent == NULL);
+ g_free (self->tree_contents_checksum);
+ self->tree_contents_checksum = g_strdup (checksum);
+}
+
+const char *
+_ostree_repo_file_tree_get_content_checksum (OstreeRepoFile *self)
+{
+ g_assert (self->parent == NULL);
+ return self->tree_contents_checksum;
+}
+
+GFile *
+_ostree_repo_file_nontree_get_local (OstreeRepoFile *self)
+{
+ const char *checksum;
+ char *path;
+ GFile *ret;
+
+ g_assert (!ostree_repo_is_archive (self->repo));
+
+ checksum = _ostree_repo_file_nontree_get_checksum (self);
+ path = ostree_repo_get_object_path (self->repo, checksum, OSTREE_OBJECT_TYPE_FILE);
+ ret = ot_util_new_file_for_path (path);
+ g_free (path);
+
+ return ret;
+}
+
+OstreeRepo *
+_ostree_repo_file_get_repo (OstreeRepoFile *self)
+{
+ return self->repo;
+}
+
+OstreeRepoFile *
+_ostree_repo_file_get_root (OstreeRepoFile *self)
+{
+ OstreeRepoFile *parent = self;
+
+ while (parent->parent)
+ parent = parent->parent;
+ return parent;
+}
+
+const char *
+_ostree_repo_file_nontree_get_checksum (OstreeRepoFile *self)
+{
+ int n;
+ gboolean is_dir;
+
+ g_assert (self->parent);
+
+ n = _ostree_repo_file_tree_find_child (self->parent, self->name, &is_dir, NULL);
+ g_assert (n >= 0 && !is_dir);
+
+ return _ostree_repo_file_tree_get_child_checksum (self->parent, n);
+}
+
+const char *
+_ostree_repo_file_tree_get_child_checksum (OstreeRepoFile *self,
+ int n)
+{
+ GVariant *files_variant;
+ const char *checksum;
+
+ g_assert (self->tree_contents);
+
+ files_variant = g_variant_get_child_value (self->tree_contents, 2);
+
+ g_variant_get_child (files_variant, n, "(@s&s)", NULL, &checksum);
+
+ g_variant_unref (files_variant);
+
+ return checksum;
+}
+
+static gboolean
+ostree_repo_file_is_native (GFile *file)
+{
+ return FALSE;
+}
+
+static gboolean
+ostree_repo_file_has_uri_scheme (GFile *file,
+ const char *uri_scheme)
+{
+ return g_ascii_strcasecmp (uri_scheme, "ostree") == 0;
+}
+
+static char *
+ostree_repo_file_get_uri_scheme (GFile *file)
+{
+ return g_strdup ("ostree");
+}
+
+static char *
+ostree_repo_file_get_basename (GFile *file)
+{
+ OstreeRepoFile *self = OSTREE_REPO_FILE (file);
+ return g_strdup (self->name);
+}
+
+static char *
+ostree_repo_file_get_path (GFile *file)
+{
+ OstreeRepoFile *self = OSTREE_REPO_FILE (file);
+ OstreeRepoFile *parent;
+ GString *buf;
+ GSList *parents;
+ GSList *iter;
+
+ buf = g_string_new ("");
+ parents = NULL;
+
+ for (parent = self->parent; parent; parent = parent->parent)
+ parents = g_slist_prepend (parents, parent);
+
+ if (parents->next)
+ {
+ for (iter = parents->next; iter; iter = iter->next)
+ {
+ parent = iter->data;
+ g_string_append_c (buf, '/');
+ g_string_append (buf, parent->name);
+ }
+ }
+ g_string_append_c (buf, '/');
+ g_string_append (buf, self->name);
+
+ g_slist_free (parents);
+
+ return g_string_free (buf, FALSE);
+}
+
+static char *
+ostree_repo_file_get_uri (GFile *file)
+{
+ OstreeRepoFile *self = OSTREE_REPO_FILE (file);
+ char *path;
+ char *uri_path;
+ char *ret;
+
+ path = g_file_get_path (file);
+ uri_path = g_filename_to_uri (path, NULL, NULL);
+ g_free (path);
+ g_assert (g_str_has_prefix (uri_path, "file://"));
+ ret = g_strconcat ("ostree://", self->commit, uri_path+strlen("file://"), NULL);
+ g_free (uri_path);
+
+ return ret;
+}
+
+static char *
+ostree_repo_file_get_parse_name (GFile *file)
+{
+ return ostree_repo_file_get_uri (file);
+}
+
+static GFile *
+ostree_repo_file_get_parent (GFile *file)
+{
+ OstreeRepoFile *self = OSTREE_REPO_FILE (file);
+
+ return g_object_ref (self->parent);
+}
+
+static GFile *
+ostree_repo_file_dup (GFile *file)
+{
+ OstreeRepoFile *self = OSTREE_REPO_FILE (file);
+
+ if (self->parent)
+ return _ostree_repo_file_new_child (self->parent, self->name);
+ else
+ return _ostree_repo_file_new_root (self->repo, self->commit);
+}
+
+static guint
+ostree_repo_file_hash (GFile *file)
+{
+ OstreeRepoFile *self = OSTREE_REPO_FILE (file);
+
+ if (self->parent)
+ return g_file_hash (self->parent) + g_str_hash (self->name);
+ else
+ return g_str_hash (self->commit);
+}
+
+static gboolean
+ostree_repo_file_equal (GFile *file1,
+ GFile *file2)
+{
+ OstreeRepoFile *self1 = OSTREE_REPO_FILE (file1);
+ OstreeRepoFile *self2 = OSTREE_REPO_FILE (file2);
+
+ if (self1->parent && self2->parent)
+ {
+ return g_str_equal (self1->name, self2->name)
+ && g_file_equal ((GFile*)self1->parent, (GFile*)self2->parent);
+ }
+ else if (!self1->parent && !self2->parent)
+ {
+ return g_str_equal (self1->commit, self2->commit);
+ }
+ else
+ return FALSE;
+}
+
+static const char *
+match_prefix (const char *path,
+ const char *prefix)
+{
+ int prefix_len;
+
+ prefix_len = strlen (prefix);
+ if (strncmp (path, prefix, prefix_len) != 0)
+ return NULL;
+
+ /* Handle the case where prefix is the root, so that
+ * the IS_DIR_SEPRARATOR check below works */
+ if (prefix_len > 0 &&
+ G_IS_DIR_SEPARATOR (prefix[prefix_len-1]))
+ prefix_len--;
+
+ return path + prefix_len;
+}
+
+static gboolean
+ostree_repo_file_prefix_matches (GFile *parent,
+ GFile *descendant)
+{
+ const char *remainder;
+ char *parent_path;
+ char *descendant_path;
+
+ parent_path = g_file_get_path (parent);
+ descendant_path = g_file_get_path (descendant);
+ remainder = match_prefix (descendant_path, parent_path);
+ g_free (parent_path);
+ g_free (descendant_path);
+ if (remainder != NULL && G_IS_DIR_SEPARATOR (*remainder))
+ return TRUE;
+ return FALSE;
+}
+
+static char *
+ostree_repo_file_get_relative_path (GFile *parent,
+ GFile *descendant)
+{
+ const char *remainder;
+ char *parent_path;
+ char *descendant_path;
+
+ parent_path = g_file_get_path (parent);
+ descendant_path = g_file_get_path (descendant);
+ remainder = match_prefix (descendant_path, parent_path);
+ g_free (parent_path);
+ g_free (descendant_path);
+
+ if (remainder != NULL && G_IS_DIR_SEPARATOR (*remainder))
+ return g_strdup (remainder + 1);
+ return NULL;
+}
+
+static GFile *
+ostree_repo_file_resolve_relative_path (GFile *file,
+ const char *relative_path)
+{
+ OstreeRepoFile *self = OSTREE_REPO_FILE (file);
+ OstreeRepoFile *parent;
+ char *filename;
+ const char *rest;
+ GFile *ret;
+
+ if (g_path_is_absolute (relative_path) && self->parent)
+ {
+ g_assert (*relative_path == '/');
+ return ostree_repo_file_resolve_relative_path ((GFile*)_ostree_repo_file_get_root (self),
+ relative_path+1);
+ }
+
+ rest = strchr (relative_path, '/');
+ if (rest)
+ {
+ rest += 1;
+ filename = g_strndup (relative_path, rest - relative_path);
+ }
+ else
+ filename = g_strdup (relative_path);
+
+ parent = (OstreeRepoFile*)_ostree_repo_file_new_child (self, filename);
+ g_free (filename);
+
+ if (!rest)
+ ret = (GFile*)parent;
+ else
+ {
+ ret = ostree_repo_file_resolve_relative_path ((GFile*)parent, rest);
+ g_clear_object (&parent);
+ }
+ return ret;
+}
+
+static GFileEnumerator *
+ostree_repo_file_enumerate_children (GFile *file,
+ const char *attributes,
+ GFileQueryInfoFlags flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ OstreeRepoFile *self = OSTREE_REPO_FILE (file);
+ return _ostree_repo_file_enumerator_new (self,
+ attributes, flags,
+ cancellable, error);
+}
+
+static GFile *
+ostree_repo_file_get_child_for_display_name (GFile *file,
+ const char *display_name,
+ GError **error)
+{
+ return g_file_get_child (file, display_name);
+}
+
+static GFile *
+get_child_local_file (OstreeRepo *repo,
+ const char *checksum)
+{
+ char *path;
+ GFile *ret;
+
+ path = ostree_repo_get_object_path (repo, checksum, OSTREE_OBJECT_TYPE_FILE);
+ ret = ot_util_new_file_for_path (path);
+ g_free (path);
+
+ return ret;
+}
+
+static gboolean
+query_child_info_file_nonarchive (OstreeRepo *repo,
+ const char *checksum,
+ GFileAttributeMatcher *matcher,
+ GFileInfo *info,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ GFileInfo *local_info = NULL;
+ GFile *local_file = NULL;
+ int i ;
+ const char *mapped_boolean[] = {
+ "standard::is-symlink"
+ };
+ const char *mapped_string[] = {
+ };
+ const char *mapped_byte_string[] = {
+ "standard::symlink-target"
+ };
+ const char *mapped_uint32[] = {
+ "standard::type",
+ "unix::device",
+ "unix::mode",
+ "unix::nlink",
+ "unix::uid",
+ "unix::gid",
+ "unix::rdev"
+ };
+ const char *mapped_uint64[] = {
+ "standard::size",
+ "standard::allocated-size",
+ "unix::inode"
+ };
+
+ if (!(g_file_attribute_matcher_matches (matcher, "unix::mode")
+ || g_file_attribute_matcher_matches (matcher, "standard::type")))
+ {
+ ret = TRUE;
+ goto out;
+ }
+
+ local_file = get_child_local_file (repo, checksum);
+ local_info = g_file_query_info (local_file,
+ OSTREE_GIO_FAST_QUERYINFO,
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ cancellable,
+ error);
+ if (!local_info)
+ goto out;
+
+ for (i = 0; i < G_N_ELEMENTS (mapped_boolean); i++)
+ g_file_info_set_attribute_boolean (info, mapped_boolean[i], g_file_info_get_attribute_boolean (local_info, mapped_boolean[i]));
+
+ for (i = 0; i < G_N_ELEMENTS (mapped_string); i++)
+ {
+ const char *string = g_file_info_get_attribute_string (local_info, mapped_string[i]);
+ if (string)
+ g_file_info_set_attribute_string (info, mapped_string[i], string);
+ }
+
+ for (i = 0; i < G_N_ELEMENTS (mapped_byte_string); i++)
+ {
+ const char *byte_string = g_file_info_get_attribute_byte_string (local_info, mapped_byte_string[i]);
+ if (byte_string)
+ g_file_info_set_attribute_byte_string (info, mapped_byte_string[i], byte_string);
+ }
+
+ for (i = 0; i < G_N_ELEMENTS (mapped_uint32); i++)
+ g_file_info_set_attribute_uint32 (info, mapped_uint32[i], g_file_info_get_attribute_uint32 (local_info, mapped_uint32[i]));
+
+ for (i = 0; i < G_N_ELEMENTS (mapped_uint64); i++)
+ g_file_info_set_attribute_uint64 (info, mapped_uint64[i], g_file_info_get_attribute_uint64 (local_info, mapped_uint64[i]));
+
+ ret = TRUE;
+ out:
+ g_clear_object (&local_info);
+ g_clear_object (&local_file);
+ return ret;
+}
+
+static gboolean
+query_child_info_file_archive (OstreeRepo *repo,
+ const char *checksum,
+ GFileAttributeMatcher *matcher,
+ GFileInfo *info,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ GFile *local_file = NULL;
+ GVariant *metadata = NULL;
+ GInputStream *input = NULL;
+ guint32 version, uid, gid, mode;
+ guint64 content_len;
+ guint32 file_type;
+ gsize bytes_read;
+ char *buf = NULL;
+
+ local_file = get_child_local_file (repo, checksum);
+
+ if (!ostree_parse_packed_file (local_file, &metadata, &input, cancellable, error))
+ goto out;
+
+ g_variant_get (metadata, "(uuuu a(ayay)t)",
+ &version, &uid, &gid, &mode,
+ NULL, &content_len);
+ uid = GUINT32_FROM_BE (uid);
+ gid = GUINT32_FROM_BE (gid);
+ mode = GUINT32_FROM_BE (mode);
+ content_len = GUINT64_FROM_BE (content_len);
+
+ g_file_info_set_attribute_boolean (info, "standard::is-symlink",
+ S_ISLNK (mode));
+ if (S_ISLNK (mode))
+ file_type = G_FILE_TYPE_SYMBOLIC_LINK;
+ else if (S_ISREG (mode))
+ file_type = G_FILE_TYPE_REGULAR;
+ else if (S_ISBLK (mode) || S_ISCHR(mode))
+ file_type = G_FILE_TYPE_SPECIAL;
+ else
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Corrupted packfile %s: Invalid mode", checksum);
+ goto out;
+ }
+ g_file_info_set_attribute_uint32 (info, "standard::type", file_type);
+
+ g_file_info_set_attribute_uint32 (info, "unix::uid", uid);
+ g_file_info_set_attribute_uint32 (info, "unix::gid", gid);
+ g_file_info_set_attribute_uint32 (info, "unix::mode", mode);
+
+ if (file_type == G_FILE_TYPE_REGULAR)
+ {
+ g_file_info_set_attribute_uint64 (info, "standard::size", content_len);
+ }
+ else if (file_type == G_FILE_TYPE_SYMBOLIC_LINK)
+ {
+ gsize len = MIN (PATH_MAX, content_len) + 1;
+ buf = g_malloc (len);
+
+ if (!g_input_stream_read_all (input, buf, len, &bytes_read, cancellable, error))
+ goto out;
+ buf[bytes_read] = '\0';
+
+ g_file_info_set_attribute_byte_string (info, "standard::symlink-target", buf);
+ }
+ else if (file_type == G_FILE_TYPE_SPECIAL)
+ {
+ guint32 device;
+
+ if (!g_input_stream_read_all (input, &device, 4, &bytes_read, cancellable, error))
+ goto out;
+
+ device = GUINT32_FROM_BE (device);
+ g_file_info_set_attribute_uint32 (info, "unix::device", device);
+ }
+
+ ret = TRUE;
+ out:
+ g_free (buf);
+ if (metadata)
+ g_variant_unref (metadata);
+ g_clear_object (&local_file);
+ g_clear_object (&input);
+ return ret;
+}
+
+static void
+set_info_from_dirmeta (GFileInfo *info,
+ GVariant *metadata)
+{
+ guint32 version, uid, gid, mode;
+
+ g_file_info_set_attribute_uint32 (info, "standard::type", G_FILE_TYPE_DIRECTORY);
+
+ /* PARSE OSTREE_SERIALIZED_DIRMETA_VARIANT */
+ g_variant_get (metadata, "(uuuu a(ayay))",
+ &version, &uid, &gid, &mode,
+ NULL);
+ version = GUINT32_FROM_BE (version);
+ uid = GUINT32_FROM_BE (uid);
+ gid = GUINT32_FROM_BE (gid);
+ mode = GUINT32_FROM_BE (mode);
+
+ g_file_info_set_attribute_uint32 (info, "unix::uid", uid);
+ g_file_info_set_attribute_uint32 (info, "unix::gid", gid);
+ g_file_info_set_attribute_uint32 (info, "unix::mode", mode);
+}
+
+static gboolean
+query_child_info_dir (OstreeRepo *repo,
+ const char *metadata_checksum,
+ GFileAttributeMatcher *matcher,
+ GFileQueryInfoFlags flags,
+ GFileInfo *info,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ GVariant *metadata = NULL;
+
+ if (!g_file_attribute_matcher_matches (matcher, "unix::mode"))
+ {
+ ret = TRUE;
+ goto out;
+ }
+
+ if (!ostree_repo_load_variant_checked (repo, OSTREE_SERIALIZED_DIRMETA_VARIANT,
+ metadata_checksum, &metadata, error))
+ goto out;
+
+ set_info_from_dirmeta (info, metadata);
+
+ ret = TRUE;
+ out:
+ if (metadata)
+ g_variant_unref (metadata);
+ return ret;
+}
+
+static gboolean
+bsearch_in_file_variant (GVariant *variant,
+ const char *name,
+ int *out_pos)
+{
+ int i, n;
+ int m;
+
+ i = 0;
+ n = g_variant_n_children (variant) - 1;
+ m = 0;
+
+ while (i <= n)
+ {
+ GVariant *child;
+ const char *cur;
+ int cmp;
+
+ m = i + ((n - i) / 2);
+
+ child = g_variant_get_child_value (variant, m);
+ g_variant_get_child (child, 0, "&s", &cur, NULL);
+
+ cmp = strcmp (cur, name);
+ if (cmp < 0)
+ i = m + 1;
+ else if (cmp > 0)
+ n = m - 1;
+ else
+ {
+ g_variant_unref (child);
+ *out_pos = m;
+ return TRUE;
+ }
+ g_variant_unref (child);
+ }
+
+ *out_pos = m;
+ return FALSE;
+}
+
+static GVariant *
+remove_variant_child (GVariant *variant,
+ int n)
+{
+ GVariantBuilder builder;
+ GVariantIter *iter;
+ int i;
+ GVariant *child;
+
+ g_variant_builder_init (&builder, g_variant_get_type (variant));
+ iter = g_variant_iter_new (variant);
+
+ i = 0;
+ while ((child = g_variant_iter_next_value (iter)) != NULL)
+ {
+ if (i != n)
+ g_variant_builder_add_value (&builder, child);
+ g_variant_unref (child);
+ }
+ g_variant_iter_free (iter);
+
+ return g_variant_builder_end (&builder);
+}
+
+static GVariant *
+insert_variant_child (GVariant *variant,
+ int n,
+ GVariant *item)
+{
+ GVariantBuilder builder;
+ GVariantIter *iter;
+ int i;
+ GVariant *child;
+
+ g_variant_builder_init (&builder, g_variant_get_type (variant));
+ iter = g_variant_iter_new (variant);
+
+ i = 0;
+ while ((child = g_variant_iter_next_value (iter)) != NULL)
+ {
+ if (i == n)
+ g_variant_builder_add_value (&builder, item);
+ g_variant_builder_add_value (&builder, child);
+ g_variant_unref (child);
+ }
+ g_variant_iter_free (iter);
+
+ return g_variant_builder_end (&builder);
+}
+
+static void
+tree_replace_contents (OstreeRepoFile *self,
+ GVariant *new_files,
+ GVariant *new_dirs)
+{
+ guint version;
+ GVariant *metadata;
+ GVariant *tmp_files = NULL;
+ GVariant *tmp_dirs = NULL;
+
+ if (!(new_files || new_dirs) && self->tree_contents)
+ return;
+ else if (!self->tree_contents)
+ {
+ version = GUINT32_TO_BE (0);
+ metadata = g_variant_new_array (G_VARIANT_TYPE ("{sv}"), NULL, 0);
+ tmp_dirs = g_variant_new_array (G_VARIANT_TYPE ("(ss)"), NULL, 0);
+ tmp_files = g_variant_new_array (G_VARIANT_TYPE ("(ss)"), NULL, 0);
+ }
+ else
+ {
+ g_variant_get_child (self->tree_contents, 0, "u", &version);
+ metadata = g_variant_get_child_value (self->tree_contents, 1);
+ if (!new_files)
+ tmp_files = g_variant_get_child_value (self->tree_contents, 2);
+ if (!new_dirs)
+ tmp_dirs = g_variant_get_child_value (self->tree_contents, 3);
+ }
+
+ if (self->tree_contents)
+ g_variant_unref (self->tree_contents);
+ self->tree_contents = g_variant_new ("(u a{sv}@a(ss)@a(sss))", version, metadata,
+ new_files ? new_files : tmp_files,
+ new_dirs ? new_dirs : tmp_dirs);
+
+ g_variant_unref (metadata);
+ if (tmp_files)
+ g_variant_unref (tmp_files);
+ if (tmp_dirs)
+ g_variant_unref (tmp_dirs);
+}
+
+void
+_ostree_repo_file_tree_remove_child (OstreeRepoFile *self,
+ const char *name)
+{
+ int i;
+ GVariant *files_variant;
+ GVariant *new_files_variant = NULL;
+ GVariant *dirs_variant;
+ GVariant *new_dirs_variant = NULL;
+
+ files_variant = g_variant_get_child_value (self->tree_contents, 2);
+ dirs_variant = g_variant_get_child_value (self->tree_contents, 3);
+
+ if (bsearch_in_file_variant (files_variant, name, &i))
+ {
+ new_files_variant = remove_variant_child (files_variant, i);
+ }
+ else
+ {
+ if (bsearch_in_file_variant (dirs_variant, name, &i))
+ {
+ new_dirs_variant = remove_variant_child (dirs_variant, i);
+ }
+ }
+
+ tree_replace_contents (self, new_files_variant, new_dirs_variant);
+
+ g_variant_unref (files_variant);
+ g_variant_unref (dirs_variant);
+}
+
+void
+_ostree_repo_file_tree_add_file (OstreeRepoFile *self,
+ const char *name,
+ const char *checksum)
+{
+ int n;
+ GVariant *files_variant;
+ GVariant *new_files_variant;
+
+ files_variant = g_variant_get_child_value (self->tree_contents, 2);
+
+ if (!bsearch_in_file_variant (files_variant, name, &n))
+ {
+ new_files_variant = insert_variant_child (files_variant, n,
+ g_variant_new ("(ss)", name, checksum));
+ g_variant_ref_sink (new_files_variant);
+ tree_replace_contents (self, new_files_variant, NULL);
+ g_variant_unref (new_files_variant);
+ }
+ g_variant_unref (files_variant);
+}
+
+void
+_ostree_repo_file_tree_add_dir (OstreeRepoFile *self,
+ const char *name,
+ const char *content_checksum,
+ const char *metadata_checksum)
+{
+ int n;
+ GVariant *dirs_variant;
+ GVariant *new_dirs_variant;
+
+ dirs_variant = g_variant_get_child_value (self->tree_contents, 3);
+
+ if (!bsearch_in_file_variant (dirs_variant, name, &n))
+ {
+ new_dirs_variant = insert_variant_child (dirs_variant, n,
+ g_variant_new ("(sss)", name, content_checksum,
+ metadata_checksum));
+ g_variant_ref_sink (new_dirs_variant);
+ tree_replace_contents (self, NULL, new_dirs_variant);
+ g_variant_unref (new_dirs_variant);
+ }
+ g_variant_unref (dirs_variant);
+}
+
+int
+_ostree_repo_file_tree_find_child (OstreeRepoFile *self,
+ const char *name,
+ gboolean *is_dir,
+ GVariant **out_container)
+{
+ int i;
+ GVariant *files_variant = NULL;
+ GVariant *dirs_variant = NULL;
+ GVariant *ret_container = NULL;
+
+ files_variant = g_variant_get_child_value (self->tree_contents, 2);
+ dirs_variant = g_variant_get_child_value (self->tree_contents, 3);
+
+ i = -1;
+ if (bsearch_in_file_variant (files_variant, name, &i))
+ {
+ *is_dir = FALSE;
+ ret_container = files_variant;
+ files_variant = NULL;
+ }
+ else
+ {
+ if (bsearch_in_file_variant (dirs_variant, name, &i))
+ {
+ *is_dir = TRUE;
+ ret_container = dirs_variant;
+ dirs_variant = NULL;
+ }
+ else
+ {
+ i = -1;
+ }
+ }
+ if (ret_container && out_container)
+ {
+ *out_container = ret_container;
+ ret_container = NULL;
+ }
+ if (ret_container)
+ g_variant_unref (ret_container);
+ if (files_variant)
+ g_variant_unref (files_variant);
+ if (dirs_variant)
+ g_variant_unref (dirs_variant);
+ return i;
+}
+
+gboolean
+_ostree_repo_file_tree_query_child (OstreeRepoFile *self,
+ int n,
+ const char *attributes,
+ GFileQueryInfoFlags flags,
+ GFileInfo **out_info,
+ GCancellable *cancellable,
+ GError **error)
+{
+ const char *name = NULL;
+ gboolean ret = FALSE;
+ GFileInfo *ret_info = NULL;
+ GVariant *files_variant = NULL;
+ GVariant *dirs_variant = NULL;
+ GVariant *tree_child_metadata = NULL;
+ GFileAttributeMatcher *matcher = NULL;
+ int c;
+
+ if (!_ostree_repo_file_ensure_resolved (self, error))
+ goto out;
+
+ matcher = g_file_attribute_matcher_new (attributes);
+
+ ret_info = g_file_info_new ();
+
+ g_assert (self->tree_contents);
+
+ files_variant = g_variant_get_child_value (self->tree_contents, 2);
+ dirs_variant = g_variant_get_child_value (self->tree_contents, 3);
+
+ c = g_variant_n_children (files_variant);
+ if (n < c)
+ {
+ const char *checksum;
+
+ g_variant_get_child (files_variant, n, "(&s&s)", &name, &checksum);
+
+ if (ostree_repo_is_archive (self->repo))
+ {
+ if (!query_child_info_file_archive (self->repo, checksum, matcher, ret_info,
+ cancellable, error))
+ goto out;
+ }
+ else
+ {
+ if (!query_child_info_file_nonarchive (self->repo, checksum, matcher, ret_info,
+ cancellable, error))
+ goto out;
+ }
+ }
+ else
+ {
+ const char *tree_checksum;
+ const char *meta_checksum;
+
+ n -= c;
+
+ c = g_variant_n_children (dirs_variant);
+
+ if (n < c)
+ {
+ g_variant_get_child (dirs_variant, n, "(&s&s&s)",
+ &name, &tree_checksum, &meta_checksum);
+
+ if (!query_child_info_dir (self->repo, meta_checksum,
+ matcher, flags, ret_info,
+ cancellable, error))
+ goto out;
+ }
+ else
+ n -= c;
+ }
+
+ if (name)
+ {
+ g_file_info_set_attribute_byte_string (ret_info, "standard::name",
+ name);
+ g_file_info_set_attribute_string (ret_info, "standard::display-name",
+ name);
+ if (*name == '.')
+ g_file_info_set_is_hidden (ret_info, TRUE);
+ }
+ else
+ {
+ g_clear_object (&ret_info);
+ }
+
+ ret = TRUE;
+ *out_info = ret_info;
+ ret_info = NULL;
+ out:
+ g_clear_object (&ret_info);
+ if (matcher)
+ g_file_attribute_matcher_unref (matcher);
+ if (tree_child_metadata)
+ g_variant_unref (tree_child_metadata);
+ g_variant_unref (files_variant);
+ g_variant_unref (dirs_variant);
+ return ret;
+}
+
+static GFileInfo *
+ostree_repo_file_query_info (GFile *file,
+ const char *attributes,
+ GFileQueryInfoFlags flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ OstreeRepoFile *self = OSTREE_REPO_FILE (file);
+ gboolean ret = FALSE;
+ GFileInfo *info = NULL;
+
+ if (!_ostree_repo_file_ensure_resolved (self, error))
+ goto out;
+
+ if (!self->parent)
+ {
+ info = g_file_info_new ();
+ set_info_from_dirmeta (info, self->tree_metadata);
+ }
+ else
+ {
+ if (!_ostree_repo_file_tree_query_child (self->parent, self->index,
+ attributes, flags,
+ &info, cancellable, error))
+ goto out;
+ }
+
+ ret = TRUE;
+ out:
+ if (!ret)
+ g_clear_object (&info);
+ return info;
+}
+
+static GFileAttributeInfoList *
+ostree_repo_file_query_settable_attributes (GFile *file,
+ GCancellable *cancellable,
+ GError **error)
+{
+ return g_file_attribute_info_list_new ();
+}
+
+static GFileAttributeInfoList *
+ostree_repo_file_query_writable_namespaces (GFile *file,
+ GCancellable *cancellable,
+ GError **error)
+{
+ return g_file_attribute_info_list_new ();
+}
+
+static GFileInputStream *
+ostree_repo_file_read (GFile *file,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ GFile *local_file = NULL;
+ GFileInputStream *ret_stream = NULL;
+ OstreeRepoFile *self = OSTREE_REPO_FILE (file);
+
+ if (self->tree_contents)
+ {
+ g_set_error_literal (error, G_IO_ERROR,
+ G_IO_ERROR_IS_DIRECTORY,
+ "Can't open directory");
+ goto out;
+ }
+
+ if (ostree_repo_is_archive (self->repo))
+ {
+ g_set_error_literal (error, G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ "Can't open archived file (yet)");
+ goto out;
+ }
+ else
+ {
+ local_file = _ostree_repo_file_nontree_get_local (self);
+ ret_stream = g_file_read (local_file, cancellable, error);
+ if (!ret_stream)
+ goto out;
+ }
+
+ ret = TRUE;
+ out:
+ g_clear_object (&local_file);
+ if (!ret)
+ g_clear_object (&ret_stream);
+ return ret_stream;
+}
+
+static void
+ostree_repo_file_file_iface_init (GFileIface *iface)
+{
+ iface->dup = ostree_repo_file_dup;
+ iface->hash = ostree_repo_file_hash;
+ iface->equal = ostree_repo_file_equal;
+ iface->is_native = ostree_repo_file_is_native;
+ iface->has_uri_scheme = ostree_repo_file_has_uri_scheme;
+ iface->get_uri_scheme = ostree_repo_file_get_uri_scheme;
+ iface->get_basename = ostree_repo_file_get_basename;
+ iface->get_path = ostree_repo_file_get_path;
+ iface->get_uri = ostree_repo_file_get_uri;
+ iface->get_parse_name = ostree_repo_file_get_parse_name;
+ iface->get_parent = ostree_repo_file_get_parent;
+ iface->prefix_matches = ostree_repo_file_prefix_matches;
+ iface->get_relative_path = ostree_repo_file_get_relative_path;
+ iface->resolve_relative_path = ostree_repo_file_resolve_relative_path;
+ iface->get_child_for_display_name = ostree_repo_file_get_child_for_display_name;
+ iface->set_display_name = NULL;
+ iface->enumerate_children = ostree_repo_file_enumerate_children;
+ iface->query_info = ostree_repo_file_query_info;
+ iface->query_filesystem_info = NULL;
+ iface->find_enclosing_mount = NULL;
+ iface->query_settable_attributes = ostree_repo_file_query_settable_attributes;
+ iface->query_writable_namespaces = ostree_repo_file_query_writable_namespaces;
+ iface->set_attribute = NULL;
+ iface->set_attributes_from_info = NULL;
+ iface->read_fn = ostree_repo_file_read;
+ iface->append_to = NULL;
+ iface->create = NULL;
+ iface->replace = NULL;
+ iface->open_readwrite = NULL;
+ iface->create_readwrite = NULL;
+ iface->replace_readwrite = NULL;
+ iface->delete_file = NULL;
+ iface->trash = NULL;
+ iface->make_directory = NULL;
+ iface->make_symbolic_link = NULL;
+ iface->copy = NULL;
+ iface->move = NULL;
+ iface->monitor_dir = NULL;
+ iface->monitor_file = NULL;
+
+ iface->supports_thread_contexts = TRUE;
+}
diff --git a/libostree/ostree-repo-file.h b/libostree/ostree-repo-file.h
new file mode 100644
index 0000000..4e16c71
--- /dev/null
+++ b/libostree/ostree-repo-file.h
@@ -0,0 +1,114 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2011 Colin Walters <walters verbum org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Author: Colin Walters <walters verbum org>
+ */
+
+#ifndef _OSTREE_REPO_FILE
+#define _OSTREE_REPO_FILE
+
+#include "ostree-repo.h"
+
+G_BEGIN_DECLS
+
+#define OSTREE_TYPE_REPO_FILE (_ostree_repo_file_get_type ())
+#define OSTREE_REPO_FILE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), OSTREE_TYPE_REPO_FILE, OstreeRepoFile))
+#define OSTREE_REPO_FILE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), OSTREE_TYPE_REPO_FILE, OstreeRepoFileClass))
+#define OSTREE_IS_LOCAL_FILE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), OSTREE_TYPE_REPO_FILE))
+#define OSTREE_IS_LOCAL_FILE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), OSTREE_TYPE_REPO_FILE))
+#define OSTREE_REPO_FILE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), OSTREE_TYPE_REPO_FILE, OstreeRepoFileClass))
+
+typedef struct _OstreeRepoFile OstreeRepoFile;
+typedef struct _OstreeRepoFileClass OstreeRepoFileClass;
+
+struct _OstreeRepoFileClass
+{
+ GObjectClass parent_class;
+};
+
+GType _ostree_repo_file_get_type (void) G_GNUC_CONST;
+
+GFile * _ostree_repo_file_new_root (OstreeRepo *repo,
+ const char *commit);
+
+OstreeRepoFile * _ostree_repo_file_new_empty_tree (OstreeRepo *repo);
+
+GFile * _ostree_repo_file_new_child (OstreeRepoFile *parent,
+ const char *name);
+
+gboolean _ostree_repo_file_ensure_resolved (OstreeRepoFile *self,
+ GError **error);
+
+gboolean _ostree_repo_file_get_xattrs (OstreeRepoFile *self,
+ GVariant **out_xattrs,
+ GCancellable *cancellable,
+ GError **error);
+
+OstreeRepo * _ostree_repo_file_get_repo (OstreeRepoFile *self);
+OstreeRepoFile * _ostree_repo_file_get_root (OstreeRepoFile *self);
+
+void _ostree_repo_file_make_empty_tree (OstreeRepoFile *self);
+
+void _ostree_repo_file_tree_set_metadata (OstreeRepoFile *self,
+ const char *checksum,
+ GVariant *metadata);
+
+void _ostree_repo_file_tree_set_content_checksum (OstreeRepoFile *self,
+ const char *checksum);
+const char *_ostree_repo_file_tree_get_content_checksum (OstreeRepoFile *self);
+
+gboolean _ostree_repo_file_is_tree (OstreeRepoFile *self);
+
+const char * _ostree_repo_file_nontree_get_checksum (OstreeRepoFile *self);
+
+GFile *_ostree_repo_file_nontree_get_local (OstreeRepoFile *self);
+
+void _ostree_repo_file_tree_remove_child (OstreeRepoFile *self,
+ const char *name);
+
+void _ostree_repo_file_tree_add_file (OstreeRepoFile *self,
+ const char *name,
+ const char *checksum);
+
+void _ostree_repo_file_tree_add_dir (OstreeRepoFile *self,
+ const char *name,
+ const char *content_checksum,
+ const char *metadata_checksum);
+
+int _ostree_repo_file_tree_find_child (OstreeRepoFile *self,
+ const char *name,
+ gboolean *is_dir,
+ GVariant **out_container);
+
+const char *_ostree_repo_file_tree_get_child_checksum (OstreeRepoFile *self,
+ int n);
+
+gboolean _ostree_repo_file_tree_query_child (OstreeRepoFile *self,
+ int n,
+ const char *attributes,
+ GFileQueryInfoFlags flags,
+ GFileInfo **out_info,
+ GCancellable *cancellable,
+ GError **error);
+
+GVariant *_ostree_repo_file_tree_get_contents (OstreeRepoFile *self);
+GVariant *_ostree_repo_file_tree_get_metadata (OstreeRepoFile *self);
+
+G_END_DECLS
+
+#endif
diff --git a/libostree/ostree-repo.c b/libostree/ostree-repo.c
index 0f5fb88..1d9e853 100644
--- a/libostree/ostree-repo.c
+++ b/libostree/ostree-repo.c
@@ -25,6 +25,7 @@
#include "ostree.h"
#include "otutil.h"
+#include "ostree-repo-file-enumerator.h"
#include <gio/gunixoutputstream.h>
#include <gio/gunixinputstream.h>
@@ -1016,142 +1017,6 @@ parsed_tree_data_free (ParsedTreeData *pdata)
g_free (pdata);
}
-static gboolean
-parse_tree (OstreeRepo *self,
- const char *sha256,
- ParsedTreeData **out_pdata,
- GError **error)
-{
- gboolean ret = FALSE;
- ParsedTreeData *ret_pdata = NULL;
- int i, n;
- guint32 version;
- GVariant *tree_variant = NULL;
- GVariant *meta_variant = NULL;
- GVariant *files_variant = NULL;
- GVariant *dirs_variant = NULL;
-
- if (!ostree_repo_load_variant_checked (self, OSTREE_SERIALIZED_TREE_VARIANT,
- sha256, &tree_variant, error))
- goto out;
-
- /* PARSE OSTREE_SERIALIZED_TREE_VARIANT */
- g_variant_get (tree_variant, "(u a{sv}@a(ss)@a(sss))",
- &version, &meta_variant, &files_variant, &dirs_variant);
- version = GUINT32_FROM_BE (version);
-
- ret_pdata = parsed_tree_data_new ();
- n = g_variant_n_children (files_variant);
- for (i = 0; i < n; i++)
- {
- const char *filename;
- const char *checksum;
-
- g_variant_get_child (files_variant, i, "(&s&s)", &filename, &checksum);
-
- g_hash_table_insert (ret_pdata->files, g_strdup (filename), g_strdup (checksum));
- }
-
- n = g_variant_n_children (dirs_variant);
- for (i = 0; i < n; i++)
- {
- const char *dirname;
- const char *tree_checksum;
- const char *meta_checksum;
- ParsedTreeData *child_tree = NULL;
- GVariant *metadata = NULL;
- ParsedDirectoryData *child_dir = NULL;
-
- g_variant_get_child (dirs_variant, i, "(&s&s&s)",
- &dirname, &tree_checksum, &meta_checksum);
-
- if (!parse_tree (self, tree_checksum, &child_tree, error))
- goto out;
-
- if (!ostree_repo_load_variant_checked (self, OSTREE_SERIALIZED_DIRMETA_VARIANT,
- meta_checksum, &metadata, error))
- {
- parsed_tree_data_free (child_tree);
- goto out;
- }
-
- child_dir = g_new0 (ParsedDirectoryData, 1);
- child_dir->tree_data = child_tree;
- child_dir->metadata_sha256 = g_strdup (meta_checksum);
- child_dir->meta_data = metadata;
-
- g_hash_table_insert (ret_pdata->directories, g_strdup (dirname), child_dir);
- }
-
- ret = TRUE;
- out:
- if (!ret)
- parsed_tree_data_free (ret_pdata);
- else
- *out_pdata = ret_pdata;
- if (tree_variant)
- g_variant_unref (tree_variant);
- if (meta_variant)
- g_variant_unref (meta_variant);
- if (files_variant)
- g_variant_unref (files_variant);
- if (dirs_variant)
- g_variant_unref (dirs_variant);
- return ret;
-}
-
-static gboolean
-load_commit_and_trees (OstreeRepo *self,
- const char *commit_sha256,
- GVariant **out_commit,
- ParsedDirectoryData **out_root_data,
- GError **error)
-{
- GVariant *ret_commit = NULL;
- ParsedDirectoryData *ret_root_data = NULL;
- ParsedTreeData *tree_data = NULL;
- char *ret_metadata_checksum = NULL;
- GVariant *root_metadata = NULL;
- gboolean ret = FALSE;
- const char *tree_contents_checksum;
- const char *tree_meta_checksum;
-
- if (!ostree_repo_load_variant_checked (self, OSTREE_SERIALIZED_COMMIT_VARIANT,
- commit_sha256, &ret_commit, error))
- goto out;
-
- /* PARSE OSTREE_SERIALIZED_COMMIT_VARIANT */
- g_variant_get_child (ret_commit, 6, "&s", &tree_contents_checksum);
- g_variant_get_child (ret_commit, 7, "&s", &tree_meta_checksum);
-
- if (!ostree_repo_load_variant_checked (self, OSTREE_SERIALIZED_DIRMETA_VARIANT,
- tree_meta_checksum, &root_metadata, error))
- goto out;
-
- if (!parse_tree (self, tree_contents_checksum, &tree_data, error))
- goto out;
-
- ret_root_data = g_new0 (ParsedDirectoryData, 1);
- ret_root_data->tree_data = tree_data;
- ret_root_data->metadata_sha256 = g_strdup (tree_meta_checksum);
- ret_root_data->meta_data = root_metadata;
- root_metadata = NULL;
-
- ret = TRUE;
- *out_commit = ret_commit;
- ret_commit = NULL;
- *out_root_data = ret_root_data;
- ret_root_data = NULL;
- out:
- if (ret_commit)
- g_variant_unref (ret_commit);
- parsed_directory_data_free (ret_root_data);
- g_free (ret_metadata_checksum);
- if (root_metadata)
- g_variant_unref (root_metadata);
- return ret;
-}
-
static GVariant *
create_empty_gvariant_dict (void)
{
@@ -1807,106 +1672,130 @@ ostree_repo_load_variant (OstreeRepo *self,
static gboolean
checkout_tree (OstreeRepo *self,
- ParsedTreeData *tree,
+ OstreeRepoFile *dir,
const char *destination,
+ GCancellable *cancellable,
GError **error);
static gboolean
checkout_one_directory (OstreeRepo *self,
const char *destination,
const char *dirname,
- ParsedDirectoryData *dir,
+ OstreeRepoFile *dir,
+ GFileInfo *dir_info,
+ GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
char *dest_path = NULL;
- guint32 version, uid, gid, mode;
GVariant *xattr_variant = NULL;
dest_path = g_build_filename (destination, dirname, NULL);
-
- /* PARSE OSTREE_SERIALIZED_DIRMETA_VARIANT */
- g_variant_get (dir->meta_data, "(uuuu a(ayay))",
- &version, &uid, &gid, &mode,
- &xattr_variant);
- version = GUINT32_FROM_BE (version);
- uid = GUINT32_FROM_BE (uid);
- gid = GUINT32_FROM_BE (gid);
- mode = GUINT32_FROM_BE (mode);
-
- if (mkdir (dest_path, (mode_t)mode) < 0)
+
+ if (!_ostree_repo_file_get_xattrs (dir, &xattr_variant, NULL, error))
+ goto out;
+
+ if (mkdir (dest_path, (mode_t)g_file_info_get_attribute_uint32 (dir_info, "unix::mode")) < 0)
{
ot_util_set_error_from_errno (error, errno);
g_prefix_error (error, "Failed to create directory '%s': ", dest_path);
goto out;
}
-
- if (!checkout_tree (self, dir->tree_data, dest_path, error))
- goto out;
- if (!ostree_set_xattrs (dest_path, xattr_variant, error))
+ if (!ostree_set_xattrs (dest_path, xattr_variant, cancellable, error))
+ goto out;
+
+ if (!checkout_tree (self, dir, dest_path, cancellable, error))
goto out;
ret = TRUE;
out:
g_free (dest_path);
- g_variant_unref (xattr_variant);
+ if (xattr_variant)
+ g_variant_unref (xattr_variant);
return ret;
}
static gboolean
checkout_tree (OstreeRepo *self,
- ParsedTreeData *tree,
+ OstreeRepoFile *dir,
const char *destination,
+ GCancellable *cancellable,
GError **error)
{
OstreeRepoPrivate *priv = GET_PRIVATE (self);
gboolean ret = FALSE;
- GHashTableIter hash_iter;
- gpointer key, value;
+ GError *temp_error = NULL;
+ GFileInfo *file_info = NULL;
+ GFileEnumerator *dir_enum = NULL;
+ GFile *child = NULL;
+ char *object_path = NULL;
+ char *dest_path = NULL;
- g_hash_table_iter_init (&hash_iter, tree->files);
- while (g_hash_table_iter_next (&hash_iter, &key, &value))
+ dir_enum = g_file_enumerate_children ((GFile*)dir, OSTREE_GIO_FAST_QUERYINFO,
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ cancellable,
+ error);
+ if (!dir_enum)
+ goto out;
+
+ while ((file_info = g_file_enumerator_next_file (dir_enum, cancellable, &temp_error)) != NULL)
{
- const char *filename = key;
- const char *checksum = value;
- char *object_path;
- char *dest_path;
+ const char *name;
+ guint32 type;
- object_path = ostree_repo_get_object_path (self, checksum, OSTREE_OBJECT_TYPE_FILE);
- dest_path = g_build_filename (destination, filename, NULL);
-
- if (priv->archive)
+ name = g_file_info_get_attribute_byte_string (file_info, "standard::name");
+ type = g_file_info_get_attribute_uint32 (file_info, "standard::type");
+
+ child = g_file_get_child ((GFile*)dir, name);
+
+ if (type == G_FILE_TYPE_DIRECTORY)
{
- if (!ostree_unpack_object (object_path, OSTREE_OBJECT_TYPE_FILE, dest_path, NULL, error))
+ if (!checkout_one_directory (self, destination, name, (OstreeRepoFile*)child, file_info, cancellable, error))
goto out;
}
else
{
- if (link (object_path, dest_path) < 0)
+ const char *checksum = _ostree_repo_file_nontree_get_checksum ((OstreeRepoFile*)child);
+
+ dest_path = g_build_filename (destination, name, NULL);
+ object_path = ostree_repo_get_object_path (self, checksum, OSTREE_OBJECT_TYPE_FILE);
+
+ if (priv->archive)
{
- ot_util_set_error_from_errno (error, errno);
- g_free (object_path);
- g_free (dest_path);
- goto out;
+ if (!ostree_unpack_object (object_path, OSTREE_OBJECT_TYPE_FILE, dest_path, NULL, error))
+ goto out;
+ }
+ else
+ {
+ if (link (object_path, dest_path) < 0)
+ {
+ ot_util_set_error_from_errno (error, errno);
+ goto out;
+ }
}
- g_free (object_path);
- g_free (dest_path);
}
- }
- g_hash_table_iter_init (&hash_iter, tree->directories);
- while (g_hash_table_iter_next (&hash_iter, &key, &value))
+ g_free (object_path);
+ object_path = NULL;
+ g_free (dest_path);
+ dest_path = NULL;
+ g_clear_object (&file_info);
+ g_clear_object (&child);
+ }
+ if (file_info == NULL && temp_error != NULL)
{
- const char *dirname = key;
- ParsedDirectoryData *dir = value;
-
- if (!checkout_one_directory (self, destination, dirname, dir, error))
- goto out;
+ g_propagate_error (error, temp_error);
+ goto out;
}
ret = TRUE;
out:
+ g_clear_object (&dir_enum);
+ g_clear_object (&file_info);
+ g_clear_object (&child);
+ g_free (object_path);
+ g_free (dest_path);
return ret;
}
@@ -1914,13 +1803,13 @@ gboolean
ostree_repo_checkout (OstreeRepo *self,
const char *rev,
const char *destination,
+ GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
- GVariant *commit = NULL;
char *resolved = NULL;
- char *root_meta_sha = NULL;
- ParsedDirectoryData *root = NULL;
+ OstreeRepoFile *root = NULL;
+ GFileInfo *root_info = NULL;
if (g_file_test (destination, G_FILE_TEST_EXISTS))
{
@@ -1933,18 +1822,23 @@ ostree_repo_checkout (OstreeRepo *self,
if (!resolve_rev (self, rev, FALSE, &resolved, error))
goto out;
- if (!load_commit_and_trees (self, resolved, &commit, &root, error))
+ root = (OstreeRepoFile*)_ostree_repo_file_new_root (self, resolved);
+ if (!_ostree_repo_file_ensure_resolved (root, error))
+ goto out;
+
+ root_info = g_file_query_info ((GFile*)root, OSTREE_GIO_FAST_QUERYINFO,
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ NULL, error);
+ if (!root_info)
goto out;
- if (!checkout_one_directory (self, destination, NULL, root, error))
+ if (!checkout_one_directory (self, destination, NULL, root, root_info, cancellable, error))
goto out;
ret = TRUE;
out:
g_free (resolved);
- if (commit)
- g_variant_unref (commit);
- parsed_directory_data_free (root);
- g_free (root_meta_sha);
+ g_clear_object (&root);
+ g_clear_object (&root_info);
return ret;
}
diff --git a/libostree/ostree-repo.h b/libostree/ostree-repo.h
index 17ec48f..5f46e46 100644
--- a/libostree/ostree-repo.h
+++ b/libostree/ostree-repo.h
@@ -18,7 +18,6 @@
*
* Author: Colin Walters <walters verbum org>
*/
-/* ostree-repo.h */
#ifndef _OSTREE_REPO
#define _OSTREE_REPO
@@ -120,9 +119,10 @@ gboolean ostree_repo_commit_from_filelist_fd (OstreeRepo *self,
GError **error);
gboolean ostree_repo_checkout (OstreeRepo *self,
- const char *ref,
- const char *destination,
- GError **error);
+ const char *ref,
+ const char *destination,
+ GCancellable *cancellable,
+ GError **error);
typedef void (*OstreeRepoObjectIter) (OstreeRepo *self, const char *path,
GFileInfo *fileinfo, gpointer user_data);
diff --git a/ostree/ot-builtin-checkout.c b/ostree/ot-builtin-checkout.c
index 8a80270..3662033 100644
--- a/ostree/ot-builtin-checkout.c
+++ b/ostree/ot-builtin-checkout.c
@@ -64,7 +64,7 @@ ostree_builtin_checkout (int argc, char **argv, const char *repo_path, GError **
commit = argv[1];
destination = argv[2];
- if (!ostree_repo_checkout (repo, commit, destination, error))
+ if (!ostree_repo_checkout (repo, commit, destination, NULL, error))
goto out;
ret = TRUE;
diff --git a/ostree/ot-builtin-compose.c b/ostree/ot-builtin-compose.c
index 0f39af0..d43a6e5 100644
--- a/ostree/ot-builtin-compose.c
+++ b/ostree/ot-builtin-compose.c
@@ -196,7 +196,7 @@ compose_branch_on_dir (OstreeRepo *repo,
branchf = ot_util_new_file_for_path (branchpath);
g_print ("Checking out %s (commit %s)...\n", branch, branchrev);
- if (!ostree_repo_checkout (repo, branchrev, branchpath, error))
+ if (!ostree_repo_checkout (repo, branchrev, branchpath, NULL, error))
goto out;
g_print ("...done\n");
g_print ("Merging over destination...\n");
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]