[ostree] libarchive: Make autocreate_parents imply autocreating root dir



commit 30c5fb1a5116e517a9d2e4df9cdc1fbd0249c965
Author: Colin Walters <walters verbum org>
Date:   Mon Feb 22 11:18:30 2016 -0500

    libarchive: Make autocreate_parents imply autocreating root dir
    
    Some Docker layers are just metadata in the `layer.json`.  If one is
    mapping Docker layers to OSTree commits, one needs to create a dummy
    root directory, because OSTree doesn't support metadata-only commits.
    
    Let's just push that logic down here because it's easier than special
    casing it in higher levels.

 src/libostree/ostree-repo-libarchive.c |   52 +++++++++++++++++++++++++----
 tests/test-libarchive-import.c         |   56 ++++++++++++++++++++++++++++++++
 2 files changed, 101 insertions(+), 7 deletions(-)
---
diff --git a/src/libostree/ostree-repo-libarchive.c b/src/libostree/ostree-repo-libarchive.c
index 64410cb..82c8dd5 100644
--- a/src/libostree/ostree-repo-libarchive.c
+++ b/src/libostree/ostree-repo-libarchive.c
@@ -292,6 +292,23 @@ write_libarchive_entry_to_mtree (OstreeRepo           *self,
 }
 #endif
 
+static gboolean
+create_empty_dir_with_uidgid (OstreeRepo   *self,
+                              guint32       uid,
+                              guint32       gid,
+                              guint8      **out_csum,
+                              GCancellable *cancellable,
+                              GError      **error)
+{
+  g_autoptr(GFileInfo) tmp_dir_info = g_file_info_new ();
+          
+  g_file_info_set_attribute_uint32 (tmp_dir_info, "unix::uid", uid);
+  g_file_info_set_attribute_uint32 (tmp_dir_info, "unix::gid", gid);
+  g_file_info_set_attribute_uint32 (tmp_dir_info, "unix::mode", 0755 | S_IFDIR);
+  
+  return _ostree_repo_write_directory_meta (self, tmp_dir_info, NULL, out_csum, cancellable, error);
+}
+
 /**
  * ostree_repo_import_archive_to_mtree:
  * @self: An #OstreeRepo
@@ -320,6 +337,7 @@ ostree_repo_import_archive_to_mtree (OstreeRepo                   *self,
   g_autofree guchar *tmp_csum = NULL;
   int r;
 
+
   while (TRUE)
     {
       r = archive_read_next_header (a, &entry);
@@ -336,13 +354,13 @@ ostree_repo_import_archive_to_mtree (OstreeRepo                   *self,
        */
       if (opts->autocreate_parents && !tmp_csum)
         {
-          g_autoptr(GFileInfo) tmp_dir_info = g_file_info_new ();
-          
-          g_file_info_set_attribute_uint32 (tmp_dir_info, "unix::uid", archive_entry_uid (entry));
-          g_file_info_set_attribute_uint32 (tmp_dir_info, "unix::gid", archive_entry_gid (entry));
-          g_file_info_set_attribute_uint32 (tmp_dir_info, "unix::mode", 0755 | S_IFDIR);
-          
-          if (!_ostree_repo_write_directory_meta (self, tmp_dir_info, NULL, &tmp_csum, cancellable, error))
+          /* Here, we auto-pick the first uid/gid we find in the
+           * archive.  Realistically this is probably always going to
+           * be root, but eh, at least we try to match.
+           */
+          if (!create_empty_dir_with_uidgid (self, archive_entry_uid (entry),
+                                             archive_entry_gid (entry),
+                                             &tmp_csum, cancellable, error))
             goto out;
         }
 
@@ -352,6 +370,26 @@ ostree_repo_import_archive_to_mtree (OstreeRepo                   *self,
         goto out;
     }
 
+  /* If we didn't import anything at all, and autocreation of parents
+   * is enabled, automatically create a root directory.  This is
+   * useful primarily when importing Docker image layers, which can
+   * just be metadata.
+   */
+  if (!ostree_mutable_tree_get_metadata_checksum (mtree) && opts->autocreate_parents)
+    {
+      char tmp_checksum[65];
+
+      if (!tmp_csum)
+        {
+          /* We didn't have any archive entries to match, so pick uid 0, gid 0. */
+          if (!create_empty_dir_with_uidgid (self, 0, 0, &tmp_csum, cancellable, error))
+            goto out;
+        }
+      
+      ostree_checksum_inplace_from_bytes (tmp_csum, tmp_checksum);
+      ostree_mutable_tree_set_metadata_checksum (mtree, tmp_checksum);
+    }
+
   ret = TRUE;
  out:
   return ret;
