diff --git a/kernel/src/sys/chdir.cpp b/kernel/src/sys/chdir.cpp index 1991e5bb..7b32e575 100644 --- a/kernel/src/sys/chdir.cpp +++ b/kernel/src/sys/chdir.cpp @@ -36,3 +36,22 @@ Result sys_chdir(Registers*, SyscallArgs args) return 0; } } + +Result sys_getcwd(Registers*, SyscallArgs args) +{ + u8* buf = (u8*)args[0]; + usize size = (usize)args[1]; + + Thread* current = Scheduler::current(); + + StringView cwd = current->current_directory_path.view(); + if (cwd.is_empty()) cwd = "/"_sv; + + usize cwd_size = cwd.length() + 1; + + if (cwd_size > size) return cwd_size; + + if (!MemoryManager::copy_to_user(buf, cwd.chars(), cwd_size)) return err(EFAULT); + + return cwd_size; +} diff --git a/libc/include/unistd.h b/libc/include/unistd.h index 49379ff2..3d6cdcd7 100644 --- a/libc/include/unistd.h +++ b/libc/include/unistd.h @@ -100,6 +100,9 @@ extern "C" /* Change the current working directory. */ int chdir(const char* path); + /* Retrieve the current working directory. */ + char* getcwd(char* buf, size_t size); + #ifdef __cplusplus } #endif diff --git a/libc/src/unistd.cpp b/libc/src/unistd.cpp index 29b0c51c..60870e6a 100644 --- a/libc/src/unistd.cpp +++ b/libc/src/unistd.cpp @@ -235,4 +235,69 @@ extern "C" long rc = syscall(SYS_chdir, path); __errno_return(rc, int); } + + static ssize_t __getcwd_wrapper(char* buf, size_t size) + { + long rc = syscall(SYS_getcwd, buf, size); + __errno_return(rc, ssize_t); + } + + char* getcwd(char* buf, size_t size) + { + if (buf) + { + ssize_t rc = __getcwd_wrapper(buf, size); + if (rc < 0) return nullptr; + + if (rc > (ssize_t)size) + { + errno = ERANGE; + return nullptr; + } + + return buf; + } + else if (size) + { + buf = (char*)malloc(size); + if (!buf) return nullptr; + + ssize_t rc = __getcwd_wrapper(buf, size); + if (rc < 0) + { + free(buf); + return nullptr; + } + + if (rc > (ssize_t)size) + { + free(buf); + errno = ERANGE; + return nullptr; + } + + return buf; + } + else + { + buf = (char*)malloc(1024); + if (!buf) return nullptr; + + ssize_t rc = __getcwd_wrapper(buf, 1024); + if (rc < 0) + { + free(buf); + return nullptr; + } + + if (rc > 1024) + { + free(buf); + + return getcwd(NULL, rc); + } + + return buf; + } + } } diff --git a/libluna/include/luna/StringView.h b/libluna/include/luna/StringView.h index 3d8ff8df..dacdc572 100644 --- a/libluna/include/luna/StringView.h +++ b/libluna/include/luna/StringView.h @@ -16,6 +16,8 @@ class StringView StringView(const StringView&); + StringView& operator=(const StringView&); + Result to_string(); const char* chars() const diff --git a/libluna/include/luna/Syscall.h b/libluna/include/luna/Syscall.h index d01005a9..e9e95394 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(chdir) + _e(ioctl) _e(stat) _e(fstat) _e(chdir) _e(getcwd) enum Syscalls { diff --git a/libluna/src/StringView.cpp b/libluna/src/StringView.cpp index 664da077..ba9ef207 100644 --- a/libluna/src/StringView.cpp +++ b/libluna/src/StringView.cpp @@ -30,6 +30,16 @@ StringView::StringView(const char* c_str, usize length) m_length = length; } +StringView& StringView::operator=(const StringView& other) +{ + if (&other == this) return *this; + + m_string = other.m_string; + m_length = other.m_length; + + return *this; +} + const char& StringView::operator[](usize index) const { expect(index < m_length, "index out of range");