[libgsystem/wip/diriter: 3/3] shutil: Change rm_rf() to use new GSDirFdIterator, and add *at variant



commit 6a4e3328694f74e357b2c2ffcef4e12500717e08
Author: Colin Walters <walters verbum org>
Date:   Fri Dec 12 08:54:11 2014 -0500

    shutil: Change rm_rf() to use new GSDirFdIterator, and add *at variant
    
    This noticeably cleans up the rm_rf() code.  And also it now becomes
    easy add a gs_shutil_rm_rf_at() variant.

 src/gsystem-shutil.c |  133 ++++++++++++++++++++++---------------------------
 src/gsystem-shutil.h |    6 ++
 2 files changed, 66 insertions(+), 73 deletions(-)
---
diff --git a/src/gsystem-shutil.c b/src/gsystem-shutil.c
index 6cd05c2..b217115 100644
--- a/src/gsystem-shutil.c
+++ b/src/gsystem-shutil.c
@@ -292,29 +292,25 @@ struct_stat_to_dt (struct stat *stbuf)
 }
 
 static gboolean
-gs_shutil_rm_rf_children (DIR                *dir,
+gs_shutil_rm_rf_children (GSDirFdIterator    *dfd_iter,
                           GCancellable       *cancellable,
                           GError            **error)
 {
   gboolean ret = FALSE;
-  int dfd;
-  DIR *child_dir = NULL;
   struct dirent *dent;
-  union dirent_storage buf;
 
-  if (g_cancellable_set_error_if_cancelled (cancellable, error))
-    goto out;
-
-  dfd = dirfd (dir);
-
-  while (readdir_r (dir, &buf.dent, &dent) == 0)
+  while (TRUE)
     {
+      if (!gs_dirfd_iterator_next_dent (dfd_iter, &dent, cancellable, error))
+        goto out;
+
       if (dent == NULL)
         break;
+
       if (dent->d_type == DT_UNKNOWN)
         {
           struct stat stbuf;
-          if (fstatat (dfd, dent->d_name, &stbuf, AT_SYMLINK_NOFOLLOW) == -1)
+          if (fstatat (dfd_iter->fd, dent->d_name, &stbuf, AT_SYMLINK_NOFOLLOW) == -1)
             {
               int errsv = errno;
               if (errsv == ENOENT)
@@ -332,52 +328,28 @@ gs_shutil_rm_rf_children (DIR                *dir,
             dent->d_type = DT_REG;
         }
 
-      if (strcmp (dent->d_name, ".") == 0 || strcmp (dent->d_name, "..") == 0)
-        continue;
-          
       if (dent->d_type == DT_DIR)
         {
-          int child_dfd = openat (dfd, dent->d_name, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | 
O_NOFOLLOW);
-
-          if (child_dfd == -1)
-            {
-              if (errno == ENOENT)
-                continue;
-              else
-                {
-                  int errsv = errno;
-                  g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errsv),
-                                       g_strerror (errsv));
-                  goto out;
-                }
-            }
+          gs_dirfd_iterator_cleanup GSDirFdIterator child_dfd_iter = { 0, };
 
-          child_dir = fdopendir (child_dfd);
-          if (!child_dir)
-            {
-              int errsv = errno;
-              g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errsv),
-                                   g_strerror (errsv));
-              goto out;
-            }
+          if (!gs_dirfd_iterator_init_at (dfd_iter->fd, dent->d_name, FALSE,
+                                          &child_dfd_iter, error))
+            goto out;
 
-          if (!gs_shutil_rm_rf_children (child_dir, cancellable, error))
+          if (!gs_shutil_rm_rf_children (&child_dfd_iter, cancellable, error))
             goto out;
 
-          if (unlinkat (dfd, dent->d_name, AT_REMOVEDIR) == -1)
+          if (unlinkat (dfd_iter->fd, dent->d_name, AT_REMOVEDIR) == -1)
             {
               int errsv = errno;
               g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errsv),
                                    g_strerror (errsv));
               goto out;
             }
-
-          (void) closedir (child_dir);
-          child_dir = NULL;
         }
       else
         {
-          if (unlinkat (dfd, dent->d_name, 0) == -1)
+          if (unlinkat (dfd_iter->fd, dent->d_name, 0) == -1)
             {
               int errsv = errno;
               if (errno != ENOENT)
@@ -389,39 +361,38 @@ gs_shutil_rm_rf_children (DIR                *dir,
             }
         }
     }
