[ostree] core: Add new "mutable tree" class, use it for tar file import



commit 2b7a83d1cc4dc44c145fbb4dccd9b994f21256da
Author: Colin Walters <walters verbum org>
Date:   Wed Dec 21 13:34:10 2011 -0500

    core: Add new "mutable tree" class, use it for tar file import
    
    The tar import code forced the resuscitation of a hackish "FileTree"
    data type for representing an in-memory tree.  Split this out
    into an OstreeMutableTree class for future use by any other in-memory
    tree construction.

 Makefile-libostree.am       |    2 +
 src/libostree/ostree-repo.c |  358 +++++++++++++++++--------------------------
 src/libostree/ostree.h      |    1 +
 3 files changed, 147 insertions(+), 214 deletions(-)
---
diff --git a/Makefile-libostree.am b/Makefile-libostree.am
index 2fc7d93..adcddf7 100644
--- a/Makefile-libostree.am
+++ b/Makefile-libostree.am
@@ -22,6 +22,8 @@ privlib_LTLIBRARIES += libostree.la
 libostree_la_SOURCES = src/libostree/ostree.h \
 	src/libostree/ostree-core.c \
 	src/libostree/ostree-core.h \
+	src/libostree/ostree-mutable-tree.c \
+	src/libostree/ostree-mutable-tree.h \
 	src/libostree/ostree-repo.c \
 	src/libostree/ostree-repo.h \
 	src/libostree/ostree-repo-file.c \
diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c
index dffc162..b23391f 100644
--- a/src/libostree/ostree-repo.c
+++ b/src/libostree/ostree-repo.c
@@ -1647,79 +1647,12 @@ import_libarchive_entry_file (OstreeRepo           *self,
   return ret;
 }
 
-typedef struct {
-  char *metadata_checksum;
-  char *contents_checksum;
-
-  GHashTable *file_checksums;
-  GHashTable *subdirs;
-} FileTree;
-
-static void
-file_tree_free (FileTree  *tree)
-{
-  g_free (tree->metadata_checksum);
-  g_free (tree->contents_checksum);
-
-  g_hash_table_destroy (tree->file_checksums);
-  g_hash_table_destroy (tree->subdirs);
-
-  g_free (tree);
-}
-
-static FileTree *
-file_tree_new (void)
-{
-  FileTree *ret = g_new0 (FileTree, 1);
-
-  ret->file_checksums = g_hash_table_new_full (g_str_hash, g_str_equal,
-                                               g_free, g_free);
-  ret->subdirs = g_hash_table_new_full (g_str_hash, g_str_equal,
-                                        g_free, (GDestroyNotify)file_tree_free);
-  return ret;
-}
-
 static gboolean
