diff options
-rw-r--r-- | Makefile-libostree.am | 2 | ||||
-rw-r--r-- | src/libostree/ostree-chain-input-stream.c | 210 | ||||
-rw-r--r-- | src/libostree/ostree-chain-input-stream.h | 67 | ||||
-rw-r--r-- | src/libostree/ostree-core.c | 502 | ||||
-rw-r--r-- | src/libostree/ostree-core.h | 100 | ||||
-rw-r--r-- | src/libostree/ostree-repo-file.c | 18 | ||||
-rw-r--r-- | src/libostree/ostree-repo.c | 297 | ||||
-rw-r--r-- | src/libostree/ostree-traverse.c | 17 | ||||
-rw-r--r-- | src/libostree/ostree.h | 1 | ||||
-rw-r--r-- | src/libotutil/ot-gio-utils.c | 39 | ||||
-rw-r--r-- | src/libotutil/ot-gio-utils.h | 8 | ||||
-rw-r--r-- | src/libotutil/ot-variant-utils.c | 14 | ||||
-rw-r--r-- | src/libotutil/ot-variant-utils.h | 2 | ||||
-rw-r--r-- | src/ostree/ostree-pull.c | 298 | ||||
-rw-r--r-- | src/ostree/ot-builtin-checksum.c | 2 | ||||
-rw-r--r-- | src/ostree/ot-builtin-diff.c | 2 | ||||
-rw-r--r-- | src/ostree/ot-builtin-fsck.c | 14 | ||||
-rw-r--r-- | src/ostree/ot-builtin-local-clone.c | 72 | ||||
-rw-r--r-- | src/ostree/ot-builtin-pack.c | 141 | ||||
-rw-r--r-- | src/ostree/ot-builtin-show.c | 10 | ||||
-rw-r--r-- | src/ostree/ot-builtin-unpack.c | 13 | ||||
-rwxr-xr-x | tests/t0000-basic.sh | 10 |
22 files changed, 1048 insertions, 791 deletions
diff --git a/Makefile-libostree.am b/Makefile-libostree.am index bc64cb75..6eb27e08 100644 --- a/Makefile-libostree.am +++ b/Makefile-libostree.am @@ -24,6 +24,8 @@ libostree_la_SOURCES = src/libostree/ostree.h \ src/libostree/ostree-core.h \ src/libostree/ostree-checksum-input-stream.c \ src/libostree/ostree-checksum-input-stream.h \ + src/libostree/ostree-chain-input-stream.c \ + src/libostree/ostree-chain-input-stream.h \ src/libostree/ostree-mutable-tree.c \ src/libostree/ostree-mutable-tree.h \ src/libostree/ostree-repo.c \ diff --git a/src/libostree/ostree-chain-input-stream.c b/src/libostree/ostree-chain-input-stream.c new file mode 100644 index 00000000..b875e075 --- /dev/null +++ b/src/libostree/ostree-chain-input-stream.c @@ -0,0 +1,210 @@ +/* -*- 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. + */ + +#include "config.h" + + +#include <gio/gio.h> +#include "ostree-chain-input-stream.h" + +enum { + PROP_0, + PROP_STREAMS +}; + +G_DEFINE_TYPE (OstreeChainInputStream, ostree_chain_input_stream, G_TYPE_INPUT_STREAM) + +struct _OstreeChainInputStreamPrivate { + GPtrArray *streams; + guint index; +}; + +static void ostree_chain_input_stream_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void ostree_chain_input_stream_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void ostree_chain_input_stream_finalize (GObject *object); +static gssize ostree_chain_input_stream_read (GInputStream *stream, + void *buffer, + gsize count, + GCancellable *cancellable, + GError **error); +static gboolean ostree_chain_input_stream_close (GInputStream *stream, + GCancellable *cancellable, + GError **error); + +static void +ostree_chain_input_stream_class_init (OstreeChainInputStreamClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GInputStreamClass *stream_class = G_INPUT_STREAM_CLASS (klass); + + g_type_class_add_private (klass, sizeof (OstreeChainInputStreamPrivate)); + + gobject_class->get_property = ostree_chain_input_stream_get_property; + gobject_class->set_property = ostree_chain_input_stream_set_property; + gobject_class->finalize = ostree_chain_input_stream_finalize; + + stream_class->read_fn = ostree_chain_input_stream_read; + stream_class->close_fn = ostree_chain_input_stream_close; + + /** + * OstreeChainInputStream:streams: (element-type GInputStream) + * + * Chain of input streams read in order. + */ + g_object_class_install_property (gobject_class, + PROP_STREAMS, + g_param_spec_pointer ("streams", + "", "", + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + +} + +static void +ostree_chain_input_stream_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + OstreeChainInputStream *self; + + self = OSTREE_CHAIN_INPUT_STREAM (object); + + switch (prop_id) + { + case PROP_STREAMS: + self->priv->streams = g_ptr_array_ref (g_value_get_pointer (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +ostree_chain_input_stream_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + OstreeChainInputStream *self; + + self = OSTREE_CHAIN_INPUT_STREAM (object); + + switch (prop_id) + { + case PROP_STREAMS: + g_value_set_pointer (value, self->priv->streams); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +ostree_chain_input_stream_finalize (GObject *object) +{ + OstreeChainInputStream *stream; + + stream = (OstreeChainInputStream*)(object); + + g_ptr_array_unref (stream->priv->streams); + + G_OBJECT_CLASS (ostree_chain_input_stream_parent_class)->finalize (object); +} + +static void +ostree_chain_input_stream_init (OstreeChainInputStream *self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + OSTREE_TYPE_CHAIN_INPUT_STREAM, + OstreeChainInputStreamPrivate); + +} + +OstreeChainInputStream * +ostree_chain_input_stream_new (GPtrArray *streams) +{ + OstreeChainInputStream *stream; + + stream = g_object_new (OSTREE_TYPE_CHAIN_INPUT_STREAM, + "streams", streams, + NULL); + + return (OstreeChainInputStream*) (stream); +} + +static gssize +ostree_chain_input_stream_read (GInputStream *stream, + void *buffer, + gsize count, + GCancellable *cancellable, + GError **error) +{ + OstreeChainInputStream *self = (OstreeChainInputStream*) stream; + GInputStream *child; + gssize res = -1; + + if (g_cancellable_set_error_if_cancelled (cancellable, error)) + return -1; + + if (self->priv->index >= self->priv->streams->len) + return 0; + + child = self->priv->streams->pdata[self->priv->index]; + + res = g_input_stream_read (child, + buffer, + count, + cancellable, + error); + if (res == 0) + self->priv->index++; + + return res; +} + +static gboolean +ostree_chain_input_stream_close (GInputStream *stream, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + OstreeChainInputStream *self = (gpointer)stream; + guint i; + + for (i = 0; i < self->priv->streams->len; i++) + { + GInputStream *child = self->priv->streams->pdata[i]; + if (!g_input_stream_close (child, cancellable, error)) + goto out; + } + + ret = TRUE; + out: + return ret; +} diff --git a/src/libostree/ostree-chain-input-stream.h b/src/libostree/ostree-chain-input-stream.h new file mode 100644 index 00000000..ac9a8ac5 --- /dev/null +++ b/src/libostree/ostree-chain-input-stream.h @@ -0,0 +1,67 @@ +/* -*- 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. + * + */ + +#ifndef __OSTREE_CHAIN_INPUT_STREAM_H__ +#define __OSTREE_CHAIN_INPUT_STREAM_H__ + +#include <gio/gio.h> + +G_BEGIN_DECLS + +#define OSTREE_TYPE_CHAIN_INPUT_STREAM (ostree_chain_input_stream_get_type ()) +#define OSTREE_CHAIN_INPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), OSTREE_TYPE_CHAIN_INPUT_STREAM, OstreeChainInputStream)) +#define OSTREE_CHAIN_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), OSTREE_TYPE_CHAIN_INPUT_STREAM, OstreeChainInputStreamClass)) +#define OSTREE_IS_CHAIN_INPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), OSTREE_TYPE_CHAIN_INPUT_STREAM)) +#define OSTREE_IS_CHAIN_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), OSTREE_TYPE_CHAIN_INPUT_STREAM)) +#define OSTREE_CHAIN_INPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), OSTREE_TYPE_CHAIN_INPUT_STREAM, OstreeChainInputStreamClass)) + +typedef struct _OstreeChainInputStream OstreeChainInputStream; +typedef struct _OstreeChainInputStreamClass OstreeChainInputStreamClass; +typedef struct _OstreeChainInputStreamPrivate OstreeChainInputStreamPrivate; + +struct _OstreeChainInputStream +{ + GInputStream parent_instance; + + /*< private >*/ + OstreeChainInputStreamPrivate *priv; +}; + +struct _OstreeChainInputStreamClass +{ + GInputStreamClass parent_class; + + /*< private >*/ + /* Padding for future expansion */ + void (*_g_reserved1) (void); + void (*_g_reserved2) (void); + void (*_g_reserved3) (void); + void (*_g_reserved4) (void); + void (*_g_reserved5) (void); +}; + +GType ostree_chain_input_stream_get_type (void) G_GNUC_CONST; + +OstreeChainInputStream * ostree_chain_input_stream_new (GPtrArray *streams); + +G_END_DECLS + +#endif /* __OSTREE_CHAIN_INPUT_STREAM_H__ */ diff --git a/src/libostree/ostree-core.c b/src/libostree/ostree-core.c index f87f31cf..d649d384 100644 --- a/src/libostree/ostree-core.c +++ b/src/libostree/ostree-core.c @@ -36,8 +36,6 @@ ostree_metadata_variant_type (OstreeObjectType objtype) { switch (objtype) { - case OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META: - return OSTREE_ARCHIVED_FILE_VARIANT_FORMAT; case OSTREE_OBJECT_TYPE_DIR_TREE: return OSTREE_TREE_GVARIANT_FORMAT; case OSTREE_OBJECT_TYPE_DIR_META: @@ -78,66 +76,6 @@ ostree_validate_rev (const char *rev, return ret; } -void -ostree_checksum_update_meta (GChecksum *checksum, - GFileInfo *file_info, - GVariant *xattrs) -{ - guint32 mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode"); - guint32 uid = g_file_info_get_attribute_uint32 (file_info, "unix::uid"); - guint32 gid = g_file_info_get_attribute_uint32 (file_info, "unix::gid"); - guint32 perms; - - if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR - || g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY) - { - /* Nothing */ - } - else if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_SYMBOLIC_LINK) - { - const char *symlink_target = g_file_info_get_symlink_target (file_info); - - g_assert (symlink_target != NULL); - - g_checksum_update (checksum, (guint8*)symlink_target, strlen (symlink_target)); - } - else if (S_ISCHR(mode) || S_ISBLK(mode)) - { - guint32 rdev = g_file_info_get_attribute_uint32 (file_info, "unix::rdev"); - rdev = GUINT32_TO_BE (rdev); - g_checksum_update (checksum, (guint8*)&rdev, 4); - } - else if (S_ISFIFO(mode)) - { - /* Nothing */ - } - else - { - g_assert_not_reached (); - } - - perms = GUINT32_TO_BE (mode & ~S_IFMT); - uid = GUINT32_TO_BE (uid); - gid = GUINT32_TO_BE (gid); - g_checksum_update (checksum, (guint8*) &uid, 4); - g_checksum_update (checksum, (guint8*) &gid, 4); - g_checksum_update (checksum, (guint8*) &perms, 4); - - if (xattrs) - { - g_checksum_update (checksum, (guint8*)g_variant_get_data (xattrs), - g_variant_get_size (xattrs)); - } - else - { - ot_lvariant GVariant *tmp_attrs = g_variant_new_array (G_VARIANT_TYPE ("(ayay)"), - NULL, 0); - g_variant_ref_sink (tmp_attrs); - g_checksum_update (checksum, (guint8*)g_variant_get_data (tmp_attrs), - g_variant_get_size (tmp_attrs)); - } -} - static char * canonicalize_xattrs (char *xattr_string, size_t len) { @@ -264,6 +202,265 @@ ostree_get_xattrs_for_file (GFile *f, return ret; } +GVariant * +ostree_file_header_new (GFileInfo *file_info, + GVariant *xattrs) +{ + guint32 uid; + guint32 gid; + guint32 mode; + guint32 rdev; + const char *symlink_target; + GVariant *ret; + ot_lvariant GVariant *tmp_xattrs = NULL; + + uid = g_file_info_get_attribute_uint32 (file_info, "unix::uid"); + gid = g_file_info_get_attribute_uint32 (file_info, "unix::gid"); + mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode"); + rdev = g_file_info_get_attribute_uint32 (file_info, "unix::rdev"); + + if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_SYMBOLIC_LINK) + symlink_target = g_file_info_get_symlink_target (file_info); + else + symlink_target = ""; + + if (xattrs == NULL) + tmp_xattrs = g_variant_ref_sink (g_variant_new_array (G_VARIANT_TYPE ("(ayay)"), NULL, 0)); + + ret = g_variant_new ("(uuuus@a(ayay))", GUINT32_TO_BE (uid), + GUINT32_TO_BE (gid), GUINT32_TO_BE (mode), GUINT32_TO_BE (rdev), + symlink_target, xattrs ? xattrs : tmp_xattrs); + g_variant_ref_sink (ret); + return ret; +} + +static gboolean +write_padding (GOutputStream *output, + guint alignment, + gsize offset, + gsize *out_bytes_written, + GChecksum *checksum, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + guint bits; + guint padding_len; + guchar padding_nuls[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + + if (alignment == 8) + bits = ((offset) & 7); + else + bits = ((offset) & 3); + + if (bits > 0) + { + padding_len = alignment - bits; + if (!ot_gio_write_update_checksum (output, (guchar*)padding_nuls, padding_len, + out_bytes_written, checksum, + cancellable, error)) + goto out; + } + + ret = TRUE; + out: + return ret; +} + +gboolean +ostree_write_variant_with_size (GOutputStream *output, + GVariant *variant, + guint64 alignment_offset, + gsize *out_bytes_written, + GChecksum *checksum, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + guint64 variant_size; + guint32 variant_size_u32_be; + gsize bytes_written; + gsize ret_bytes_written = 0; + + /* Write variant size */ + variant_size = g_variant_get_size (variant); + g_assert (variant_size < G_MAXUINT32); + variant_size_u32_be = GUINT32_TO_BE((guint32) variant_size); + + bytes_written = 0; + if (!ot_gio_write_update_checksum (output, &variant_size_u32_be, 4, + &bytes_written, checksum, + cancellable, error)) + goto out; + ret_bytes_written += bytes_written; + alignment_offset += bytes_written; + + bytes_written = 0; + /* Pad to offset of 8, write variant */ + if (!write_padding (output, 8, alignment_offset, &bytes_written, checksum, + cancellable, error)) + goto out; + ret_bytes_written += bytes_written; + + bytes_written = 0; + if (!ot_gio_write_update_checksum (output, g_variant_get_data (variant), + variant_size, &bytes_written, checksum, + cancellable, error)) + goto out; + ret_bytes_written += bytes_written; + + ret = TRUE; + if (out_bytes_written) + *out_bytes_written = ret_bytes_written; + out: + return ret; +} + +gboolean +ostree_write_file_header_update_checksum (GOutputStream *out, + GVariant *header, + GChecksum *checksum, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + gsize bytes_written; + + if (!ostree_write_variant_with_size (out, header, 0, &bytes_written, checksum, + cancellable, error)) + goto out; + + ret = TRUE; + out: + return ret; +} + +gboolean +ostree_raw_file_to_content_stream (GInputStream *input, + GFileInfo *file_info, + GVariant *xattrs, + GInputStream **out_input, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + gpointer header_data; + gsize header_size; + ot_lobj GInputStream *ret_input = NULL; + ot_lvariant GVariant *file_header = NULL; + ot_lptrarray GPtrArray *streams = NULL; + ot_lobj GOutputStream *header_out_stream = NULL; + ot_lobj GInputStream *header_in_stream = NULL; + + file_header = ostree_file_header_new (file_info, xattrs); + + header_out_stream = g_memory_output_stream_new (NULL, 0, g_realloc, g_free); + + if (!ostree_write_variant_with_size (header_out_stream, file_header, 0, NULL, NULL, + cancellable, error)) + goto out; + + header_size = g_memory_output_stream_get_data_size ((GMemoryOutputStream*) header_out_stream); + header_data = g_memory_output_stream_steal_data ((GMemoryOutputStream*) header_out_stream); + header_in_stream = g_memory_input_stream_new_from_data (header_data, header_size, g_free); + + streams = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref); + + g_ptr_array_add (streams, g_object_ref (header_in_stream)); + g_ptr_array_add (streams, g_object_ref (input)); + + ret_input = (GInputStream*)ostree_chain_input_stream_new (streams); + + ret = TRUE; + ot_transfer_out_value (out_input, &ret_input); + out: + return ret; +} + +gboolean +ostree_content_file_parse (GFile *content_path, + gboolean trusted, + GInputStream **out_input, + GFileInfo **out_file_info, + GVariant **out_xattrs, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + guint64 length; + guint32 archive_header_size; + guchar dummy[4]; + gsize bytes_read; + ot_lobj GInputStream *ret_input = NULL; + ot_lobj GFileInfo *content_file_info = NULL; + ot_lobj GFileInfo *ret_file_info = NULL; + ot_lvariant GVariant *ret_xattrs = NULL; + ot_lvariant GVariant *file_header = NULL; + ot_lfree guchar *buf = NULL; + + ret_input = (GInputStream*)g_file_read (content_path, cancellable, error); + if (!ret_input) + goto out; + + content_file_info = g_file_input_stream_query_info ((GFileInputStream*)ret_input, + OSTREE_GIO_FAST_QUERYINFO, + cancellable, error); + if (!content_file_info) + goto out; + + length = g_file_info_get_size (content_file_info); + + if (!g_input_stream_read_all (ret_input, + &archive_header_size, 4, &bytes_read, + cancellable, error)) + goto out; + archive_header_size = GUINT32_FROM_BE (archive_header_size); + if (archive_header_size > length) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "File header size %u exceeds size %" G_GUINT64_FORMAT, + (guint)archive_header_size, length); + goto out; + } + + /* Skip over padding */ + if (!g_input_stream_read_all (ret_input, + dummy, 4, &bytes_read, + cancellable, error)) + goto out; + + buf = g_malloc (archive_header_size); + if (!g_input_stream_read_all (ret_input, buf, archive_header_size, &bytes_read, + cancellable, error)) + goto out; + file_header = g_variant_new_from_data (OSTREE_FILE_HEADER_GVARIANT_FORMAT, + buf, archive_header_size, trusted, + g_free, buf); + buf = NULL; + + if (!ostree_file_header_parse (file_header, + out_file_info ? &ret_file_info : NULL, + out_xattrs ? &ret_xattrs : NULL, + error)) + goto out; + if (ret_file_info) + g_file_info_set_size (ret_file_info, length - archive_header_size - 8); + + if (g_file_info_get_file_type (ret_file_info) != G_FILE_TYPE_REGULAR) + { + g_clear_object (&ret_input); + } + + /* Now give the input stream at its current position as return value */ + + ret = TRUE; + ot_transfer_out_value (out_input, &ret_input); + ot_transfer_out_value (out_file_info, &ret_file_info); + ot_transfer_out_value (out_xattrs, &ret_xattrs); + out: + return ret; +} + gboolean ostree_checksum_file_from_input (GFileInfo *file_info, GVariant *xattrs, @@ -274,8 +471,6 @@ ostree_checksum_file_from_input (GFileInfo *file_info, GError **error) { gboolean ret = FALSE; - guint32 mode; - ot_lvariant GVariant *dirmeta = NULL; ot_lfree guchar *ret_csum = NULL; GChecksum *checksum = NULL; @@ -286,38 +481,28 @@ ostree_checksum_file_from_input (GFileInfo *file_info, if (!ot_gio_splice_update_checksum (NULL, in, checksum, cancellable, error)) goto out; } + else if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY) + { + ot_lvariant GVariant *dirmeta = ostree_create_directory_metadata (file_info, xattrs); + g_checksum_update (checksum, g_variant_get_data (dirmeta), + g_variant_get_size (dirmeta)); + + } else { - mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode"); + ot_lvariant GVariant *file_header = NULL; - if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY) - { - dirmeta = ostree_create_directory_metadata (file_info, xattrs); - g_checksum_update (checksum, g_variant_get_data (dirmeta), - g_variant_get_size (dirmeta)); + file_header = ostree_file_header_new (file_info, xattrs); - } - else if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR) + if (!ostree_write_file_header_update_checksum (NULL, file_header, checksum, + cancellable, error)) + goto out; + + if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR) { if (!ot_gio_splice_update_checksum (NULL, in, checksum, cancellable, error)) goto out; } - else if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_SYMBOLIC_LINK - || S_ISCHR(mode) || S_ISBLK(mode) - || S_ISFIFO(mode)) - { - /* We update the checksum below */ - } - else - { - g_set_error (error, G_IO_ERROR, - G_IO_ERROR_FAILED, - "Unsupported file (must be regular, symbolic link, fifo, or character/block device)"); - goto out; - } - - if (objtype != OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT) - ostree_checksum_update_meta (checksum, file_info, xattrs); } ret_csum = ot_csum_from_gchecksum (checksum); @@ -358,7 +543,7 @@ ostree_checksum_file (GFile *f, goto out; } - if (objtype == OSTREE_OBJECT_TYPE_RAW_FILE) + if (objtype == OSTREE_OBJECT_TYPE_FILE) { if (!ostree_get_xattrs_for_file (f, &xattrs, cancellable, error)) goto out; @@ -509,12 +694,8 @@ ostree_object_type_to_string (OstreeObjectType objtype) { switch (objtype) { - case OSTREE_OBJECT_TYPE_RAW_FILE: + case OSTREE_OBJECT_TYPE_FILE: return "file"; - case OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT: - return "archive-content"; - case OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META: - return "archive-meta"; case OSTREE_OBJECT_TYPE_DIR_TREE: return "dirtree"; case OSTREE_OBJECT_TYPE_DIR_META: @@ -531,11 +712,7 @@ OstreeObjectType ostree_object_type_from_string (const char *str) { if (!strcmp (str, "file")) - return OSTREE_OBJECT_TYPE_RAW_FILE; - else if (!strcmp (str, "archive-content")) - return OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT; - else if (!strcmp (str, "archive-meta")) - return OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META; + return OSTREE_OBJECT_TYPE_FILE; else if (!strcmp (str, "dirtree")) return OSTREE_OBJECT_TYPE_DIR_TREE; else if (!strcmp (str, "dirmeta")) @@ -747,42 +924,11 @@ ostree_get_relative_pack_data_path (gboolean is_meta, return get_pack_name (is_meta, FALSE, "objects/pack/", checksum); } -GVariant * -ostree_create_archive_file_metadata (GFileInfo *finfo, - GVariant *xattrs) -{ - guint32 uid, gid, mode, rdev; - GVariantBuilder pack_builder; - GVariant *ret = NULL; - - uid = g_file_info_get_attribute_uint32 (finfo, G_FILE_ATTRIBUTE_UNIX_UID); - gid = g_file_info_get_attribute_uint32 (finfo, G_FILE_ATTRIBUTE_UNIX_GID); - mode = g_file_info_get_attribute_uint32 (finfo, G_FILE_ATTRIBUTE_UNIX_MODE); - rdev = g_file_info_get_attribute_uint32 (finfo, G_FILE_ATTRIBUTE_UNIX_RDEV); - - g_variant_builder_init (&pack_builder, OSTREE_ARCHIVED_FILE_VARIANT_FORMAT); - g_variant_builder_add (&pack_builder, "u", GUINT32_TO_BE (uid)); - g_variant_builder_add (&pack_builder, "u", GUINT32_TO_BE (gid)); - g_variant_builder_add (&pack_builder, "u", GUINT32_TO_BE (mode)); - g_variant_builder_add (&pack_builder, "u", GUINT32_TO_BE (rdev)); - if (S_ISLNK (mode)) - g_variant_builder_add (&pack_builder, "s", g_file_info_get_symlink_target (finfo)); - else - g_variant_builder_add (&pack_builder, "s", ""); - - g_variant_builder_add (&pack_builder, "@a(ayay)", xattrs ? xattrs : g_variant_new_array (G_VARIANT_TYPE ("(ayay)"), NULL, 0)); - - ret = g_variant_builder_end (&pack_builder); - g_variant_ref_sink (ret); - - return ret; -} - gboolean -ostree_parse_archived_file_meta (GVariant *metadata, - GFileInfo **out_file_info, - GVariant **out_xattrs, - GError **error) +ostree_file_header_parse (GVariant *metadata, + GFileInfo **out_file_info, + GVariant **out_xattrs, + GError **error) { gboolean ret = FALSE; guint32 uid, gid, mode, rdev; @@ -1212,62 +1358,58 @@ ostree_read_pack_entry_raw (guchar *pack_data, return ret; } -GInputStream * -ostree_read_pack_entry_as_stream (GVariant *pack_entry) +gboolean +ostree_parse_file_pack_entry (GVariant *pack_entry, + GInputStream **out_input, + GFileInfo **out_info, + GVariant **out_xattrs, + GCancellable *cancellable, + GError **error) { - GInputStream *memory_input; - GInputStream *ret_input = NULL; - GVariant *pack_data = NULL; + gboolean ret = FALSE; guchar entry_flags; - gconstpointer data_ptr; - gsize data_len; + ot_lvariant GVariant *file_header = NULL; + ot_lvariant GVariant *pack_data = NULL; + ot_lobj GInputStream *memory_input = NULL; + ot_lobj GInputStream *ret_input = NULL; + ot_lobj GFileInfo *ret_info = NULL; + ot_lvariant GVariant *ret_xattrs = NULL; g_variant_get_child (pack_entry, 1, "y", &entry_flags); + g_variant_get_child (pack_entry, 2, "@(uuuusa(ayay))", &file_header); g_variant_get_child (pack_entry, 3, "@ay", &pack_data); - data_ptr = g_variant_get_fixed_array (pack_data, &data_len, 1); - memory_input = g_memory_input_stream_new_from_data (data_ptr, data_len, NULL); - g_object_set_data_full ((GObject*)memory_input, "ostree-mem-gvariant", - pack_data, (GDestroyNotify) g_variant_unref); + if (!ostree_file_header_parse (file_header, &ret_info, &ret_xattrs, + error)) + goto out; + g_file_info_set_size (ret_info, g_variant_get_size (pack_data)); - if (entry_flags & OSTREE_PACK_FILE_ENTRY_FLAG_GZIP) + if (g_file_info_get_file_type (ret_info) == G_FILE_TYPE_REGULAR) { - GConverter *decompressor; - - decompressor = (GConverter*)g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP); - ret_input = (GInputStream*)g_object_new (G_TYPE_CONVERTER_INPUT_STREAM, - "converter", decompressor, - "base-stream", memory_input, - "close-base-stream", TRUE, - NULL); - g_object_unref (memory_input); - g_object_unref (decompressor); - } - else - { - ret_input = memory_input; - memory_input = NULL; - } - - return ret_input; -} - -gboolean -ostree_read_pack_entry_variant (GVariant *pack_entry, - OstreeObjectType expected_objtype, - gboolean trusted, - GVariant **out_variant, - GCancellable *cancellable, - GError **error) -{ - gboolean ret = FALSE; - ot_lvariant GVariant *ret_variant = NULL; + memory_input = ot_variant_read (pack_data); - g_variant_get_child (pack_entry, 2, "v", &ret_variant); + if (entry_flags & OSTREE_PACK_FILE_ENTRY_FLAG_GZIP) + { + ot_lobj GConverter *decompressor = NULL; + + decompressor = (GConverter*)g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP); + ret_input = (GInputStream*)g_object_new (G_TYPE_CONVERTER_INPUT_STREAM, + "converter", decompressor, + "base-stream", memory_input, + "close-base-stream", TRUE, + NULL); + } + else + { + ret_input = g_object_ref (memory_input); + } + } ret = TRUE; - ot_transfer_out_value (out_variant, &ret_variant); - /* out: */ + ot_transfer_out_value (out_input, &ret_input); + ot_transfer_out_value (out_info, &ret_info); + ot_transfer_out_value (out_xattrs, &ret_xattrs); + out: return ret; } @@ -1346,7 +1488,7 @@ ostree_validate_structureof_objtype (guchar objtype, GError **error) { OstreeObjectType objtype_v = (OstreeObjectType) objtype; - if (objtype_v < OSTREE_OBJECT_TYPE_RAW_FILE + if (objtype_v < OSTREE_OBJECT_TYPE_FILE || objtype_v > OSTREE_OBJECT_TYPE_COMMIT) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, diff --git a/src/libostree/ostree-core.h b/src/libostree/ostree-core.h index 02ccb016..32de9057 100644 --- a/src/libostree/ostree-core.h +++ b/src/libostree/ostree-core.h @@ -32,22 +32,29 @@ G_BEGIN_DECLS #define OSTREE_EMPTY_STRING_SHA256 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; typedef enum { - OSTREE_OBJECT_TYPE_RAW_FILE = 1, /* .raw */ - OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT = 2, /* .archive-content */ - OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META = 3, /* .archive-meta */ - OSTREE_OBJECT_TYPE_DIR_TREE = 4, /* .dirtree */ - OSTREE_OBJECT_TYPE_DIR_META = 5, /* .dirmeta */ - OSTREE_OBJECT_TYPE_COMMIT = 6 /* .commit */ + OSTREE_OBJECT_TYPE_FILE = 1, /* .file */ + OSTREE_OBJECT_TYPE_DIR_TREE = 2, /* .dirtree */ + OSTREE_OBJECT_TYPE_DIR_META = 3, /* .dirmeta */ + OSTREE_OBJECT_TYPE_COMMIT = 4 /* .commit */ } OstreeObjectType; -#define OSTREE_OBJECT_TYPE_IS_META(t) (t >= 3 && t <= 6) +#define OSTREE_OBJECT_TYPE_IS_META(t) (t >= 2 && t <= 4) #define OSTREE_OBJECT_TYPE_LAST OSTREE_OBJECT_TYPE_COMMIT + /* - * xattr objects: - * a(ayay) - array of (name, value) pairs, both binary data, though name is a bytestring + * file objects: + * <BE guint32 containing variant length> + * u - uid + * u - gid + * u - mode + * u - rdev + * s - symlink target + * a(ayay) - xattrs + * --- + * data */ -#define OSTREE_XATTR_GVARIANT_FORMAT "a(ayay)" +#define OSTREE_FILE_HEADER_GVARIANT_FORMAT G_VARIANT_TYPE ("(uuuusa(ayay))") /* * dirmeta objects: @@ -78,16 +85,6 @@ typedef enum { */ #define OSTREE_COMMIT_GVARIANT_FORMAT G_VARIANT_TYPE ("(a{sv}aya(say)sstayay)") -/* Archive file objects: - * u - uid - * u - gid - * u - mode - * u - rdev - * s - symlink target - * a(ayay) - xattrs - */ -#define OSTREE_ARCHIVED_FILE_VARIANT_FORMAT G_VARIANT_TYPE ("(uuuusa(ayay))") - /* Pack super index * s - OSTv0SUPERPACKINDEX * a{sv} - Metadata @@ -115,9 +112,9 @@ typedef enum { * * Repeating pair of: * <padding to alignment of 8> - * ( yyayay ) - objtype, flags, checksum, data + * ( ayy(uuuusa(ayay))ay) ) - checksum, flags, file meta, data */ -#define OSTREE_PACK_DATA_FILE_VARIANT_FORMAT G_VARIANT_TYPE ("(yyayay)") +#define OSTREE_PACK_DATA_FILE_VARIANT_FORMAT G_VARIANT_TYPE ("(ayy(uuuusa(ayay))ay)") /* Meta Pack files * s - OSTv0PACKMETAFILE @@ -195,6 +192,43 @@ gboolean ostree_map_metadata_file (GFile *file, GVariant **out_variant, GError **error); +GVariant *ostree_file_header_new (GFileInfo *file_info, + GVariant *xattrs); + +gboolean ostree_write_variant_with_size (GOutputStream *output, + GVariant *variant, + guint64 alignment_offset, + gsize *out_bytes_written, + GChecksum *checksum, + GCancellable *cancellable, + GError **error); + +gboolean ostree_file_header_parse (GVariant *data, + GFileInfo **out_file_info, + GVariant **out_xattrs, + GError **error); + +gboolean ostree_content_file_parse (GFile *content_path, + gboolean trusted, + GInputStream **out_input, + GFileInfo **out_file_info, + GVariant **out_xattrs, + GCancellable *cancellable, + GError **error); + +gboolean ostree_write_file_header_update_checksum (GOutputStream *out, + GVariant *header, + GChecksum *checksum, + GCancellable *cancellable, + GError **error); + +gboolean ostree_raw_file_to_content_stream (GInputStream *input, + GFileInfo *file_info, + GVariant *xattrs, + GInputStream **out_input, + GCancellable *cancellable, + GError **error); + gboolean ostree_checksum_file_from_input (GFileInfo *file_info, GVariant *xattrs, GInputStream *in, @@ -257,14 +291,6 @@ gboolean ostree_create_temp_hardlink (GFile *dir, GCancellable *cancellable, GError **error); -GVariant *ostree_create_archive_file_metadata (GFileInfo *file_info, - GVariant *xattrs); - -gboolean ostree_parse_archived_file_meta (GVariant *data, - GFileInfo **out_file_info, - GVariant **out_xattrs, - GError **error); - gboolean ostree_read_pack_entry_raw (guchar *pack_data, guint64 pack_len, guint64 object_offset, @@ -274,14 +300,12 @@ gboolean ostree_read_pack_entry_raw (guchar *pack_data, GCancellable *cancellable, GError **error); -GInputStream *ostree_read_pack_entry_as_stream (GVariant *pack_entry); - -gboolean ostree_read_pack_entry_variant (GVariant *pack_entry, - OstreeObjectType expected_objtype, - gboolean trusted, - GVariant **out_variant, - GCancellable *cancellable, - GError **error); +gboolean ostree_parse_file_pack_entry (GVariant *pack_entry, + GInputStream **out_input, + GFileInfo **out_info, + GVariant **out_xattrs, + GCancellable *cancellable, + GError **error); gboolean ostree_pack_index_search (GVariant *index, GVariant *csum_bytes, diff --git a/src/libostree/ostree-repo-file.c b/src/libostree/ostree-repo-file.c index 58477b6f..005f59e6 100644 --- a/src/libostree/ostree-repo-file.c +++ b/src/libostree/ostree-repo-file.c @@ -943,7 +943,7 @@ ostree_repo_file_read (GFile *file, OstreeRepoFile *self = OSTREE_REPO_FILE (file); const char *checksum; ot_lobj GFile *local_file = NULL; - ot_lobj GFileInputStream *ret_stream = NULL; + ot_lobj GInputStream *ret_stream = NULL; if (!ostree_repo_file_ensure_resolved (self, error)) goto out; @@ -958,18 +958,8 @@ ostree_repo_file_read (GFile *file, checksum = ostree_repo_file_get_checksum (self); - if (ostree_repo_get_mode (self->repo) == OSTREE_REPO_MODE_ARCHIVE) - { - local_file = ostree_repo_get_object_path (self->repo, checksum, - OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT); - } - else - { - local_file = ostree_repo_get_file_object_path (self->repo, checksum); - } - - ret_stream = g_file_read (local_file, cancellable, error); - if (!ret_stream) + if (!ostree_repo_load_file (self->repo, checksum, &ret_stream, + NULL, NULL, cancellable, error)) goto out; ret = TRUE; @@ -978,7 +968,7 @@ ostree_repo_file_read (GFile *file, g_clear_object (&ret_stream); else g_object_ref (ret_stream); - return ret_stream; + return (GFileInputStream*)ret_stream; } static void diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c index 64d65dbe..327f1870 100644 --- a/src/libostree/ostree-repo.c +++ b/src/libostree/ostree-repo.c @@ -728,32 +728,11 @@ ostree_repo_get_mode (OstreeRepo *self) return priv->mode; } -static OstreeObjectType -get_objtype_for_repo_file (OstreeRepo *self) -{ - OstreeRepoPrivate *priv = GET_PRIVATE (self); - if (priv->mode == OSTREE_REPO_MODE_ARCHIVE) - return OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META; - else - return OSTREE_OBJECT_TYPE_RAW_FILE; -} - GFile * ostree_repo_get_file_object_path (OstreeRepo *self, const char *checksum) { - return ostree_repo_get_object_path (self, checksum, get_objtype_for_repo_file (self)); -} - -static GFileInfo * -dup_file_info_owned_by_me (GFileInfo *file_info) -{ - GFileInfo *ret = g_file_info_dup (file_info); - - g_file_info_set_attribute_uint32 (ret, "unix::uid", geteuid ()); - g_file_info_set_attribute_uint32 (ret, "unix::gid", getegid ()); - - return ret; + return ostree_repo_get_object_path (self, checksum, OSTREE_OBJECT_TYPE_FILE); } static gboolean @@ -805,64 +784,49 @@ commit_tmpfile_trusted (OstreeRepo *self, } static gboolean -impl_stage_archive_file_object_from_raw (OstreeRepo *self, - GFileInfo *file_info, - GVariant *xattrs, - GInputStream *input, - const char *expected_checksum, - guchar **out_csum, - GCancellable *cancellable, - GError **error) +impl_stage_archive_file_object (OstreeRepo *self, + GFileInfo *file_info, + GVariant *xattrs, + GInputStream *input, + const char *expected_checksum, + guchar **out_csum, + GCancellable *cancellable, + GError **error) { gboolean ret = FALSE; OstreeRepoPrivate *priv = GET_PRIVATE (self); const char *actual_checksum; ot_lvariant GVariant *archive_metadata = NULL; ot_lobj GFileInfo *temp_info = NULL; - ot_lobj GFile *meta_temp_file = NULL; - ot_lobj GFile *content_temp_file = NULL; - ot_lobj GInputStream *mem = NULL; - ot_lobj OstreeChecksumInputStream *checksum_input = NULL; + ot_lobj GFile *temp_file = NULL; + ot_lobj GOutputStream *out = NULL; ot_lfree guchar *ret_csum = NULL; + ot_lvariant GVariant *file_header = NULL; GChecksum *checksum = NULL; if (expected_checksum || out_csum) - { - checksum = g_checksum_new (G_CHECKSUM_SHA256); - if (input) - checksum_input = ostree_checksum_input_stream_new (input, checksum); - } + checksum = g_checksum_new (G_CHECKSUM_SHA256); - archive_metadata = ostree_create_archive_file_metadata (file_info, xattrs); + file_header = ostree_file_header_new (file_info, xattrs); - mem = g_memory_input_stream_new_from_data (g_variant_get_data (archive_metadata), - g_variant_get_size (archive_metadata), - NULL); - - if (!ostree_create_temp_file_from_input (priv->tmp_dir, - "archive-tmp-", NULL, - NULL, NULL, mem, - &meta_temp_file, - cancellable, error)) + if (!ostree_create_temp_regular_file (priv->tmp_dir, + "archive-tmp-", NULL, + &temp_file, &out, + cancellable, error)) goto out; - temp_info = dup_file_info_owned_by_me (file_info); - /* Archived content files should always be readable by all and - * read/write by owner. If the base file is executable then - * we're also executable. - */ - g_file_info_set_attribute_uint32 (temp_info, "unix::mode", - g_file_info_get_attribute_uint32 (file_info, "unix::mode") | 0644); - if (!ostree_create_temp_file_from_input (priv->tmp_dir, - "archive-tmp-", NULL, - temp_info, NULL, - checksum_input ? (GInputStream*)checksum_input : input, - &content_temp_file, - cancellable, error)) + if (!ostree_write_file_header_update_checksum (out, file_header, checksum, + cancellable, error)) goto out; - if (checksum) - ostree_checksum_update_meta (checksum, file_info, xattrs); + if (input && checksum) + { + if (!ot_gio_splice_update_checksum (out, input, checksum, cancellable, error)) + goto out; + } + + if (!g_output_stream_close (out, cancellable, error)) + goto out; if (expected_checksum && checksum) { @@ -870,7 +834,7 @@ impl_stage_archive_file_object_from_raw (OstreeRepo *self, { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Corrupted %s object %s (actual checksum is %s)", - ostree_object_type_to_string (OSTREE_OBJECT_TYPE_RAW_FILE), + ostree_object_type_to_string (OSTREE_OBJECT_TYPE_FILE), expected_checksum, g_checksum_get_string (checksum)); goto out; } @@ -881,12 +845,8 @@ impl_stage_archive_file_object_from_raw (OstreeRepo *self, else actual_checksum = g_checksum_get_string (checksum); - if (!commit_tmpfile_trusted (self, actual_checksum, OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT, - content_temp_file, cancellable, error)) - goto out; - - if (!commit_tmpfile_trusted (self, actual_checksum, OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META, - meta_temp_file, cancellable, error)) + if (!commit_tmpfile_trusted (self, actual_checksum, OSTREE_OBJECT_TYPE_FILE, + temp_file, cancellable, error)) goto out; if (checksum) @@ -921,6 +881,7 @@ stage_object_impl (OstreeRepo *self, ot_lfree char *pack_checksum = NULL; ot_lfree guchar *ret_csum = NULL; ot_lobj OstreeChecksumInputStream *checksum_input = NULL; + ot_lvariant GVariant *file_header = NULL; GChecksum *checksum = NULL; g_return_val_if_fail (priv->in_transaction, FALSE); @@ -948,32 +909,31 @@ stage_object_impl (OstreeRepo *self, } } - g_assert (objtype != OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT); - g_assert (objtype != OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META); - if (stored_path == NULL && pack_checksum == NULL) { - if (objtype == OSTREE_OBJECT_TYPE_RAW_FILE) + if (objtype == OSTREE_OBJECT_TYPE_FILE) { g_assert (file_info != NULL); if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR) g_assert (input != NULL); + else + g_assert (input == NULL); } - else if (OSTREE_OBJECT_TYPE_IS_META (objtype)) + else { g_assert (xattrs == NULL); g_assert (input != NULL); } - if (objtype == OSTREE_OBJECT_TYPE_RAW_FILE && priv->mode == OSTREE_REPO_MODE_ARCHIVE) + if (objtype == OSTREE_OBJECT_TYPE_FILE && priv->mode == OSTREE_REPO_MODE_ARCHIVE) { - if (!impl_stage_archive_file_object_from_raw (self, file_info, xattrs, input, - expected_checksum, - out_csum ? &ret_csum : NULL, - cancellable, error)) + if (!impl_stage_archive_file_object (self, file_info, xattrs, input, + expected_checksum, + out_csum ? &ret_csum : NULL, + cancellable, error)) goto out; } - else + else { if (out_csum) { @@ -981,6 +941,15 @@ stage_object_impl (OstreeRepo *self, if (input) checksum_input = ostree_checksum_input_stream_new (input, checksum); } + + if (objtype == OSTREE_OBJECT_TYPE_FILE && checksum) + { + file_header = ostree_file_header_new (file_info, xattrs); + + if (!ostree_write_file_header_update_checksum (NULL, file_header, checksum, + cancellable, error)) + goto out; + } if (!ostree_create_temp_file_from_input (priv->tmp_dir, ostree_object_type_to_string (objtype), NULL, @@ -990,9 +959,6 @@ stage_object_impl (OstreeRepo *self, cancellable, error)) goto out; - if (checksum && !OSTREE_OBJECT_TYPE_IS_META (objtype)) - ostree_checksum_update_meta (checksum, file_info, xattrs); - if (!checksum) actual_checksum = expected_checksum; else @@ -1961,6 +1927,7 @@ ostree_repo_resync_cached_remote_pack_indexes (OstreeRepo *self, g_hash_table_insert (new_pack_meta_indexes, pack_checksum, pack_checksum); pack_checksum = NULL; /* transfer ownership */ } + g_variant_iter_free (superindex_contents_iter); g_variant_get_child (superindex_variant, 3, "a(ayay)", &superindex_contents_iter); @@ -2009,7 +1976,7 @@ ostree_repo_resync_cached_remote_pack_indexes (OstreeRepo *self, ret = TRUE; ot_transfer_out_value (out_cached_meta_indexes, &ret_cached_meta_indexes); ot_transfer_out_value (out_cached_data_indexes, &ret_cached_data_indexes); - ot_transfer_out_value (out_uncached_meta_indexes, &ret_uncached_data_indexes); + ot_transfer_out_value (out_uncached_meta_indexes, &ret_uncached_meta_indexes); ot_transfer_out_value (out_uncached_data_indexes, &ret_uncached_data_indexes); out: if (superindex_contents_iter) @@ -2465,7 +2432,7 @@ stage_directory_to_mtree_internal (OstreeRepo *self, g_free (child_file_csum); child_file_csum = NULL; - if (!stage_object_impl (self, OSTREE_OBJECT_TYPE_RAW_FILE, FALSE, + if (!stage_object_impl (self, OSTREE_OBJECT_TYPE_FILE, FALSE, modified_info, xattrs, file_input, NULL, &child_file_csum, cancellable, error)) goto out; @@ -2652,7 +2619,7 @@ import_libarchive_entry_file (OstreeRepo *self, if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR) archive_stream = ostree_libarchive_input_stream_new (a); - if (!stage_object_impl (self, OSTREE_OBJECT_TYPE_RAW_FILE, FALSE, + if (!stage_object_impl (self, OSTREE_OBJECT_TYPE_FILE, FALSE, file_info, NULL, archive_stream, NULL, out_csum, cancellable, error)) @@ -2954,11 +2921,7 @@ list_loose_object_dir (OstreeRepo *self, goto loop_next; if (g_str_has_suffix (name, ".file")) - objtype = OSTREE_OBJECT_TYPE_RAW_FILE; - else if (g_str_has_suffix (name, ".archive-meta")) - objtype = OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META; - else if (g_str_has_suffix (name, ".archive-content")) - objtype = OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT; + objtype = OSTREE_OBJECT_TYPE_FILE; else if (g_str_has_suffix (name, ".dirtree")) objtype = OSTREE_OBJECT_TYPE_DIR_TREE; else if (g_str_has_suffix (name, ".dirmeta")) @@ -3140,7 +3103,6 @@ ostree_repo_map_pack_file (OstreeRepo *self, return ret; } - gboolean ostree_repo_load_file (OstreeRepo *self, const char *checksum, @@ -3151,103 +3113,83 @@ ostree_repo_load_file (OstreeRepo *self, GError **error) { gboolean ret = FALSE; - guchar *content_pack_data; - guint64 content_pack_len; - guint64 content_pack_offset; + guchar *pack_data; + guint64 pack_len; + guint64 pack_offset; ot_lvariant GVariant *packed_object = NULL; ot_lvariant GVariant *archive_meta = NULL; - ot_lobj GFile *content_loose_path = NULL; + ot_lvariant GVariant *file_data = NULL; + ot_lvariant GVariant *file_header = NULL; + ot_lobj GFile *loose_path = NULL; ot_lobj GFileInfo *content_loose_info = NULL; - ot_lfree char *content_pack_checksum = NULL; + ot_lfree char *pack_checksum = NULL; ot_lobj GInputStream *ret_input = NULL; ot_lobj GFileInfo *ret_file_info = NULL; ot_lvariant GVariant *ret_xattrs = NULL; - if (ostree_repo_get_mode (self) == OSTREE_REPO_MODE_ARCHIVE) - { - /* First, read the metadata */ - if (!ostree_repo_load_variant (self, OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META, checksum, - &archive_meta, error)) - goto out; - if (!ostree_parse_archived_file_meta (archive_meta, - &ret_file_info, - &ret_xattrs, - error)) - goto out; + if (!ostree_repo_find_object (self, OSTREE_OBJECT_TYPE_FILE, + checksum, &loose_path, + &pack_checksum, &pack_offset, + cancellable, error)) + goto out; - if (g_file_info_get_file_type (ret_file_info) == G_FILE_TYPE_REGULAR) + if (loose_path) + { + if (ostree_repo_get_mode (self) == OSTREE_REPO_MODE_ARCHIVE) { - /* Blah, right now we need to look up the content too to get the file size */ - if (!ostree_repo_find_object (self, OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT, - checksum, &content_loose_path, - &content_pack_checksum, &content_pack_offset, - cancellable, error)) + if (!ostree_content_file_parse (loose_path, TRUE, + out_input ? &ret_input : NULL, + &ret_file_info, &ret_xattrs, + cancellable, error)) goto out; - - if (content_loose_path) + } + else + { + ret_file_info = g_file_query_info (loose_path, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + cancellable, error); + if (!ret_file_info) + goto out; + + if (out_xattrs) { - content_loose_info = g_file_query_info (content_loose_path, OSTREE_GIO_FAST_QUERYINFO, - G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, cancellable, error); - if (!content_loose_info) + if (!ostree_get_xattrs_for_file (loose_path, &ret_xattrs, + cancellable, error)) goto out; - - g_file_info_set_attribute_uint64 (ret_file_info, - "standard::size", - g_file_info_get_attribute_uint64 (content_loose_info, "standard::size")); } - /* fixme - don't have file size for packed =/ */ - - /* Now, look for the content */ - if (out_input) + + if (out_input && g_file_info_get_file_type (ret_file_info) == G_FILE_TYPE_REGULAR) { - if (content_pack_checksum != NULL) - { - if (!ostree_repo_map_pack_file (self, content_pack_checksum, FALSE, - &content_pack_data, &content_pack_len, - cancellable, error)) - goto out; - if (!ostree_read_pack_entry_raw (content_pack_data, content_pack_len, - content_pack_offset, TRUE, FALSE, - &packed_object, cancellable, error)) - goto out; - ret_input = ostree_read_pack_entry_as_stream (packed_object); - } - else if (content_loose_path != NULL) - { - ret_input = (GInputStream*)g_file_read (content_loose_path, cancellable, error); - if (!ret_input) - goto out; - } - else - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, - "Couldn't find object '%s'", checksum); - goto out; - } + ret_input = (GInputStream*) g_file_read (loose_path, cancellable, error); + if (!ret_input) + goto out; } } } - else + else if (pack_checksum) { - content_loose_path = ostree_repo_get_object_path (self, checksum, OSTREE_OBJECT_TYPE_RAW_FILE); - ret_file_info = g_file_query_info (content_loose_path, OSTREE_GIO_FAST_QUERYINFO, - G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, cancellable, error); - if (!ret_file_info) + if (!ostree_repo_map_pack_file (self, pack_checksum, FALSE, + &pack_data, &pack_len, + cancellable, error)) goto out; - /* Now, look for the content */ - if (g_file_info_get_file_type (ret_file_info) == G_FILE_TYPE_REGULAR - && out_input) - { - ret_input = (GInputStream*)g_file_read (content_loose_path, cancellable, error); - if (!ret_input) - goto out; - } - if (out_xattrs) - { - if (!ostree_get_xattrs_for_file (content_loose_path, &ret_xattrs, cancellable,error)) - goto out; - } + if (!ostree_read_pack_entry_raw (pack_data, pack_len, + pack_offset, TRUE, FALSE, + &packed_object, cancellable, error)) + goto out; + + if (!ostree_parse_file_pack_entry (packed_object, + out_input ? &ret_input : NULL, + out_file_info ? &ret_file_info : NULL, + out_xattrs ? &ret_xattrs : NULL, + cancellable, error)) + goto out; + } + else + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "Couldn't find object '%s'", checksum); + goto out; } ret = TRUE; @@ -3537,9 +3479,7 @@ ostree_repo_load_variant (OstreeRepo *self, TRUE, TRUE, &packed_object, cancellable, error)) goto out; - if (!ostree_read_pack_entry_variant (packed_object, objtype, TRUE, - &ret_variant, cancellable, error)) - goto out; + g_variant_get_child (packed_object, 2, "v", &ret_variant); } else { @@ -3760,14 +3700,9 @@ checkout_one_file (OstreeRepo *self, checksum = ostree_repo_file_get_checksum ((OstreeRepoFile*)src); - /* First check for a loose object */ - if (priv->mode == OSTREE_REPO_MODE_ARCHIVE && mode == OSTREE_REPO_CHECKOUT_MODE_USER) - { - possible_loose_path = ostree_repo_get_object_path (self, checksum, OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT); - } - else if (priv->mode == OSTREE_REPO_MODE_BARE && mode == OSTREE_REPO_CHECKOUT_MODE_NONE) + if (priv->mode == OSTREE_REPO_MODE_BARE && mode == OSTREE_REPO_CHECKOUT_MODE_NONE) { - possible_loose_path = ostree_repo_get_object_path (self, checksum, OSTREE_OBJECT_TYPE_RAW_FILE); + possible_loose_path = ostree_repo_get_object_path (self, checksum, OSTREE_OBJECT_TYPE_FILE); } if (possible_loose_path && lstat (ot_gfile_get_path_cached (possible_loose_path), &stbuf) >= 0) diff --git a/src/libostree/ostree-traverse.c b/src/libostree/ostree-traverse.c index 148372ef..f35c83a8 100644 --- a/src/libostree/ostree-traverse.c +++ b/src/libostree/ostree-traverse.c @@ -72,20 +72,9 @@ ostree_traverse_dirtree (OstreeRepo *repo, g_variant_get_child (files_variant, i, "(&s@ay)", &filename, &csum_v); g_free (tmp_checksum); tmp_checksum = ostree_checksum_from_bytes_v (csum_v); - if (ostree_repo_get_mode (repo) == OSTREE_REPO_MODE_BARE) - { - key = ostree_object_name_serialize (tmp_checksum, OSTREE_OBJECT_TYPE_RAW_FILE); - g_hash_table_replace (inout_reachable, key, key); - key = NULL; - } - else - { - key = ostree_object_name_serialize (tmp_checksum, OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META); - g_hash_table_replace (inout_reachable, key, key); - key = ostree_object_name_serialize (tmp_checksum, OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT); - g_hash_table_replace (inout_reachable, key, key); - key = NULL; - } + key = ostree_object_name_serialize (tmp_checksum, OSTREE_OBJECT_TYPE_FILE); + g_hash_table_replace (inout_reachable, key, key); + key = NULL; } dirs_variant = g_variant_get_child_value (tree, 1); diff --git a/src/libostree/ostree.h b/src/libostree/ostree.h index a4b78450..9dda6b38 100644 --- a/src/libostree/ostree.h +++ b/src/libostree/ostree.h @@ -23,6 +23,7 @@ #ifndef __OSTREE_H__ #include <ostree-checksum-input-stream.h> +#include <ostree-chain-input-stream.h> #include <ostree-core.h> #include <ostree-repo.h> #include <ostree-mutable-tree.h> diff --git a/src/libotutil/ot-gio-utils.c b/src/libotutil/ot-gio-utils.c index 3cd72eff..72eacf37 100644 --- a/src/libotutil/ot-gio-utils.c +++ b/src/libotutil/ot-gio-utils.c @@ -229,6 +229,36 @@ ot_gfile_get_basename_cached (GFile *file) } gboolean +ot_gio_write_update_checksum (GOutputStream *out, + gconstpointer data, + gsize len, + gsize *out_bytes_written, + GChecksum *checksum, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + + if (out) + { + if (!g_output_stream_write_all (out, data, len, out_bytes_written, + cancellable, error)) + goto out; + } + else if (out_bytes_written) + { + *out_bytes_written = len; + } + + if (checksum) + g_checksum_update (checksum, data, len); + + ret = TRUE; + out: + return ret; +} + +gboolean ot_gio_splice_update_checksum (GOutputStream *out, GInputStream *in, GChecksum *checksum, @@ -247,12 +277,9 @@ ot_gio_splice_update_checksum (GOutputStream *out, { if (!g_input_stream_read_all (in, buf, sizeof(buf), &bytes_read, cancellable, error)) goto out; - g_checksum_update (checksum, (guint8*)buf, bytes_read); - if (out) - { - if (!g_output_stream_write_all (out, buf, bytes_read, &bytes_written, cancellable, error)) - goto out; - } + if (!ot_gio_write_update_checksum (out, buf, bytes_read, &bytes_written, checksum, + cancellable, error)) + goto out; } while (bytes_read > 0); } diff --git a/src/libotutil/ot-gio-utils.h b/src/libotutil/ot-gio-utils.h index 59db7142..c98e73a5 100644 --- a/src/libotutil/ot-gio-utils.h +++ b/src/libotutil/ot-gio-utils.h @@ -61,6 +61,14 @@ gboolean ot_gfile_load_contents_utf8 (GFile *file, GCancellable *cancellable, GError **error); +gboolean ot_gio_write_update_checksum (GOutputStream *out, + gconstpointer data, + gsize len, + gsize *out_bytes_written, + GChecksum *checksum, + GCancellable *cancellable, + GError **error); + gboolean ot_gio_splice_get_checksum (GOutputStream *out, GInputStream *in, guchar **out_csum, diff --git a/src/libotutil/ot-variant-utils.c b/src/libotutil/ot-variant-utils.c index 58f3e490..3932386e 100644 --- a/src/libotutil/ot-variant-utils.c +++ b/src/libotutil/ot-variant-utils.c @@ -175,3 +175,17 @@ ot_util_variant_from_stream (GInputStream *src, out: return ret; } + +GInputStream * +ot_variant_read (GVariant *variant) +{ + GMemoryInputStream *ret = NULL; + + ret = (GMemoryInputStream*)g_memory_input_stream_new_from_data (g_variant_get_data (variant), + g_variant_get_size (variant), + NULL); + g_object_set_data_full ((GObject*)ret, "ot-variant-data", + g_variant_ref (variant), (GDestroyNotify) g_variant_unref); + return (GInputStream*)ret; +} + diff --git a/src/libotutil/ot-variant-utils.h b/src/libotutil/ot-variant-utils.h index 49882535..95ed2e9c 100644 --- a/src/libotutil/ot-variant-utils.h +++ b/src/libotutil/ot-variant-utils.h @@ -69,6 +69,8 @@ gboolean ot_util_variant_from_stream (GInputStream *src, GCancellable *cancellable, GError **error); +GInputStream *ot_variant_read (GVariant *variant); + G_END_DECLS #endif diff --git a/src/ostree/ostree-pull.c b/src/ostree/ostree-pull.c index 21dae465..7a48b114 100644 --- a/src/ostree/ostree-pull.c +++ b/src/ostree/ostree-pull.c @@ -34,27 +34,6 @@ static GOptionEntry options[] = { { NULL }, }; -static void -log_verbose (const char *fmt, - ...) G_GNUC_PRINTF (1, 2); - -static void -log_verbose (const char *fmt, - ...) -{ - va_list args; - char *msg; - - if (!verbose) - return; - - va_start (args, fmt); - - msg = g_strdup_vprintf (fmt, args); - g_print ("%s\n", msg); - g_free (msg); -} - typedef struct { OstreeRepo *repo; char *remote_name; @@ -122,8 +101,10 @@ static void sync_progress (OtPullData *pull_data) { if (pull_data->stdout_is_tty) - g_print ("%c8%" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT " KiB", - 0x1b, (pull_data->dl_current_bytes / 1024), (pull_data->dl_total_bytes / 1024)); + { + g_print ("%c8%" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT " KiB", + 0x1b, (pull_data->dl_current_bytes / 1024), (pull_data->dl_total_bytes / 1024)); + } } static void @@ -193,6 +174,7 @@ fetch_uri (OtPullData *pull_data, if (pull_data->stdout_is_tty) { + g_print ("%c7", 0x1B); g_print ("0/? KiB"); pull_data->dl_current_bytes = 0; pull_data->dl_total_bytes = 0; @@ -221,7 +203,8 @@ fetch_uri (OtPullData *pull_data, if (!g_output_stream_close (output_stream, NULL, error)) goto out; - g_print ("\n"); + if (pull_data->stdout_is_tty) + g_print ("\n"); ret = TRUE; ot_transfer_out_value (out_temp_filename, &ret_temp_filename); @@ -489,43 +472,30 @@ fetch_loose_object (OtPullData *pull_data, return ret; } -static void -unlink_file_on_unref (GFile *f) -{ - (void) ot_gfile_unlink (f, NULL, NULL); - g_object_unref (f); -} - static gboolean -fetch_object_if_not_stored (OtPullData *pull_data, - const char *checksum, - OstreeObjectType objtype, - GInputStream **out_input, - GCancellable *cancellable, - GError **error) +find_object_ensure_packs (OtPullData *pull_data, + const char *checksum, + OstreeObjectType objtype, + gboolean *out_is_stored, + GFile **out_remote_pack_path, + guint64 *out_remote_pack_offset, + GCancellable *cancellable, + GError **error) { gboolean ret = FALSE; - guint64 pack_offset = 0; - gboolean is_stored; - gboolean is_meta; - ot_lobj GInputStream *ret_input = NULL; - ot_lobj GFile *temp_path = NULL; + gboolean ret_is_stored; ot_lobj GFile *stored_path = NULL; - ot_lobj GFile *pack_path = NULL; ot_lfree char *local_pack_checksum = NULL; ot_lfree char *remote_pack_checksum = NULL; - ot_lvariant GVariant *pack_entry = NULL; - GMappedFile *pack_map = NULL; - - is_meta = OSTREE_OBJECT_TYPE_IS_META (objtype); + ot_lobj GFile *ret_remote_pack_path = NULL; if (!ostree_repo_find_object (pull_data->repo, objtype, checksum, &stored_path, &local_pack_checksum, NULL, cancellable, error)) goto out; - is_stored = (stored_path != NULL || local_pack_checksum != NULL); - if (!is_stored) + ret_is_stored = (stored_path != NULL || local_pack_checksum != NULL); + if (!ret_is_stored) { if (!pull_data->fetched_packs) { @@ -538,102 +508,90 @@ fetch_object_if_not_stored (OtPullData *pull_data, } if (!find_object_in_remote_packs (pull_data, checksum, objtype, - &remote_pack_checksum, &pack_offset, + &remote_pack_checksum, out_remote_pack_offset, cancellable, error)) goto out; + + if (remote_pack_checksum) + { + if (!fetch_one_pack_file (pull_data, remote_pack_checksum, OSTREE_OBJECT_TYPE_IS_META (objtype), + &ret_remote_pack_path, cancellable, error)) + goto out; + } } + + ret = TRUE; + if (out_is_stored) + *out_is_stored = ret_is_stored; + ot_transfer_out_value (out_remote_pack_path, &ret_remote_pack_path); + /* offset set above */ + out: + return ret; +} + +static gboolean +fetch_and_store_metadata (OtPullData *pull_data, + const char *checksum, + OstreeObjectType objtype, + GVariant **out_variant, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + guint64 pack_offset = 0; + gboolean is_stored; + ot_lvariant GVariant *ret_variant = NULL; + ot_lobj GFile *remote_pack_path = NULL; + ot_lobj GFile *temp_path = NULL; + ot_lobj GInputStream *input = NULL; + ot_lvariant GVariant *pack_entry = NULL; + ot_lvariant GVariant *metadata = NULL; + GMappedFile *pack_map = NULL; + + g_assert (OSTREE_OBJECT_TYPE_IS_META (objtype)); + + if (!find_object_ensure_packs (pull_data, checksum, objtype, + &is_stored, &remote_pack_path, &pack_offset, + cancellable, error)) + goto out; - if (remote_pack_checksum != NULL) + if (remote_pack_path != NULL) { g_assert (!is_stored); - if (!fetch_one_pack_file (pull_data, remote_pack_checksum, is_meta, - &pack_path, cancellable, error)) - goto out; - - pack_map = g_mapped_file_new (ot_gfile_get_path_cached (pack_path), FALSE, error); + pack_map = g_mapped_file_new (ot_gfile_get_path_cached (remote_pack_path), FALSE, error); if (!pack_map) goto out; if (!ostree_read_pack_entry_raw ((guchar*)g_mapped_file_get_contents (pack_map), g_mapped_file_get_length (pack_map), - pack_offset, FALSE, is_meta, &pack_entry, + pack_offset, FALSE, TRUE, &pack_entry, cancellable, error)) goto out; - /* Kind of a hack... */ - ret_input = ostree_read_pack_entry_as_stream (pack_entry); - g_object_set_data_full ((GObject*)ret_input, "ostree-pull-pack-map", - pack_map, (GDestroyNotify) g_mapped_file_unref); - pack_map = NULL; /* Transfer ownership */ + g_variant_get_child (pack_entry, 2, "v", &metadata); + + input = ot_variant_read (metadata); } else if (!is_stored) { if (!fetch_loose_object (pull_data, checksum, objtype, &temp_path, cancellable, error)) goto out; - ret_input = (GInputStream*)g_file_read (temp_path, cancellable, error); - if (!ret_input) + input = (GInputStream*)g_file_read (temp_path, cancellable, error); + if (!input) goto out; - g_object_set_data_full ((GObject*)ret_input, "ostree-tmpfile-unlink", - g_object_ref (temp_path), - (GDestroyNotify)unlink_file_on_unref); } - ret = TRUE; - ot_transfer_out_value (out_input, &ret_input); - out: - if (pack_map) - g_mapped_file_unref (pack_map); - return ret; -} - -static gboolean -fetch_and_store_object (OtPullData *pull_data, - const char *checksum, - OstreeObjectType objtype, - GCancellable *cancellable, - GError **error) -{ - gboolean ret = FALSE; - ot_lobj GFileInfo *file_info = NULL; - ot_lobj GInputStream *input = NULL; - - g_assert (objtype != OSTREE_OBJECT_TYPE_RAW_FILE); - - if (!fetch_object_if_not_stored (pull_data, checksum, objtype, &input, - cancellable, error)) - goto out; - if (input) { - if (!ostree_repo_stage_object (pull_data->repo, objtype, checksum, NULL, NULL, - input, cancellable, error)) + g_assert (remote_pack_path != NULL || !is_stored); + if (!ostree_repo_stage_object (pull_data->repo, objtype, checksum, + NULL, NULL, input, + cancellable, error)) goto out; - - log_verbose ("Staged object: %s.%s", checksum, ostree_object_type_to_string (objtype)); } - ret = TRUE; - out: - return ret; -} - -static gboolean -fetch_and_store_metadata (OtPullData *pull_data, - const char *checksum, - OstreeObjectType objtype, - GVariant **out_variant, - GCancellable *cancellable, - GError **error) -{ - gboolean ret = FALSE; - ot_lvariant GVariant *ret_variant = NULL; - - if (!fetch_and_store_object (pull_data, checksum, objtype, - cancellable, error)) - goto out; - if (!ostree_repo_load_variant (pull_data->repo, objtype, checksum, &ret_variant, error)) goto out; @@ -641,6 +599,10 @@ fetch_and_store_metadata (OtPullData *pull_data, ret = TRUE; ot_transfer_out_value (out_variant, &ret_variant); out: + if (temp_path) + (void) ot_gfile_unlink (temp_path, NULL, NULL); + if (pack_map) + g_mapped_file_unref (pack_map); return ret; } @@ -651,66 +613,66 @@ fetch_and_store_file (OtPullData *pull_data, GError **error) { gboolean ret = FALSE; - gboolean skip_archive_fetch; + gboolean is_stored; + guint64 pack_offset; + ot_lobj GFile *remote_pack_path = NULL; + ot_lobj GFile *temp_path = NULL; + ot_lvariant GVariant *pack_entry = NULL; ot_lobj GInputStream *input = NULL; - ot_lobj GFile *stored_path = NULL; - ot_lfree char *pack_checksum = NULL; - ot_lvariant GVariant *archive_metadata = NULL; - ot_lobj GFileInfo *archive_file_info = NULL; - ot_lvariant GVariant *archive_xattrs = NULL; - - /* If we're fetching from an archive into a bare repository, we need - * to explicitly check for raw file types locally. - */ - if (ostree_repo_get_mode (pull_data->repo) == OSTREE_REPO_MODE_BARE) + ot_lobj GFileInfo *file_info = NULL; + ot_lvariant GVariant *xattrs = NULL; + GMappedFile *pack_map = NULL; + + if (!find_object_ensure_packs (pull_data, checksum, OSTREE_OBJECT_TYPE_FILE, + &is_stored, &remote_pack_path, &pack_offset, + cancellable, error)) + goto out; + + if (remote_pack_path != NULL) { - if (!ostree_repo_find_object (pull_data->repo, OSTREE_OBJECT_TYPE_RAW_FILE, - checksum, &stored_path, &pack_checksum, - NULL, cancellable, error)) + g_assert (!is_stored); + + pack_map = g_mapped_file_new (ot_gfile_get_path_cached (remote_pack_path), FALSE, error); + if (!pack_map) + goto out; + + if (!ostree_read_pack_entry_raw ((guchar*)g_mapped_file_get_contents (pack_map), + g_mapped_file_get_length (pack_map), + pack_offset, FALSE, FALSE, &pack_entry, + cancellable, error)) + goto out; + + if (!ostree_parse_file_pack_entry (pack_entry, &input, &file_info, &xattrs, + cancellable, error)) goto out; - skip_archive_fetch = (stored_path || pack_checksum); - } - else - { - skip_archive_fetch = FALSE; + if (!ostree_repo_stage_object (pull_data->repo, OSTREE_OBJECT_TYPE_FILE, checksum, + file_info, xattrs, input, + cancellable, error)) + goto out; } - - if (!skip_archive_fetch) + else if (!is_stored) { - if (!fetch_object_if_not_stored (pull_data, checksum, - OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META, - &input, cancellable, error)) + if (!fetch_loose_object (pull_data, checksum, OSTREE_OBJECT_TYPE_FILE, &temp_path, + cancellable, error)) goto out; - if (input != NULL) - { - if (!ot_util_variant_from_stream (input, OSTREE_ARCHIVED_FILE_VARIANT_FORMAT, - FALSE, &archive_metadata, cancellable, error)) - goto out; - - if (!ostree_parse_archived_file_meta (archive_metadata, &archive_file_info, - &archive_xattrs, error)) - goto out; - - g_clear_object (&input); - if (g_file_info_get_file_type (archive_file_info) == G_FILE_TYPE_REGULAR) - { - if (!fetch_object_if_not_stored (pull_data, checksum, - OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT, - &input, cancellable, error)) - goto out; - } + if (!ostree_content_file_parse (temp_path, FALSE, &input, &file_info, &xattrs, + cancellable, error)) + goto out; - if (!ostree_repo_stage_object (pull_data->repo, OSTREE_OBJECT_TYPE_RAW_FILE, checksum, - archive_file_info, archive_xattrs, input, - cancellable, error)) - goto out; - } - } + if (!ostree_repo_stage_object (pull_data->repo, OSTREE_OBJECT_TYPE_FILE, checksum, + file_info, xattrs, input, + cancellable, error)) + goto out; + } ret = TRUE; out: + if (temp_path) + (void) ot_gfile_unlink (temp_path, NULL, NULL); + if (pack_map) + g_mapped_file_unref (pack_map); return ret; } @@ -770,8 +732,8 @@ fetch_and_store_tree_metadata_recurse (OtPullData *pull_data, g_free (tmp_checksum); tmp_checksum = ostree_checksum_from_bytes_v (meta_csum); - if (!fetch_and_store_object (pull_data, tmp_checksum, OSTREE_OBJECT_TYPE_DIR_META, - cancellable, error)) + if (!fetch_and_store_metadata (pull_data, tmp_checksum, OSTREE_OBJECT_TYPE_DIR_META, + NULL, cancellable, error)) goto out; g_free (tmp_checksum); @@ -807,8 +769,8 @@ fetch_and_store_commit_metadata_recurse (OtPullData *pull_data, g_free (tmp_checksum); tmp_checksum = ostree_checksum_from_bytes_v (tree_meta_csum); - if (!fetch_and_store_object (pull_data, tmp_checksum, OSTREE_OBJECT_TYPE_DIR_META, - cancellable, error)) + if (!fetch_and_store_metadata (pull_data, tmp_checksum, OSTREE_OBJECT_TYPE_DIR_META, + NULL, cancellable, error)) goto out; g_free (tmp_checksum); diff --git a/src/ostree/ot-builtin-checksum.c b/src/ostree/ot-builtin-checksum.c index e42454d5..3ef35797 100644 --- a/src/ostree/ot-builtin-checksum.c +++ b/src/ostree/ot-builtin-checksum.c @@ -79,7 +79,7 @@ ostree_builtin_checksum (int argc, char **argv, GFile *repo_path_path, GError ** data.loop = g_main_loop_new (NULL, FALSE); data.error = error; - ostree_checksum_file_async (f, OSTREE_OBJECT_TYPE_RAW_FILE, G_PRIORITY_DEFAULT, NULL, on_checksum_received, &data); + ostree_checksum_file_async (f, OSTREE_OBJECT_TYPE_FILE, G_PRIORITY_DEFAULT, NULL, on_checksum_received, &data); g_main_loop_run (data.loop); diff --git a/src/ostree/ot-builtin-diff.c b/src/ostree/ot-builtin-diff.c index 38a22a3f..47ee5af3 100644 --- a/src/ostree/ot-builtin-diff.c +++ b/src/ostree/ot-builtin-diff.c @@ -77,7 +77,7 @@ get_file_checksum (GFile *f, } else { - if (!ostree_checksum_file (f, OSTREE_OBJECT_TYPE_RAW_FILE, + if (!ostree_checksum_file (f, OSTREE_OBJECT_TYPE_FILE, &csum, cancellable, error)) goto out; ret_checksum = ostree_checksum_from_bytes (csum); diff --git a/src/ostree/ot-builtin-fsck.c b/src/ostree/ot-builtin-fsck.c index 6046512d..c617ccd6 100644 --- a/src/ostree/ot-builtin-fsck.c +++ b/src/ostree/ot-builtin-fsck.c @@ -203,7 +203,6 @@ fsck_reachable_objects_from_commits (OtFsckData *data, GVariant *serialized_key = key; const char *checksum; OstreeObjectType objtype; - OstreeObjectType checksum_objtype; ostree_object_name_deserialize (serialized_key, &checksum, &objtype); @@ -211,8 +210,6 @@ fsck_reachable_objects_from_commits (OtFsckData *data, g_clear_object (&file_info); ot_clear_gvariant (&xattrs); - checksum_objtype = objtype; - if (objtype == OSTREE_OBJECT_TYPE_COMMIT || objtype == OSTREE_OBJECT_TYPE_DIR_TREE || objtype == OSTREE_OBJECT_TYPE_DIR_META) @@ -253,19 +250,12 @@ fsck_reachable_objects_from_commits (OtFsckData *data, g_variant_get_size (metadata), NULL); } - else if (objtype == OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT) - { - /* Handled via ARCHIVED_FILE_META */ - continue; - } - else if (objtype == OSTREE_OBJECT_TYPE_RAW_FILE - || objtype == OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META) + else if (objtype == OSTREE_OBJECT_TYPE_FILE) { guint32 mode; if (!ostree_repo_load_file (data->repo, checksum, &input, &file_info, &xattrs, cancellable, error)) goto out; - checksum_objtype = OSTREE_OBJECT_TYPE_RAW_FILE; /* Override */ mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode"); if (!ostree_validate_structureof_file_mode (mode, error)) @@ -281,7 +271,7 @@ fsck_reachable_objects_from_commits (OtFsckData *data, g_free (computed_csum); if (!ostree_checksum_file_from_input (file_info, xattrs, input, - checksum_objtype, &computed_csum, + objtype, &computed_csum, cancellable, error)) goto out; diff --git a/src/ostree/ot-builtin-local-clone.c b/src/ostree/ot-builtin-local-clone.c index 208875f2..ee1e66d4 100644 --- a/src/ostree/ot-builtin-local-clone.c +++ b/src/ostree/ot-builtin-local-clone.c @@ -94,18 +94,18 @@ copy_dir_contents_recurse (GFile *src, } static gboolean -import_loose_object (OtLocalCloneData *data, - const char *checksum, - OstreeObjectType objtype, - GCancellable *cancellable, - GError **error) +import_one_object (OtLocalCloneData *data, + const char *checksum, + OstreeObjectType objtype, + GCancellable *cancellable, + GError **error) { gboolean ret = FALSE; ot_lobj GFile *objfile = NULL; ot_lobj GFileInfo *file_info = NULL; ot_lobj GFile *content_path = NULL; ot_lobj GFileInfo *archive_info = NULL; - ot_lvariant GVariant *archive_metadata = NULL; + ot_lvariant GVariant *metadata = NULL; ot_lvariant GVariant *xattrs = NULL; ot_lobj GInputStream *input = NULL; @@ -116,48 +116,29 @@ import_loose_object (OtLocalCloneData *data, if (file_info == NULL) goto out; - if (objtype == OSTREE_OBJECT_TYPE_RAW_FILE) + if (objtype == OSTREE_OBJECT_TYPE_FILE) { - if (!ostree_get_xattrs_for_file (objfile, &xattrs, cancellable, error)) - goto out; - } - - if (objtype == OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT) - ; - else if (objtype == OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META) - { - if (!ostree_repo_load_variant (data->src_repo, OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META, checksum, &archive_metadata, error)) - goto out; - - if (!ostree_parse_archived_file_meta (archive_metadata, &archive_info, &xattrs, error)) + if (!ostree_repo_load_file (data->src_repo, checksum, + &input, &file_info, &xattrs, + cancellable, error)) goto out; - content_path = ostree_repo_get_object_path (data->src_repo, checksum, OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT); - - if (g_file_info_get_file_type (archive_info) == G_FILE_TYPE_REGULAR) - { - input = (GInputStream*)g_file_read (content_path, NULL, error); - if (!input) - goto out; - } - - if (!ostree_repo_stage_object_trusted (data->dest_repo, OSTREE_OBJECT_TYPE_RAW_FILE, - checksum, FALSE, archive_info, xattrs, input, - NULL, error)) + if (!ostree_repo_stage_object_trusted (data->dest_repo, OSTREE_OBJECT_TYPE_FILE, + checksum, FALSE, file_info, xattrs, input, + cancellable, error)) goto out; } else { - if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR) - { - input = (GInputStream*)g_file_read (objfile, NULL, error); - if (!input) - goto out; - } + if (!ostree_repo_load_variant (data->src_repo, objtype, checksum, &metadata, + error)) + goto out; + + input = ot_variant_read (metadata); - if (!ostree_repo_stage_object_trusted (data->dest_repo, objtype, checksum, - FALSE, file_info, xattrs, input, - NULL, error)) + if (!ostree_repo_stage_object_trusted (data->dest_repo, objtype, + checksum, FALSE, NULL, NULL, input, + cancellable, error)) goto out; } @@ -273,20 +254,13 @@ ostree_builtin_local_clone (int argc, char **argv, GFile *repo_path, GError **er while (g_hash_table_iter_next (&hash_iter, &key, &value)) { GVariant *serialized_key = key; - GVariant *objdata = value; const char *checksum; OstreeObjectType objtype; - gboolean is_loose; ostree_object_name_deserialize (serialized_key, &checksum, &objtype); - g_variant_get_child (objdata, 0, "b", &is_loose); - - if (is_loose) - { - if (!import_loose_object (&data, checksum, objtype, cancellable, error)) - goto out; - } + if (!import_one_object (&data, checksum, objtype, cancellable, error)) + goto out; } if (!ostree_repo_commit_transaction (data.dest_repo, NULL, error)) diff --git a/src/ostree/ot-builtin-pack.c b/src/ostree/ot-builtin-pack.c index b2f81b6d..7ea5deaa 100644 --- a/src/ostree/ot-builtin-pack.c +++ b/src/ostree/ot-builtin-pack.c @@ -151,44 +151,6 @@ write_padding (GOutputStream *output, return ret; } -static gboolean -write_variant_with_size (GOutputStream *output, - GVariant *variant, - GChecksum *checksum, - guint64 *inout_offset, - GCancellable *cancellable, - GError **error) -{ - gboolean ret = FALSE; - guint64 variant_size; - guint32 variant_size_u32_be; - - g_assert ((*inout_offset & 3) == 0); - - /* Write variant size */ - variant_size = g_variant_get_size (variant); - g_assert (variant_size < G_MAXUINT32); - variant_size_u32_be = GUINT32_TO_BE((guint32) variant_size); - - if (!write_bytes_update_checksum (output, (guchar*)&variant_size_u32_be, 4, - checksum, inout_offset, cancellable, error)) - goto out; - - /* Pad to offset of 8, write variant */ - if (!write_padding (output, 8, checksum, inout_offset, cancellable, error)) - goto out; - g_assert ((*inout_offset & 7) == 0); - - if (!write_bytes_update_checksum (output, g_variant_get_data (variant), - variant_size, checksum, - inout_offset, cancellable, error)) - goto out; - - ret = TRUE; - out: - return ret; -} - static gint compare_index_content (gconstpointer ap, gconstpointer bp) @@ -235,27 +197,6 @@ delete_loose_object (OtRepackData *data, object_path = ostree_repo_get_object_path (data->repo, checksum, objtype); - /* This is gross - we need to specially clean up symbolic link object content */ - if (objtype == OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META) - { - if (!ot_util_variant_map (object_path, OSTREE_ARCHIVED_FILE_VARIANT_FORMAT, &archive_meta, error)) - goto out; - if (!ostree_parse_archived_file_meta (archive_meta, &file_info, &xattrs, error)) - goto out; - - if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_REGULAR) - { - content_object_path = ostree_repo_get_object_path (data->repo, checksum, - OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT); - if (!ot_gfile_unlink (content_object_path, cancellable, error)) - { - g_prefix_error (error, "Failed to delete archived content '%s'", - ot_gfile_get_path_cached (content_object_path)); - goto out; - } - } - } - if (!ot_gfile_unlink (object_path, cancellable, error)) { g_prefix_error (error, "Failed to delete archived file metadata '%s'", @@ -307,15 +248,16 @@ pack_one_data_object (OtRepackData *data, GError **error) { gboolean ret = FALSE; - guint64 objsize; guchar entry_flags = 0; GInputStream *read_object_in; /* nofree */ ot_lobj GFile *object_path = NULL; - ot_lobj GFileInputStream *object_input = NULL; - ot_lobj GFileInfo *object_file_info = NULL; + ot_lobj GInputStream *input = NULL; + ot_lobj GFileInfo *file_info = NULL; + ot_lvariant GVariant *xattrs = NULL; ot_lobj GMemoryOutputStream *object_data_stream = NULL; ot_lobj GConverter *compressor = NULL; ot_lobj GConverterInputStream *compressed_object_input = NULL; + ot_lvariant GVariant *file_header = NULL; ot_lvariant GVariant *ret_packed_object = NULL; switch (data->int_compression) @@ -332,46 +274,44 @@ pack_one_data_object (OtRepackData *data, } object_path = ostree_repo_get_object_path (data->repo, checksum, objtype); - - object_input = g_file_read (object_path, cancellable, error); - if (!object_input) - goto out; - object_file_info = g_file_input_stream_query_info (object_input, OSTREE_GIO_FAST_QUERYINFO, cancellable, error); - if (!object_file_info) + if (!ostree_repo_load_file (data->repo, checksum, &input, &file_info, &xattrs, + cancellable, error)) goto out; - objsize = g_file_info_get_attribute_uint64 (object_file_info, G_FILE_ATTRIBUTE_STANDARD_SIZE); - - g_assert_cmpint (objsize, ==, expected_objsize); - - object_data_stream = (GMemoryOutputStream*)g_memory_output_stream_new (NULL, 0, g_realloc, g_free); + file_header = ostree_file_header_new (file_info, xattrs); - if (entry_flags & OSTREE_PACK_FILE_ENTRY_FLAG_GZIP) - { - compressor = (GConverter*)g_zlib_compressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP, OT_GZIP_COMPRESSION_LEVEL); - compressed_object_input = (GConverterInputStream*)g_object_new (G_TYPE_CONVERTER_INPUT_STREAM, - "converter", compressor, - "base-stream", object_input, - "close-base-stream", TRUE, - NULL); - read_object_in = (GInputStream*)compressed_object_input; - } - else + object_data_stream = (GMemoryOutputStream*)g_memory_output_stream_new (NULL, 0, g_realloc, g_free); + if (input != NULL) { - read_object_in = (GInputStream*)object_input; - } + if (entry_flags & OSTREE_PACK_FILE_ENTRY_FLAG_GZIP) + { + compressor = (GConverter*)g_zlib_compressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP, OT_GZIP_COMPRESSION_LEVEL); + compressed_object_input = (GConverterInputStream*)g_object_new (G_TYPE_CONVERTER_INPUT_STREAM, + "converter", compressor, + "base-stream", input, + "close-base-stream", TRUE, + NULL); + read_object_in = (GInputStream*)compressed_object_input; + } + else + { + read_object_in = (GInputStream*)input; + } - if (!g_output_stream_splice ((GOutputStream*)object_data_stream, read_object_in, - G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET, - cancellable, error)) - goto out; + if (!g_output_stream_splice ((GOutputStream*)object_data_stream, read_object_in, + G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET, + cancellable, error)) + goto out; + } { guchar *data = g_memory_output_stream_get_data (object_data_stream); gsize data_len = g_memory_output_stream_get_data_size (object_data_stream); - ret_packed_object = g_variant_new ("(yy@ay@ay)", (guchar)objtype, entry_flags, + ret_packed_object = g_variant_new ("(@ayy@(uuuusa(ayay))@ay)", ostree_checksum_to_bytes_v (checksum), + entry_flags, + file_header, ot_gvariant_new_bytearray (data, data_len)); } @@ -433,9 +373,10 @@ create_pack_file (OtRepackData *data, g_variant_new_array (G_VARIANT_TYPE ("{sv}"), NULL, 0), (guint64)objects->len); - if (!write_variant_with_size (pack_out, pack_header, pack_checksum, &offset, - cancellable, error)) + if (!ostree_write_variant_with_size (pack_out, pack_header, offset, &bytes_written, pack_checksum, + cancellable, error)) goto out; + offset += bytes_written; for (i = 0; i < objects->len; i++) { @@ -475,9 +416,11 @@ create_pack_file (OtRepackData *data, g_ptr_array_add (index_content_list, g_variant_ref_sink (index_entry)); index_entry = NULL; - if (!write_variant_with_size (pack_out, packed_object, pack_checksum, - &offset, cancellable, error)) + bytes_written = 0; + if (!ostree_write_variant_with_size (pack_out, packed_object, offset, &bytes_written, + pack_checksum, cancellable, error)) goto out; + offset += bytes_written; } if (!g_output_stream_close (pack_out, cancellable, error)) @@ -830,13 +773,11 @@ do_stats_gather_loose (OtRepackData *data, case OSTREE_OBJECT_TYPE_DIR_META: n_dirmeta++; break; - case OSTREE_OBJECT_TYPE_RAW_FILE: - case OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META: + case OSTREE_OBJECT_TYPE_FILE: n_files++; break; - case OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT: - /* Counted under files by META */ - break; + default: + g_assert_not_reached (); } } diff --git a/src/ostree/ot-builtin-show.c b/src/ostree/ot-builtin-show.c index 6711981f..ea85cc1a 100644 --- a/src/ostree/ot-builtin-show.c +++ b/src/ostree/ot-builtin-show.c @@ -91,7 +91,7 @@ show_repo_meta (OstreeRepo *repo, ot_lobj GFile *object_path = NULL; ot_lobj GInputStream *in = NULL; - for (objtype = OSTREE_OBJECT_TYPE_RAW_FILE; objtype <= OSTREE_OBJECT_TYPE_COMMIT; objtype++) + for (objtype = OSTREE_OBJECT_TYPE_FILE; objtype <= OSTREE_OBJECT_TYPE_COMMIT; objtype++) { g_clear_object (&object_path); @@ -109,7 +109,7 @@ show_repo_meta (OstreeRepo *repo, print_variant (variant); break; } - else if (objtype == OSTREE_OBJECT_TYPE_RAW_FILE) + else if (objtype == OSTREE_OBJECT_TYPE_FILE) { in = (GInputStream*)g_file_read (object_path, NULL, error); if (!in) @@ -121,12 +121,6 @@ show_repo_meta (OstreeRepo *repo, g_print ("%s", buf); } while (bytes_read > 0); } - else if (objtype == OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, - "Can't show archived files yet"); - goto out; - } else g_assert_not_reached (); } diff --git a/src/ostree/ot-builtin-unpack.c b/src/ostree/ot-builtin-unpack.c index 1092c70a..3f97ca00 100644 --- a/src/ostree/ot-builtin-unpack.c +++ b/src/ostree/ot-builtin-unpack.c @@ -102,31 +102,24 @@ unpack_one_object (OstreeRepo *repo, ot_lvariant GVariant *xattrs = NULL; ot_lvariant GVariant *meta = NULL; - g_assert (objtype != OSTREE_OBJECT_TYPE_RAW_FILE); - - if (objtype == OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META) + if (objtype == OSTREE_OBJECT_TYPE_FILE) { if (!ostree_repo_load_file (repo, checksum, &input, &file_info, &xattrs, cancellable, error)) goto out; - if (!ostree_repo_stage_object_trusted (repo, OSTREE_OBJECT_TYPE_RAW_FILE, + if (!ostree_repo_stage_object_trusted (repo, OSTREE_OBJECT_TYPE_FILE, checksum, TRUE, file_info, xattrs, input, cancellable, error)) goto out; } - else if (objtype == OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT) - { - /* nothing; handled in META case */ - } else { if (!ostree_repo_load_variant (repo, objtype, checksum, &meta, error)) goto out; - input = g_memory_input_stream_new_from_data (g_variant_get_data (meta), - g_variant_get_size (meta), NULL); + input = ot_variant_read (meta); if (!ostree_repo_stage_object_trusted (repo, objtype, checksum, TRUE, NULL, NULL, input, cancellable, error)) diff --git a/tests/t0000-basic.sh b/tests/t0000-basic.sh index 6cb79ab2..dfdb6a19 100755 --- a/tests/t0000-basic.sh +++ b/tests/t0000-basic.sh @@ -19,21 +19,13 @@ set -e -echo "1..30" +echo "1..29" . libtest.sh -echo hello > afile -assert_streq "$(ostree checksum afile)" e56457ac3d60e89083e3492c738588f28311ea44c347f57f12e8b7f35d518fe3 - setup_test_repository "regular" echo "ok setup" -assert_file_has_content ${test_tmpdir}/repo/objects/3a/9b4a6fb6885c2548e35c9382b316ad073ef7c1872a97cc9661e6403777cbaf.file moo -assert_streq "$(readlink ${test_tmpdir}/repo/objects/d4/69b152ab4c8ddcfdfd5b15510560bcb76ae4ffea6eace4074435e5a5d05622.file)" nonexistent - -echo "ok check" - $OSTREE checkout test2 checkout-test2 echo "ok checkout" |