summaryrefslogtreecommitdiff
path: root/kernel/fs/vfs.c
diff options
context:
space:
mode:
authorAnton Kling <anton@kling.gg>2023-11-16 22:55:30 +0100
committerAnton Kling <anton@kling.gg>2023-11-16 22:55:30 +0100
commit6723c96863425bda541e321127f6944bf008446a (patch)
treecb2836166dfe819e9942fdb87a6ce41cb684061c /kernel/fs/vfs.c
parenta288258785bac3c2000227532f4a17210813c506 (diff)
VFS: Do canonicalization of the current working directory
Diffstat (limited to 'kernel/fs/vfs.c')
-rw-r--r--kernel/fs/vfs.c64
1 files changed, 50 insertions, 14 deletions
diff --git a/kernel/fs/vfs.c b/kernel/fs/vfs.c
index 2347369..d0c1b95 100644
--- a/kernel/fs/vfs.c
+++ b/kernel/fs/vfs.c
@@ -125,25 +125,61 @@ vfs_inode_t *vfs_internal_open(const char *file) {
return ret;
}
-char *vfs_clean_path(const char *path, char *resolved_path) {
- char *clean = resolved_path;
- int prev_slash = 0;
- char *ptr = clean;
+// Does canonicalization of absolute paths
+int vfs_clean_path(const char *path, char *result) {
+ // It has to be a absolute path
+ if ('/' != *path)
+ return 0;
+ const char *result_start = result;
+ int start_directory = 0;
+ int should_insert_slash = 0;
for (; *path; path++) {
- if (prev_slash && '/' == *path) {
- continue;
+ if (start_directory) {
+ start_directory = 0;
+ if ('/' == *path) {
+ path++;
+ } else if (0 == memcmp(path, "./", 2) || 0 == memcmp(path, ".\0", 2)) {
+ path++;
+ } else if (0 == memcmp(path, "../", 3) || 0 == memcmp(path, "..\0", 3)) {
+ path += 2;
+ if (result_start + 2 > result) {
+ // The path is probably something like "/.." or
+ // "/../foo". A "/.." should become a "/"
+ // Therefore it skips going back to the parent
+ if (*path == '/') {
+ if (result_start == result)
+ return 0;
+ result--;
+ }
+ } else {
+ if ('/' != *path) {
+ should_insert_slash = 1;
+ }
+ result--;
+ result--;
+ for (; result_start <= result && '/' != *result; result--)
+ ;
+ }
+ }
}
- prev_slash = ('/' == *path);
- *ptr = *path;
- ptr++;
+ start_directory = ('/' == *path);
+ if ('\0' == *path)
+ break;
+ *result = *path;
+ result++;
+ }
+ if (should_insert_slash) {
+ *result = '/';
+ result++;
}
- *ptr = '\0';
- return clean;
+ *result = '\0';
+ return 1;
}
char *vfs_resolve_path(const char *file, char *resolved_path) {
if ('/' == *file) {
- return vfs_clean_path(file, resolved_path);
+ assert(vfs_clean_path(file, resolved_path));
+ return resolved_path;
}
const char *cwd = get_current_task()->current_working_directory;
size_t l = strlen(cwd);
@@ -152,8 +188,8 @@ char *vfs_resolve_path(const char *file, char *resolved_path) {
char r[256];
strcpy(r, cwd);
strcat(r, file);
- char *final = vfs_clean_path(r, resolved_path);
- return final;
+ assert(vfs_clean_path(r, resolved_path));
+ return resolved_path;
}
int vfs_fstat(int fd, struct stat *buf) {