From acdb4a71b94394b9e48d7ab9e408b9843b410924 Mon Sep 17 00:00:00 2001 From: "K. Lange" Date: Sat, 29 Jun 2019 20:36:48 +0900 Subject: [PATCH] libc: add realpath (with ToaruOS path mechanics; not Unix) --- base/usr/include/stdlib.h | 5 ++ libc/stdlib/realpath.c | 102 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 libc/stdlib/realpath.c diff --git a/base/usr/include/stdlib.h b/base/usr/include/stdlib.h index 613f0086..708d0c09 100644 --- a/base/usr/include/stdlib.h +++ b/base/usr/include/stdlib.h @@ -65,4 +65,9 @@ typedef struct { long int quot; long int rem; } ldiv_t; extern div_t div(int numerator, int denominator); extern ldiv_t ldiv(long numerator, long denominator); +/* These are supposed to be in limits, but gcc screwed us */ +#define PATH_MAX 4096 +#define NAME_MAX 255 +extern char *realpath(const char *path, char *resolved_path); + _End_C_Header diff --git a/libc/stdlib/realpath.c b/libc/stdlib/realpath.c new file mode 100644 index 00000000..dc8d13c3 --- /dev/null +++ b/libc/stdlib/realpath.c @@ -0,0 +1,102 @@ +#include +#include +#include +#include +#include +#include + +#ifndef __toaru__ +#undef realpath +#define realpath _realpath_toaru +#endif + +#define SYMLINK_MAX 5 + +static void _append_dir(char *out, char *element) { + strcat(out,"/"); + strcat(out,element); +} + +static void _remove_last(char * out) { + char * last = strrchr(out,'/'); + if (last) { + *last = '\0'; + } +} + +/** + * This is accurate to how we handle paths in ToaruOS. + * It's not correct for real symbolic link handling, + * so it needs some work for that. + */ +char *realpath(const char *path, char *resolved_path) { + /* + * Basically the same as what we do in the kernel for canonicalize_path + * but slightly more complicated because of the requirement to check + * symlinks... this is going to get interesting. + */ + if (!path) { + errno = -EINVAL; + return NULL; + } + + if (!resolved_path) { + /* Can't support this yet. */ + errno = -EINVAL; + return NULL; + } + + /* If we're lucky, we can do this with no allocations, so let's start here... */ + char working_path[PATH_MAX+1]; + memcpy(working_path, path, strlen(path)+1); + + *resolved_path = 0; + + if (working_path[0] != '/') { + /* Begin by retreiving the current working directory */ + char cwd[PATH_MAX+1]; + if (!getcwd(cwd, PATH_MAX)) { + /* Not actually sure if this is the right choice for this, but whatever. */ + errno = -ENOTDIR; + return NULL; + } + + char *save; + char *tok = strtok_r(cwd,"/",&save); + do { + _append_dir(resolved_path, tok); + } while ((tok = strtok_r(NULL,"/",&save))); + } + + char *save; + char *tok = strtok_r(working_path,"/",&save); + do { + if (!strcmp(tok,".")) continue; + if (!strcmp(tok,"..")) { + _remove_last(resolved_path); + continue; + } else { + _append_dir(resolved_path, tok); + } + } while ((tok = strtok_r(NULL,"/",&save))); + + if (resolved_path[0] == '\0') { + strcat(resolved_path,"/"); + } + + return resolved_path; +} + +#ifndef __toaru__ +int main(int argc, char * argv[]) { + char tmp[PATH_MAX+1]; + + if (!realpath(argv[1], tmp)) { + fprintf(stderr, "invalid path, errno=%d\n", errno); + return 1; + } + + fprintf(stderr, "%s=%s\n", argv[1], tmp); + return 0; +} +#endif