From 9ee6421e1b6fbabdbfb3ab0846c3294ff262020f Mon Sep 17 00:00:00 2001 From: Florian Fischer Date: Fri, 19 Jan 2024 14:55:01 +0100 Subject: [PATCH 1/6] fs: add callbacks to change file attributes --- mentos/inc/fs/vfs_types.h | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/mentos/inc/fs/vfs_types.h b/mentos/inc/fs/vfs_types.h index edd97f8..aa36d56 100644 --- a/mentos/inc/fs/vfs_types.h +++ b/mentos/inc/fs/vfs_types.h @@ -18,6 +18,9 @@ /// Forward declaration of the VFS file. typedef struct vfs_file_t vfs_file_t; +/// Forward declaration of the inode attributes. +struct iattr; + /// Function used to create a directory. typedef int (*vfs_mkdir_callback)(const char *, mode_t); /// Function used to remove a directory. @@ -48,6 +51,10 @@ typedef int (*vfs_ioctl_callback)(vfs_file_t *, int, void *); typedef int (*vfs_symlink_callback)(const char *, const char *); /// Function that reads the symbolic link data associated with a file. typedef ssize_t (*vfs_readlink_callback)(vfs_file_t *, char *, size_t); +/// Function used to modify the attributes of an fs entry. +typedef int (*vfs_setattr_callback)(const char *, struct iattr *); +/// Function used to modify the attributes of a file. +typedef int (*vfs_fsetattr_callback)(vfs_file_t *, struct iattr *); /// @brief Filesystem information. typedef struct file_system_type { @@ -71,6 +78,8 @@ typedef struct vfs_sys_operations_t { vfs_creat_callback creat_f; /// Symbolic link creation function. vfs_symlink_callback symlink_f; + /// Modifies the attributes of a file. + vfs_setattr_callback setattr_f; } vfs_sys_operations_t; /// @brief Set of functions used to perform operations on files. @@ -95,6 +104,8 @@ typedef struct vfs_file_operations_t { vfs_getdents_callback getdents_f; /// Reads the symbolik link data. vfs_readlink_callback readlink_f; + /// Modifies the attributes of a file. + vfs_fsetattr_callback setattr_f; } vfs_file_operations_t; /// @brief Data structure that contains information about the mounted filesystems. @@ -162,3 +173,30 @@ typedef struct vfs_file_descriptor_t { /// Flags for file opening modes. int flags_mask; } vfs_file_descriptor_t; + +/// @brief Data structure containing attributes of a file. +struct iattr { + unsigned int ia_valid; + mode_t ia_mode; + uid_t ia_uid; + gid_t ia_gid; + uint32_t ia_atime; + uint32_t ia_mtime; + uint32_t ia_ctime; +}; + +#define ATTR_MODE (1 << 0) +#define ATTR_UID (1 << 1) +#define ATTR_GID (1 << 2) +#define ATTR_ATIME (1 << 3) +#define ATTR_MTIME (1 << 4) +#define ATTR_CTIME (1 << 5) + +#define IATTR_CHOWN(user, group) \ + { .ia_valid = ATTR_UID | ATTR_GID, \ + .ia_uid = user, \ + .ia_gid = group } + +#define IATTR_CHMOD(mode) \ + { .ia_valid = ATTR_MODE, \ + .ia_mode = mode } From 61024ac3f3f2054c375eefb96ace6e5a36bc554a Mon Sep 17 00:00:00 2001 From: Florian Fischer Date: Fri, 19 Jan 2024 14:56:29 +0100 Subject: [PATCH 2/6] add *chmod, and *chown syscalls --- doc/syscall.md | 8 +-- libc/CMakeLists.txt | 2 + libc/inc/sys/unistd.h | 38 ++++++++++ libc/src/unistd/chmod.c | 12 ++++ libc/src/unistd/chown.c | 14 ++++ mentos/CMakeLists.txt | 1 + mentos/inc/fs/attr.h | 16 +++++ mentos/src/fs/attr.c | 137 ++++++++++++++++++++++++++++++++++++ mentos/src/system/syscall.c | 11 +-- 9 files changed, 230 insertions(+), 9 deletions(-) create mode 100644 libc/src/unistd/chmod.c create mode 100644 libc/src/unistd/chown.c create mode 100644 mentos/inc/fs/attr.h create mode 100644 mentos/src/fs/attr.c diff --git a/doc/syscall.md b/doc/syscall.md index 1769c76..96f9663 100644 --- a/doc/syscall.md +++ b/doc/syscall.md @@ -30,8 +30,8 @@ If the column is empty it means that it's not implemented yet. 2 | 12 | sys_chdir | process/process.c | const char * | - | - | - | - | 2 | 13 | sys_time | klib/time.c | int * | - | - | - | - | | 14 | sys_mknod | | const char * | int | dev_t | - | - | - | 15 | sys_chmod | | const char * | mode_t | - | - | - | - | 16 | sys_lchown | | const char * | uid_t | gid_t | - | - | + 1 | 15 | sys_chmod | fs/attr.c | const char * | mode_t | - | - | - | + | 16 | sys_lchown | fs/attr.c | const char * | uid_t | gid_t | - | - | 2 | 18 | sys_stat | fs/stat.c | char * | struct __old_kernel_stat * | - | - | - | 2 | 19 | sys_lseek | fs/read_write.c | unsigned int | off_t | unsigned int | - | - | 2 | 20 | sys_getpid | process/scheduler.c | - | - | - | - | - | @@ -101,7 +101,7 @@ If the column is empty it means that it's not implemented yet. | 92 | sys_truncate | | const char * | unsigned long | - | - | - | | 93 | sys_ftruncate | | unsigned int | unsigned long | - | - | - | | 94 | sys_fchmod | | unsigned int | mode_t | - | - | - | - | 95 | sys_fchown | | unsigned int | uid_t | gid_t | - | - | + 1 | 95 | sys_fchown | fs/attr.c | unsigned int | uid_t | gid_t | - | - | | 96 | sys_getpriority | | int | int | - | - | - | | 97 | sys_setpriority | | int | int | int | - | - | | 99 | sys_statfs | | const char * | struct statfs * | - | - | - | @@ -186,7 +186,7 @@ If the column is empty it means that it's not implemented yet. | 179 | sys_rt_sigsuspend | | sigset_t * | size_t | - | - | - | | 180 | sys_pread | | unsigned int | char * | size_t | loff_t | - | | 181 | sys_pwrite | | unsigned int | const char * | size_t | loff_t | - | - | 182 | sys_chown | | const char * | uid_t | gid_t | - | - | + 1 | 182 | sys_chown | vfs/attr.c | const char * | uid_t | gid_t | - | - | 1 | 183 | sys_getcwd | process/process.c | char * | unsigned long | - | - | - | | 184 | sys_capget | | cap_user_header_t | cap_user_data_t | - | - | - | | 185 | sys_capset | | cap_user_header_t | const cap_user_data_t | - | - | - | diff --git a/libc/CMakeLists.txt b/libc/CMakeLists.txt index b0a247d..964ed96 100644 --- a/libc/CMakeLists.txt +++ b/libc/CMakeLists.txt @@ -33,6 +33,8 @@ add_library( ${CMAKE_SOURCE_DIR}/libc/src/sys/utsname.c ${CMAKE_SOURCE_DIR}/libc/src/sys/mman.c ${CMAKE_SOURCE_DIR}/libc/src/sys/ioctl.c + ${CMAKE_SOURCE_DIR}/libc/src/unistd/chmod.c + ${CMAKE_SOURCE_DIR}/libc/src/unistd/chown.c ${CMAKE_SOURCE_DIR}/libc/src/unistd/creat.c ${CMAKE_SOURCE_DIR}/libc/src/unistd/getppid.c ${CMAKE_SOURCE_DIR}/libc/src/unistd/getpid.c diff --git a/libc/inc/sys/unistd.h b/libc/inc/sys/unistd.h index af2a5a8..5809eb0 100644 --- a/libc/inc/sys/unistd.h +++ b/libc/inc/sys/unistd.h @@ -288,3 +288,41 @@ int dup(int fd); /// previous request would have generated a SIGALRM signal. Otherwise, alarm() /// shall return 0. unsigned alarm(int seconds); + +/// @brief Change the file's mode bits. +/// @param pathname The pathname of the file to change mode. +/// @param mode The mode bits to set. +/// @return On success, 0 is returned. +/// On error, -1 is returned, and errno is set appropriately. +int chmod(const char *pathname, mode_t mode); + +/// @brief Change the file's mode bits. +/// @param fd The fd pointing to the opened file. +/// @param mode The mode bits to set. +/// @return On success, 0 is returned. +/// On error, -1 is returned, and errno is set appropriately. +int fchmod(int fd, mode_t mode); + +/// @brief Change the owner and group of a file. +/// @param pathname The pathname of the file to change. +/// @param owner The new owner to set. +/// @param owner The new group to set. +/// @return On success, 0 is returned. +/// On error, -1 is returned, and errno is set appropriately. +int chown(const char *pathname, uid_t owner, gid_t group); + +/// @brief Change the owner and group of a file. +/// @param fd The fd pointing to the opened file. +/// @param owner The new owner to set. +/// @param owner The new group to set. +/// @return On success, 0 is returned. +/// On error, -1 is returned, and errno is set appropriately. +int fchown(int fd, uid_t owner, gid_t group); + +/// @brief Change the owner and group of a file. +/// @param pathname The pathname of the file to change. +/// @param owner The new owner to set. +/// @param owner The new group to set. +/// @return On success, 0 is returned. +/// On error, -1 is returned, and errno is set appropriately. +int lchown(const char *pathname, uid_t owner, gid_t group); diff --git a/libc/src/unistd/chmod.c b/libc/src/unistd/chmod.c new file mode 100644 index 0000000..4a16fb4 --- /dev/null +++ b/libc/src/unistd/chmod.c @@ -0,0 +1,12 @@ +/// @file chmod.c +/// @brief +/// @copyright (c) 2024 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "sys/unistd.h" +#include "sys/errno.h" +#include "system/syscall_types.h" + +_syscall2(int, chmod, const char *, pathname, mode_t, mode) + +_syscall2(int, fchmod, int, fd, mode_t, mode) diff --git a/libc/src/unistd/chown.c b/libc/src/unistd/chown.c new file mode 100644 index 0000000..580607c --- /dev/null +++ b/libc/src/unistd/chown.c @@ -0,0 +1,14 @@ +/// @file chown.c +/// @brief +/// @copyright (c) 2024 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "sys/unistd.h" +#include "sys/errno.h" +#include "system/syscall_types.h" + +_syscall3(int, chown, const char *, pathname, uid_t, owner, gid_t, group) + +_syscall3(int, lchown, const char *, pathname, uid_t, owner, gid_t, group) + +_syscall3(int, fchown, int, fd, uid_t, owner, gid_t, group) diff --git a/mentos/CMakeLists.txt b/mentos/CMakeLists.txt index d3cabf2..2080460 100644 --- a/mentos/CMakeLists.txt +++ b/mentos/CMakeLists.txt @@ -38,6 +38,7 @@ set(KERNEL_SOURCES ${CMAKE_SOURCE_DIR}/mentos/src/drivers/ps2.c ${CMAKE_SOURCE_DIR}/mentos/src/drivers/keyboard/keyboard.c ${CMAKE_SOURCE_DIR}/mentos/src/drivers/keyboard/keymap.c + ${CMAKE_SOURCE_DIR}/mentos/src/fs/attr.c ${CMAKE_SOURCE_DIR}/mentos/src/fs/vfs.c ${CMAKE_SOURCE_DIR}/mentos/src/fs/read_write.c ${CMAKE_SOURCE_DIR}/mentos/src/fs/open.c diff --git a/mentos/inc/fs/attr.h b/mentos/inc/fs/attr.h new file mode 100644 index 0000000..384d450 --- /dev/null +++ b/mentos/inc/fs/attr.h @@ -0,0 +1,16 @@ +/// @file attr.h +/// @brief change file attributes +/// @copyright (c) 2024 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "stddef.h" + +int sys_chown(const char* path, uid_t owner, gid_t group); + +int sys_lchown(const char* path, uid_t owner, gid_t group); + +int sys_fchown(int fd, uid_t owner, gid_t group); + +int sys_chmod(const char* path, mode_t mode); + +int sys_fchmod(int fd, mode_t mode); diff --git a/mentos/src/fs/attr.c b/mentos/src/fs/attr.c new file mode 100644 index 0000000..59dec27 --- /dev/null +++ b/mentos/src/fs/attr.c @@ -0,0 +1,137 @@ +/// @file attr.c +/// @brief change file attributes +/// @copyright (c) 2014-2024 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include "libgen.h" +#include "process/scheduler.h" +#include "fcntl.h" +#include "fs/vfs.h" +#include "io/debug.h" +#include "limits.h" +#include "process/process.h" +#include "stdio.h" +#include "string.h" +#include "sys/errno.h" +#include "system/printk.h" +#include "system/syscall.h" + +static int __setattr(const char *path, struct iattr* attr, bool_t follow_links) { + // Allocate a variable for the path. + char absolute_path[PATH_MAX]; + if (!realpath(path, absolute_path, sizeof(absolute_path))) { + pr_err("sys_chown(%s): Cannot get the absolute path.", path); + return -ENOENT; + } + + super_block_t *sb = vfs_get_superblock(absolute_path); + if (sb == NULL) { + pr_err("do_chown(%s): Cannot find the superblock!\n", absolute_path); + return -ENOENT; + } + vfs_file_t *sb_root = sb->root; + if (sb_root == NULL) { + pr_err("do_chown(%s): Cannot find the superblock root!\n", absolute_path); + return -ENOENT; + } + + // TODO: resolve links + + // Check if the function is implemented. + if (sb_root->sys_operations->setattr_f == NULL) { + pr_err("setattr(%s): Function not supported in current filesystem.", absolute_path); + return -ENOSYS; + } + return sb_root->sys_operations->setattr_f(absolute_path, attr); +} + +static inline void __iattr_set_owner_or_group(struct iattr *attr, uid_t owner, gid_t group) { + if (owner != -1) { + attr->ia_valid |= ATTR_UID; + attr->ia_uid = owner; + } + if (group != -1) { + attr->ia_valid |= ATTR_GID; + attr->ia_gid = group; + } +} + +int sys_chown(const char* path, uid_t owner, gid_t group) { + struct iattr attr = {0}; + __iattr_set_owner_or_group(&attr, owner, group); + return __setattr(path, &attr, true); +} + +int sys_lchown(const char* path, uid_t owner, gid_t group) { + struct iattr attr = {0}; + __iattr_set_owner_or_group(&attr, owner, group); + return __setattr(path, &attr, false); +} + +int sys_fchown(int fd, uid_t owner, gid_t group) { + task_struct *task = scheduler_get_current_process(); + + // Check the current FD. + if (fd < 0 || fd >= task->max_fd) { + return -EBADF; + } + + // Get the file. + vfs_file_t *file = task->fd_list[fd].file_struct; + if (file == NULL) { + return -EBADF; + } + + if (!(task->uid == 0) || (task->uid == file->uid)) { + return -EPERM; + } + + if (owner != -1) { + file->uid = owner; + } + + if (group != -1) { + file->gid = group; + } + + if (file->fs_operations->setattr_f == NULL) { + pr_err("No setattr function found for the current filesystem.\n"); + return -ENOSYS; + } + struct iattr attr = {0}; + __iattr_set_owner_or_group(&attr, owner, group); + return file->fs_operations->setattr_f(file, &attr); +} + +int sys_chmod(const char* path, mode_t mode) { + struct iattr attr = IATTR_CHMOD(mode); + return __setattr(path, &attr, true); +} + +int sys_fchmod(int fd, mode_t mode) { + task_struct *task = scheduler_get_current_process(); + + // Check the current FD. + if (fd < 0 || fd >= task->max_fd) { + return -EBADF; + } + + // Get the file. + vfs_file_t *file = task->fd_list[fd].file_struct; + if (file == NULL) { + return -EBADF; + } + + if (!(task->uid == 0) || (task->uid == file->uid)) { + return -EPERM; + } + + file->mask &= 0xFFFFFFFF & mode; + + if (file->fs_operations->setattr_f == NULL) { + pr_err("No setattr function found for the current filesystem.\n"); + return -ENOSYS; + } + struct iattr attr = IATTR_CHMOD(mode); + return file->fs_operations->setattr_f(file, &attr); +} diff --git a/mentos/src/system/syscall.c b/mentos/src/system/syscall.c index 9613cbe..900abc1 100644 --- a/mentos/src/system/syscall.c +++ b/mentos/src/system/syscall.c @@ -13,6 +13,7 @@ #include "descriptor_tables/isr.h" #include "devices/fpu.h" +#include "fs/attr.h" #include "fs/vfs.h" #include "fs/ioctl.h" #include "hardware/timer.h" @@ -70,8 +71,8 @@ void syscall_init(void) sys_call_table[__NR_chdir] = (SystemCall)sys_chdir; sys_call_table[__NR_time] = (SystemCall)sys_time; sys_call_table[__NR_mknod] = (SystemCall)sys_ni_syscall; - sys_call_table[__NR_chmod] = (SystemCall)sys_ni_syscall; - sys_call_table[__NR_lchown] = (SystemCall)sys_ni_syscall; + sys_call_table[__NR_chmod] = (SystemCall)sys_chmod; + sys_call_table[__NR_lchown] = (SystemCall)sys_lchown; sys_call_table[__NR_stat] = (SystemCall)sys_stat; sys_call_table[__NR_lseek] = (SystemCall)sys_lseek; sys_call_table[__NR_getpid] = (SystemCall)sys_getpid; @@ -140,8 +141,8 @@ void syscall_init(void) sys_call_table[__NR_munmap] = (SystemCall)sys_munmap; sys_call_table[__NR_truncate] = (SystemCall)sys_ni_syscall; sys_call_table[__NR_ftruncate] = (SystemCall)sys_ni_syscall; - sys_call_table[__NR_fchmod] = (SystemCall)sys_ni_syscall; - sys_call_table[__NR_fchown] = (SystemCall)sys_ni_syscall; + sys_call_table[__NR_fchmod] = (SystemCall)sys_fchmod; + sys_call_table[__NR_fchown] = (SystemCall)sys_fchown; sys_call_table[__NR_getpriority] = (SystemCall)sys_ni_syscall; sys_call_table[__NR_setpriority] = (SystemCall)sys_ni_syscall; sys_call_table[__NR_statfs] = (SystemCall)sys_ni_syscall; @@ -226,7 +227,7 @@ void syscall_init(void) sys_call_table[__NR_rt_sigsuspend] = (SystemCall)sys_ni_syscall; sys_call_table[__NR_pread] = (SystemCall)sys_ni_syscall; sys_call_table[__NR_pwrite] = (SystemCall)sys_ni_syscall; - sys_call_table[__NR_chown] = (SystemCall)sys_ni_syscall; + sys_call_table[__NR_chown] = (SystemCall)sys_chown; sys_call_table[__NR_getcwd] = (SystemCall)sys_getcwd; sys_call_table[__NR_capget] = (SystemCall)sys_ni_syscall; sys_call_table[__NR_capset] = (SystemCall)sys_ni_syscall; From 761abc0172eb86db23142f1bca247a2f8b63367d Mon Sep 17 00:00:00 2001 From: Florian Fischer Date: Sat, 20 Jan 2024 12:42:20 +0100 Subject: [PATCH 3/6] add simple chown program --- programs/CMakeLists.txt | 1 + programs/chown.c | 65 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 programs/chown.c diff --git a/programs/CMakeLists.txt b/programs/CMakeLists.txt index 82c711f..6c7bd88 100644 --- a/programs/CMakeLists.txt +++ b/programs/CMakeLists.txt @@ -1,5 +1,6 @@ # List of programs. set(PROGRAM_LIST + chown.c id.c stat.c false.c diff --git a/programs/chown.c b/programs/chown.c new file mode 100644 index 0000000..d94c2b8 --- /dev/null +++ b/programs/chown.c @@ -0,0 +1,65 @@ +/// @file chown.c +/// @brief change file ownership +/// @copyright (c) 2024 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + char *idptr; + char *saveptr; + char *endptr; + uid_t uid = -1; + gid_t gid = -1; + passwd_t *pwd; + group_t *grp; + + if (argc != 3) { + fprintf(STDERR_FILENO, "%s: [OWNER][:[GROUP]] FILE\n", argv[0]); + exit(EXIT_FAILURE); + } + + idptr = strtok_r(argv[1], ":", &saveptr); + if (argv[1][0] != ':') { /* Skip the username */ + uid = strtol(idptr, &endptr, 10); /* Allow a numeric string */ + if (*endptr != '\0') { /* Was not pure numeric string */ + pwd = getpwnam(idptr); /* Try getting UID for username */ + if (pwd == NULL) { + fprintf(STDERR_FILENO, "%s: invalid user: %s\n", argv[0], idptr); + exit(EXIT_FAILURE); + } + + uid = pwd->pw_uid; + } + idptr = strtok_r(NULL, ":", &saveptr); + } + + if (idptr != NULL) { + gid = strtol(idptr, &endptr, 10); /* Allow a numeric string */ + if (*endptr != '\0') { /* Was not pure numeric string */ + grp = getgrnam(idptr); /* Try getting GID for groupname */ + if (grp == NULL) { + fprintf(STDERR_FILENO, "%s: invalid group: %s\n", argv[0], idptr); + exit(EXIT_FAILURE); + } + + gid = grp->gr_gid; + } + } + + if (chown(argv[2], uid, gid) == -1) { + fprintf(STDERR_FILENO, "%s: changing ownership of %s: %s\n", + argv[0], argv[2], strerror(errno)); + exit(EXIT_FAILURE); + } + + exit(EXIT_SUCCESS); +} From 548feeaf7d4978daeb700e5b37c649bbdff41ee8 Mon Sep 17 00:00:00 2001 From: Florian Fischer Date: Sat, 20 Jan 2024 13:05:43 +0100 Subject: [PATCH 4/6] add simple chmod implementation --- programs/CMakeLists.txt | 1 + programs/chmod.c | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 programs/chmod.c diff --git a/programs/CMakeLists.txt b/programs/CMakeLists.txt index 6c7bd88..6eb1fa1 100644 --- a/programs/CMakeLists.txt +++ b/programs/CMakeLists.txt @@ -1,5 +1,6 @@ # List of programs. set(PROGRAM_LIST + chmod.c chown.c id.c stat.c diff --git a/programs/chmod.c b/programs/chmod.c new file mode 100644 index 0000000..aeee2bf --- /dev/null +++ b/programs/chmod.c @@ -0,0 +1,37 @@ +/// @file chmod.c +/// @brief change file permissions +/// @copyright (c) 2024 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + mode_t mode = 0; + char *endptr; + gid_t gid = -1; + + if (argc != 3) { + fprintf(STDERR_FILENO, "%s: MODE FILE\n", argv[0]); + exit(EXIT_FAILURE); + } + + mode = strtol(argv[1], &endptr, 8); + if (*endptr != '\0') { + fprintf(STDERR_FILENO, "%s: invalid mode: '%s'\n", argv[0], argv[1]); + exit(EXIT_FAILURE); + } + + if (chmod(argv[2], mode) == -1) { + fprintf(STDERR_FILENO, "%s: changing permissions of %s: %s\n", + argv[0], argv[2], strerror(errno)); + exit(EXIT_FAILURE); + } + + exit(EXIT_SUCCESS); +} From f4f57e075052882ede67916c0d7a149fabc2c242 Mon Sep 17 00:00:00 2001 From: Florian Fischer Date: Fri, 26 Jan 2024 13:33:44 +0100 Subject: [PATCH 5/6] ext2: implement setattr support This adds support for chown and chmod on etx2 filesystems. --- mentos/src/fs/ext2.c | 105 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/mentos/src/fs/ext2.c b/mentos/src/fs/ext2.c index c23c8b9..f12973f 100644 --- a/mentos/src/fs/ext2.c +++ b/mentos/src/fs/ext2.c @@ -379,10 +379,12 @@ static int ext2_fstat(vfs_file_t *file, stat_t *stat); static int ext2_ioctl(vfs_file_t *file, int request, void *data); static ssize_t ext2_getdents(vfs_file_t *file, dirent_t *dirp, off_t doff, size_t count); static ssize_t ext2_readlink(vfs_file_t *file, char *buffer, size_t bufsize); +static int ext2_fsetattr(vfs_file_t *file, struct iattr *attr); static int ext2_mkdir(const char *path, mode_t mode); static int ext2_rmdir(const char *path); static int ext2_stat(const char *path, stat_t *stat); +static int ext2_setattr(const char *path, struct iattr *attr); static vfs_file_t *ext2_creat(const char *path, mode_t permission); static vfs_file_t *ext2_mount(vfs_file_t *block_device, const char *path); @@ -397,6 +399,7 @@ static vfs_sys_operations_t ext2_sys_operations = { .stat_f = ext2_stat, .creat_f = ext2_creat, .symlink_f = NULL, + .setattr_f = ext2_setattr, }; /// Filesystem file operations. @@ -411,6 +414,7 @@ static vfs_file_operations_t ext2_fs_operations = { .ioctl_f = ext2_ioctl, .getdents_f = ext2_getdents, .readlink_f = ext2_readlink, + .setattr_f = ext2_fsetattr, }; // ============================================================================ @@ -3011,6 +3015,107 @@ static int ext2_stat(const char *path, stat_t *stat) return __ext2_stat(&inode, stat); } +/// @brief Sets the attributes of an inode and saves it +/// @param inode The inode to set the attributes +/// @param stat The structure where the attributes are stored. +/// @return 0 if success. +static int __ext2_setattr(ext2_inode_t *inode, struct iattr *attr) +{ + if (attr->ia_valid & ATTR_MODE) { + inode->mode = (inode->mode & ~0xfff) | attr->ia_mode; + } + if (attr->ia_valid & ATTR_UID) { + inode->uid = attr->ia_uid; + } + if (attr->ia_valid & ATTR_GID) { + inode->gid = attr->ia_gid; + } + if (attr->ia_valid & ATTR_ATIME) { + inode->atime = attr->ia_atime; + } + if (attr->ia_valid & ATTR_MTIME) { + inode->mtime = attr->ia_mtime; + } + if (attr->ia_valid & ATTR_CTIME) { + inode->ctime = attr->ia_ctime; + } + return 0; +} + +static int __ext2_check_setattr_permission(uid_t file_owner) { + task_struct *task = scheduler_get_current_process(); + return task->uid == 0 || task->uid == file_owner; +} + +/// @brief Set attributes of the file at the given position. +/// @param file The file struct. +/// @param stat The structure where the attributes are stored. +/// @return 0 if success. +static int ext2_fsetattr(vfs_file_t *file, struct iattr *attr) +{ + if (!__ext2_check_setattr_permission(file->uid)) { + return -EPERM; + } + // Get the filesystem. + ext2_filesystem_t *fs = (ext2_filesystem_t *)file->device; + if (fs == NULL) { + pr_err("The file does not belong to an EXT2 filesystem `%s`.\n", file->name); + return -EPERM; + } + // Get the inode associated with the file. + ext2_inode_t inode; + if (ext2_read_inode(fs, &inode, file->ino) == -1) { + pr_err("Failed to read the inode `%s`.\n", file->name); + return -ENOENT; + } + + __ext2_setattr(&inode, attr); + return ext2_write_inode(fs, &inode, file->ino); +} + +/// @brief Set attributes of a file +/// @param path The path where the file resides. +/// @param stat The structure where the information are stored. +/// @return 0 if success. +static int ext2_setattr(const char *path, struct iattr *attr) +{ + pr_debug("ext2_setattr(%s, %p)\n", path, stat); + // Get the absolute path. + char absolute_path[PATH_MAX]; + // If the first character is not the '/' then get the absolute path. + if (!realpath(path, absolute_path, sizeof(absolute_path))) { + pr_err("Cannot get the absolute path for path `%s`.\n", path); + return -ENOENT; + } + // Get the EXT2 filesystem. + ext2_filesystem_t *fs = get_ext2_filesystem(absolute_path); + if (fs == NULL) { + pr_err("Failed to get the EXT2 filesystem for absolute path `%s`.\n", absolute_path); + return -ENOENT; + } + // Prepare the structure for the direntry. + ext2_dirent_t direntry; + memset(&direntry, 0, sizeof(ext2_dirent_t)); + // Resolve the path. + if (ext2_resolve_path_direntry(fs->root, absolute_path, &direntry)) { + pr_err("Failed to resolve path `%s`.\n", absolute_path); + return -ENOENT; + } + // Get the inode associated with the directory entry. + ext2_inode_t inode; + if (ext2_read_inode(fs, &inode, direntry.inode) == -1) { + pr_err("ext2_stat(%s): Failed to read the inode of `%s`.\n", path, direntry.name); + return -ENOENT; + } + + if (!__ext2_check_setattr_permission(inode.uid)) { + return -EPERM; + } + + __ext2_setattr(&inode, attr); + return ext2_write_inode(fs, &inode, direntry.inode); +} + /// @brief Mounts the block device as an EXT2 filesystem. /// @param block_device the block device formatted as EXT2. /// @return the VFS root node of the EXT2 filesystem. From 2ab2dd8a11d38eb3c7454c3eeaaaa49e036a439c Mon Sep 17 00:00:00 2001 From: Florian Fischer Date: Tue, 13 Feb 2024 12:49:29 +0100 Subject: [PATCH 6/6] add manual pages for chown and chmod --- files/usr/share/man/chmod.man | 22 ++++++++++++++++++++++ files/usr/share/man/chown.man | 19 +++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 files/usr/share/man/chmod.man create mode 100644 files/usr/share/man/chown.man diff --git a/files/usr/share/man/chmod.man b/files/usr/share/man/chmod.man new file mode 100644 index 0000000..882692c --- /dev/null +++ b/files/usr/share/man/chmod.man @@ -0,0 +1,22 @@ +SYNOPSIS + chmod MODE FILE + +DESCRIPTION + chmod changes the file mode bits of the given file according to mode, which + must be an octal number representing the bit pattern for the new mode bits. + + The numeric mode is from one to four octal digits (0-7), derived by adding + up the bits with values 4, 2, and 1. Omitted digits are assumed to be + leading zeros. The first digit selects the set user ID (4) and set group + ID (2) and restricted deletion or sticky (1) attributes. The second digit + selects permissions for the user who owns the file: read (4), write (2), + and execute (1); the third selects permissions for other users in the file's + group, with the same values; and the fourth for other users not in the + file's group, with the same values. + + chmod never changes the permissions of symbolic links; the chmod system call + cannot change their permissions. + +EXAMPLES + chmod 555 executable + Changes the mode bits of executable to r-xr-xr-x. diff --git a/files/usr/share/man/chown.man b/files/usr/share/man/chown.man new file mode 100644 index 0000000..511b5da --- /dev/null +++ b/files/usr/share/man/chown.man @@ -0,0 +1,19 @@ +SYNOPSIS + chown [OWNER][:[GROUP]] FILE + +DESCRIPTION + chown changes the user and/or group ownership of the given file. + If only a owner is given the file's group is not changed. If the owner + is followed by a colon and a group name (or numeric group ID), the group + ownership is changed as well. If the colon and group are given, but the + owner is omitted, only the group of the file is changed. + + chown never changes the ownership of symbolic links; the chown system call + cannot change their ownership. + +EXAMPLES + chown root /u + Change the owner of /u to "root". + + chown root:staff /u + Likewise, but also change its group to "staff".