From 417e50575013313536db31969e295f65cb70c82b Mon Sep 17 00:00:00 2001 From: apio Date: Wed, 12 Apr 2023 18:11:36 +0200 Subject: [PATCH] kernel+libc: Add unlink(), rmdir(), remove() --- kernel/CMakeLists.txt | 1 + kernel/src/fs/VFS.h | 27 ++++++++++++++++++++ kernel/src/fs/tmpfs/FileSystem.cpp | 16 ++++++++++++ kernel/src/fs/tmpfs/FileSystem.h | 39 ++++++++++++++++++++++++++++ kernel/src/sys/link.cpp | 32 +++++++++++++++++++++++ libc/CMakeLists.txt | 2 +- libc/include/stdio.h | 3 +++ libc/include/unistd.h | 6 +++++ libc/src/stdio.cpp | 6 +++++ libc/src/unistd.cpp | 13 ++++++++++ libluna/include/luna/Syscall.h | 2 +- libluna/include/luna/Vector.h | 41 +++++++++++++++++++++++++----- 12 files changed, 179 insertions(+), 9 deletions(-) create mode 100644 kernel/src/sys/link.cpp diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index dc378736..725e5957 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -36,6 +36,7 @@ set(SOURCES src/sys/getdents.cpp src/sys/stat.cpp src/sys/chdir.cpp + src/sys/link.cpp src/fs/VFS.cpp src/fs/tmpfs/FileSystem.cpp src/fs/devices/DeviceRegistry.cpp diff --git a/kernel/src/fs/VFS.h b/kernel/src/fs/VFS.h index e9d9231e..d86395a2 100644 --- a/kernel/src/fs/VFS.h +++ b/kernel/src/fs/VFS.h @@ -43,6 +43,10 @@ namespace VFS virtual Result add_entry(SharedPtr inode, const char* name) = 0; + virtual Result remove_entry(const char* name) = 0; + + virtual usize entries() const = 0; + // File-specific methods virtual Result read(u8* buf, usize offset, usize length) const = 0; @@ -67,6 +71,9 @@ namespace VFS return 0; } + virtual void did_link() = 0; + virtual void did_unlink() = 0; + // Metadata changers virtual Result chmod(mode_t mode) = 0; @@ -110,6 +117,16 @@ namespace VFS return err(ENOTDIR); } + Result remove_entry(const char*) override + { + return err(ENOTDIR); + } + + usize entries() const override + { + return 0; + } + bool blocking() const override { return false; @@ -151,6 +168,16 @@ namespace VFS return err(ENOTDIR); } + Result remove_entry(const char*) override + { + return err(ENOTDIR); + } + + usize entries() const override + { + return 0; + } + InodeType type() const override { return InodeType::Device; diff --git a/kernel/src/fs/tmpfs/FileSystem.cpp b/kernel/src/fs/tmpfs/FileSystem.cpp index 7d1ece2f..d441be44 100644 --- a/kernel/src/fs/tmpfs/FileSystem.cpp +++ b/kernel/src/fs/tmpfs/FileSystem.cpp @@ -79,6 +79,22 @@ namespace TmpFS TRY(m_entries.try_append(move(entry))); + inode->did_link(); + + return {}; + } + + Result DirInode::remove_entry(const char* name) + { + SharedPtr inode = TRY(find(name)); + + if (inode->type() == VFS::InodeType::Directory && inode->entries() != 2) return err(ENOTEMPTY); + + m_entries.remove_first_matching( + [&](const VFS::DirectoryEntry& entry) { return !strcmp(entry.name.chars(), name); }); + + inode->did_unlink(); + return {}; } diff --git a/kernel/src/fs/tmpfs/FileSystem.h b/kernel/src/fs/tmpfs/FileSystem.h index 8061c3d0..52b61883 100644 --- a/kernel/src/fs/tmpfs/FileSystem.h +++ b/kernel/src/fs/tmpfs/FileSystem.h @@ -96,6 +96,16 @@ namespace TmpFS return {}; } + void did_link() override + { + m_nlinks++; + } + + void did_unlink() override + { + m_nlinks--; + } + virtual ~FileInode() = default; private: @@ -105,6 +115,7 @@ namespace TmpFS mode_t m_mode; u32 m_uid { 0 }; u32 m_gid { 0 }; + u32 m_nlinks { 0 }; }; class DeviceInode : public VFS::DeviceInode @@ -196,6 +207,16 @@ namespace TmpFS return {}; } + void did_link() override + { + m_nlinks++; + } + + void did_unlink() override + { + m_nlinks--; + } + virtual ~DeviceInode() = default; private: @@ -205,6 +226,7 @@ namespace TmpFS mode_t m_mode; u32 m_uid { 0 }; u32 m_gid { 0 }; + u32 m_nlinks { 0 }; }; class DirInode : public VFS::Inode @@ -298,6 +320,23 @@ namespace TmpFS return VFS::InodeType::Directory; } + void did_link() override + { + } + + void did_unlink() override + { + m_self = {}; + m_entries.clear(); + } + + usize entries() const override + { + return m_entries.size(); + } + + Result remove_entry(const char* name) override; + Result> create_file(const char* name) override; Result> create_subdirectory(const char* name) override; diff --git a/kernel/src/sys/link.cpp b/kernel/src/sys/link.cpp new file mode 100644 index 00000000..ccbc8919 --- /dev/null +++ b/kernel/src/sys/link.cpp @@ -0,0 +1,32 @@ +#include "memory/MemoryManager.h" +#include "sys/Syscall.h" +#include "thread/Scheduler.h" +#include + +Result sys_unlink(Registers*, SyscallArgs args) +{ + auto path = TRY(MemoryManager::strdup_from_user(args[0])); + int flags = (int)args[1]; + + Thread* current = Scheduler::current(); + + PathParser parser = TRY(PathParser::create(path.chars())); + + auto dirname = TRY(parser.dirname()); + auto basename = TRY(parser.basename()); + + if (basename.view() == ".") return err(EINVAL); + + auto inode = TRY(VFS::resolve_path(dirname.chars(), current->auth, current->current_directory)); + if (!VFS::can_write(inode, current->auth)) return err(EACCES); + + if (flags > 0) + { + auto child = TRY(inode->find(basename.chars())); + if (child->type() != VFS::InodeType::Directory) return err(ENOTDIR); + } + + TRY(inode->remove_entry(basename.chars())); + + return 0; +} diff --git a/libc/CMakeLists.txt b/libc/CMakeLists.txt index 83015d48..e3f9374d 100644 --- a/libc/CMakeLists.txt +++ b/libc/CMakeLists.txt @@ -53,7 +53,7 @@ add_custom_target(libc COMMAND ${CMAKE_AR} -x $ COMMAND ${CMAKE_AR} -x $ COMMAND ${CMAKE_AR} -rcs ${CMAKE_CURRENT_BINARY_DIR}/libc.a *.o - COMMAND rm *.o + COMMAND /usr/bin/rm *.o WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} DEPENDS bare_libc luna crt0 ) diff --git a/libc/include/stdio.h b/libc/include/stdio.h index e5b49797..d8515bcf 100644 --- a/libc/include/stdio.h +++ b/libc/include/stdio.h @@ -128,6 +128,9 @@ extern "C" /* Write an error message to standard error. */ void perror(const char* s); + /* Remove a file from the filesystem. */ + int remove(const char* path); + #ifdef __cplusplus } #endif diff --git a/libc/include/unistd.h b/libc/include/unistd.h index 3d6cdcd7..cc699a89 100644 --- a/libc/include/unistd.h +++ b/libc/include/unistd.h @@ -103,6 +103,12 @@ extern "C" /* Retrieve the current working directory. */ char* getcwd(char* buf, size_t size); + /* Remove a name from the filesystem. */ + int unlink(const char* path); + + /* Remove a directory from the filesystem. */ + int rmdir(const char* path); + #ifdef __cplusplus } #endif diff --git a/libc/src/stdio.cpp b/libc/src/stdio.cpp index 1a2469f9..c0f66379 100644 --- a/libc/src/stdio.cpp +++ b/libc/src/stdio.cpp @@ -336,6 +336,12 @@ extern "C" if (s && *s) fprintf(stderr, "%s: ", s); fprintf(stderr, "%s\n", strerror(err)); } + + int remove(const char* path) + { + // On Luna, unlink() allows removal of directories. + return unlink(path); + } } void debug_log_impl(const char* format, va_list ap) diff --git a/libc/src/unistd.cpp b/libc/src/unistd.cpp index 60870e6a..8521a7f2 100644 --- a/libc/src/unistd.cpp +++ b/libc/src/unistd.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -300,4 +301,16 @@ extern "C" return buf; } } + + int unlink(const char* path) + { + long rc = syscall(SYS_unlink, path, 0); + __errno_return(rc, int); + } + + int rmdir(const char* path) + { + long rc = syscall(SYS_unlink, path, 1); + __errno_return(rc, int); + } } diff --git a/libluna/include/luna/Syscall.h b/libluna/include/luna/Syscall.h index e9e95394..48305f72 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(getcwd) + _e(ioctl) _e(stat) _e(fstat) _e(chdir) _e(getcwd) _e(unlink) enum Syscalls { diff --git a/libluna/include/luna/Vector.h b/libluna/include/luna/Vector.h index 27c12aac..76175703 100644 --- a/libluna/include/luna/Vector.h +++ b/libluna/include/luna/Vector.h @@ -111,13 +111,7 @@ template class Vector { if (m_size == 0) return {}; - T item = move(m_data[0]); - - m_size--; - - memmove(m_data, m_data + 1, m_size * sizeof(T)); - - return move(item); + return remove_at(0); } const T& operator[](usize index) const @@ -177,8 +171,41 @@ template class Vector return m_size; } + T remove_at(usize index) + { + check(index < m_size); + + T item = move(m_data[index]); + + memmove(m_data + index, m_data + (index + 1), (m_size - (index + 1)) * sizeof(T)); + + m_size--; + + return move(item); + } + + template Option remove_first_matching(Callback callback) + { + Option index = {}; + + for (usize i = 0; i < m_size; i++) + { + if (callback(m_data[i])) + { + index = i; + break; + } + } + + if (!index.has_value()) return {}; + + return remove_at(index.value()); + } + void clear() { + for (usize i = 0; i < m_size; i++) { m_data[i].~T(); } + m_size = m_capacity = 0; free_impl(m_data); m_data = nullptr;