diff options
Diffstat (limited to 'src/db.c')
| -rw-r--r-- | src/db.c | 166 |
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 |
