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