aboutsummaryrefslogtreecommitdiff
path: root/db.c
diff options
context:
space:
mode:
authorMr. Goblin <mrgoblin@mrgoblin.net>2026-09-19 19:09:11 +0300
committerMr. Goblin <mrgoblin@mrgoblin.net>2026-09-19 19:09:11 +0300
commit01438bd1be578c3b43c9ad29b0a2d6707ee122b8 (patch)
treed3e8dfd3b6482e1dac32837d0d57847f0d67ed2c /db.c
parent2cba815df5713fbadecc86e373ec5f6c8a07ced5 (diff)
all files are in root; changed help message
Diffstat (limited to 'db.c')
-rw-r--r--db.c198
1 files changed, 198 insertions, 0 deletions
diff --git a/db.c b/db.c
new file mode 100644
index 0000000..c547013
--- /dev/null
+++ b/db.c
@@ -0,0 +1,198 @@
+/*-
+ * Copyright (c) 2026, Mr. Goblin
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
+ * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+#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 (0 != code) {
+ if (ENOENT == errno)
+ res.data = 0;
+ else if (EACCES == errno)
+ res.code = dbe_access;
+ else
+ res.code = dbe_unknown;
+ } else {
+ res.data = S_IFDIR == (st.st_mode & S_IFMT);
+ }
+ 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 (dbe_ok != val.code)
+ return val.code;
+ else if (val.data)
+ return dbe_ok;
+ code = mkdir(path, rights);
+ if (code != 0) {
+ if (EACCES == errno)
+ return dbe_access;
+ else if (EEXIST == errno)
+ 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 (sizeof(buf) < sz)
+ return dbe_inval;
+ strncpy(buf, path, sz);
+ buf[sz-1] = '\0';
+ code = make_dir_ifne(buf, rights);
+ if (dbe_ok != code)
+ return code;
+ if (*p) {
+ code = chdir(buf);
+ if (0 != code)
+ return dbe_access;
+ code = do_make_dir_path(p+1, rights);
+ if (dbe_ok != code)
+ return code;
+ 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 (-1 == pid) {
+ fprintf(stderr, "can't fork\n");
+ return 1;
+ } else if (0 == pid) {
+ execlp("ls", "ls", "-laR", NULL);
+ _exit(128);
+ } else {
+ wait(NULL);
+ }
+ pid = fork();
+ if (-1 == pid) {
+ fprintf(stderr, "can't fork\n");
+ return 1;
+ } else if (0 == pid) {
+ execlp("rm", "rm", "-rf", "test_db", NULL);
+ _exit(127);
+ } else {
+ wait(NULL);
+ }
+ return 0;
+}
+
+#endif