-file_tree_walk (FileTree     *dir,
-                GPtrArray    *split_path,
-                guint         start,
-                FileTree    **out_parent,
-                GError      **error)
-{
-  if (start >= split_path->len)
-    {
-      g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
-                   "No such file or directory: %s",
-                   (char*)split_path->pdata[start]);
-      return FALSE;
-    }
-  else if (start == split_path->len - 1)
-    {
-      *out_parent = dir;
-      return TRUE;
-    }
-  else
-    {
-      FileTree *subdir = g_hash_table_lookup (dir->subdirs, split_path->pdata[start]);
-
-      if (!subdir)
-        {
-          g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
-                       "No such file or directory: %s",
-                       (char*)split_path->pdata[start]);
-          return FALSE;
-        }
-
-      return file_tree_walk (subdir, split_path, start + 1, out_parent, error);
-    }
-}
-
-static gboolean
-file_tree_import_recurse (OstreeRepo           *self,
-                          FileTree             *tree,
-                          char                **out_contents_checksum,
-                          GCancellable         *cancellable,
-                          GError              **error)
+stage_mutable_tree_recurse (OstreeRepo           *self,
+                            OstreeMutableTree    *tree,
+                            char                **out_contents_checksum,
+                            GCancellable         *cancellable,
+                            GError              **error)
 {
   gboolean ret = FALSE;
   GChecksum *ret_contents_checksum_obj = NULL;
@@ -1735,22 +1668,22 @@ file_tree_import_recurse (OstreeRepo           *self,
   dir_metadata_checksums = g_hash_table_new_full (g_str_hash, g_str_equal,
                                                   (GDestroyNotify)g_free, (GDestroyNotify)g_free);
 
-  g_hash_table_iter_init (&hash_iter, tree->subdirs);
+  g_hash_table_iter_init (&hash_iter, ostree_mutable_tree_get_subdirs (tree));
   while (g_hash_table_iter_next (&hash_iter, &key, &value))
     {
       const char *name = key;
-      FileTree *child_dir = value;
+      OstreeMutableTree *child_dir = value;
       char *child_dir_contents_checksum;
 
-      if (!file_tree_import_recurse (self, child_dir, &child_dir_contents_checksum, cancellable, error))
+      if (!stage_mutable_tree_recurse (self, child_dir, &child_dir_contents_checksum, cancellable, error))
         goto out;
       
       g_hash_table_replace (dir_contents_checksums, g_strdup (name), child_dir_contents_checksum);
       g_hash_table_replace (dir_metadata_checksums, g_strdup (name),
-                            g_strdup (child_dir->metadata_checksum));
+                            g_strdup (ostree_mutable_tree_get_metadata_checksum (child_dir)));
     }
     
-  serialized_tree = create_tree_variant_from_hashes (tree->file_checksums,
+  serialized_tree = create_tree_variant_from_hashes (ostree_mutable_tree_get_files (tree),
                                                      dir_contents_checksums,
                                                      dir_metadata_checksums);
       
@@ -1772,124 +1705,94 @@ file_tree_import_recurse (OstreeRepo           *self,
   ot_clear_gvariant (&serialized_tree);
   return ret;
 }
-                          
+
 static gboolean
-stage_libarchive_into_root (OstreeRepo           *self,
-                            FileTree             *root,
-                            GFile                *archive_f,
-                            OstreeRepoCommitModifier *modifier,
-                            GCancellable         *cancellable,
-                            GError              **error)
+stage_libarchive_entry_into_root (OstreeRepo           *self,
+                                  OstreeMutableTree    *root,
+                                  struct archive       *a,
+                                  struct archive_entry *entry,
+                                  OstreeRepoCommitModifier *modifier,
+                                  GCancellable         *cancellable,
+                                  GError              **error)
 {
   gboolean ret = FALSE;
-  int r;
-  struct archive *a;
-  struct archive_entry *entry;
+  const char *pathname;
+  const char *hardlink;
+  const char *basename;
   GFileInfo *file_info = NULL;
   GChecksum *tmp_checksum = NULL;
   GPtrArray *split_path = NULL;
   GPtrArray *hardlink_split_path = NULL;
+  OstreeMutableTree *subdir = NULL;
+  OstreeMutableTree *parent = NULL;
+  OstreeMutableTree *hardlink_source_parent = NULL;
+  char *hardlink_source_checksum = NULL;
+  OstreeMutableTree *hardlink_source_subdir = NULL;
 
-  a = archive_read_new ();
-  archive_read_support_compression_all (a);
-  archive_read_support_format_all (a);
-  if (archive_read_open_filename (a, ot_gfile_get_path_cached (archive_f), 8192) != ARCHIVE_OK)
+  pathname = archive_entry_pathname (entry); 
+      
+  if (!ot_util_path_split_validate (pathname, &split_path, error))
+    goto out;
+
+  if (split_path->len == 0)
     {
-      propagate_libarchive_error (error, a);
-      goto out;
+      parent = NULL;
+      basename = NULL;
+    }
+  else
+    {
+      if (!ostree_mutable_tree_walk (root, split_path, 0, &parent, error))
+        goto out;
+      basename = (char*)split_path->pdata[split_path->len-1];
     }
 
-  while (TRUE)
+  hardlink = archive_entry_hardlink (entry);
+  if (hardlink)
     {
-      const char *pathname;
-      const char *hardlink;
-      const char *basename;
-      FileTree *parent;
+      const char *hardlink_basename;
+      
+      g_assert (parent != NULL);
 
-      r = archive_read_next_header (a, &entry);
-      if (r == ARCHIVE_EOF)
-        break;
-      else if (r != ARCHIVE_OK)
+      if (!ot_util_path_split_validate (hardlink, &hardlink_split_path, error))
+        goto out;
+      if (hardlink_split_path->len == 0)
         {
-          propagate_libarchive_error (error, a);
+          g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                       "Invalid hardlink path %s", hardlink);
           goto out;
         }
-
-      pathname = archive_entry_pathname (entry); 
       
-      if (split_path)
-        g_ptr_array_unref (split_path);
-      if (!ot_util_path_split_validate (pathname, &split_path, error))
+      hardlink_basename = hardlink_split_path->pdata[hardlink_split_path->len - 1];
+      
+      if (!ostree_mutable_tree_walk (root, hardlink_split_path, 0, &hardlink_source_parent, error))
         goto out;
-
-      if (split_path->len == 0)
-        {
-          parent = NULL;
-          basename = NULL;
-        }
-      else
-        {
-          if (!file_tree_walk (root, split_path, 0, &parent, error))
-            goto out;
-          basename = (char*)split_path->pdata[split_path->len-1];
-        }
-
-      if (parent)
+      
+      if (!ostree_mutable_tree_lookup (hardlink_source_parent, hardlink_basename,
+                                       &hardlink_source_checksum,
+                                       &hardlink_source_subdir,
+                                       error))
         {
-          if (!parent->metadata_checksum)
-            {
-              g_set_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS,
-                           "No such file or directory: %s", pathname);
+              g_prefix_error (error, "While resolving hardlink target: ");
               goto out;
-            }
         }
-
-      hardlink = archive_entry_hardlink (entry);
-      if (hardlink)
+      
+      if (hardlink_source_subdir)
         {
-          FileTree *hardlink_parent;
-          const char *hardlink_basename;
-          const char *hardlink_source_checksum;
-
-          if (!ot_util_path_split_validate (hardlink, &hardlink_split_path, error))
-            goto out;
-          if (hardlink_split_path->len == 0)
-            {
-              g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                           "Invalid hardlink path %s", hardlink);
-              goto out;
-            }
-
-          if (!file_tree_walk (root, hardlink_split_path, 0, &hardlink_parent, error))
-            goto out;
-
-
-          hardlink_basename = hardlink_split_path->pdata[hardlink_split_path->len - 1];
-
-          g_assert (parent);
-          hardlink_source_checksum = g_hash_table_lookup (hardlink_parent->file_checksums, hardlink_basename);
-          if (!hardlink_source_checksum)
-            {
-              g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                           "Hardlink %s refers to nonexistent path %s",
-                           pathname, hardlink);
-              goto out;
-            }
-
-          if (g_hash_table_lookup (parent->subdirs, basename))
-            {
-              g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                           "Directory exists: %s", hardlink);
-              goto out;
-            }
-
-          g_hash_table_replace (parent->file_checksums,
-                                g_strdup (basename),
-                                g_strdup (hardlink_source_checksum));
-          continue;
+          g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                       "Hardlink %s refers to directory %s",
+                       pathname, hardlink);
+          goto out;
         }
