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.
This commit is contained in:
Colin Walters
2016-01-01 17:26:12 -05:00
parent e7f7081054
commit 91e060699f
2 changed files with 53 additions and 0 deletions

View File

@@ -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

View File

@@ -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)