diff options
author | Colin Walters <walters@verbum.org> | 2016-01-01 17:26:12 -0500 |
---|---|---|
committer | Colin Walters <walters@verbum.org> | 2016-01-02 19:42:53 -0500 |
commit | 91e060699f5559c49335ce19f4b23ba70dfd6bb3 (patch) | |
tree | 78dcfe4ef90591870d54a7a92b905f5fc6872368 | |
parent | e7f7081054311670411b8ad34f144c99822538c1 (diff) | |
download | libglnx-91e060699f5559c49335ce19f4b23ba70dfd6bb3.tar.gz |
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.
-rw-r--r-- | glnx-dirfd.c | 49 | ||||
-rw-r--r-- | glnx-dirfd.h | 4 |
2 files changed, 53 insertions, 0 deletions
diff --git a/glnx-dirfd.c b/glnx-dirfd.c index d126f15..4861ccf 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; @@ -190,6 +192,53 @@ glnx_dirfd_iterator_next_dent (GLnxDirFdIterator *dfd_iter, } /** + * 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 5b7b77a..c13e3dc 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) |