[ostree/wip/objtype] more WIP



commit 5a96d4e10f87831bf786947781f785f7371f5b07
Author: Colin Walters <walters verbum org>
Date:   Wed Dec 14 23:38:30 2011 -0500

    more WIP

 src/libostree/ostree-core.c         |  143 +++++++++++++------------
 src/libostree/ostree-core.h         |   16 ++--
 src/libostree/ostree-repo-file.c    |    4 +-
 src/libostree/ostree-repo.c         |  200 +++++++++++++++++++++++------------
 src/ostree/ostree-pull.c            |    6 +
 src/ostree/ot-builtin-fsck.c        |   43 ++++----
 src/ostree/ot-builtin-local-clone.c |   16 +++-
 7 files changed, 256 insertions(+), 172 deletions(-)
---
diff --git a/src/libostree/ostree-core.c b/src/libostree/ostree-core.c
index 4b38c4e..e7c45fc 100644
--- a/src/libostree/ostree-core.c
+++ b/src/libostree/ostree-core.c
@@ -245,13 +245,16 @@ ostree_checksum_file_from_input (GFileInfo        *file_info,
       goto out;
     }
 
-  ostree_checksum_update_stat (ret_checksum,
-                               g_file_info_get_attribute_uint32 (file_info, "unix::uid"),
-                               g_file_info_get_attribute_uint32 (file_info, "unix::gid"),
-                               g_file_info_get_attribute_uint32 (file_info, "unix::mode"));
-  /* FIXME - ensure empty xattrs are the same as NULL xattrs */
-  if (xattrs)
-    g_checksum_update (ret_checksum, (guint8*)g_variant_get_data (xattrs), g_variant_get_size (xattrs));
+  if (objtype != OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT)
+    {
+      ostree_checksum_update_stat (ret_checksum,
+                                   g_file_info_get_attribute_uint32 (file_info, "unix::uid"),
+                                   g_file_info_get_attribute_uint32 (file_info, "unix::gid"),
+                                   g_file_info_get_attribute_uint32 (file_info, "unix::mode"));
+      /* FIXME - ensure empty xattrs are the same as NULL xattrs */
+      if (xattrs)
+        g_checksum_update (ret_checksum, (guint8*)g_variant_get_data (xattrs), g_variant_get_size (xattrs));
+    }
 
   ret = TRUE;
   ot_transfer_out_value (out_checksum, &ret_checksum);
@@ -291,7 +294,7 @@ ostree_checksum_file (GFile            *f,
         goto out;
     }
 
