From 3f1bcab27f1f6ee77e4a8d2a88858ed2e6d2aa70 Mon Sep 17 00:00:00 2001
From: Colin Walters <walters@verbum.org>
Date: Thu, 20 Apr 2017 21:26:17 -0400
Subject: [PATCH] lib/cleanup: Port some of the cleanup code to fd-relative and
 new style

There aren't many users of `g_file_enumerator_iterate()` left - those
remaining are usually good candidates for porting.  There's some more
porting to do in this file; a mix of trivial and harder.  This
one is a good candidate for an individual commit.

Closes: #803
Approved by: jlebon
---
 src/libostree/ostree-sysroot-cleanup.c | 171 +++++++++++--------------
 src/libostree/ostree-sysroot-deploy.c  |  11 +-
 src/libostree/ostree-sysroot-private.h |   3 +-
 3 files changed, 86 insertions(+), 99 deletions(-)

diff --git a/src/libostree/ostree-sysroot-cleanup.c b/src/libostree/ostree-sysroot-cleanup.c
index 022654c3..2933d459 100644
--- a/src/libostree/ostree-sysroot-cleanup.c
+++ b/src/libostree/ostree-sysroot-cleanup.c
@@ -25,127 +25,112 @@
 
 #include "ostree-sysroot-private.h"
 
+/* Like glnx_dirfd_iterator_init_at(), but if %ENOENT, then set
+ * @out_exists to %FALSE, and return successfully.
+ */
+static gboolean
+dfd_iter_init_allow_noent (int dfd,
+                           const char *path,
+                           GLnxDirFdIterator *dfd_iter,
+                           gboolean *out_exists,
+                           GError **error)
+{
+  glnx_fd_close int fd = glnx_opendirat_with_errno (dfd, path, TRUE);
+  if (fd < 0)
+    {
+      if (errno != ENOENT)
+        return glnx_throw_errno (error);
+      *out_exists = FALSE;
+      return TRUE;
+    }
+  if (!glnx_dirfd_iterator_init_take_fd (fd, dfd_iter, error))
+    return FALSE;
+  fd = -1;
+  *out_exists = TRUE;
+  return TRUE;
+}
+
+/* @deploydir_dfd: Directory FD for ostree/deploy
+ * @osname: Target osname
+ * @inout_deployments: All deployments in this subdir will be appended to this array
+ */
 gboolean
-_ostree_sysroot_list_deployment_dirs_for_os (GFile               *osdir,
+_ostree_sysroot_list_deployment_dirs_for_os (int                  deploydir_dfd,
+                                             const char          *osname,
                                              GPtrArray           *inout_deployments,
                                              GCancellable        *cancellable,
                                              GError             **error)
 {
-  gboolean ret = FALSE;
-  const char *osname = glnx_basename (gs_file_get_path_cached (osdir));
-  g_autoptr(GFileEnumerator) dir_enum = NULL;
-  g_autoptr(GFile) osdeploy_dir = NULL;
-  GError *temp_error = NULL;
-
-  osdeploy_dir = g_file_get_child (osdir, "deploy");
-
-  dir_enum = g_file_enumerate_children (osdeploy_dir, OSTREE_GIO_FAST_QUERYINFO,
-                                        G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
-                                        NULL, &temp_error);
-  if (!dir_enum)
-    {
-      if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
-        {
-          g_clear_error (&temp_error);
-          goto done;
-        } 
-      else
-        {
-          g_propagate_error (error, temp_error);
-          goto out;
-        }
-    }
+  g_auto(GLnxDirFdIterator) dfd_iter = { 0, };
+  gboolean exists;
+  const char *osdeploy_path = glnx_strjoina (osname, "/deploy");
+  if (!dfd_iter_init_allow_noent (deploydir_dfd, osdeploy_path, &dfd_iter, &exists, error))
+    return FALSE;
+  if (!exists)
+    return TRUE;
 
   while (TRUE)
     {
-      const char *name;
-      GFileInfo *file_info = NULL;
-      GFile *child = NULL;
-      glnx_unref_object OstreeDeployment *deployment = NULL;
-      g_autofree char *csum = NULL;
-      gint deployserial;
+      struct dirent *dent;
 
-      if (!g_file_enumerator_iterate (dir_enum, &file_info, &child,
-                                      cancellable, error))
-        goto out;
-      if (file_info == NULL)
+      if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error))
+        return FALSE;
+      if (dent == NULL)
         break;
 
-      name = g_file_info_get_name (file_info);
-
-      if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_DIRECTORY)
+      if (dent->d_type != DT_DIR)
         continue;
 
