[ostree] For archive checkouts, actually unpack the packfiles
- From: Colin Walters <walters src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [ostree] For archive checkouts, actually unpack the packfiles
- Date: Tue, 1 Nov 2011 15:01:25 +0000 (UTC)
commit a89764231543c2a64da1e492963436ae97d327a6
Author: Colin Walters <walters verbum org>
Date: Tue Nov 1 10:59:07 2011 -0400
For archive checkouts, actually unpack the packfiles
src/libostree/ostree-core.c | 257 +++++++++++++++++++++++++++++++++++++++++++
src/libostree/ostree-core.h | 6 +
src/libostree/ostree-repo.c | 226 +++++--------------------------------
3 files changed, 294 insertions(+), 195 deletions(-)
---
diff --git a/src/libostree/ostree-core.c b/src/libostree/ostree-core.c
index 4befb01..e36845d 100644
--- a/src/libostree/ostree-core.c
+++ b/src/libostree/ostree-core.c
@@ -554,3 +554,260 @@ ostree_pack_object (GOutputStream *output,
return ret;
}
+static gboolean
+splice_and_checksum (GOutputStream *out,
+ GInputStream *in,
+ GChecksum *checksum,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+
+ if (checksum != NULL)
+ {
+ gsize bytes_read, bytes_written;
+ char buf[4096];
+ do
+ {
+ if (!g_input_stream_read_all (in, buf, sizeof(buf), &bytes_read, cancellable, error))
+ goto out;
+ if (checksum)
+ g_checksum_update (checksum, (guint8*)buf, bytes_read);
+ if (!g_output_stream_write_all (out, buf, bytes_read, &bytes_written, cancellable, error))
+ goto out;
+ }
+ while (bytes_read > 0);
+ }
+ else
+ {
+ if (g_output_stream_splice (out, in, 0, cancellable, error) < 0)
+ goto out;
+ }
+
+ ret = TRUE;
+ out:
+ return ret;
+}
+
+static gboolean
+unpack_meta (const char *path,
+ const char *dest_path,
+ GChecksum **out_checksum,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ GFile *file = NULL;
+ GFile *dest_file = NULL;
+ GFileInputStream *in = NULL;
+ GChecksum *ret_checksum = NULL;
+ GFileOutputStream *out = NULL;
+
+ file = ot_util_new_file_for_path (path);
+ dest_file = ot_util_new_file_for_path (dest_path);
+
+ if (out_checksum)
+ ret_checksum = g_checksum_new (G_CHECKSUM_SHA256);
+
+ in = g_file_read (file, NULL, error);
+ if (!in)
+ goto out;
+
+ out = g_file_replace (dest_file, NULL, FALSE, 0, NULL, error);
+ if (!out)
+ goto out;
+
+ if (!splice_and_checksum ((GOutputStream*)out, (GInputStream*)in, ret_checksum, NULL, error))
+ goto out;
+
+ if (!g_output_stream_close ((GOutputStream*)out, NULL, error))
+ goto out;
+
+ ret = TRUE;
+ if (out_checksum)
+ *out_checksum = ret_checksum;
+ ret_checksum = NULL;
+ out:
+ if (!ret)
+ (void) unlink (dest_path);
+ if (ret_checksum)
+ g_checksum_free (ret_checksum);
+ g_clear_object (&file);
+ g_clear_object (&dest_file);
+ g_clear_object (&in);
+ 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;
+ char *metadata_buf = NULL;
+ GVariant *metadata = NULL;
+ GVariant *xattrs = 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, bytes_written;
+ int temp_fd = -1;
+
+ file = ot_util_new_file_for_path (path);
+
+ in = g_file_read (file, NULL, error);
+ if (!in)
+ goto out;
+
+ if (!g_input_stream_read_all ((GInputStream*)in, &metadata_len, 4, &bytes_read, NULL, error))
+ goto out;
+ if (bytes_read != 4)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Corrupted packfile; too short while reading metadata length");
+ goto out;
+ }
+
+ metadata_len = GUINT32_FROM_BE (metadata_len);
+ metadata_buf = g_malloc (metadata_len);
+
+ if (!g_input_stream_read_all ((GInputStream*)in, metadata_buf, metadata_len, &bytes_read, NULL, error))
+ goto out;
+ if (bytes_read != metadata_len)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Corrupted packfile; too short while reading metadata");
+ goto out;
+ }
+
+ metadata = g_variant_new_from_data (G_VARIANT_TYPE (OSTREE_PACK_FILE_VARIANT_FORMAT),
+ metadata_buf, metadata_len, FALSE, NULL, NULL);
+
+ g_variant_get (metadata, "(uuuu a(ayay)t)",
+ &version, &uid, &gid, &mode,
+ &xattrs, &content_len);
+ uid = GUINT32_FROM_BE (uid);
+ gid = GUINT32_FROM_BE (gid);
+ mode = GUINT32_FROM_BE (mode);
+ content_len = GUINT64_FROM_BE (content_len);
+
+ dest_file = ot_util_new_file_for_path (dest_path);
+
+ if (out_checksum)
+ ret_checksum = g_checksum_new (G_CHECKSUM_SHA256);
+
+ if (S_ISREG (mode))
+ {
+ out = g_file_replace (dest_file, NULL, FALSE, 0, NULL, error);
+ if (!out)
+ goto out;
+
+ if (!splice_and_checksum ((GOutputStream*)out, (GInputStream*)in, ret_checksum, NULL, error))
+ goto out;
+
+ if (!g_output_stream_close ((GOutputStream*)out, NULL, error))
+ goto out;
+ }
+ else if (S_ISLNK (mode))
+ {
+ char target[PATH_MAX+1];
+
+ if (!g_input_stream_read_all ((GInputStream*)in, target, sizeof(target)-1, &bytes_read, NULL, error))
+ goto out;
+ target[bytes_read] = '\0';
+ if (ret_checksum)
+ g_checksum_update (ret_checksum, (guint8*)target, bytes_read);
+ if (symlink (target, dest_path) < 0)
+ {
+ ot_util_set_error_from_errno (error, errno);
+ goto out;
+ }
+ }
+ else if (S_ISCHR (mode) || S_ISBLK (mode))
+ {
+ guint32 dev;
+
+ if (!g_input_stream_read_all ((GInputStream*)in, &dev, 4, &bytes_read, NULL, error))
+ goto out;
+ if (bytes_read != 4)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Corrupted packfile; too short while reading device id");
+ goto out;
+ }
+ dev = GUINT32_FROM_BE (dev);
+ if (ret_checksum)
+ g_checksum_update (ret_checksum, (guint8*)&dev, 4);
+ if (mknod (dest_path, mode, dev) < 0)
+ {
+ ot_util_set_error_from_errno (error, errno);
+ goto out;
+ }
+ }
+ else
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Corrupted packfile; invalid mode %u", mode);
+ goto out;
+ }
+
+ if (!S_ISLNK (mode))
+ {
+ if (chmod (dest_path, mode) < 0)
+ {
+ ot_util_set_error_from_errno (error, errno);
+ goto out;
+ }
+ }
+
+ if (!ostree_set_xattrs (dest_path, xattrs, error))
+ goto out;
+
+ if (ret_checksum)
+ {
+ ostree_checksum_update_stat (ret_checksum, uid, gid, mode);
+ g_checksum_update (ret_checksum, (guint8*)g_variant_get_data (xattrs), g_variant_get_size (xattrs));
+ }
+
+ ret = TRUE;
+ if (out_checksum)
+ *out_checksum = ret_checksum;
+ ret_checksum = NULL;
+ out:
+ if (!ret)
+ (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);
+ g_clear_object (&out);
+ if (metadata)
+ g_variant_unref (metadata);
+ if (xattrs)
+ g_variant_unref (xattrs);
+ return ret;
+}
+
+gboolean
+ostree_unpack_object (const char *path,
+ OstreeObjectType objtype,
+ const char *dest_path,
+ GChecksum **out_checksum,
+ GError **error)
+{
+ if (objtype == OSTREE_OBJECT_TYPE_META)
+ return unpack_meta (path, dest_path, out_checksum, error);
+ else
+ return unpack_file (path, dest_path, out_checksum, error);
+}
+
+
+
diff --git a/src/libostree/ostree-core.h b/src/libostree/ostree-core.h
index 3c16918..c1fb491 100644
--- a/src/libostree/ostree-core.h
+++ b/src/libostree/ostree-core.h
@@ -131,6 +131,12 @@ gboolean ostree_pack_object (GOutputStream *output,
GCancellable *cancellable,
GError **error);
+gboolean ostree_unpack_object (const char *path,
+ OstreeObjectType objtype,
+ const char *dest_path,
+ GChecksum **out_checksum,
+ GError **error);
+
void ostree_checksum_update_stat (GChecksum *checksum, guint32 uid, guint32 gid, guint32 mode);
diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c
index 721f62b..d0f83de 100644
--- a/src/libostree/ostree-repo.c
+++ b/src/libostree/ostree-repo.c
@@ -910,178 +910,6 @@ ostree_repo_link_file (OstreeRepo *self,
return TRUE;
}
-static gboolean
-unpack_and_checksum_packfile (OstreeRepo *self,
- const char *path,
- gchar **out_filename,
- GChecksum **out_checksum,
- GError **error)
-{
- OstreeRepoPrivate *priv = GET_PRIVATE (self);
- gboolean ret = FALSE;
- GFile *file = NULL;
- char *temp_path = NULL;
- GFile *temp_file = NULL;
- GFileOutputStream *temp_out = NULL;
- char *metadata_buf = NULL;
- GVariant *metadata = NULL;
- GVariant *xattrs = NULL;
- GFileInputStream *in = NULL;
- GChecksum *ret_checksum = NULL;
- guint32 metadata_len;
- guint32 version, uid, gid, mode;
- guint64 content_len;
- gsize bytes_read, bytes_written;
- char buf[8192];
- int temp_fd = -1;
-
- file = ot_util_new_file_for_path (path);
-
- in = g_file_read (file, NULL, error);
- if (!in)
- goto out;
-
- if (!g_input_stream_read_all ((GInputStream*)in, &metadata_len, 4, &bytes_read, NULL, error))
- goto out;
- if (bytes_read != 4)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Corrupted packfile; too short while reading metadata length");
- goto out;
- }
-
- metadata_len = GUINT32_FROM_BE (metadata_len);
- metadata_buf = g_malloc (metadata_len);
-
- if (!g_input_stream_read_all ((GInputStream*)in, metadata_buf, metadata_len, &bytes_read, NULL, error))
- goto out;
- if (bytes_read != metadata_len)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Corrupted packfile; too short while reading metadata");
- goto out;
- }
-
- metadata = g_variant_new_from_data (G_VARIANT_TYPE (OSTREE_PACK_FILE_VARIANT_FORMAT),
- metadata_buf, metadata_len, FALSE, NULL, NULL);
-
- g_variant_get (metadata, "(uuuu a(ayay)t)",
- &version, &uid, &gid, &mode,
- &xattrs, &content_len);
- uid = GUINT32_FROM_BE (uid);
- gid = GUINT32_FROM_BE (gid);
- mode = GUINT32_FROM_BE (mode);
- content_len = GUINT64_FROM_BE (content_len);
-
- temp_path = g_build_filename (priv->path, "tmp-packfile-XXXXXX");
- temp_file = ot_util_new_file_for_path (temp_path);
-
- ret_checksum = g_checksum_new (G_CHECKSUM_SHA256);
-
- if (S_ISREG (mode))
- {
- temp_fd = g_mkstemp (temp_path);
- if (temp_fd < 0)
- {
- ot_util_set_error_from_errno (error, errno);
- goto out;
- }
- close (temp_fd);
- temp_fd = -1;
- temp_out = g_file_replace (temp_file, NULL, FALSE, 0, NULL, error);
- if (!temp_out)
- goto out;
-
- do
- {
- if (!g_input_stream_read_all ((GInputStream*)in, buf, sizeof(buf), &bytes_read, NULL, error))
- goto out;
- g_checksum_update (ret_checksum, (guint8*)buf, bytes_read);
- if (!g_output_stream_write_all ((GOutputStream*)temp_out, buf, bytes_read, &bytes_written, NULL, error))
- goto out;
- }
- while (bytes_read > 0);
-
- if (!g_output_stream_close ((GOutputStream*)temp_out, NULL, error))
- goto out;
- }
- else if (S_ISLNK (mode))
- {
- g_assert (sizeof (buf) > PATH_MAX);
-
- if (!g_input_stream_read_all ((GInputStream*)in, buf, sizeof(buf), &bytes_read, NULL, error))
- goto out;
- buf[bytes_read] = '\0';
- if (symlink (buf, temp_path) < 0)
- {
- ot_util_set_error_from_errno (error, errno);
- goto out;
- }
- }
- else if (S_ISCHR (mode) || S_ISBLK (mode))
- {
- guint32 dev;
-
- if (!g_input_stream_read_all ((GInputStream*)in, &dev, 4, &bytes_read, NULL, error))
- goto out;
- if (bytes_read != 4)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Corrupted packfile; too short while reading device id");
- goto out;
- }
- dev = GUINT32_FROM_BE (dev);
- if (mknod (temp_path, mode, dev) < 0)
- {
- ot_util_set_error_from_errno (error, errno);
- goto out;
- }
- }
- else
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Corrupted packfile; invalid mode %u", mode);
- goto out;
- }
-
- if (!S_ISLNK (mode))
- {
- if (chmod (temp_path, mode) < 0)
- {
- ot_util_set_error_from_errno (error, errno);
- goto out;
- }
- }
-
- if (!ostree_set_xattrs (temp_path, xattrs, error))
- goto out;
-
- ostree_checksum_update_stat (ret_checksum, uid, gid, mode);
- g_checksum_update (ret_checksum, (guint8*)g_variant_get_data (xattrs), g_variant_get_size (xattrs));
-
- ret = TRUE;
- *out_checksum = ret_checksum;
- ret_checksum = NULL;
- *out_filename = temp_path;
- temp_path = NULL;
- out:
- if (ret_checksum)
- g_checksum_free (ret_checksum);
- g_free (metadata_buf);
- if (temp_path)
- (void) unlink (temp_path);
- g_free (temp_path);
- g_clear_object (&file);
- g_clear_object (&in);
- g_clear_object (&temp_file);
- g_clear_object (&temp_out);
- if (metadata)
- g_variant_unref (metadata);
- if (xattrs)
- g_variant_unref (xattrs);
- return ret;
-}
-
gboolean
ostree_repo_store_packfile (OstreeRepo *self,
const char *expected_checksum,
@@ -1089,23 +917,18 @@ ostree_repo_store_packfile (OstreeRepo *self,
OstreeObjectType objtype,
GError **error)
{
+ OstreeRepoPrivate *priv = GET_PRIVATE (self);
gboolean ret = FALSE;
- char *tempfile = NULL;
+ GString *tempfile_path = NULL;
GChecksum *checksum = NULL;
struct stat stbuf;
gboolean did_exist;
- if (objtype == OSTREE_OBJECT_TYPE_META)
- {
- if (!ostree_stat_and_checksum_file (-1, path, objtype, &checksum, &stbuf, error))
- goto out;
- }
- else
- {
- if (!unpack_and_checksum_packfile (self, path, &tempfile, &checksum, error))
- goto out;
-
- }
+ tempfile_path = g_string_new (priv->path);
+ g_string_append_printf (tempfile_path, "/tmp-unpack-%s", expected_checksum);
+
+ if (!ostree_unpack_object (path, objtype, tempfile_path->str, &checksum, error))
+ goto out;
if (strcmp (g_checksum_get_string (checksum), expected_checksum) != 0)
{
@@ -1115,7 +938,7 @@ ostree_repo_store_packfile (OstreeRepo *self,
goto out;
}
- if (!ostree_repo_store_object_trusted (self, tempfile ? tempfile : path,
+ if (!ostree_repo_store_object_trusted (self, tempfile_path ? tempfile_path->str : path,
expected_checksum,
objtype,
TRUE, FALSE, &did_exist, error))
@@ -1123,9 +946,11 @@ ostree_repo_store_packfile (OstreeRepo *self,
ret = TRUE;
out:
- if (tempfile)
- (void) unlink (tempfile);
- g_free (tempfile);
+ if (tempfile_path)
+ {
+ (void) unlink (tempfile_path->str);
+ g_string_free (tempfile_path, TRUE);
+ }
if (checksum)
g_checksum_free (checksum);
return ret;
@@ -2184,8 +2009,9 @@ checkout_one_directory (OstreeRepo *self,
if (!checkout_tree (self, dir->tree_data, dest_path, error))
goto out;
- /* TODO - xattrs */
-
+ if (!ostree_set_xattrs (dest_path, xattr_variant, error))
+ goto out;
+
ret = TRUE;
out:
g_free (dest_path);
@@ -2199,6 +2025,7 @@ checkout_tree (OstreeRepo *self,
const char *destination,
GError **error)
{
+ OstreeRepoPrivate *priv = GET_PRIVATE (self);
gboolean ret = FALSE;
GHashTableIter hash_iter;
gpointer key, value;
@@ -2213,15 +2040,24 @@ checkout_tree (OstreeRepo *self,
object_path = get_object_path (self, checksum, OSTREE_OBJECT_TYPE_FILE);
dest_path = g_build_filename (destination, filename, NULL);
- if (link (object_path, dest_path) < 0)
+
+ if (priv->archive)
{
- ot_util_set_error_from_errno (error, errno);
+ if (!ostree_unpack_object (object_path, OSTREE_OBJECT_TYPE_FILE, dest_path, NULL, error))
+ goto out;
+ }
+ else
+ {
+ if (link (object_path, dest_path) < 0)
+ {
+ ot_util_set_error_from_errno (error, errno);
+ g_free (object_path);
+ g_free (dest_path);
+ goto out;
+ }
g_free (object_path);
g_free (dest_path);
- goto out;
}
- g_free (object_path);
- g_free (dest_path);
}
g_hash_table_iter_init (&hash_iter, tree->directories);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]