-
-      g_clear_object (&file_info);
+      g_assert (hardlink_source_checksum);
+      
+      if (!ostree_mutable_tree_replace_file (parent,
+                                             basename,
+                                             hardlink_source_checksum,
+                                             error))
+        goto out;
+    }
+  else
+    {
       file_info = file_info_from_archive_entry_and_modifier (entry, modifier);
 
       if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_UNKNOWN)
@@ -1899,65 +1802,94 @@ stage_libarchive_into_root (OstreeRepo           *self,
           goto out;
         }
 
-      ot_clear_checksum (&tmp_checksum);
-
       if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY)
         {
-          FileTree *dir;
-
-          if (parent)
-            {
-            }
 
           if (!stage_directory_meta (self, file_info, NULL, &tmp_checksum, cancellable, error))
             goto out;
 
           if (parent == NULL)
             {
-              dir = root;
+              subdir = g_object_ref (root);
             }
           else
             {
-              if (g_hash_table_lookup (parent->file_checksums, basename))
-                {
-                  g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                               "Can't replace file with directory: %s", pathname);
-                  goto out;
-                }
-              /* Allow duplicate directories */
-              if (!g_hash_table_lookup (parent->subdirs, basename))
-                {
-                  dir = file_tree_new ();
-                  g_assert (basename);
-                  g_hash_table_replace (parent->subdirs, g_strdup (basename), dir);
-                }
+              if (!ostree_mutable_tree_ensure_dir (parent, basename, &subdir, error))
+                goto out;
             }
-          g_free (dir->metadata_checksum);
-          dir->metadata_checksum = g_strdup (g_checksum_get_string (tmp_checksum));
+
+          ostree_mutable_tree_set_metadata_checksum (subdir, g_checksum_get_string (tmp_checksum));
         }
       else 
         {
-          if (g_hash_table_lookup (parent->subdirs, basename))
+          if (parent == NULL)
             {
               g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                           "Can't replace directory with file: %s", pathname);
+                           "Can't import file as root");
               goto out;
             }
 
           if (!import_libarchive_entry_file (self, a, entry, file_info, &tmp_checksum, cancellable, error))
             goto out;
+          
+          if (!ostree_mutable_tree_replace_file (parent, basename,
+                                                 g_checksum_get_string (tmp_checksum),
+                                                 error))
+            goto out;
+        }
+    }
 