-      if (!_ostree_sysroot_parse_deploy_path_name (name, &csum, &deployserial, error))
-        goto out;
-      
-      deployment = ostree_deployment_new (-1, osname, csum, deployserial, NULL, -1);
-      g_ptr_array_add (inout_deployments, g_object_ref (deployment));
+      g_autofree char *csum = NULL;
+      gint deployserial;
+      if (!_ostree_sysroot_parse_deploy_path_name (dent->d_name, &csum, &deployserial, error))
+        return FALSE;
+
+      g_ptr_array_add (inout_deployments, ostree_deployment_new (-1, osname, csum, deployserial, NULL, -1));
     }
 
- done:
-  ret = TRUE;
- out:
-  return ret;
+  return TRUE;
 }
 
+/* Return in @out_deployments a new array of OstreeDeployment loaded from the
+ * filesystem state.
+ */
 static gboolean
 list_all_deployment_directories (OstreeSysroot       *self,
                                  GPtrArray          **out_deployments,
                                  GCancellable        *cancellable,
                                  GError             **error)
 {
-  gboolean ret = FALSE;
-  g_autoptr(GFileEnumerator) dir_enum = NULL;
-  g_autoptr(GFile) deploydir = NULL;
-  g_autoptr(GPtrArray) ret_deployments = NULL;
-  GError *temp_error = NULL;
+  g_autoptr(GPtrArray) ret_deployments =
+    g_ptr_array_new_with_free_func (g_object_unref);
 
-  deploydir = g_file_resolve_relative_path (self->path, "ostree/deploy");
-
-  ret_deployments = g_ptr_array_new_with_free_func (g_object_unref);
-
-  dir_enum = g_file_enumerate_children (deploydir, OSTREE_GIO_FAST_QUERYINFO,
-                                        G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
-                                        cancellable, &temp_error);
-  if (!dir_enum)
-    {
-      if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
-        {
-          g_clear_error (&temp_error);
-          goto done;
-        } 
-      else
-        {
-          g_propagate_error (error, temp_error);
-          goto out;
-        }
-    }
+  g_auto(GLnxDirFdIterator) dfd_iter = { 0, };
+  gboolean exists;
+  if (!dfd_iter_init_allow_noent (self->sysroot_fd, "ostree/deploy", &dfd_iter, &exists, error))
+    return FALSE;
+  if (!exists)
+    return TRUE;
 
   while (TRUE)
     {
-      GFileInfo *file_info = NULL;
-      GFile *child = NULL;
+      struct dirent *dent;
 
-      if (!g_file_enumerator_iterate (dir_enum, &file_info, &child,
-                                      NULL, error))
-        goto out;
-      if (file_info == NULL)
+      if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error))
+        return FALSE;
+      if (dent == NULL)
         break;
 
-      if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_DIRECTORY)
+      if (dent->d_type != DT_DIR)
         continue;
-      
-      if (!_ostree_sysroot_list_deployment_dirs_for_os (child, ret_deployments,
+
+      if (!_ostree_sysroot_list_deployment_dirs_for_os (dfd_iter.fd, dent->d_name,
+                                                        ret_deployments,
                                                         cancellable, error))
-        goto out;
+        return FALSE;
     }
-  
- done:
-  ret = TRUE;
+
   ot_transfer_out_value (out_deployments, &ret_deployments);
- out:
-  return ret;
+  return TRUE;
 }
 
 static gboolean
