From 91e060699f5559c49335ce19f4b23ba70dfd6bb3 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Fri, 1 Jan 2016 17:26:12 -0500 Subject: [PATCH] dirfd: Add a public API to ensure a filled dtype It's quite common to iterate over a directory recursively, only caring about the file type, but not other bits returned by `stat()`. Good file systems fill in `dt_type`, but not all do. This function papers over that in userspace conveniently. --- glnx-dirfd.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ glnx-dirfd.h | 4 ++++ 2 files changed, 53 insertions(+) diff --git a/glnx-dirfd.c b/glnx-dirfd.c index d126f15a..4861ccfe 100644 --- a/glnx-dirfd.c +++ b/glnx-dirfd.c @@ -168,6 +168,8 @@ glnx_dirfd_iterator_next_dent (GLnxDirFdIterator *dfd_iter, gboolean ret = FALSE; GLnxRealDirfdIterator *real_dfd_iter = (GLnxRealDirfdIterator*) dfd_iter; + g_return_val_if_fail (out_dent, FALSE); + if (g_cancellable_set_error_if_cancelled (cancellable, error)) goto out; @@ -189,6 +191,53 @@ glnx_dirfd_iterator_next_dent (GLnxDirFdIterator *dfd_iter, return ret; } +/** + * glnx_dirfd_iterator_next_dent_ensure_dtype: + * @dfd_iter: A directory iterator + * @out_dent: (out) (transfer none): Pointer to dirent; do not free + * @cancellable: Cancellable + * @error: Error + * + * A variant of @glnx_dirfd_iterator_next_dent, which will ensure the + * `dent->d_type` member is filled in by calling `fstatat` + * automatically if the underlying filesystem type sets `DT_UNKNOWN`. + */ +gboolean +glnx_dirfd_iterator_next_dent_ensure_dtype (GLnxDirFdIterator *dfd_iter, + struct dirent **out_dent, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + struct dirent *ret_dent; + + g_return_val_if_fail (out_dent, FALSE); + + if (!glnx_dirfd_iterator_next_dent (dfd_iter, out_dent, cancellable, error)) + goto out; + + ret_dent = *out_dent; + + if (ret_dent) + { + + if (ret_dent->d_type == DT_UNKNOWN) + { + struct stat stbuf; + if (TEMP_FAILURE_RETRY (fstatat (dfd_iter->fd, ret_dent->d_name, &stbuf, AT_SYMLINK_NOFOLLOW)) != 0) + { + glnx_set_error_from_errno (error); + goto out; + } + ret_dent->d_type = IFTODT (stbuf.st_mode); + } + } + + ret = TRUE; + out: + return ret; +} + /** * glnx_dirfd_iterator_clear: * @dfd_iter: Iterator, will be de-initialized diff --git a/glnx-dirfd.h b/glnx-dirfd.h index 5b7b77a9..c13e3dc5 100644 --- a/glnx-dirfd.h +++ b/glnx-dirfd.h @@ -60,6 +60,10 @@ gboolean glnx_dirfd_iterator_next_dent (GLnxDirFdIterator *dfd_iter, struct dirent **out_dent, GCancellable *cancellable, GError **error); +gboolean glnx_dirfd_iterator_next_dent_ensure_dtype (GLnxDirFdIterator *dfd_iter, + struct dirent **out_dent, + GCancellable *cancellable, + GError **error); void glnx_dirfd_iterator_clear (GLnxDirFdIterator *dfd_iter); G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GLnxDirFdIterator, glnx_dirfd_iterator_clear)