[ostree] repo: Port -refs.c to openat()



commit ca57ec4aa56e0e3ecfb4c5f4f34b84633a22fb66
Author: Colin Walters <walters verbum org>
Date:   Tue Jan 26 21:34:31 2016 -0500

    repo: Port -refs.c to openat()
    
    I'd like to incrementally convert all of `ostree-repo*.c` to
    fd-relative usage, so that we can sanely introduce
    `ostree_repo_new_at()` which doesn't involve GFile.
    
    This one is medium risk, but passes the test suite.

 libglnx                             |    2 +-
 src/libostree/ostree-repo-private.h |    2 -
 src/libostree/ostree-repo-refs.c    |  245 ++++++++++++++++++++++-------------
 src/libostree/ostree-repo.c         |    4 -
 tests/admin-test.sh                 |    2 +
 5 files changed, 155 insertions(+), 100 deletions(-)
---
diff --git a/libglnx b/libglnx
index 0313864..7695227 160000
--- a/libglnx
+++ b/libglnx
@@ -1 +1 @@
-Subproject commit 03138641298fd6799f46b16423871f959332bacf
+Subproject commit 769522753c25537e520adc322fa62e5390272add
diff --git a/src/libostree/ostree-repo-private.h b/src/libostree/ostree-repo-private.h
index b6ea317..463b3dd 100644
--- a/src/libostree/ostree-repo-private.h
+++ b/src/libostree/ostree-repo-private.h
@@ -50,8 +50,6 @@ struct OstreeRepo {
   int    repo_dir_fd;
   GFile *tmp_dir;
   int    tmp_dir_fd;
-  GFile *local_heads_dir;
-  GFile *remote_heads_dir;
   GFile *objects_dir;
   GFile *state_dir;
   int objects_dir_fd;
diff --git a/src/libostree/ostree-repo-refs.c b/src/libostree/ostree-repo-refs.c
index 4fc415b..68e34f2 100644
--- a/src/libostree/ostree-repo-refs.c
+++ b/src/libostree/ostree-repo-refs.c
@@ -25,19 +25,19 @@
 
 static gboolean
 add_ref_to_set (const char       *remote,
-                GFile            *base,
-                GFile            *child,
+                int               base_fd,
+                const char       *path,
                 GHashTable       *refs,
                 GCancellable     *cancellable,
                 GError          **error)
 {
   gboolean ret = FALSE;
   char *contents;
-  char *relpath;
   gsize len;
   GString *refname;
 
-  if (!g_file_load_contents (child, cancellable, &contents, &len, NULL, error))
+  contents = glnx_file_get_contents_utf8_at (base_fd, path, &len, cancellable, error);
+  if (!contents)
     goto out;
 
   g_strchomp (contents);
@@ -48,9 +48,7 @@ add_ref_to_set (const char       *remote,
       g_string_append (refname, remote);
       g_string_append_c (refname, ':');
     }
-  relpath = g_file_get_relative_path (base, child);
-  g_string_append (refname, relpath);
-  g_free (relpath);
+  g_string_append (refname, path);
           
   g_hash_table_insert (refs, g_string_free (refname, FALSE), contents);
 
@@ -117,43 +115,68 @@ write_checksum_file_at (OstreeRepo   *self,
 }
 
 static gboolean
+openat_ignore_enoent (int dfd,
+                      const char *path,
+                      int *out_fd,
+                      GError **error)
+{
+  gboolean ret = FALSE;
+  int target_fd = -1;
+  
+  target_fd = openat (dfd, path, O_CLOEXEC | O_RDONLY);
+  if (target_fd < 0)
+    {
+      if (errno != ENOENT)
+        {
+          glnx_set_error_from_errno (error);
+          goto out;
+        }
+    }
+
+  ret = TRUE;
+  *out_fd = target_fd;
+ out:
+  return ret;
+}
+
+static gboolean
 find_ref_in_remotes (OstreeRepo         *self,
                      const char         *rev,
-                     GFile             **out_file,
+                     int                *out_fd,
                      GError            **error)
 {
   gboolean ret = FALSE;
-  g_autoptr(GFileEnumerator) dir_enum = NULL;
-  g_autoptr(GFile) ret_file = NULL;
+  g_auto(GLnxDirFdIterator) dfd_iter = { 0, };
+  glnx_fd_close int ret_fd = -1;
 
-  dir_enum = g_file_enumerate_children (self->remote_heads_dir, OSTREE_GIO_FAST_QUERYINFO,
-                                        G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
-                                        NULL, error);
-  if (!dir_enum)
+  if (!glnx_dirfd_iterator_init_at (self->repo_dir_fd, "refs/remotes", TRUE, &dfd_iter, error))
     goto out;
 
   while (TRUE)
     {
-      GFileInfo *file_info;
-      GFile *child;
-      if (!gs_file_enumerator_iterate (dir_enum, &file_info, &child,
-                                       NULL, error))
+      struct dirent *dent = NULL;
+      glnx_fd_close int remote_dfd = -1;
+
+      if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, NULL, error))
         goto out;
-      if (file_info == NULL)
+      if (dent == NULL)
         break;
-      if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_DIRECTORY)
+
+      if (dent->d_type != DT_DIR)
         continue;
 
-      g_clear_object (&ret_file);
-      ret_file = g_file_resolve_relative_path (child, rev);
-      if (!g_file_query_exists (ret_file, NULL))
-        g_clear_object (&ret_file);
-      else
+      if (!glnx_opendirat (dfd_iter.fd, dent->d_name, TRUE, &remote_dfd, error))
+        goto out;
+
+      if (!openat_ignore_enoent (remote_dfd, rev, &ret_fd, error))
+        goto out;
+
+      if (ret_fd != -1)
         break;
     }
 
   ret = TRUE;