diff --git a/tests/test-libarchive-import.c b/tests/test-libarchive-import.c
index 1dd0c68..928b149 100644
--- a/tests/test-libarchive-import.c
+++ b/tests/test-libarchive-import.c
@@ -32,6 +32,7 @@
 typedef struct {
   OstreeRepo *repo;
   int fd;
+  int fd_empty;
   char *tmpd;
 } TestData;
 
@@ -88,6 +89,19 @@ test_data_init (TestData *td)
   g_assert_cmpint (ARCHIVE_OK, ==, archive_write_close (a));
   g_assert_cmpint (ARCHIVE_OK, ==, archive_write_free (a));
 
+  td->fd_empty = openat (AT_FDCWD, "empty.tar.gz", O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, 0644);
+  g_assert (td->fd_empty >= 0);
+  (void) unlink ("empty.tar.gz");
+
+  a = archive_write_new ();
+  g_assert (a);
+
+  g_assert_cmpint (0, ==, archive_write_set_format_pax (a));
+  g_assert_cmpint (0, ==, archive_write_add_filter_gzip (a));
+  g_assert_cmpint (0, ==, archive_write_open_fd (a, td->fd_empty));
+  g_assert_cmpint (ARCHIVE_OK, ==, archive_write_close (a));
+  g_assert_cmpint (ARCHIVE_OK, ==, archive_write_free (a));
+
   { g_autoptr(GFile) repopath = g_file_new_for_path ("repo");
     td->repo = ostree_repo_new (repopath);
 
@@ -110,6 +124,46 @@ spawn_cmdline (const char *cmd, GError **error)
 }
 
 static void
+test_libarchive_noautocreate_empty (gconstpointer data)
+{
+  TestData *td = (void*)data;
+  GError *error = NULL;
+  struct archive *a = archive_read_new ();
+  OstreeRepoImportArchiveOptions opts = { 0, };
+  glnx_unref_object OstreeMutableTree *mtree = ostree_mutable_tree_new ();
+
+  g_assert_cmpint (0, ==, lseek (td->fd_empty, 0, SEEK_SET));
+  g_assert_cmpint (0, ==, archive_read_support_format_all (a));
+  g_assert_cmpint (0, ==, archive_read_support_filter_all (a));
+  g_assert_cmpint (0, ==, archive_read_open_fd (a, td->fd_empty, 8192));
+
+  (void)ostree_repo_import_archive_to_mtree (td->repo, &opts, a, mtree, NULL, NULL, &error);
+  g_assert_no_error (error);
+  g_assert (ostree_mutable_tree_get_metadata_checksum (mtree) == NULL);
+}
+
+static void
+test_libarchive_autocreate_empty (gconstpointer data)
+{
+  TestData *td = (void*)data;
+  GError *error = NULL;
+  struct archive *a = archive_read_new ();
+  OstreeRepoImportArchiveOptions opts = { 0, };
+  glnx_unref_object OstreeMutableTree *mtree = ostree_mutable_tree_new ();
+
+  opts.autocreate_parents = 1;
+
+  g_assert_cmpint (0, ==, lseek (td->fd_empty, 0, SEEK_SET));
+  g_assert_cmpint (0, ==, archive_read_support_format_all (a));
+  g_assert_cmpint (0, ==, archive_read_support_filter_all (a));
+  g_assert_cmpint (0, ==, archive_read_open_fd (a, td->fd_empty, 8192));
+
+  (void)ostree_repo_import_archive_to_mtree (td->repo, &opts, a, mtree, NULL, NULL, &error);
+  g_assert_no_error (error);
+  g_assert (ostree_mutable_tree_get_metadata_checksum (mtree) != NULL);
+}
+
+static void
 test_libarchive_error_device_file (gconstpointer data)
 {
   TestData *td = (void*)data;
@@ -189,6 +243,8 @@ int main (int argc, char **argv)
 
   g_test_init (&argc, &argv, NULL);
 
+  g_test_add_data_func ("/libarchive/noautocreate-empty", &td, test_libarchive_noautocreate_empty);
+  g_test_add_data_func ("/libarchive/autocreate-empty", &td, test_libarchive_autocreate_empty);
   g_test_add_data_func ("/libarchive/error-device-file", &td, test_libarchive_error_device_file);
   g_test_add_data_func ("/libarchive/ignore-device-file", &td, test_libarchive_ignore_device_file);
 


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