From 8f0afd1f5443b262f4e469ff26f5dc763f00e473 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Tue, 8 Nov 2011 19:37:41 -0500 Subject: [PATCH] core: Add API for just effectively stat()ing packed files This will allow us to implement more of a VFS-like API on top. --- libostree/ostree-core.c | 81 +++++++++++++++++++++++++++++------------ libostree/ostree-core.h | 10 ++++- 2 files changed, 67 insertions(+), 24 deletions(-) diff --git a/libostree/ostree-core.c b/libostree/ostree-core.c index a54f6285..904ce05d 100644 --- a/libostree/ostree-core.c +++ b/libostree/ostree-core.c @@ -627,29 +627,20 @@ unpack_meta (const char *path, return ret; } - -static gboolean -unpack_file (const char *path, - const char *dest_path, - GChecksum **out_checksum, - GError **error) +gboolean +ostree_parse_packed_file (GFile *file, + GVariant **out_metadata, + GInputStream **out_content, + GCancellable *cancellable, + GError **error) { gboolean ret = FALSE; - GFile *file = NULL; - GFile *dest_file = NULL; char *metadata_buf = NULL; - GVariant *metadata = NULL; - GVariant *xattrs = NULL; + GVariant *ret_metadata = NULL; GFileInputStream *in = NULL; - GFileOutputStream *out = NULL; - GChecksum *ret_checksum = NULL; guint32 metadata_len; - guint32 version, uid, gid, mode; - guint64 content_len; gsize bytes_read; - file = ot_util_new_file_for_path (path); - in = g_file_read (file, NULL, error); if (!in) goto out; @@ -664,6 +655,13 @@ unpack_file (const char *path, } metadata_len = GUINT32_FROM_BE (metadata_len); + if (metadata_len > OSTREE_MAX_METADATA_SIZE) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Corrupted packfile; metadata length %u is larger than maximum %u", + metadata_len, OSTREE_MAX_METADATA_SIZE); + goto out; + } metadata_buf = g_malloc (metadata_len); if (!g_input_stream_read_all ((GInputStream*)in, metadata_buf, metadata_len, &bytes_read, NULL, error)) @@ -675,9 +673,47 @@ unpack_file (const char *path, goto out; } - metadata = g_variant_new_from_data (G_VARIANT_TYPE (OSTREE_PACK_FILE_VARIANT_FORMAT), - metadata_buf, metadata_len, FALSE, NULL, NULL); - + ret_metadata = g_variant_new_from_data (G_VARIANT_TYPE (OSTREE_PACK_FILE_VARIANT_FORMAT), + metadata_buf, metadata_len, FALSE, + (GDestroyNotify)g_free, + metadata_buf); + metadata_buf = NULL; + + ret = TRUE; + *out_metadata = ret_metadata; + ret_metadata = NULL; + *out_content = (GInputStream*)in; + in = NULL; + out: + g_clear_object (&in); + if (ret_metadata) + g_variant_unref (ret_metadata); + return ret; +} + +static gboolean +unpack_file (const char *path, + const char *dest_path, + GChecksum **out_checksum, + GError **error) +{ + gboolean ret = FALSE; + GFile *file = NULL; + GFile *dest_file = NULL; + GVariant *metadata = NULL; + GVariant *xattrs = NULL; + GInputStream *in = NULL; + GFileOutputStream *out = NULL; + GChecksum *ret_checksum = NULL; + guint32 version, uid, gid, mode; + guint64 content_len; + gsize bytes_read; + + file = ot_util_new_file_for_path (path); + + if (!ostree_parse_packed_file (file, &metadata, &in, NULL, error)) + goto out; + g_variant_get (metadata, "(uuuu@a(ayay)t)", &version, &uid, &gid, &mode, &xattrs, &content_len); @@ -697,7 +733,7 @@ unpack_file (const char *path, if (!out) goto out; - if (!splice_and_checksum ((GOutputStream*)out, (GInputStream*)in, ret_checksum, NULL, error)) + if (!splice_and_checksum ((GOutputStream*)out, in, ret_checksum, NULL, error)) goto out; if (!g_output_stream_close ((GOutputStream*)out, NULL, error)) @@ -707,7 +743,7 @@ unpack_file (const char *path, { char target[PATH_MAX+1]; - if (!g_input_stream_read_all ((GInputStream*)in, target, sizeof(target)-1, &bytes_read, NULL, error)) + if (!g_input_stream_read_all (in, target, sizeof(target)-1, &bytes_read, NULL, error)) goto out; target[bytes_read] = '\0'; if (ret_checksum) @@ -722,7 +758,7 @@ unpack_file (const char *path, { guint32 dev; - if (!g_input_stream_read_all ((GInputStream*)in, &dev, 4, &bytes_read, NULL, error)) + if (!g_input_stream_read_all (in, &dev, 4, &bytes_read, NULL, error)) goto out; if (bytes_read != 4) { @@ -773,7 +809,6 @@ unpack_file (const char *path, (void) unlink (dest_path); if (ret_checksum) g_checksum_free (ret_checksum); - g_free (metadata_buf); g_clear_object (&file); g_clear_object (&dest_file); g_clear_object (&in); diff --git a/libostree/ostree-core.h b/libostree/ostree-core.h index 959a46b7..3dc70b48 100644 --- a/libostree/ostree-core.h +++ b/libostree/ostree-core.h @@ -26,6 +26,8 @@ G_BEGIN_DECLS +#define OSTREE_MAX_METADATA_SIZE (1 << 26) + #define OSTREE_GIO_FAST_QUERYINFO "standard::name,standard::type,standard::is-symlink,standard::symlink-target,unix::*" #define OSTREE_EMPTY_STRING_SHA256 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; @@ -128,11 +130,17 @@ gboolean ostree_stat_and_checksum_file (int dirfd, const char *path, #define OSTREE_PACK_FILE_VARIANT_FORMAT "(uuuua(ayay)t)" gboolean ostree_pack_object (GOutputStream *output, - GFile *path, + GFile *file, OstreeObjectType objtype, GCancellable *cancellable, GError **error); +gboolean ostree_parse_packed_file (GFile *file, + GVariant **out_metadata, + GInputStream **out_content, + GCancellable *cancellable, + GError **error); + gboolean ostree_unpack_object (const char *path, OstreeObjectType objtype, const char *dest_path,