-  if (!OSTREE_OBJECT_TYPE_IS_META(objtype))
+  if (objtype == OSTREE_OBJECT_TYPE_RAW_FILE)
     {
       xattrs = ostree_get_xattrs_for_file (f, error);
       if (!xattrs)
@@ -454,7 +457,7 @@ ostree_parse_metadata_file (GFile                       *file,
   GVariant *container = NULL;
   guint32 actual_type;
 
-  if (!ot_util_variant_map (file, G_VARIANT_TYPE (OSTREE_SERIALIZED_VARIANT_FORMAT),
+  if (!ot_util_variant_map (file, OSTREE_SERIALIZED_VARIANT_FORMAT,
                             &container, error))
     goto out;
 
@@ -486,12 +489,53 @@ ostree_parse_metadata_file (GFile                       *file,
   return ret;
 }
 
+const char *
+ostree_object_type_to_string (OstreeObjectType objtype)
+{
+  switch (objtype)
+    {
+    case OSTREE_OBJECT_TYPE_RAW_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:
+      return "dirmeta";
+    case OSTREE_OBJECT_TYPE_COMMIT:
+      return "commit";
+    default:
+      g_assert_not_reached ();
+      return NULL;
+    }
+}
+
+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;
+  else if (!strcmp (str, "dirtree"))
+    return OSTREE_OBJECT_TYPE_DIR_TREE;
+  else if (!strcmp (str, "dirmeta"))
+    return OSTREE_OBJECT_TYPE_DIR_META;
+  else if (!strcmp (str, "commit"))
+    return OSTREE_OBJECT_TYPE_COMMIT;
+  g_assert_not_reached ();
+  return 0;
+}
+
 char *
 ostree_get_relative_object_path (const char *checksum,
                                  OstreeObjectType type)
 {
   GString *path;
-  const char *type_string;
 
   g_assert (strlen (checksum) == 64);
 
@@ -500,37 +544,15 @@ ostree_get_relative_object_path (const char *checksum,
   g_string_append_len (path, checksum, 2);
   g_string_append_c (path, '/');
   g_string_append (path, checksum + 2);
-  switch (type)
-    {
-    case OSTREE_OBJECT_TYPE_RAW_FILE:
-      type_string = ".file";
-      break;
-    case OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT:
-      type_string = ".archive-content";
-      break;
-    case OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META:
-      type_string = ".archive-meta";
-      break;
-    case OSTREE_OBJECT_TYPE_DIR_TREE:
-      type_string = ".dirtree";
-      break;
-    case OSTREE_OBJECT_TYPE_DIR_META:
-      type_string = ".dirmeta";
-      break;
-    case OSTREE_OBJECT_TYPE_COMMIT:
-      type_string = ".commit";
-      break;
-    default:
-      g_assert_not_reached ();
-    }
-  g_string_append (path, type_string);
+  g_string_append_c (path, '.');
+  g_string_append (path, ostree_object_type_to_string (type));
+
   return g_string_free (path, FALSE);
 }
 
 GVariant *
 ostree_create_archive_file_metadata (GFileInfo         *finfo,
-                                     GVariant          *xattrs,
-                                     const char        *content_checksum)
+                                     GVariant          *xattrs)
 {
   guint32 uid, gid, mode, rdev;
   GVariantBuilder pack_builder;
@@ -543,8 +565,6 @@ ostree_create_archive_file_metadata (GFileInfo         *finfo,
 
   g_variant_builder_init (&pack_builder, OSTREE_ARCHIVED_FILE_VARIANT_FORMAT);
   g_variant_builder_add (&pack_builder, "u", GUINT32_TO_BE (0));   /* Version */ 
-  /* If you later add actual metadata here, don't forget to byteswap it to Big Endian if necessary */
-  g_variant_builder_add (&pack_builder, "@a{sv}", g_variant_new_array (G_VARIANT_TYPE ("{sv}"), NULL, 0));
   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));
@@ -556,8 +576,6 @@ ostree_create_archive_file_metadata (GFileInfo         *finfo,
 
   g_variant_builder_add (&pack_builder, "@a(ayay)", xattrs ? xattrs : g_variant_new_array (G_VARIANT_TYPE ("(ayay)"), NULL, 0));
 
-  g_variant_builder_add (&pack_builder, "s", content_checksum);
-
   ret = g_variant_builder_end (&pack_builder);
   g_variant_ref_sink (ret);
   
@@ -568,20 +586,17 @@ gboolean
 ostree_parse_archived_file_meta (GVariant         *metadata,
                                  GFileInfo       **out_file_info,
                                  GVariant        **out_xattrs,
-                                 char            **out_content_checksum,
                                  GError          **error)
 {
   gboolean ret = FALSE;
   GFileInfo *ret_file_info = NULL;
-  GVariant *metametadata = NULL;
   GVariant *ret_xattrs = NULL;
   guint32 version, uid, gid, mode, rdev;
   const char *symlink_target;
-  char *ret_content_checksum;
 
-  g_variant_get (metadata, "(u a{sv}uuuu&s a(ayay)s)",
-                 &version, &metametadata, &uid, &gid, &mode, &rdev,
-                 &symlink_target, &ret_xattrs, &ret_content_checksum);
+  g_variant_get (metadata, "(uuuuu&s a(ayay))",
+                 &version, &uid, &gid, &mode, &rdev,
+                 &symlink_target, &ret_xattrs);
   version = GUINT32_FROM_BE (version);
 
   if (version != 0)
@@ -596,12 +611,6 @@ ostree_parse_archived_file_meta (GVariant         *metadata,
   mode = GUINT32_FROM_BE (mode);
   rdev = GUINT32_FROM_BE (rdev);
 
-  if (!ostree_validate_checksum_string (ret_content_checksum, error))
-    {
-      g_prefix_error (error, "While parsing archived file metadata: ");
-      goto out;
-    }
-
   ret_file_info = g_file_info_new ();
   g_file_info_set_attribute_uint32 (ret_file_info, "standard::type", ot_gfile_type_for_mode (mode));
   g_file_info_set_attribute_boolean (ret_file_info, "standard::is-symlink", S_ISLNK (mode));
@@ -635,12 +644,9 @@ ostree_parse_archived_file_meta (GVariant         *metadata,
   ret = TRUE;
   ot_transfer_out_value(out_file_info, &ret_file_info);
   ot_transfer_out_value(out_xattrs, &ret_xattrs);
-  ot_transfer_out_value(out_content_checksum, &ret_content_checksum);
  out:
   g_clear_object (&ret_file_info);
   ot_clear_gvariant (&ret_xattrs);
-  ot_clear_gvariant (&metametadata);
-  g_free (ret_content_checksum);
   return ret;
 }
 
@@ -659,7 +665,11 @@ ostree_create_file_from_input (GFile            *dest_file,
   GFileOutputStream *out = NULL;
   guint32 uid, gid, mode;
   GChecksum *ret_checksum = NULL;
-  gboolean is_meta = OSTREE_OBJECT_TYPE_IS_META (objtype);
+  gboolean is_meta;
+  gboolean is_archived_content;
+
+  is_meta = OSTREE_OBJECT_TYPE_IS_META (objtype);
+  is_archived_content = objtype == OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT;
 
   if (g_cancellable_set_error_if_cancelled (cancellable, error))
     return FALSE;
@@ -670,14 +680,13 @@ ostree_create_file_from_input (GFile            *dest_file,
     }
   else
     {
-      mode = S_IFREG | 0666;
+      mode = S_IFREG | 0664;
     }
   dest_path = ot_gfile_get_path_cached (dest_file);
 
   if (S_ISDIR (mode))
     {
-      if (mkdir (ot_gfile_get_path_cached (dest_file),
-                 g_file_info_get_attribute_uint32 (finfo, "unix::mode")) < 0)
+      if (mkdir (ot_gfile_get_path_cached (dest_file), mode) < 0)
         {
           ot_util_set_error_from_errno (error, errno);
           goto out;
@@ -748,7 +757,7 @@ ostree_create_file_from_input (GFile            *dest_file,
       goto out;
     }
 
-  if (finfo != NULL)
+  if (finfo != NULL && !is_meta && !is_archived_content)
     {
       uid = g_file_info_get_attribute_uint32 (finfo, "unix::uid");
       gid = g_file_info_get_attribute_uint32 (finfo, "unix::gid");
@@ -759,11 +768,6 @@ ostree_create_file_from_input (GFile            *dest_file,
           goto out;
         }
     }
-  else
-    {
-      uid = geteuid ();
-      gid = getegid ();
-    }
 
   if (!S_ISLNK (mode))
     {
@@ -781,9 +785,14 @@ ostree_create_file_from_input (GFile            *dest_file,
         goto out;
     }
 
-  if (ret_checksum && !is_meta)
+  if (ret_checksum && !is_meta && !is_archived_content)
     {
-      ostree_checksum_update_stat (ret_checksum, uid, gid, mode);
+      g_assert (finfo != NULL);
+
+      ostree_checksum_update_stat (ret_checksum,
+                                   g_file_info_get_attribute_uint32 (finfo, "unix::uid"),
+                                   g_file_info_get_attribute_uint32 (finfo, "unix::gid"),
+                                   mode);
       if (xattrs)
         g_checksum_update (ret_checksum, (guint8*)g_variant_get_data (xattrs), g_variant_get_size (xattrs));
     }
diff --git a/src/libostree/ostree-core.h b/src/libostree/ostree-core.h
index 08100e0..e18ba91 100644
--- a/src/libostree/ostree-core.h
+++ b/src/libostree/ostree-core.h
@@ -43,7 +43,7 @@ typedef enum {
 #define OSTREE_OBJECT_TYPE_IS_META(t) (t >= 3 && t <= 6)
 #define OSTREE_OBJECT_TYPE_LAST OSTREE_OBJECT_TYPE_COMMIT
 
-#define OSTREE_SERIALIZED_VARIANT_FORMAT "(uv)"
+#define OSTREE_SERIALIZED_VARIANT_FORMAT G_VARIANT_TYPE("(uv)")
 
 /*
  * xattr objects:
@@ -87,25 +87,25 @@ typedef enum {
 #define OSTREE_COMMIT_GVARIANT_FORMAT "(ua{sv}ssstss)"
 
 /* Archive file objects:
- *
- * metadata variant:
  * u - Version
- * a(sv) - metadata (yes I put metadata in your metadata)
  * u - uid
  * u - gid
  * u - mode
  * u - rdev
  * s - symlink target
  * a(ayay) - xattrs
- * s - content checksum
  */
-#define OSTREE_ARCHIVED_FILE_VARIANT_FORMAT G_VARIANT_TYPE ("(ua{sv}uuuusa(ayay)s)")
+#define OSTREE_ARCHIVED_FILE_VARIANT_FORMAT G_VARIANT_TYPE ("(uuuuusa(ayay))")
 
 gboolean ostree_validate_checksum_string (const char *sha256,
                                           GError    **error);
 
 void ostree_checksum_update_stat (GChecksum *checksum, guint32 uid, guint32 gid, guint32 mode);
 
+const char * ostree_object_type_to_string (OstreeObjectType objtype);
+
+OstreeObjectType ostree_object_type_from_string (const char *str);
+
 char *ostree_get_relative_object_path (const char        *checksum,
                                        OstreeObjectType   type);
 
@@ -181,13 +181,11 @@ gboolean ostree_create_temp_regular_file (GFile            *dir,
                                           GError          **error);
 
 GVariant *ostree_create_archive_file_metadata (GFileInfo   *file_info,
-                                               GVariant    *xattrs,
-                                               const char  *content_checksum);
+                                               GVariant    *xattrs);
 
 gboolean ostree_parse_archived_file_meta (GVariant         *data,
                                           GFileInfo       **out_file_info,
                                           GVariant        **out_xattrs,
-                                          char            **out_content_checksum,
                                           GError          **error);
 
 
diff --git a/src/libostree/ostree-repo-file.c b/src/libostree/ostree-repo-file.c
index d8e3b8f..81222d8 100644
--- a/src/libostree/ostree-repo-file.c
+++ b/src/libostree/ostree-repo-file.c
@@ -323,7 +323,7 @@ _ostree_repo_file_get_xattrs (OstreeRepoFile  *self,
                                        &metadata, error))
         goto out;
 
-      if (!ostree_parse_archived_file_meta (metadata, NULL, &ret_xattrs, NULL, error))
+      if (!ostree_parse_archived_file_meta (metadata, NULL, &ret_xattrs, error))
         goto out;
     }
   else
@@ -1041,7 +1041,7 @@ _ostree_repo_file_tree_query_child (OstreeRepoFile  *self,
           if (!ostree_parse_metadata_file (local_child, OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META,
                                            &archive_metadata, error))
             goto out;
-          if (!ostree_parse_archived_file_meta (archive_metadata, &ret_info, NULL, NULL, error))
+          if (!ostree_parse_archived_file_meta (archive_metadata, &ret_info, NULL, error))
             goto out;
 	}
       else
diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c
index 4be3a35..0722b11 100644
--- a/src/libostree/ostree-repo.c
+++ b/src/libostree/ostree-repo.c
@@ -37,8 +37,6 @@
 #include "ostree-libarchive-input-stream.h"
 #endif
 
-#define PENDING_TRANSACTION_OBJECT_GVARIANT_FORMAT (G_VARIANT_TYPE("(us)"))
-
 enum {
   PROP_0,
 
@@ -185,7 +183,7 @@ ostree_repo_init (OstreeRepo *self)
   
   priv->pending_transaction_tmpfiles = g_hash_table_new_full (g_str_hash, g_str_equal,
                                                               g_free,
-                                                              (GDestroyNotify)g_variant_unref);
+                                                              g_free);
 }
 
 OstreeRepo*
@@ -670,6 +668,13 @@ ostree_repo_get_file_object_path (OstreeRepo   *self,
   return ostree_repo_get_object_path (self, checksum, get_objtype_for_repo_file (self));
 }
 
+static char *
+create_checksum_and_objtype (const char *checksum,
+                             OstreeObjectType objtype)
+{
+  return g_strconcat (checksum, ".", ostree_object_type_to_string (objtype), NULL);
+}
+
 gboolean      
 ostree_repo_has_object (OstreeRepo           *self,
                         OstreeObjectType      objtype,
@@ -680,9 +685,12 @@ ostree_repo_has_object (OstreeRepo           *self,
 {
   gboolean ret = FALSE;
   OstreeRepoPrivate *priv = GET_PRIVATE (self);
+  char *tmp_key = NULL;
   GFile *object_path = NULL;
 
-  if (g_hash_table_lookup (priv->pending_transaction_tmpfiles, checksum))
+  tmp_key = create_checksum_and_objtype (checksum, objtype);
+
+  if (g_hash_table_lookup (priv->pending_transaction_tmpfiles, tmp_key))
     {
       *out_have_object = TRUE;
     }
@@ -695,6 +703,7 @@ ostree_repo_has_object (OstreeRepo           *self,
   
   ret = TRUE;
   /* out: */
+  g_free (tmp_key);
   g_clear_object (&object_path);
   return ret;
 }
@@ -745,30 +754,44 @@ impl_stage_archive_file_object_from_raw (OstreeRepo         *self,
   if (!ostree_create_temp_file_from_input (priv->tmp_dir,
                                            "archive-tmp-", NULL,
                                            temp_info, NULL, input,
-                                           OSTREE_OBJECT_TYPE_RAW_FILE,
+                                           OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT,
                                            &temp_file,
-                                           &content_checksum,
+                                           &ret_checksum,
                                            cancellable, error))
     goto out;
-  
-  archive_metadata = ostree_create_archive_file_metadata (file_info, xattrs, 
-                                                          g_checksum_get_string (content_checksum));
-  
+
+  ostree_checksum_update_stat (ret_checksum,
+                               g_file_info_get_attribute_uint32 (file_info, "unix::uid"),
+                               g_file_info_get_attribute_uint32 (file_info, "unix::gid"),
+                               g_file_info_get_attribute_uint32 (file_info, "unix::mode"));
+  /* FIXME - ensure empty xattrs are the same as NULL xattrs */
+  if (xattrs)
+    g_checksum_update (ret_checksum, (guint8*)g_variant_get_data (xattrs), g_variant_get_size (xattrs));
+
+  if (expected_checksum && strcmp (g_checksum_get_string (ret_checksum), expected_checksum) != 0)
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                   "Corrupted object %s (actual checksum is %s)",
+                   expected_checksum, g_checksum_get_string (ret_checksum));
+      goto out;
+    }
+
   g_hash_table_insert (priv->pending_transaction_tmpfiles,
-                       g_strdup (g_checksum_get_string (content_checksum)),
-                       g_variant_new ("(us)", OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT,
-                                      ot_gfile_get_basename_cached (temp_file)));
+                       create_checksum_and_objtype (g_checksum_get_string (ret_checksum), OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT),
+                       g_strdup (ot_gfile_get_basename_cached (temp_file)));
+  
+  archive_metadata = ostree_create_archive_file_metadata (file_info, xattrs);
   
   serialized = ostree_wrap_metadata_variant (OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META, archive_metadata);
   mem = g_memory_input_stream_new_from_data (g_variant_get_data (serialized),
                                              g_variant_get_size (serialized),
                                              NULL);
-  
+
   if (!stage_object (self, OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META,
                      NULL, NULL, mem,
-                     expected_checksum, out_checksum ? &ret_checksum : NULL, cancellable, error))
+                     g_checksum_get_string (ret_checksum), NULL, cancellable, error))
     goto out;
-  
+
   ret = TRUE;
   ot_transfer_out_value (out_checksum, &ret_checksum);
  out:
@@ -795,73 +818,95 @@ impl_stage_raw_file_object_from_archive (OstreeRepo         *self,
   gboolean ret = FALSE;
   OstreeRepoPrivate *priv = GET_PRIVATE (self);
   GFile *temp_file = NULL;
-  GChecksum *ret_checksum = NULL;
   GVariant *archive_metadata = NULL;
   GMemoryOutputStream *tmp_archive_meta = NULL;
   GFileInfo *archived_info = NULL;
   GVariant *archived_xattrs = NULL;
-  char *archived_content_checksum = NULL;
-  GVariant *archived_content = NULL; /* const */
-  guint32 pending_objtype;
+  char *archived_content_key = NULL;
   const char *archived_content_path;
   GFile *archived_content_file = NULL;
   GInputStream *archived_content_input = NULL;
+  GVariant *variant = NULL;
+  guint32 archive_meta_objtype;
+
+  if (!expected_checksum)
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+                   "Can't stage untrusted archive in bare repository");
+      goto out;
+    }
+  g_assert (out_checksum == NULL);
 
   tmp_archive_meta = (GMemoryOutputStream*)g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
 
-  if (!g_output_stream_splice ((GOutputStream*)tmp_archive_meta, input, 0, cancellable, error))
+  if (!g_output_stream_splice ((GOutputStream*)tmp_archive_meta, input, G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET, cancellable, error))
     goto out;
 
-  archive_metadata = g_variant_new_from_data (OSTREE_ARCHIVED_FILE_VARIANT_FORMAT,
-                                              g_memory_output_stream_get_data (tmp_archive_meta),
-                                              g_memory_output_stream_get_size (tmp_archive_meta),
-                                              FALSE, NULL, NULL);
+  variant = g_variant_new_from_data (OSTREE_SERIALIZED_VARIANT_FORMAT,
+                                     g_memory_output_stream_get_data (tmp_archive_meta),
+                                     g_memory_output_stream_get_data_size (tmp_archive_meta),
+                                     FALSE, (GDestroyNotify)g_object_unref, g_object_ref (tmp_archive_meta));
+  g_clear_object (&tmp_archive_meta);
+
+  g_variant_get (variant, "(uv)", &archive_meta_objtype, &archive_metadata);
+  ot_util_variant_take_ref (archive_metadata);
+  archive_meta_objtype = GUINT32_FROM_BE (archive_meta_objtype);
+  if (archive_meta_objtype != OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META)
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                   "Archived file has invalid object type '%d'",
+                   archive_meta_objtype);
+      goto out;
+    }
 
   if (!ostree_parse_archived_file_meta (archive_metadata, &archived_info,
-                                        &archived_xattrs, &archived_content_checksum, error))
+                                        &archived_xattrs, error))
     goto out;
+
+  archived_content_key = create_checksum_and_objtype (expected_checksum, OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT);
           
-  archived_content = g_hash_table_lookup (priv->pending_transaction_tmpfiles, archived_content_checksum);
-  if (archived_content == NULL)
+  archived_content_path = g_hash_table_lookup (priv->pending_transaction_tmpfiles, archived_content_key);
+  if (archived_content_path == NULL)
     {
       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                   "Archived file references uncommitted content '%s'",
-                   archived_content_checksum);
+                   "Archived file references unstaged content '%s'",
+                   expected_checksum);
       goto out;
     }
 
