From 2a967f4b8b1ab477e344a156f57460f128c10612 Mon Sep 17 00:00:00 2001 From: apio Date: Tue, 11 Apr 2023 22:15:21 +0200 Subject: [PATCH] kernel+libc: Add chdir() --- kernel/CMakeLists.txt | 1 + kernel/src/sys/chdir.cpp | 38 +++++++++++++++++++++++++ libc/include/unistd.h | 3 ++ libc/src/unistd.cpp | 6 ++++ libluna/include/luna/PathParser.h | 11 +++++++- libluna/include/luna/Syscall.h | 2 +- libluna/src/PathParser.cpp | 46 +++++++++++++++++++++++++++++++ 7 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 kernel/src/sys/chdir.cpp diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index b46efcc5..dc378736 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -35,6 +35,7 @@ set(SOURCES src/sys/waitpid.cpp src/sys/getdents.cpp src/sys/stat.cpp + src/sys/chdir.cpp src/fs/VFS.cpp src/fs/tmpfs/FileSystem.cpp src/fs/devices/DeviceRegistry.cpp diff --git a/kernel/src/sys/chdir.cpp b/kernel/src/sys/chdir.cpp new file mode 100644 index 00000000..1991e5bb --- /dev/null +++ b/kernel/src/sys/chdir.cpp @@ -0,0 +1,38 @@ +#include "memory/MemoryManager.h" +#include "sys/Syscall.h" +#include "thread/Scheduler.h" +#include + +Result sys_chdir(Registers*, SyscallArgs args) +{ + auto path = TRY(MemoryManager::strdup_from_user(args[0])); + + Thread* current = Scheduler::current(); + + if (PathParser::is_absolute(path.view())) + { + SharedPtr inode = TRY(VFS::resolve_path(path.chars(), current->auth)); + + if (inode->type() != VFS::InodeType::Directory) return err(ENOTDIR); + + current->current_directory = inode; + current->current_directory_path = move(path); + + return 0; + } + else + { + SharedPtr inode = TRY(VFS::resolve_path(path.chars(), current->auth, current->current_directory)); + + if (inode->type() != VFS::InodeType::Directory) return err(ENOTDIR); + + auto old_wdir = current->current_directory_path.view(); + + String new_path = TRY(PathParser::join(old_wdir.is_empty() ? "/"_sv : old_wdir, path.view())); + + current->current_directory = inode; + current->current_directory_path = move(new_path); + + return 0; + } +} diff --git a/libc/include/unistd.h b/libc/include/unistd.h index a8c1bcfc..49379ff2 100644 --- a/libc/include/unistd.h +++ b/libc/include/unistd.h @@ -97,6 +97,9 @@ extern "C" /* Duplicate a file descriptor. */ int dup(int fd); + /* Change the current working directory. */ + int chdir(const char* path); + #ifdef __cplusplus } #endif diff --git a/libc/src/unistd.cpp b/libc/src/unistd.cpp index 845f0235..29b0c51c 100644 --- a/libc/src/unistd.cpp +++ b/libc/src/unistd.cpp @@ -229,4 +229,10 @@ extern "C" { return fcntl(fd, F_DUPFD, 0); } + + int chdir(const char* path) + { + long rc = syscall(SYS_chdir, path); + __errno_return(rc, int); + } } diff --git a/libluna/include/luna/PathParser.h b/libluna/include/luna/PathParser.h index 44e9fbb9..cf6de4c0 100644 --- a/libluna/include/luna/PathParser.h +++ b/libluna/include/luna/PathParser.h @@ -11,11 +11,20 @@ class PathParser PathParser(PathParser&& other); PathParser(const PathParser&) = delete; + static Result join(StringView path1, StringView path2); + + static Result realpath(StringView path); + + static bool is_absolute(StringView path) + { + return *path.chars() == '/'; + } + ~PathParser(); bool is_absolute() const { - return *m_original == '/'; + return is_absolute(StringView { m_original }); } Result basename(); diff --git a/libluna/include/luna/Syscall.h b/libluna/include/luna/Syscall.h index 00eb17dc..d01005a9 100644 --- a/libluna/include/luna/Syscall.h +++ b/libluna/include/luna/Syscall.h @@ -4,7 +4,7 @@ _e(exit) _e(clock_gettime) _e(mmap) _e(munmap) _e(usleep) _e(open) _e(close) _e(read) _e(getpid) _e(write) \ _e(lseek) _e(mkdir) _e(execve) _e(mknod) _e(fork) _e(waitpid) _e(getppid) _e(fcntl) _e(getdents) _e(getuid) \ _e(geteuid) _e(getgid) _e(getegid) _e(setuid) _e(setgid) _e(seteuid) _e(setegid) _e(chmod) _e(chown) \ - _e(ioctl) _e(stat) _e(fstat) + _e(ioctl) _e(stat) _e(fstat) _e(chdir) enum Syscalls { diff --git a/libluna/src/PathParser.cpp b/libluna/src/PathParser.cpp index 6ae26b7c..3ddd8f4c 100644 --- a/libluna/src/PathParser.cpp +++ b/libluna/src/PathParser.cpp @@ -1,6 +1,7 @@ #include #include #include +#include Result PathParser::create(const char* path) { @@ -59,3 +60,48 @@ Result PathParser::dirname() // We must copy this as we cannot rely on the original string. return String::from_cstring(result); } + +Result PathParser::join(StringView path1, StringView path2) +{ + StringBuilder sb; + TRY(sb.add(path1)); + + if (path1[path1.length() - 1] != '/') TRY(sb.add('/')); + + TRY(sb.add(path2)); + + String result = TRY(sb.string()); + + return realpath(result.view()); +} + +Result PathParser::realpath(StringView path) +{ + if (!is_absolute(path)) return String {}; + + Vector parts; + PathParser parser = TRY(PathParser::create(path.chars())); + + const char* part; + while (parser.next().try_set_value(part)) + { + StringView view = part; + if (view == ".") continue; + if (view == "..") + { + parts.try_pop(); + continue; + } + + TRY(parts.try_append(view)); + } + + StringBuilder sb; + for (const auto& section : parts) + { + TRY(sb.add('/')); + TRY(sb.add(section)); + } + + return sb.string(); +}