diff options
author | dzwdz | 2022-08-08 19:04:27 +0200 |
---|---|---|
committer | dzwdz | 2022-08-08 19:04:27 +0200 |
commit | f2703089da21898e9c3127615e98c1717c7ceeb5 (patch) | |
tree | d4a80164a20b34cbf594e72d758708be23c0e6e1 /src/user/lib | |
parent | a4634ea9458fcc4856ad52bcf383efcb9134091f (diff) |
user/libc: cwd
Diffstat (limited to 'src/user/lib')
-rw-r--r-- | src/user/lib/file.c | 41 | ||||
-rw-r--r-- | src/user/lib/include/unistd.h | 9 | ||||
-rw-r--r-- | src/user/lib/stdlib.c | 84 |
3 files changed, 120 insertions, 14 deletions
diff --git a/src/user/lib/file.c b/src/user/lib/file.c index 942b522..080217c 100644 --- a/src/user/lib/file.c +++ b/src/user/lib/file.c @@ -18,7 +18,11 @@ FILE *fopen(const char *path, const char *mode) { FILE *f; handle_t h; int flags = 0; - if (path && path[0] == '!') { + char *tmppath = NULL; + if (!path) { + errno = -1; + return NULL; + } else if (path[0] == '!') { /* special handling for "!files" */ path++; if (!strcmp(path, "stdin")) return file_clone(stdin, mode); @@ -26,23 +30,32 @@ FILE *fopen(const char *path, const char *mode) { if (!strcmp(path, "stderr")) return file_clone(stderr, mode); errno = -1; return NULL; - } else { - if (mode[0] == 'w' || mode[0] == 'a') - flags |= OPEN_CREATE; + } - h = _syscall_open(path, strlen(path), flags); - if (h < 0) { - errno = -h; - return NULL; - } + if (path && path[0] != '/') { + size_t len = absolutepath(NULL, path, 0); + tmppath = malloc(len); + if (!tmppath) return NULL; + absolutepath(tmppath, path, len); + path = tmppath; + } - if (mode[0] == 'w') - _syscall_write(h, NULL, 0, 0, WRITE_TRUNCATE); + if (mode[0] == 'w' || mode[0] == 'a') + flags |= OPEN_CREATE; - f = fdopen(h, mode); - if (!f) close(h); - return f; + h = _syscall_open(path, strlen(path), flags); + if (tmppath) free(tmppath); + if (h < 0) { + errno = -h; + return NULL; } + + if (mode[0] == 'w') + _syscall_write(h, NULL, 0, 0, WRITE_TRUNCATE); + + f = fdopen(h, mode); + if (!f) close(h); + return f; } FILE *freopen(const char *path, const char *mode, FILE *f) { diff --git a/src/user/lib/include/unistd.h b/src/user/lib/include/unistd.h index 4f367ca..aedca1b 100644 --- a/src/user/lib/include/unistd.h +++ b/src/user/lib/include/unistd.h @@ -6,3 +6,12 @@ int close(handle_t h); _Noreturn void exit(int); int execv(const char *path, char *const argv[]); + +int chdir(const char *path); +char *getcwd(char *buf, size_t size); +/* Converts a relative path to an absolute one, simplifying it if possible. + * If in == NULL - return the length of cwd (without a trailing slash) + * If size isn't enough to fit the path, returns the amount of bytes needed to fit + * it, including the null byte. + * @return 0 on failure, length of the path otherwise */ +size_t absolutepath(char *out, const char *in, size_t size); diff --git a/src/user/lib/stdlib.c b/src/user/lib/stdlib.c index 94e12d3..566eb3e 100644 --- a/src/user/lib/stdlib.c +++ b/src/user/lib/stdlib.c @@ -1,6 +1,8 @@ +#include <camellia/path.h> #include <camellia/syscalls.h> #include <errno.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> #include <unistd.h> #include <user/lib/elfload.h> @@ -49,3 +51,85 @@ int execv(const char *path, char *const argv[]) { _Noreturn void abort(void) { _syscall_exit(1); } + + +static char *cwd = NULL, *cwd2 = NULL; +static size_t cwdcapacity = 0; + +int chdir(const char *path) { + handle_t h; + char *tmp; + size_t len = absolutepath(NULL, path, 0) + 1; /* +1 for the trailing slash */ + if (cwdcapacity < len) { + cwdcapacity = len; + if (cwd) { + cwd = realloc(cwd, len); + cwd2 = realloc(cwd2, len); + } else { + cwd = malloc(len); + cwd[0] = '/'; + cwd[1] = '\0'; + cwd2 = malloc(len); + cwd2[0] = '/'; + cwd2[1] = '\0'; + } + } + absolutepath(cwd2, path, cwdcapacity); + len = strlen(cwd2); + if (cwd2[len - 1] != '/') { + cwd2[len] = '/'; + cwd2[len + 1] = '\0'; + } + + h = _syscall_open(cwd2, strlen(cwd2), 0); + if (h < 0) { + errno = ENOENT; + return -1; + } + _syscall_close(h); + + tmp = cwd; + cwd = cwd2; + cwd2 = tmp; + return 0; +} + +char *getcwd(char *buf, size_t size) { + const char *realcwd = cwd ? cwd : "/"; + // TODO bounds checking + memcpy(buf, realcwd, strlen(realcwd) + 1); + return buf; +} + +size_t absolutepath(char *out, const char *in, size_t size) { + const char *realcwd = cwd ? cwd : "/"; + size_t len, pos = 0; + if (!in) return strlen(realcwd); + + if (!(in[0] == '/')) { + len = strlen(realcwd); + if (pos + len <= size && out != realcwd) + memcpy(out + pos, realcwd, len); + pos += len; + + if (realcwd[len - 1] != '/') { + if (pos + 1 <= size) out[pos] = '/'; + pos++; + } + } + + len = strlen(in); + if (pos + len <= size) + memcpy(out + pos, in, len); + pos += len; + + if (pos <= size) { + pos = path_simplify(out, out, pos); + if (pos > 0) out[pos] = '\0'; + } + + if (pos + 1 <= size) out[pos] = '\0'; + pos++; + + return pos; +} |