-  g_variant_get (archived_content, "(u&s)", &pending_objtype, &archived_content_path);
-  g_assert (pending_objtype == OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT);
-
   archived_content_file = g_file_get_child (priv->tmp_dir, archived_content_path);
-  archived_content_input = (GInputStream*)g_file_read (archived_content_file, cancellable, error);
-  if (!archived_content_input)
-    goto out;
+  if (g_file_info_get_file_type (archived_info) == G_FILE_TYPE_REGULAR)
+    {
+      archived_content_input = (GInputStream*)g_file_read (archived_content_file, cancellable, error);
+      if (!archived_content_input)
+        goto out;
+    }
 
   if (!ostree_create_temp_file_from_input (priv->tmp_dir,
                                            "store-tmp-", NULL,
                                            archived_info, archived_xattrs,
                                            archived_content_input,
                                            OSTREE_OBJECT_TYPE_RAW_FILE,
-                                           &temp_file, &ret_checksum,
+                                           &temp_file, NULL,
                                            cancellable, error))
     goto out;
 
   g_hash_table_insert (priv->pending_transaction_tmpfiles,
-                       g_strdup (g_checksum_get_string (ret_checksum)),
-                       g_variant_new ("(us)", OSTREE_OBJECT_TYPE_RAW_FILE,
-                                      ot_gfile_get_basename_cached (temp_file)));
+                       create_checksum_and_objtype (expected_checksum, OSTREE_OBJECT_TYPE_RAW_FILE),
+                       g_strdup (ot_gfile_get_basename_cached (temp_file)));
+  g_hash_table_remove (priv->pending_transaction_tmpfiles, archived_content_key);
 
   ret = TRUE;
  out:
   g_clear_object (&temp_file);
   g_clear_object (&tmp_archive_meta);