-  ot_transfer_out_value (out_file, &ret_file);
+  *out_fd = ret_fd; ret_fd = -1;
  out:
   return ret;
 }
@@ -210,9 +233,8 @@ resolve_refspec (OstreeRepo     *self,
 {
   gboolean ret = FALSE;
   __attribute__((unused)) GCancellable *cancellable = NULL;
-  GError *temp_error = NULL;
   g_autofree char *ret_rev = NULL;
-  g_autoptr(GFile) child = NULL;
+  glnx_fd_close int target_fd = -1;
   
   g_return_val_if_fail (ref != NULL, FALSE);
 
@@ -223,40 +245,42 @@ resolve_refspec (OstreeRepo     *self,
     }
   else if (remote != NULL)
     {
-      child = ot_gfile_resolve_path_printf (self->remote_heads_dir, "%s/%s",
-                                            remote, ref);
-      if (!g_file_query_exists (child, NULL))
-        g_clear_object (&child);
+      const char *remote_ref = glnx_strjoina ("refs/remotes/", remote, "/", ref);
+
+      if (!openat_ignore_enoent (self->repo_dir_fd, remote_ref, &target_fd, error))
+        goto out;
     }
   else
     {
-      child = g_file_resolve_relative_path (self->local_heads_dir, ref);
+      const char *local_ref = glnx_strjoina ("refs/heads/", ref);
 
-      if (!g_file_query_exists (child, NULL))
+      if (!openat_ignore_enoent (self->repo_dir_fd, local_ref, &target_fd, error))
+        goto out;
+
+      if (target_fd == -1)
         {
-          g_clear_object (&child);
+          local_ref = glnx_strjoina ("refs/remotes/", ref);
 
-          child = g_file_resolve_relative_path (self->remote_heads_dir, ref);
+          if (!openat_ignore_enoent (self->repo_dir_fd, local_ref, &target_fd, error))
+            goto out;
 
-          if (!g_file_query_exists (child, NULL))
+          if (target_fd == -1)
             {
-              g_clear_object (&child);
-              
-              if (!find_ref_in_remotes (self, ref, &child, error))
+              if (!find_ref_in_remotes (self, ref, &target_fd, error))
                 goto out;
             }
         }
     }
 
-  if (child)
+  if (target_fd != -1)
     {
-      if ((ret_rev = gs_file_load_contents_utf8 (child, NULL, &temp_error)) == NULL)
+      ret_rev = glnx_fd_readall_utf8 (target_fd, NULL, NULL, error);
+      if (!ret_rev)
         {
-          g_propagate_error (error, temp_error);
-          g_prefix_error (error, "Couldn't open ref '%s': ", gs_file_get_path_cached (child));
+          g_prefix_error (error, "Couldn't open ref '%s': ", ref);
           goto out;
         }
-
+          
       g_strchomp (ret_rev);
       if (!ostree_validate_checksum_string (ret_rev, error))
         goto out;
@@ -433,43 +457,50 @@ ostree_repo_resolve_rev (OstreeRepo     *self,
 static gboolean
 enumerate_refs_recurse (OstreeRepo    *repo,
                         const char    *remote,
-                        GFile         *base,
-                        GFile         *dir,
+                        int            base_dfd,
+                        GString       *base_path,
+                        int            child_dfd,
+                        const char    *path,
                         GHashTable    *refs,
                         GCancellable  *cancellable,
                         GError       **error)
 {
   gboolean ret = FALSE;
-  g_autoptr(GFileEnumerator) enumerator = NULL;
+  g_auto(GLnxDirFdIterator) dfd_iter = { 0, };
 
-  enumerator = g_file_enumerate_children (dir, OSTREE_GIO_FAST_QUERYINFO,
-                                          G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
-                                          cancellable, error);
-  if (!enumerator)
+  if (!glnx_dirfd_iterator_init_at (child_dfd, path, FALSE, &dfd_iter, error))
     goto out;
 
   while (TRUE)
     {
-      GFileInfo *file_info = NULL;
-      GFile *child = NULL;
+      guint len = base_path->len;
+      struct dirent *dent = NULL;
 
-      if (!gs_file_enumerator_iterate (enumerator, &file_info, &child,
-                                       NULL, error))
+      if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error))
         goto out;
-      if (file_info == NULL)
+      if (dent == NULL)
         break;
 
-      if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY)
+      g_string_append (base_path, dent->d_name);
+
+      if (dent->d_type == DT_DIR)
         {
-          if (!enumerate_refs_recurse (repo, remote, base, child, refs, cancellable, error))
+          g_string_append_c (base_path, '/');
+
+          if (!enumerate_refs_recurse (repo, remote, base_dfd, base_path,
+                                       dfd_iter.fd, dent->d_name,
+                                       refs, cancellable, error))
             goto out;
+          
         }
-      else if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR)
+      else if (dent->d_type == DT_REG)
         {
-          if (!add_ref_to_set (remote, base, child, refs,
+          if (!add_ref_to_set (remote, base_dfd, base_path->str, refs,
                                cancellable, error))
             goto out;
         }
+
+      g_string_truncate (base_path, len);
     }
 
   ret = TRUE;
@@ -505,35 +536,55 @@ ostree_repo_list_refs (OstreeRepo       *self,
 
   if (refspec_prefix)
     {
-      g_autoptr(GFile) dir = NULL;
-      g_autoptr(GFile) child = NULL;
-      g_autoptr(GFileInfo) info = NULL;
+      struct stat stbuf;
+      const char *prefix_path;
+      const char *path;
 
       if (!ostree_parse_refspec (refspec_prefix, &remote, &ref_prefix, error))
         goto out;
 
       if (remote)
-        dir = g_file_get_child (self->remote_heads_dir, remote);
+        {
+          prefix_path = glnx_strjoina ("refs/remotes/", remote, "/");
+          path = glnx_strjoina (prefix_path, ref_prefix);
+        }
       else
-        dir = g_object_ref (self->local_heads_dir);
-
-      child = g_file_resolve_relative_path (dir, ref_prefix);
-      if (!ot_gfile_query_info_allow_noent (child, OSTREE_GIO_FAST_QUERYINFO, 0,
-                                            &info, cancellable, error))
-        goto out;
+        {
+          prefix_path = "refs/heads/";
+          path = glnx_strjoina (prefix_path, ref_prefix);
+        }
 
-      if (info)
+      if (fstatat (self->repo_dir_fd, path, &stbuf, 0) < 0)
+        {
+          if (errno != ENOENT)
+            {
+              glnx_set_error_from_errno (error);
+              goto out;
+            }
+        }
+      else
         {
-          if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY)
+          if (S_ISDIR (stbuf.st_mode))
             {
-              if (!enumerate_refs_recurse (self, remote, child, child,
-                                           ret_all_refs,
-                                           cancellable, error))
+              glnx_fd_close int base_fd = -1;
+              g_autoptr(GString) base_path = g_string_new ("");
+
+              if (!glnx_opendirat (self->repo_dir_fd, path, TRUE, &base_fd, error))
+                goto out;
+
+              if (!enumerate_refs_recurse (self, remote, base_fd, base_path,
+                                           base_fd, ".",
+                                           ret_all_refs, cancellable, error))
                 goto out;
             }
           else
             {
-              if (!add_ref_to_set (remote, dir, child, ret_all_refs,
+              glnx_fd_close int prefix_dfd = -1;
+              
+              if (!glnx_opendirat (self->repo_dir_fd, prefix_path, TRUE, &prefix_dfd, error))
+                goto out;
+
+              if (!add_ref_to_set (remote, prefix_dfd, ref_prefix, ret_all_refs,
                                    cancellable, error))
                 goto out;
             }
@@ -541,33 +592,41 @@ ostree_repo_list_refs (OstreeRepo       *self,
     }
   else
     {
-      g_autoptr(GFileEnumerator) remote_enumerator = NULL;
+      g_auto(GLnxDirFdIterator) dfd_iter = { 0, };
+      g_autoptr(GString) base_path = g_string_new ("");
+      glnx_fd_close int refs_heads_dfd = -1;
+              
+      if (!glnx_opendirat (self->repo_dir_fd, "refs/heads", TRUE, &refs_heads_dfd, error))
+        goto out;
 
-      if (!enumerate_refs_recurse (self, NULL, self->local_heads_dir, self->local_heads_dir,
-                                   ret_all_refs,
-                                   cancellable, error))
+      if (!enumerate_refs_recurse (self, NULL, refs_heads_dfd, base_path,
+                                   refs_heads_dfd, ".",
+                                   ret_all_refs, cancellable, error))
         goto out;
 
-      remote_enumerator = g_file_enumerate_children (self->remote_heads_dir, OSTREE_GIO_FAST_QUERYINFO,
-                                                     0,
-                                                     cancellable, error);
-      if (!remote_enumerator)
+      g_string_truncate (base_path, 0);
+
+      if (!glnx_dirfd_iterator_init_at (self->repo_dir_fd, "refs/remotes", TRUE, &dfd_iter, error))
         goto out;
 
       while (TRUE)
         {
-          GFileInfo *info;
-          GFile *child;
-          const char *name;
+          struct dirent *dent;
+          glnx_fd_close int remote_dfd = -1;
 
-          if (!gs_file_enumerator_iterate (remote_enumerator, &info, &child,
-                                           cancellable, error))
+          if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error))
             goto out;
-          if (!info)
+          if (!dent)
             break;
 
-          name = g_file_info_get_name (info);
-          if (!enumerate_refs_recurse (self, name, child, child,
+          if (dent->d_type != DT_DIR)
+            continue;
+
+          if (!glnx_opendirat (dfd_iter.fd, dent->d_name, TRUE, &remote_dfd, error))
+            goto out;
+          
+          if (!enumerate_refs_recurse (self, dent->d_name, remote_dfd, base_path,
+                                       remote_dfd, ".",
                                        ret_all_refs,
                                        cancellable, error))
             goto out;
diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c
index d5b9aea..2136208 100644
--- a/src/libostree/ostree-repo.c
+++ b/src/libostree/ostree-repo.c
@@ -518,8 +518,6 @@ ostree_repo_finalize (GObject *object)
   g_clear_object (&self->tmp_dir);
   if (self->tmp_dir_fd)
     (void) close (self->tmp_dir_fd);
-  g_clear_object (&self->local_heads_dir);
-  g_clear_object (&self->remote_heads_dir);
   g_clear_object (&self->objects_dir);
   if (self->objects_dir_fd != -1)
     (void) close (self->objects_dir_fd);
@@ -605,8 +603,6 @@ ostree_repo_constructed (GObject *object)
   g_assert (self->repodir != NULL);
 
   self->tmp_dir = g_file_resolve_relative_path (self->repodir, "tmp");
-  self->local_heads_dir = g_file_resolve_relative_path (self->repodir, "refs/heads");
-  self->remote_heads_dir = g_file_resolve_relative_path (self->repodir, "refs/remotes");
 
   self->objects_dir = g_file_get_child (self->repodir, "objects");
   self->deltas_dir = g_file_get_child (self->repodir, "deltas");
diff --git a/tests/admin-test.sh b/tests/admin-test.sh
index a587d79..c4644d3 100755
--- a/tests/admin-test.sh
+++ b/tests/admin-test.sh
@@ -155,6 +155,8 @@ assert_not_streq ${rev} ${newrev}
 assert_file_has_content sysroot/ostree/deploy/testos/deploy/${newrev}.0/etc/os-release 'NAME=TestOS'
 ${CMD_PREFIX} ostree admin status
 validate_bootloader
+${CMD_PREFIX} ostree --repo=sysroot/ostree/repo refs testos:testos > reftest.txt
+assert_file_has_content reftest.txt testos:buildmaster/x86_64-runtime
 
 echo "ok upgrade"
 


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