@@ -154,7 +139,7 @@ parse_bootdir_name (const char *name,
                     char      **out_csum)
 {
   const char *lastdash;
-  
+
   if (out_osname)
     *out_osname = NULL;
   if (out_csum)
@@ -164,7 +149,7 @@ parse_bootdir_name (const char *name,
 
   if (!lastdash)
     return FALSE;
-      
+
   if (!ostree_validate_checksum_string (lastdash + 1, NULL))
     return FALSE;
 
@@ -183,7 +168,6 @@ list_all_boot_directories (OstreeSysroot       *self,
                            GError             **error)
 {
   gboolean ret = FALSE;
-  g_autoptr(GFileEnumerator) dir_enum = NULL;
   g_autoptr(GFile) boot_ostree = NULL;
   g_autoptr(GPtrArray) ret_bootdirs = NULL;
   GError *temp_error = NULL;
@@ -192,9 +176,10 @@ list_all_boot_directories (OstreeSysroot       *self,
 
   ret_bootdirs = g_ptr_array_new_with_free_func (g_object_unref);
 
-  dir_enum = g_file_enumerate_children (boot_ostree, OSTREE_GIO_FAST_QUERYINFO,
-                                        G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
-                                        cancellable, &temp_error);
+  g_autoptr(GFileEnumerator) dir_enum =
+    g_file_enumerate_children (boot_ostree, OSTREE_GIO_FAST_QUERYINFO,
+                               G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+                               cancellable, &temp_error);
   if (!dir_enum)
     {
       if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
diff --git a/src/libostree/ostree-sysroot-deploy.c b/src/libostree/ostree-sysroot-deploy.c
index ed8c8bca..6cf4b7eb 100644
--- a/src/libostree/ostree-sysroot-deploy.c
+++ b/src/libostree/ostree-sysroot-deploy.c
@@ -1899,19 +1899,20 @@ allocate_deployserial (OstreeSysroot           *self,
                        GCancellable            *cancellable,
                        GError                 **error)
 {
-  guint i;
   int new_deployserial = 0;
   g_autoptr(GPtrArray) tmp_current_deployments =
     g_ptr_array_new_with_free_func (g_object_unref);
 
-  const char *osdir_name = glnx_strjoina ("ostree/deploy/", osname);
-  g_autoptr(GFile) osdir = g_file_resolve_relative_path (self->path, osdir_name);
+  glnx_fd_close int deploy_dfd = -1;
+  if (!glnx_opendirat (self->sysroot_fd, "ostree/deploy", TRUE, &deploy_dfd, error))
+    return FALSE;
 
-  if (!_ostree_sysroot_list_deployment_dirs_for_os (osdir, tmp_current_deployments,
+  if (!_ostree_sysroot_list_deployment_dirs_for_os (deploy_dfd, osname,
+                                                    tmp_current_deployments,
                                                     cancellable, error))
     return FALSE;
 
-  for (i = 0; i < tmp_current_deployments->len; i++)
+  for (guint i = 0; i < tmp_current_deployments->len; i++)
     {
       OstreeDeployment *deployment = tmp_current_deployments->pdata[i];
 
diff --git a/src/libostree/ostree-sysroot-private.h b/src/libostree/ostree-sysroot-private.h
index 4bc7802b..26cfd363 100644
--- a/src/libostree/ostree-sysroot-private.h
+++ b/src/libostree/ostree-sysroot-private.h
@@ -87,7 +87,8 @@ _ostree_sysroot_parse_deploy_path_name (const char *name,
                                         GError    **error);
 
 gboolean
-_ostree_sysroot_list_deployment_dirs_for_os (GFile               *osdir,
+_ostree_sysroot_list_deployment_dirs_for_os (int                  deploydir_dfd,
+                                             const char          *osname,
                                              GPtrArray           *inout_deployments,
                                              GCancellable        *cancellable,
                                              GError             **error);