+  ot_clear_gvariant (&variant);
   ot_clear_gvariant (&archive_metadata);
   g_clear_object (&archived_info);
   ot_clear_gvariant (&archived_xattrs);
   g_clear_object (&archived_content_input);
   g_clear_object (&archived_content_file);
-  g_free (archived_content_checksum);
+  g_free (archived_content_key);
   return ret;
 }
 
@@ -883,6 +928,8 @@ stage_object (OstreeRepo         *self,
   GFile *temp_file = NULL;
   gboolean already_exists;
   const char *actual_checksum;
+
+  g_return_val_if_fail (priv->in_transaction, FALSE);
   
   if (g_cancellable_set_error_if_cancelled (cancellable, error))
     return FALSE;
@@ -897,6 +944,18 @@ stage_object (OstreeRepo         *self,
   else
     already_exists = FALSE;
 
+  if (objtype == OSTREE_OBJECT_TYPE_RAW_FILE || objtype == OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT)
+    {
+      g_assert (file_info != NULL);
+      if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR)
+        g_assert (input != NULL);
+    }
+  else if (OSTREE_OBJECT_TYPE_IS_META (objtype))
+    {
+      g_assert (xattrs == NULL);
+      g_assert (input != NULL);
+    }
+
   if (!already_exists)
     {
       if (objtype == OSTREE_OBJECT_TYPE_RAW_FILE && priv->mode == OSTREE_REPO_MODE_ARCHIVE)
@@ -917,17 +976,14 @@ stage_object (OstreeRepo         *self,
         }
       else 
         {
-          if (objtype == OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT && priv->mode == OSTREE_REPO_MODE_ARCHIVE)
+          if (priv->mode == OSTREE_REPO_MODE_ARCHIVE
+              && expected_checksum == NULL
+              && (objtype == OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META
+                  || objtype == OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT))
             {
-              temp_info = dup_file_info_owned_by_me (file_info);
-              if (!ostree_create_temp_file_from_input (priv->tmp_dir,
-                                                       "store-tmp-", NULL,
-                                                       temp_info, NULL, input,
-                                                       objtype,
-                                                       &temp_file,
-                                                       out_checksum ? &ret_checksum : NULL,
-                                                       cancellable, error))
-            goto out;
+              g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+                           "Importing untrusted archive files into an archive repo is not supported");
+              goto out;
             }
           else
             {
@@ -956,8 +1012,8 @@ stage_object (OstreeRepo         *self,
             }
           
           g_hash_table_insert (priv->pending_transaction_tmpfiles,
-                               g_strdup (actual_checksum),
-                               g_variant_new ("(us)", objtype, ot_gfile_get_basename_cached (temp_file)));
+                               create_checksum_and_objtype (actual_checksum, objtype),
+                               g_strdup (ot_gfile_get_basename_cached (temp_file)));
           g_clear_object (&temp_file);
         }
     }
