diff options
author | Colin Walters <walters@verbum.org> | 2017-09-06 14:06:37 -0400 |
---|---|---|
committer | Colin Walters <walters@verbum.org> | 2017-09-07 16:05:26 -0400 |
commit | 627d4e2f15572e853279d4bb9511ef2618bef6b5 (patch) | |
tree | 76fa88f77b9d651ff6c40c5c800ab225854980b7 | |
parent | 47d816329370ca315d4ffec9872690b1fd4c27c9 (diff) | |
download | libglnx-627d4e2f15572e853279d4bb9511ef2618bef6b5.tar.gz |
fdio: Add glnx_fstatat_allow_noent()
This is a very common pattern in both ostree/rpm-ostree. Make a better API for
this. I thought a lot about simply zeroing out `struct stat` but that feels
dangerous; none of the values have seem obviously `cannot be zero`.
-rw-r--r-- | glnx-fdio.h | 38 | ||||
-rw-r--r-- | tests/test-libglnx-fdio.c | 22 |
2 files changed, 60 insertions, 0 deletions
diff --git a/glnx-fdio.h b/glnx-fdio.h index 4ee24af..518135c 100644 --- a/glnx-fdio.h +++ b/glnx-fdio.h @@ -296,6 +296,44 @@ glnx_fstatat (int dfd, } /** + * glnx_fstatat_allow_noent: + * @dfd: Directory FD to stat beneath + * @path: Path to stat beneath @dfd + * @buf: (out caller-allocates): Return location for stat details + * @flags: Flags to pass to fstatat() + * @error: Return location for a #GError, or %NULL + * + * Like glnx_fstatat(), but handles `ENOENT` in a non-error way. Instead, + * on success `errno` will be zero, otherwise it will be preserved. Hence + * you can test `if (errno == 0)` to conditionalize on the file existing, + * or `if (errno == ENOENT)` for non-existence. + * + * Returns: %TRUE on success, %FALSE otherwise (errno is preserved) + * Since: UNRELEASED + */ +static inline gboolean +glnx_fstatat_allow_noent (int dfd, + const char *path, + struct stat *out_buf, + int flags, + GError **error) +{ + if (TEMP_FAILURE_RETRY (fstatat (dfd, path, out_buf, flags)) != 0) + { + if (errno != ENOENT) + { + int errsv = errno; + (void) glnx_throw_errno_prefix (error, "fstatat(%s)", path); + errno = errsv; + return FALSE; + } + } + else + errno = 0; + return TRUE; +} + +/** * glnx_renameat: * * Wrapper around renameat() which adds #GError support and ensures that it diff --git a/tests/test-libglnx-fdio.c b/tests/test-libglnx-fdio.c index 16b6692..4b81a95 100644 --- a/tests/test-libglnx-fdio.c +++ b/tests/test-libglnx-fdio.c @@ -189,6 +189,27 @@ test_stdio_file (void) g_assert_no_error (local_error); } +static void +test_fstatat (void) +{ + g_autoptr(GError) local_error = NULL; + GError **error = &local_error; + struct stat stbuf = { 0, }; + + if (!glnx_fstatat_allow_noent (AT_FDCWD, ".", &stbuf, 0, error)) + goto out; + g_assert_cmpint (errno, ==, 0); + g_assert_no_error (local_error); + g_assert (S_ISDIR (stbuf.st_mode)); + if (!glnx_fstatat_allow_noent (AT_FDCWD, "nosuchfile", &stbuf, 0, error)) + goto out; + g_assert_cmpint (errno, ==, ENOENT); + g_assert_no_error (local_error); + + out: + g_assert_no_error (local_error); +} + int main (int argc, char **argv) { int ret; @@ -199,6 +220,7 @@ int main (int argc, char **argv) g_test_add_func ("/stdio-file", test_stdio_file); g_test_add_func ("/renameat2-noreplace", test_renameat2_noreplace); g_test_add_func ("/renameat2-exchange", test_renameat2_exchange); + g_test_add_func ("/fstat", test_fstatat); ret = g_test_run(); |