diff --git a/kernel/include/kernel/FS/Ext2/Inode.h b/kernel/include/kernel/FS/Ext2/Inode.h index dfcd24fd8d..10119f2783 100644 --- a/kernel/include/kernel/FS/Ext2/Inode.h +++ b/kernel/include/kernel/FS/Ext2/Inode.h @@ -37,6 +37,7 @@ namespace Kernel virtual BAN::ErrorOr read_impl(off_t, BAN::ByteSpan) override; virtual BAN::ErrorOr write_impl(off_t, BAN::ConstByteSpan) override; virtual BAN::ErrorOr truncate_impl(size_t) override; + virtual BAN::ErrorOr chmod_impl(mode_t) override; private: uint32_t fs_block_of_data_block_index(uint32_t data_block_index); diff --git a/kernel/include/kernel/FS/Inode.h b/kernel/include/kernel/FS/Inode.h index b13486bff6..d98d9fdbb1 100644 --- a/kernel/include/kernel/FS/Inode.h +++ b/kernel/include/kernel/FS/Inode.h @@ -99,6 +99,7 @@ namespace Kernel BAN::ErrorOr read(off_t, BAN::ByteSpan buffer); BAN::ErrorOr write(off_t, BAN::ConstByteSpan buffer); BAN::ErrorOr truncate(size_t); + BAN::ErrorOr chmod(mode_t); bool has_data() const; protected: @@ -115,6 +116,7 @@ namespace Kernel virtual BAN::ErrorOr read_impl(off_t, BAN::ByteSpan) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr write_impl(off_t, BAN::ConstByteSpan) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr truncate_impl(size_t) { return BAN::Error::from_errno(ENOTSUP); } + virtual BAN::ErrorOr chmod_impl(mode_t) { return BAN::Error::from_errno(ENOTSUP); } virtual bool has_data_impl() const { dwarnln("nonblock not supported"); return true; } private: diff --git a/kernel/include/kernel/FS/RamFS/Inode.h b/kernel/include/kernel/FS/RamFS/Inode.h index 75bd4a54ea..6119a4094f 100644 --- a/kernel/include/kernel/FS/RamFS/Inode.h +++ b/kernel/include/kernel/FS/RamFS/Inode.h @@ -56,6 +56,8 @@ namespace Kernel ASSERT((inode_info.mode & Inode::Mode::TYPE_MASK) == 0); } + virtual BAN::ErrorOr chmod_impl(mode_t) override; + protected: RamFileSystem& m_fs; FullInodeInfo m_inode_info; diff --git a/kernel/include/kernel/Process.h b/kernel/include/kernel/Process.h index 3421a72e61..6fde6a6918 100644 --- a/kernel/include/kernel/Process.h +++ b/kernel/include/kernel/Process.h @@ -97,6 +97,8 @@ namespace Kernel BAN::ErrorOr sys_read(int fd, void* buffer, size_t count); BAN::ErrorOr sys_write(int fd, const void* buffer, size_t count); + BAN::ErrorOr sys_chmod(const char*, mode_t); + BAN::ErrorOr sys_pipe(int fildes[2]); BAN::ErrorOr sys_dup(int fildes); BAN::ErrorOr sys_dup2(int fildes, int fildes2); diff --git a/kernel/kernel/FS/Ext2/Inode.cpp b/kernel/kernel/FS/Ext2/Inode.cpp index 2781e36e3d..85d306d281 100644 --- a/kernel/kernel/FS/Ext2/Inode.cpp +++ b/kernel/kernel/FS/Ext2/Inode.cpp @@ -242,6 +242,16 @@ namespace Kernel return {}; } + BAN::ErrorOr Ext2Inode::chmod_impl(mode_t mode) + { + ASSERT((mode & Inode::Mode::TYPE_MASK) == 0); + if (m_inode.mode == mode) + return {}; + m_inode.mode = (m_inode.mode & Inode::Mode::TYPE_MASK) | mode; + TRY(sync()); + return {}; + } + BAN::ErrorOr Ext2Inode::list_next_inodes_impl(off_t offset, DirectoryEntryList* list, size_t list_size) { ASSERT(mode().ifdir()); diff --git a/kernel/kernel/FS/Inode.cpp b/kernel/kernel/FS/Inode.cpp index b66369b49c..f846ba4e7e 100644 --- a/kernel/kernel/FS/Inode.cpp +++ b/kernel/kernel/FS/Inode.cpp @@ -129,6 +129,14 @@ namespace Kernel return truncate_impl(size); } + BAN::ErrorOr Inode::chmod(mode_t mode) + { + ASSERT((mode & Inode::Mode::TYPE_MASK) == 0); + LockGuard _(m_lock); + Thread::TerminateBlocker blocker(Thread::current()); + return chmod_impl(mode); + } + bool Inode::has_data() const { LockGuard _(m_lock); diff --git a/kernel/kernel/FS/RamFS/Inode.cpp b/kernel/kernel/FS/RamFS/Inode.cpp index 2b7f7ffee1..0492b00d62 100644 --- a/kernel/kernel/FS/RamFS/Inode.cpp +++ b/kernel/kernel/FS/RamFS/Inode.cpp @@ -26,6 +26,14 @@ namespace Kernel this->rdev = 0; } + + BAN::ErrorOr RamInode::chmod_impl(mode_t mode) + { + ASSERT((mode & Inode::Mode::TYPE_MASK) == 0); + m_inode_info.mode = (m_inode_info.mode & Inode::Mode::TYPE_MASK) | mode; + return {}; + } + /* RAM FILE INODE @@ -193,9 +201,9 @@ namespace Kernel { BAN::RefPtr inode; if (Mode(mode).ifreg()) - inode = TRY(RamFileInode::create(m_fs, mode, uid, gid)); + inode = TRY(RamFileInode::create(m_fs, mode & ~Inode::Mode::TYPE_MASK, uid, gid)); else if (Mode(mode).ifdir()) - inode = TRY(RamDirectoryInode::create(m_fs, ino(), mode, uid, gid)); + inode = TRY(RamDirectoryInode::create(m_fs, ino(), mode & ~Inode::Mode::TYPE_MASK, uid, gid)); else ASSERT_NOT_REACHED(); diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index 57180db24a..a2119eeedf 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -733,6 +733,21 @@ namespace Kernel return TRY(m_open_file_descriptors.write(fd, BAN::ByteSpan((uint8_t*)buffer, count))); } + BAN::ErrorOr Process::sys_chmod(const char* path, mode_t mode) + { + if (mode & S_IFMASK) + return BAN::Error::from_errno(EINVAL); + + LockGuard _(m_lock); + validate_string_access(path); + + auto absolute_path = TRY(absolute_path_of(path)); + auto file = TRY(VirtualFileSystem::get().file_from_absolute_path(m_credentials, absolute_path, O_WRONLY)); + TRY(file.inode->chmod(mode)); + + return 0; + } + BAN::ErrorOr Process::sys_pipe(int fildes[2]) { LockGuard _(m_lock); diff --git a/kernel/kernel/Syscall.cpp b/kernel/kernel/Syscall.cpp index 93f4c010a8..ccc9e8946e 100644 --- a/kernel/kernel/Syscall.cpp +++ b/kernel/kernel/Syscall.cpp @@ -199,6 +199,9 @@ namespace Kernel case SYS_POWEROFF: ret = Process::current().sys_poweroff((int)arg1); break; + case SYS_CHMOD: + ret = Process::current().sys_chmod((const char*)arg1, (mode_t)arg2); + break; default: dwarnln("Unknown syscall {}", syscall); break; diff --git a/libc/include/sys/syscall.h b/libc/include/sys/syscall.h index 797f8475be..c5a51817f9 100644 --- a/libc/include/sys/syscall.h +++ b/libc/include/sys/syscall.h @@ -55,6 +55,7 @@ __BEGIN_DECLS #define SYS_MUNMAP 52 #define SYS_TTY_CTRL 53 #define SYS_POWEROFF 54 +#define SYS_CHMOD 55 __END_DECLS diff --git a/libc/sys/stat.cpp b/libc/sys/stat.cpp index 457e65ab67..09b6140d30 100644 --- a/libc/sys/stat.cpp +++ b/libc/sys/stat.cpp @@ -4,6 +4,11 @@ #include #include +int chmod(const char* path, mode_t mode) +{ + return syscall(SYS_CHMOD, path, mode); +} + int fstat(int fildes, struct stat* buf) { return syscall(SYS_FSTAT, fildes, buf);