aboutsummaryrefslogtreecommitdiff
path: root/src/db.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/db.c')
-rw-r--r--src/db.c166
1 files changed, 166 insertions, 0 deletions
diff --git a/src/db.c b/src/db.c
new file mode 100644
index 0000000..a46f806
--- /dev/null
+++ b/src/db.c
@@ -0,0 +1,166 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <wait.h>
+#include <string.h>
+#include <limits.h>
+#include <errno.h>
+#include "db.h"
+
+#ifndef PATH_MAX
+# define PATH_MAX 4096
+#endif
+
+#ifndef NAME_MAX
+# define NAME_MAX 255
+#endif
+
+#define DIR_NAME_BUF_SIZE (NAME_MAX+1)
+
+
+static const char *
+find_chr_or_zero(const char *s, char ch)
+{
+ while (*s && *s != ch)
+ s++;
+ return s;
+}
+
+static const char *
+find_chr_or_zero_n(const char *s, char ch, int n)
+{
+ int i = 0;
+ while (i < n && *s && *s != ch) {
+ s++;
+ i++;
+ }
+ return s;
+}
+
+static struct db_value_int
+does_dir_exist(const char *path)
+{
+ struct db_value_int res = {0};
+ struct stat st = {0};
+ int code;
+ res.code = dbe_ok;
+ res.data = 1;
+ code = stat(path, &st);
+ if (code != 0) {
+ if (errno == ENOENT)
+ res.data = 0;
+ else if (errno == EACCES)
+ res.code = dbe_access;
+ else
+ res.code = dbe_unknown;
+ } else {
+ res.data = ((st.st_mode & S_IFMT) == S_IFDIR) ? 1 : 0;
+ }
+ return res;
+}
+
+static enum db_error
+make_dir_ifne(const char *path, int rights)
+{
+ struct db_value_int val = {0};
+ int code;
+ val = does_dir_exist(path);
+ if (val.code != dbe_ok)
+ return val.code;
+ else if (val.data)
+ return dbe_ok;
+ code = mkdir(path, rights);
+ if (code != 0) {
+ if (errno == EACCES)
+ return dbe_access;
+ else if (errno == EEXIST)
+ return dbe_notdir;
+ }
+ return dbe_ok;
+}
+
+static enum db_error
+do_make_dir_path(const char *path, int rights)
+{
+ char buf[DIR_NAME_BUF_SIZE] = {0};
+ const char *p = find_chr_or_zero(path, '/');
+ unsigned sz = p - path + 1, code;
+ if (sz > sizeof(buf))
+ return dbe_inval;
+ strncpy(buf, path, sz);
+ buf[sz-1] = '\0';
+ code = make_dir_ifne(buf, rights);
+ if (code != dbe_ok)
+ return code;
+ if (*p) {
+ code = chdir(buf);
+ if (0 != code)
+ return dbe_access;
+ do_make_dir_path(p+1, rights);
+ code = chdir("..");
+ if (0 != code)
+ return dbe_access;
+ }
+ return dbe_ok;
+}
+
+/* mkdir -p */
+enum db_error
+make_dir_path(const char *path, int rights)
+{
+ return do_make_dir_path(path, rights);
+}
+
+/* ==================================================================== */
+
+#ifdef BTASKTD_DB_TEST
+
+#include <stdio.h>
+
+#define TEST_CODE(code) \
+ do { \
+ const char *s = NULL; \
+ switch (code) { \
+ case dbe_ok: s = "NO_ERROR"; break; \
+ case dbe_notdir: s = "NOT_DIR"; break; \
+ case dbe_inval: s = "INV_INPUT"; break; \
+ case dbe_access: s = "ACCESS"; break; \
+ default: s = "UNKNOWN"; \
+ } \
+ fprintf(stderr, "%s\n", s); \
+ } while (0)
+
+
+int
+main(void)
+{
+ int i, pid;
+ const char *path = "test_db/super_test/mtest";
+ for (i = 0; i < 10; i++)
+ TEST_CODE(make_dir_path(path, 0777));
+ pid = fork();
+ if (pid == -1) {
+ fprintf(stderr, "can't fork\n");
+ return 1;
+ } else if (pid == 0) {
+ execlp("ls", "ls", "-laR", NULL);
+ _exit(128);
+ } else {
+ wait(NULL);
+ }
+ pid = fork();
+ if (pid == -1) {
+ fprintf(stderr, "can't fork\n");
+ return 1;
+ } else if (pid == 0) {
+ execlp("rm", "rm", "-rf", "test_db", NULL);
+ _exit(128);
+ } else {
+ wait(NULL);
+ }
+ return 0;
+}
+
+#endif