[libglnx] fdio: Add glnx_fstatat_allow_noent()



commit 627d4e2f15572e853279d4bb9511ef2618bef6b5
Author: Colin Walters <walters verbum org>
Date:   Wed Sep 6 14:06:37 2017 -0400

    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`.

 glnx-fdio.h               |   38 ++++++++++++++++++++++++++++++++++++++
 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();
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]