mirror of
https://github.com/ostreedev/ostree.git
synced 2025-03-14 04:59:00 +03:00
Since we're making a shared library, it should be usable by non-GPL apps. To allow more code sharing between the core and the tests, move them to the LGPLv2+ too. A few bits of test and other code are still GPL. See the new COPYING file for more information.
1429 lines
38 KiB
C
1429 lines
38 KiB
C
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
|
|
*
|
|
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library 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
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; 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) || S_ISFIFO(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;
|
|
}
|