-  /* Ignore error result from readdir_r, that's what others
-   * seem to do =(
-   */
 
   ret = TRUE;
  out:
-  if (child_dir) (void) closedir (child_dir);
   return ret;
 }
 
 /**
- * gs_shutil_rm_rf:
- * @path: A file or directory
- * @cancellable:
- * @error:
+ * gs_shutil_rm_rf_at:
+ * @dfd: A directory file descriptor, or -1 for current
+ * @path: Path
+ * @cancellable: Cancellable
+ * @error: Error
  *
- * Recursively delete the filename referenced by @path; it may be a
- * file or directory.  No error is thrown if @path does not exist.
+ * Recursively delete the filename referenced by the combination of
+ * the directory fd dfd and @path; it may be a file or directory.  No
+ * error is thrown if @path does not exist.
  */
 gboolean
-gs_shutil_rm_rf (GFile        *path,
-                 GCancellable *cancellable,
-                 GError      **error)
+gs_shutil_rm_rf_at (int           dfd,
+                    const char   *path,
+                    GCancellable *cancellable,
+                    GError      **error)
 {
   gboolean ret = FALSE;
-  int dfd = -1;
-  DIR *d = NULL;
+  int target_dfd = -1;
+  gs_dirfd_iterator_cleanup GSDirFdIterator dfd_iter = { 0, };
 
   /* With O_NOFOLLOW first */
-  dfd = openat (AT_FDCWD, gs_file_get_path_cached (path),
-                O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW);
+  target_dfd = openat (dfd, path,
+                       O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW);
 
-  if (dfd == -1)
+  if (target_dfd == -1)
     {
       int errsv = errno;
       if (errsv == ENOENT)
@@ -430,8 +401,12 @@ gs_shutil_rm_rf (GFile        *path,
         }
       else if (errsv == ENOTDIR || errsv == ELOOP)
         {
-          if (!gs_file_unlink (path, cancellable, error))
-            goto out;
+          if (unlinkat (dfd, path, 0) != 0)
+            {
+              g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errsv),
+                                   g_strerror (errsv));
+              goto out;
+            }
         }
       else
         {
@@ -442,19 +417,14 @@ gs_shutil_rm_rf (GFile        *path,
     }
   else
     {
-      d = fdopendir (dfd);
-      if (!d)
-        {
-          int errsv = errno;
-          g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errsv),
-                               g_strerror (errsv));
-          goto out;
-        }
+      if (!gs_dirfd_iterator_init_take_fd (target_dfd, &dfd_iter, error))
+        goto out;
+      target_dfd = -1;
 
-      if (!gs_shutil_rm_rf_children (d, cancellable, error))
+      if (!gs_shutil_rm_rf_children (&dfd_iter, cancellable, error))
         goto out;
 
-      if (rmdir (gs_file_get_path_cached (path)) == -1)
+      if (unlinkat (dfd, path, AT_REMOVEDIR) == -1)
         {
           int errsv = errno;
           if (errsv != ENOENT)
@@ -468,7 +438,24 @@ gs_shutil_rm_rf (GFile        *path,
 
   ret = TRUE;
  out:
-  if (d) (void) closedir (d);
+  if (target_dfd != -1) (void) close (target_dfd);
   return ret;
 }
 
+/**
+ * gs_shutil_rm_rf:
+ * @path: A file or directory
+ * @cancellable:
+ * @error:
+ *
+ * Recursively delete the filename referenced by @path; it may be a
+ * file or directory.  No error is thrown if @path does not exist.
+ */
+gboolean
+gs_shutil_rm_rf (GFile        *path,
+                 GCancellable *cancellable,
+                 GError      **error)
+{
+  return gs_shutil_rm_rf_at (-1, gs_file_get_path_cached (path), cancellable, error);
+}
+
diff --git a/src/gsystem-shutil.h b/src/gsystem-shutil.h
index 3cdea77..ebab583 100644
--- a/src/gsystem-shutil.h
+++ b/src/gsystem-shutil.h
@@ -38,6 +38,12 @@ gs_shutil_cp_a (GFile         *src,
                 GError       **error);
 
 gboolean
+gs_shutil_rm_rf_at (int            fd,
+                    const char    *path,
+                    GCancellable  *cancellable,
+                    GError       **error);
+
+gboolean
 gs_shutil_rm_rf (GFile        *path,
                  GCancellable *cancellable,
                  GError      **error);


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