summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Walters <walters@verbum.org>2014-12-12 08:54:11 -0500
committerColin Walters <walters@verbum.org>2014-12-17 21:40:22 -0500
commitf5a904e3cc16b2bd459fcbb88bc070ad238c8af3 (patch)
treed3ff2fc11519e1e3831e2715bdd6dd8e33000b33
parentf08b02df75cf14a5227dc265a9194ac62a9c1481 (diff)
downloadlibgsystem-f5a904e3cc16b2bd459fcbb88bc070ad238c8af3.tar.gz
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.
-rw-r--r--src/gsystem-shutil.c133
-rw-r--r--src/gsystem-shutil.h6
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);