From 2f5a68b43ae9293a83c3b412edd2f77d4303eb11 Mon Sep 17 00:00:00 2001
From: "Peter W. Draper" <p.w.draper@durham.ac.uk>
Date: Thu, 23 Apr 2020 19:15:46 +0100
Subject: [PATCH] Add utility function to check that a directory exists and if
 not report that or attempt to create it, in safe ways...

---
 src/tools.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/tools.h |  2 ++
 2 files changed, 51 insertions(+)

diff --git a/src/tools.c b/src/tools.c
index 1287d0b634..2f1969d91d 100644
--- a/src/tools.c
+++ b/src/tools.c
@@ -24,12 +24,16 @@
 
 /* Some standard headers. */
 #include <ctype.h>
+#include <errno.h>
 #include <math.h>
 #include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/resource.h>
+#include <sys/stat.h>
 #include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 /* This object's header. */
 #include "tools.h"
@@ -1058,3 +1062,48 @@ char *trim_both(char *s) {
   if (s == NULL || strlen(s) < 2) return s;
   return trim_trailing(trim_leading(s));
 }
+
+/**
+ * @brief safe check directory existence and creation.
+ *
+ * Doesn't try to re-create an existing directory and makes sure that it can
+ * have files created in it. If the directory doesn't exist and we want to
+ * create it then we try to do that with an appropriate mask that should
+ * honour the users umask. If the directory is something odd like a broken
+ * link then that is dereferenced so should also result in an error, since
+ * it doesn't exist and cannot be created. Finally we check that an existing
+ * file with this name is indeed a directory.
+ *
+ * @param dir the directory we need to exist.
+ * @param create create if not already exists, otherwise non-existence is an
+ *               error.
+ */
+void safe_checkdir(const char *dir, int create) {
+
+  if (access(dir, W_OK | X_OK) != 0) {
+
+    /* A file with this name and the minimally correct permissions does not
+     * exist. */
+    if (create) {
+      if (mkdir(dir, 0777) != 0)
+        error("Failed to create directory %s (%s)", dir, strerror(errno));
+    } else {
+      error("directory %s does not exist or cannot be used (%s)", dir,
+            strerror(errno));
+    }
+  } else {
+
+    /* Exists and has the minimally correct permissions, is this a
+     * directory? */
+    struct stat sb;
+    if (stat(dir, &sb) != 0) {
+      /* Weird error, can stat all existing files. */
+      error("Failed to stat directory %s (%s)", dir, strerror(errno));
+    } else if ((sb.st_mode & S_IFMT) != S_IFDIR) {
+      error("%s is not a directory, cannot use or create.", dir);
+    }
+  }
+
+  /* Success. */
+  return;
+}
diff --git a/src/tools.h b/src/tools.h
index a34904bcbb..8f7a65b7aa 100644
--- a/src/tools.h
+++ b/src/tools.h
@@ -64,4 +64,6 @@ char *trim_leading(char *s);
 char *trim_trailing(char *s);
 char *trim_both(char *s);
 
+void safe_checkdir(const char *dir, int create);
+
 #endif /* SWIFT_TOOL_H */
-- 
GitLab