summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Walters <walters@verbum.org>2017-09-06 14:06:37 -0400
committerColin Walters <walters@verbum.org>2017-09-07 16:05:26 -0400
commit627d4e2f15572e853279d4bb9511ef2618bef6b5 (patch)
tree76fa88f77b9d651ff6c40c5c800ab225854980b7
parent47d816329370ca315d4ffec9872690b1fd4c27c9 (diff)
downloadlibglnx-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.h38
-rw-r--r--tests/test-libglnx-fdio.c22
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();