-          if (parent == NULL)
-            {
-              g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                           "Can't import file as root");
-              goto out;
-            }
+  ret = TRUE;
+ out:
+  g_clear_object (&file_info);
+  ot_clear_checksum (&tmp_checksum);
+  g_clear_object (&parent);
+  g_clear_object (&subdir);
+  g_clear_object (&hardlink_source_parent);
+  g_free (hardlink_source_checksum);
+  g_clear_object (&hardlink_source_subdir);
+  if (hardlink_split_path)
+    g_ptr_array_unref (hardlink_split_path);
+  if (split_path)
+    g_ptr_array_unref (split_path);
+  return ret;
+}
+                          
+static gboolean
+stage_libarchive_into_root (OstreeRepo           *self,
+                            OstreeMutableTree    *root,
+                            GFile                *archive_f,
+                            OstreeRepoCommitModifier *modifier,
+                            GCancellable         *cancellable,
+                            GError              **error)
+{
+  gboolean ret = FALSE;
+  struct archive *a;
+  struct archive_entry *entry;
+  int r;
 
-          g_hash_table_replace (parent->file_checksums,
-                                g_strdup (basename),
-                                g_strdup (g_checksum_get_string (tmp_checksum)));
+  a = archive_read_new ();
+  archive_read_support_compression_all (a);
+  archive_read_support_format_all (a);
+  if (archive_read_open_filename (a, ot_gfile_get_path_cached (archive_f), 8192) != ARCHIVE_OK)
+    {
+      propagate_libarchive_error (error, a);
+      goto out;
+    }
+
+  while (TRUE)
+    {
+      r = archive_read_next_header (a, &entry);
+      if (r == ARCHIVE_EOF)
+        break;
+      else if (r != ARCHIVE_OK)
+        {
+          propagate_libarchive_error (error, a);
+          goto out;
         }
+
+      if (!stage_libarchive_entry_into_root (self, root, a, entry, modifier, cancellable, error))
+        goto out;
     }
   if (archive_read_close (a) != ARCHIVE_OK)
     {
@@ -1967,8 +1899,7 @@ stage_libarchive_into_root (OstreeRepo           *self,
 
   ret = TRUE;
  out:
-  g_clear_object (&file_info);
-  ot_clear_checksum (&tmp_checksum);
+  (void)archive_read_close (a);
   return ret;
 }
 #endif
@@ -1990,7 +1921,7 @@ ostree_repo_commit_tarfiles (OstreeRepo *self,
   OstreeRepoPrivate *priv = GET_PRIVATE (self);
   gboolean ret = FALSE;
   GChecksum *ret_commit_checksum = NULL;
-  FileTree *root = NULL;
+  OstreeMutableTree *root = NULL;
   char *root_contents_checksum = NULL;
   char *current_head = NULL;
   int i;
@@ -2010,7 +1941,7 @@ ostree_repo_commit_tarfiles (OstreeRepo *self,
   if (!ostree_repo_resolve_rev (self, parent, TRUE, &current_head, error))
     goto out;
 
-  root = file_tree_new ();
+  root = ostree_mutable_tree_new ();
 
   for (i = 0; i < tarfiles->len; i++)
     {
@@ -2020,11 +1951,11 @@ ostree_repo_commit_tarfiles (OstreeRepo *self,
         goto out;
     }
 
-  if (!file_tree_import_recurse (self, root, &root_contents_checksum, cancellable, error))
+  if (!stage_mutable_tree_recurse (self, root, &root_contents_checksum, cancellable, error))
     goto out;
 
   if (!do_commit_write_ref (self, branch, current_head, subject, body, metadata,
-                            root_contents_checksum, root->metadata_checksum, &ret_commit_checksum,
+                            root_contents_checksum, ostree_mutable_tree_get_metadata_checksum (root), &ret_commit_checksum,
                             cancellable, error))
     goto out;
   
@@ -2035,8 +1966,7 @@ ostree_repo_commit_tarfiles (OstreeRepo *self,
   ot_clear_checksum (&ret_commit_checksum);
   g_free (current_head);
   g_free (root_contents_checksum);
-  if (root)
-    file_tree_free (root);
+  g_clear_object (&root);
   return ret;
 #else
   g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
diff --git a/src/libostree/ostree.h b/src/libostree/ostree.h
index d683080..da42981 100644
--- a/src/libostree/ostree.h
+++ b/src/libostree/ostree.h
@@ -25,5 +25,6 @@
 #include <ostree-core.h>
 #include <ostree-repo.h>
 #include <ostree-checkout.h>
+#include <ostree-mutable-tree.h>
 
 #endif



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