@@ -1034,6 +1090,7 @@ ostree_repo_commit_transaction (OstreeRepo     *self,
   GFile *f = NULL;
   GHashTableIter iter;
   gpointer key, value;
+  char *checksum = NULL;
 
   g_return_val_if_fail (priv->in_transaction == TRUE, FALSE);
 
@@ -1042,12 +1099,17 @@ ostree_repo_commit_transaction (OstreeRepo     *self,
   g_hash_table_iter_init (&iter, priv->pending_transaction_tmpfiles);
   while (g_hash_table_iter_next (&iter, &key, &value))
     {
-      const char *checksum = key;
-      GVariant *data = value;
-      guint32 objtype;
-      const char *filename;
+      const char *checksum_and_type = key;
+      const char *filename = value;
+      const char *type_str;
+      OstreeObjectType objtype;
 
-      g_variant_get (data, "(u&s)", &objtype, &filename);
+      type_str = strrchr (checksum_and_type, '.');
+      g_assert (type_str);
+      g_free (checksum);
+      checksum = g_strndup (checksum_and_type, type_str - checksum_and_type);
+
+      objtype = ostree_object_type_from_string (type_str + 1);
 
       g_clear_object (&f);
       f = g_file_get_child (priv->tmp_dir, filename);
@@ -1058,6 +1120,7 @@ ostree_repo_commit_transaction (OstreeRepo     *self,
 
   ret = TRUE;
  out:
+  g_free (checksum);
   g_hash_table_remove_all (priv->pending_transaction_tmpfiles);
   g_clear_object (&f);
   return ret;
@@ -2084,9 +2147,9 @@ iter_object_dir (OstreeRepo             *self,
       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_CONTENT;
-      else if (g_str_has_suffix (name, ".archive-content"))
         objtype = OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META;
+      else if (g_str_has_suffix (name, ".archive-content"))
+        objtype = OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT;
       else if (g_str_has_suffix (name, ".dirtree"))
         objtype = OSTREE_OBJECT_TYPE_DIR_TREE;
       else if (g_str_has_suffix (name, ".dirmeta"))
@@ -2238,7 +2301,6 @@ checkout_tree (OstreeRepo               *self,
   GError *temp_error = NULL;
   GVariant *archive_metadata = NULL;
   GFileInfo *file_info = NULL;
-  char *archive_content_checksum = NULL;
   GVariant *xattrs = NULL;
   GFileEnumerator *dir_enum = NULL;
   GFile *src_child = NULL;
@@ -2295,19 +2357,20 @@ checkout_tree (OstreeRepo               *self,
               if (!ostree_parse_metadata_file (object_path, OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META, &archive_metadata, error))
                 goto out;
               
-              g_free (archive_content_checksum);
-              archive_content_checksum = NULL;
               ot_clear_gvariant (&xattrs);
-              if (!ostree_parse_archived_file_meta (archive_metadata, NULL, &xattrs, &archive_content_checksum, error))
+              if (!ostree_parse_archived_file_meta (archive_metadata, NULL, &xattrs, error))
                 goto out;
               
               g_clear_object (&content_object_path);
-              content_object_path = ostree_repo_get_object_path (self, archive_content_checksum, OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT);
+              content_object_path = ostree_repo_get_object_path (self, checksum, OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT);
 
               g_clear_object (&content_input);
-              content_input = (GInputStream*)g_file_read (content_object_path, cancellable, error);
-              if (!content_input)
-                goto out;
+              if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR)
+                {
+                  content_input = (GInputStream*)g_file_read (content_object_path, cancellable, error);
+                  if (!content_input)
+                    goto out;
+                }
 
               if (!checkout_file_from_input (dest_path, mode, file_info, xattrs, 
                                              content_input, cancellable, error))
@@ -2342,7 +2405,6 @@ checkout_tree (OstreeRepo               *self,
   g_clear_object (&content_object_path);
   g_clear_object (&content_input);
   g_clear_object (&dest_path);
-  g_free (archive_content_checksum);
   g_free (dest_path);
   return ret;
 }
diff --git a/src/ostree/ostree-pull.c b/src/ostree/ostree-pull.c
index 38f76d8..0f377e0 100644
--- a/src/ostree/ostree-pull.c
+++ b/src/ostree/ostree-pull.c
@@ -373,9 +373,15 @@ ostree_builtin_pull (int argc, char **argv, const char *repo_path, GError **erro
     {
       if (!ostree_validate_checksum_string (rev, error))
         goto out;
+
+      if (!ostree_repo_prepare_transaction (repo, NULL, error))
+        goto out;
       
       if (!store_commit_recurse (repo, soup, base_uri, rev, error))
         goto out;
+
+      if (!ostree_repo_commit_transaction (repo, NULL, error))
+        goto out;
       
       if (!ostree_repo_write_ref (repo, remote, branch, rev, error))
         goto out;
diff --git a/src/ostree/ot-builtin-fsck.c b/src/ostree/ot-builtin-fsck.c
index 0043ff5..1fec01d 100644
--- a/src/ostree/ot-builtin-fsck.c
+++ b/src/ostree/ot-builtin-fsck.c
@@ -42,16 +42,15 @@ typedef struct {
 
 static gboolean
 checksum_archived_file (OtFsckData   *data,
+                        const char   *exp_checksum,
                         GFile        *file,
                         GChecksum   **out_checksum,
                         GError      **error)
 {
   gboolean ret = FALSE;
   GChecksum *ret_checksum = NULL;
-  GInputStream *in = NULL;
   GVariant *archive_metadata = NULL;
   GVariant *xattrs = NULL;
-  char *content_checksum = NULL;
   GFile *content_path = NULL;
   GInputStream *content_input = NULL;
   GFileInfo *file_info = NULL;
@@ -62,23 +61,27 @@ checksum_archived_file (OtFsckData   *data,
   if (!ostree_parse_metadata_file (file, OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META, &archive_metadata, error))
     goto out;
 
-  if (!ostree_parse_archived_file_meta (archive_metadata, &file_info, &xattrs, &content_checksum, error))
+  if (!ostree_parse_archived_file_meta (archive_metadata, &file_info, &xattrs, error))
     goto out;
 
-  content_path = ostree_repo_get_object_path (data->repo, content_checksum, OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT);
-  content_input = (GInputStream*)g_file_read (content_path, NULL, error);
-  if (!content_input)
-    goto out;
+  content_path = ostree_repo_get_object_path (data->repo, exp_checksum, OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT);
+
+  if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR)
+    {
+      content_input = (GInputStream*)g_file_read (content_path, NULL, error);
+      if (!content_input)
+        goto out;
+    }
 
   ret_checksum = g_checksum_new (G_CHECKSUM_SHA256);
 
   mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode");
   if (S_ISREG (mode))
     {
-      g_assert (in != NULL);
+      g_assert (content_input != NULL);
       do
         {
-          if (!g_input_stream_read_all (in, buf, sizeof(buf), &bytes_read, NULL, error))
+          if (!g_input_stream_read_all (content_input, buf, sizeof(buf), &bytes_read, NULL, error))
             goto out;
           g_checksum_update (ret_checksum, (guint8*)buf, bytes_read);
         }
@@ -110,11 +113,9 @@ checksum_archived_file (OtFsckData   *data,
   ot_transfer_out_value (out_checksum, &ret_checksum);
  out:
   ot_clear_checksum (&ret_checksum);
-  g_clear_object (&in);
   g_clear_object (&file_info);
   ot_clear_gvariant (&xattrs);
   ot_clear_gvariant (&archive_metadata);
-  g_free (content_checksum);
   g_clear_object (&content_path);
   g_clear_object (&content_input);
   return ret;
@@ -129,40 +130,38 @@ object_iter_callback (OstreeRepo    *repo,
                       gpointer       user_data)
 {
   OtFsckData *data = user_data;
-  const char *path = NULL;
   GChecksum *real_checksum = NULL;
   GError *error = NULL;
 
-  path = ot_gfile_get_path_cached (objf);
-
   /* nlinks = g_file_info_get_attribute_uint32 (file_info, "unix::nlink");
      if (nlinks < 2 && !quiet)
      g_printerr ("note: floating object: %s\n", path); */
 
-  if (ostree_repo_get_mode (repo) == OSTREE_REPO_MODE_ARCHIVE
-      && !OSTREE_OBJECT_TYPE_IS_META (objtype))
+  if (objtype == OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META)
     {
-      if (!g_str_has_suffix (path, ".archive"))
+      if (!g_str_has_suffix (ot_gfile_get_path_cached (objf), ".archive-meta"))
         {
           g_set_error (&error, G_IO_ERROR, G_IO_ERROR_FAILED,
                        "Invalid archive filename '%s'",
-                       path);
+                       ot_gfile_get_path_cached (objf));
           goto out;
         }
-      if (!checksum_archived_file (data, objf, &real_checksum, &error))
+      if (!checksum_archived_file (data, exp_checksum, objf, &real_checksum, &error))
         goto out;
     }
+  else if (objtype == OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT)
+    ; /* Handled above */
   else
     {
       if (!ostree_checksum_file (objf, objtype, &real_checksum, NULL, &error))
         goto out;
     }
 
-  if (strcmp (exp_checksum, g_checksum_get_string (real_checksum)) != 0)
+  if (real_checksum && strcmp (exp_checksum, g_checksum_get_string (real_checksum)) != 0)
     {
       data->had_error = TRUE;
-      g_printerr ("ERROR: corrupted object '%s' expected checksum: %s\n",
-                  exp_checksum, g_checksum_get_string (real_checksum));
+      g_printerr ("ERROR: corrupted object '%s'; actual checksum: %s\n",
+                  ot_gfile_get_path_cached (objf), g_checksum_get_string (real_checksum));
     }
 
   data->n_objects++;
diff --git a/src/ostree/ot-builtin-local-clone.c b/src/ostree/ot-builtin-local-clone.c
index b730acf..c50f764 100644
--- a/src/ostree/ot-builtin-local-clone.c
+++ b/src/ostree/ot-builtin-local-clone.c
@@ -25,7 +25,8 @@
 #include "ot-builtins.h"
 #include "ostree.h"
 
-#include <glib/gi18n.h>
+#include <unistd.h>
+#include <stdlib.h>
 
 static GOptionEntry options[] = {
   { NULL }
@@ -101,8 +102,10 @@ object_iter_callback (OstreeRepo   *repo,
   if (objtype == OSTREE_OBJECT_TYPE_RAW_FILE)
     xattrs = ostree_get_xattrs_for_file (objfile, &error);
   
-  if (objtype == OSTREE_OBJECT_TYPE_RAW_FILE
-      || objtype == OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT)
+  if (((objtype == OSTREE_OBJECT_TYPE_RAW_FILE
+        || objtype == OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT)
+       && g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR)
+      || OSTREE_OBJECT_TYPE_IS_META (objtype))
     {
       input = (GInputStream*)g_file_read (objfile, NULL, &error);
       if (!input)
@@ -121,6 +124,7 @@ object_iter_callback (OstreeRepo   *repo,
     {
       g_printerr ("%s\n", error->message);
       g_clear_error (&error);
+      exit (1);
     }
 }
 
@@ -182,8 +186,14 @@ ostree_builtin_local_clone (int argc, char **argv, const char *repo_path, GError
 
   data.uids_differ = g_file_info_get_attribute_uint32 (src_info, "unix::uid") != g_file_info_get_attribute_uint32 (dest_info, "unix::uid");
 
+  if (!ostree_repo_prepare_transaction (data.dest_repo, NULL, error))
+    goto out;
+
   if (!ostree_repo_iter_objects (data.src_repo, object_iter_callback, &data, error))
     goto out;
+
+  if (!ostree_repo_commit_transaction (data.dest_repo, NULL, error))
+    goto out;
   
   src_dir = g_file_resolve_relative_path (src_repo_dir, "refs/heads");
   dest_dir = g_file_resolve_relative_path (dest_repo_dir, "refs/heads");



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]