From 761e76c552484296fc5146ed8086a8c379d30adf Mon Sep 17 00:00:00 2001 From: Enrico Fraccaroli Date: Fri, 5 Apr 2024 14:58:43 +0200 Subject: [PATCH 01/40] Remove file after running the test in `t_creat` --- programs/tests/t_creat.c | 44 +++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/programs/tests/t_creat.c b/programs/tests/t_creat.c index 0589adb9..638e29ef 100644 --- a/programs/tests/t_creat.c +++ b/programs/tests/t_creat.c @@ -11,27 +11,29 @@ #include #include -int main(int argc, char* argv[]) { - int fd = creat("foo", 0660); - if (fd < 0) { - printf("creat: foo: %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } - if (write(fd, "foo", 3) != 3) { - printf("write: foo: %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } +int main(int argc, char *argv[]) +{ + int fd = creat("foo", 0660); + if (fd < 0) { + printf("creat: foo: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + if (write(fd, "foo", 3) != 3) { + printf("write: foo: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } - struct stat_t st; - if (stat("foo", &st) < 0) { - printf("stat: foo: %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } + struct stat_t st; + if (stat("foo", &st) < 0) { + printf("stat: foo: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } - if (st.st_size != 3) { - printf("Wrong file size. (expected: 3, is: %u)\n", st.st_size); - exit(EXIT_FAILURE); - } - - return 0; + if (st.st_size != 3) { + printf("Wrong file size. (expected: 3, is: %u)\n", st.st_size); + exit(EXIT_FAILURE); + } + // Remove the file. + unlink("foo"); + return 0; } From 2ce3415e6b0a0b0a42a94706a71886d687a1316e Mon Sep 17 00:00:00 2001 From: Enrico Fraccaroli Date: Fri, 5 Apr 2024 18:07:21 +0200 Subject: [PATCH 02/40] Add more comments --- libc/inc/sys/unistd.h | 6 +++--- mentos/inc/fs/vfs.h | 22 +++++++++++--------- mentos/inc/fs/vfs_types.h | 43 +++++++++++++++++++++++++-------------- mentos/src/drivers/ps2.c | 19 +++++++++++++++++ mentos/src/drivers/rtc.c | 20 +++++++++++++++++- mentos/src/elf/elf.c | 12 ++++++----- mentos/src/fs/vfs.c | 10 --------- 7 files changed, 88 insertions(+), 44 deletions(-) diff --git a/libc/inc/sys/unistd.h b/libc/inc/sys/unistd.h index 5809eb03..d7b0e328 100644 --- a/libc/inc/sys/unistd.h +++ b/libc/inc/sys/unistd.h @@ -306,7 +306,7 @@ 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. +/// @param group 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); @@ -314,7 +314,7 @@ 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. +/// @param group 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); @@ -322,7 +322,7 @@ 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. +/// @param group 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/mentos/inc/fs/vfs.h b/mentos/inc/fs/vfs.h index a022dc7e..b84003c4 100644 --- a/mentos/inc/fs/vfs.h +++ b/mentos/inc/fs/vfs.h @@ -38,18 +38,18 @@ int vfs_register_filesystem(file_system_type *fs); int vfs_unregister_filesystem(file_system_type *fs); /// @brief Given an absolute path to a file, vfs_open_abspath() returns a file struct, used to access the file. -/// @param abspath An absolute path to a file. -/// @param flags Used to set the file status flags and file access modes of the open file description. -/// @param mode Specifies the file mode bits be applied when a new file is created. +/// @param absolute_path An absolute path to a file. +/// @param flags Used to set the file status flags and file access modes of the open file description. +/// @param mode Specifies the file mode bits be applied when a new file is created. /// @return Returns a file struct, or NULL. -vfs_file_t *vfs_open_abspath(const char *pathname, int flags, mode_t mode); +vfs_file_t *vfs_open_abspath(const char *absolute_path, int flags, mode_t mode); /// @brief Given a pathname for a file, vfs_open() returns a file struct, used to access the file. -/// @param pathname A pathname for a file. -/// @param flags Used to set the file status flags and file access modes of the open file description. -/// @param mode Specifies the file mode bits be applied when a new file is created. +/// @param path A pathname for a file. +/// @param flags Used to set the file status flags and file access modes of the open file description. +/// @param mode Specifies the file mode bits be applied when a new file is created. /// @return Returns a file struct, or NULL. -vfs_file_t *vfs_open(const char *pathname, int flags, mode_t mode); +vfs_file_t *vfs_open(const char *path, int flags, mode_t mode); /// @brief Decreases the number of references to a given file, if the /// references number reaches 0, close the file. @@ -199,13 +199,15 @@ int vfs_destroy_task(struct task_struct *task); /// @return -errno on fail, fd on success. int get_unused_fd(void); + /// @brief Return new smallest available file desriptor. +/// @param fd the descriptor of the file we want to duplicate. /// @return -errno on fail, fd on success. int sys_dup(int fd); -/// @brief Check if the requested open flags against the file mask +/// @brief Check if the requested open flags against the file mask. /// @param flags The requested open flags. -/// @param mode The permissions of the file. +/// @param mask The permissions of the file. /// @param uid The owner of the task opening the file. /// @param gid The group of the task opening the file. /// @return 0 on fail, 1 on success. diff --git a/mentos/inc/fs/vfs_types.h b/mentos/inc/fs/vfs_types.h index aa36d563..2a46a03b 100644 --- a/mentos/inc/fs/vfs_types.h +++ b/mentos/inc/fs/vfs_types.h @@ -176,27 +176,40 @@ typedef struct vfs_file_descriptor_t { /// @brief Data structure containing attributes of a file. struct iattr { + /// Validity check on iattr struct. unsigned int ia_valid; + /// Access mode. mode_t ia_mode; + /// Owner uid. uid_t ia_uid; + /// Owner gid. gid_t ia_gid; + /// Time of last access. uint32_t ia_atime; + /// Time of last data modification. uint32_t ia_mtime; + /// Time of last status change. 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 } +#define ATTR_MODE (1 << 0) ///< Flag set to specify the validity of MODE. +#define ATTR_UID (1 << 1) ///< Flag set to specify the validity of UID. +#define ATTR_GID (1 << 2) ///< Flag set to specify the validity of GID. +#define ATTR_ATIME (1 << 3) ///< Flag set to specify the validity of ATIME. +#define ATTR_MTIME (1 << 4) ///< Flag set to specify the validity of MTIME. +#define ATTR_CTIME (1 << 5) ///< Flag set to specify the validity of CTIME. + +/// Used to initialize an iattr inside the chown function. +#define IATTR_CHOWN(user, group) \ + { \ + .ia_valid = ATTR_UID | ATTR_GID, \ + .ia_uid = (user), \ + .ia_gid = (group) \ + } + +/// Used to initialize an iattr inside the chmod function. +#define IATTR_CHMOD(mode) \ + { \ + .ia_valid = ATTR_MODE, \ + .ia_mode = (mode) \ + } diff --git a/mentos/src/drivers/ps2.c b/mentos/src/drivers/ps2.c index 5cb6d0e7..dc89e50f 100644 --- a/mentos/src/drivers/ps2.c +++ b/mentos/src/drivers/ps2.c @@ -73,60 +73,79 @@ unsigned char ps2_read(void) return inportb(PS2_DATA); } +/// @brief Writes the given command to the PS2 port. +/// @param command the command to write. static inline void __ps2_write_command(unsigned char command) { __ps2_wait_write(); outportb(PS2_COMMAND, command); } +/// @brief Reads the PS2 controller status. +/// @return the PS2 controller status. static inline unsigned char __ps2_get_controller_status(void) { __ps2_write_command(0x20); return ps2_read(); } +/// @brief Sets the PS2 controller status. +/// @param status the PS2 controller status. static inline void __ps2_set_controller_status(unsigned char status) { __ps2_write_command(0x60); ps2_write(status); } +/// @brief Checks if the PS2 controller is dual channel. +/// @return 1 if dual channel, 0 otherwise. static inline int __ps2_is_dual_channel(void) { return bit_check(__ps2_get_controller_status(), 6) != 0; } +/// @brief Enables the first PS2 port. static inline void __ps2_enable_first_port(void) { __ps2_write_command(PS2_CTRL_P1_ENABLE); } +/// @brief Enables the second PS2 port. static inline void __ps2_enable_second_port(void) { __ps2_write_command(PS2_CTRL_P2_ENABLE); } +/// @brief Disables the first PS2 port. static inline void __ps2_disable_first_port(void) { __ps2_write_command(PS2_CTRL_P1_DISABLE); } +/// @brief Disables the second PS2 port. static inline void __ps2_disable_second_port(void) { __ps2_write_command(PS2_CTRL_P2_DISABLE); } +/// @brief Writes on the first PS2 port. +/// @param byte the value to write. static inline void __ps2_write_first_port(unsigned char byte) { ps2_write(byte); } +/// @brief Writes on the second PS2 port. +/// @param byte the value to write. static inline void __ps2_write_second_port(unsigned char byte) { __ps2_write_command(0xD4); ps2_write(byte); } +/// @brief Returns the string describing the received response. +/// @param response the response received from the PS2 device. +/// @return the string describing the received response. static const char *__ps2_get_response_error_message(unsigned response) { if (response == 0x01) { diff --git a/mentos/src/drivers/rtc.c b/mentos/src/drivers/rtc.c index 43c72e37..c441c4f6 100644 --- a/mentos/src/drivers/rtc.c +++ b/mentos/src/drivers/rtc.c @@ -28,6 +28,10 @@ tm_t previous_global_time; /// Data type is BCD. int is_bcd; +/// @brief Checks if the two time values are different. +/// @param t0 the first time value. +/// @param t1 the second time value. +/// @return 1 if they are different, 0 otherwise. static inline unsigned int rtc_are_different(tm_t *t0, tm_t *t1) { if (t0->tm_sec != t1->tm_sec) { return 1; } @@ -41,30 +45,41 @@ static inline unsigned int rtc_are_different(tm_t *t0, tm_t *t1) } /// @brief Check if rtc is updating time currently. +/// @return 1 if RTC is updating, 0 otherwise. static inline unsigned int is_updating_rtc(void) { outportb(CMOS_ADDR, 0x0A); uint32_t status = inportb(CMOS_DATA); - return (status & 0x80U); + return (status & 0x80U) != 0; } +/// @brief Reads the given register. +/// @param reg the register to read. +/// @return the value we read. static inline unsigned char read_register(unsigned char reg) { outportb(CMOS_ADDR, reg); return inportb(CMOS_DATA); } +/// @brief Writes on the given register. +/// @param reg the register on which we need to write. +/// @param value the value we want to write. static inline void write_register(unsigned char reg, unsigned char value) { outportb(CMOS_ADDR, reg); outportb(CMOS_DATA, value); } +/// @brief Transforms a Binary-Coded Decimal (BCD) to decimal. +/// @param bcd the BCD value. +/// @return the decimal value. static inline unsigned char bcd2bin(unsigned char bcd) { return ((bcd >> 4u) * 10) + (bcd & 0x0Fu); } +/// @brief Reads the current datetime value from a real-time clock. static inline void rtc_read_datetime(void) { if (read_register(0x0Cu) & 0x10u) { @@ -88,6 +103,7 @@ static inline void rtc_read_datetime(void) } } +/// @brief Updates the internal datetime value. static inline void rtc_update_datetime(void) { static unsigned int first_update = 1; @@ -108,6 +124,8 @@ static inline void rtc_update_datetime(void) } } +/// @brief Callback for RTC. +/// @param f the current registers. static inline void rtc_handler_isr(pt_regs *f) { rtc_update_datetime(); diff --git a/mentos/src/elf/elf.c b/mentos/src/elf/elf.c index ea82b1f7..7bdb928c 100644 --- a/mentos/src/elf/elf.c +++ b/mentos/src/elf/elf.c @@ -48,7 +48,6 @@ static inline elf_program_header_t *elf_get_program_header_table(elf_header_t *h /// @brief Returns a pointer to the desired section header. /// @param header a pointer to the ELF header. /// @param idx The index of the section header. -/// @param shdr Where we store the content we read. /// @return a pointer to the desired section header. static inline elf_section_header_t *elf_get_section_header(elf_header_t *header, unsigned idx) { @@ -79,9 +78,10 @@ static inline const char *elf_get_section_header_string_table(elf_header_t *head return (const char *)((uintptr_t)header + elf_get_section_header(header, header->shstrndx)->offset); } -/// @brief Returns a pointer to the section header string table. +/// @brief Returns a pointer to the section header symbol table. /// @param header a pointer to the ELF header. -/// @return a pointer to the section header string table, or NULL on failure. +/// @param section_header a pointer to the ELF section header. +/// @return a pointer to the section header symbol table, or NULL on failure. static inline const char *elf_get_symbol_string_table(elf_header_t *header, elf_section_header_t *section_header) { if (section_header->link == SHT_NULL) { @@ -94,9 +94,9 @@ static inline const char *elf_get_symbol_string_table(elf_header_t *header, elf_ // GET ELF OBJECTS NAME // ============================================================================ -/// @brief Returns the name of the given entry in the section header string table. +/// @brief Returns the name of the given section header. /// @param header a pointer to the ELF header. -/// @param name_offset the offset where the desired name resides inside the table. +/// @param section_header a pointer to the section header. /// @return a pointer to the name, or NULL on failure. static inline const char *elf_get_section_header_name(elf_header_t *header, elf_section_header_t *section_header) { @@ -109,6 +109,8 @@ static inline const char *elf_get_section_header_name(elf_header_t *header, elf_ /// @brief Returns a pointer to the section header string table. /// @param header a pointer to the ELF header. +/// @param section_header a pointer to the section header. +/// @param symbol a pointer to the symbol we want to get the name for. /// @return a pointer to the section header string table, or NULL on failure. static inline const char *elf_get_symbol_name(elf_header_t *header, elf_section_header_t *section_header, elf_symbol_t *symbol) { diff --git a/mentos/src/fs/vfs.c b/mentos/src/fs/vfs.c index 1265f9d7..e604b2d9 100644 --- a/mentos/src/fs/vfs.c +++ b/mentos/src/fs/vfs.c @@ -704,12 +704,6 @@ static inline int __valid_open_permissions( return 0; } -/// @brief Checks if the requests in flags are valid. -/// @param flags the flags to check. -/// @param mask the mask to check against. -/// @param uid the uid of the owner. -/// @param gid the gid of the owner. -/// @return 1 on success, 0 otherwise. int vfs_valid_open_permissions(int flags, mode_t mask, uid_t uid, gid_t gid) { // Check the permissions. @@ -734,10 +728,6 @@ int vfs_valid_open_permissions(int flags, mode_t mask, uid_t uid, gid_t gid) return __valid_open_permissions(mask, flags, S_IROTH, S_IWOTH); } -/// @brief Checks if the task is allowed to execute the file -/// @param task the task to execute the file. -/// @param file the file to execute. -/// @return 1 on success, 0 otherwise. int vfs_valid_exec_permission(task_struct *task, vfs_file_t *file) { // Init, and all root processes may execute any file with an execute bit set From 6b8fcad539fcb0851b7394e2455b94a656147704 Mon Sep 17 00:00:00 2001 From: "Enrico Fraccaroli (Galfurian)" Date: Sun, 7 Apr 2024 09:49:27 +0200 Subject: [PATCH 03/40] Add more comments. --- libc/inc/sys/unistd.h | 2 +- mentos/src/drivers/keyboard/keyboard.c | 7 ++ mentos/src/elf/elf.c | 15 +++- mentos/src/fs/ext2.c | 94 ++++++++++++++++++++++++-- 4 files changed, 108 insertions(+), 10 deletions(-) diff --git a/libc/inc/sys/unistd.h b/libc/inc/sys/unistd.h index d7b0e328..bde20028 100644 --- a/libc/inc/sys/unistd.h +++ b/libc/inc/sys/unistd.h @@ -51,7 +51,7 @@ off_t lseek(int fd, off_t offset, int whence); /// @brief Delete a name and possibly the file it refers to. /// @param path The path to the file. -/// @return +/// @return 0 on success, -errno on failure. int unlink(const char *path); /// @brief Creates a symbolic link. diff --git a/mentos/src/drivers/keyboard/keyboard.c b/mentos/src/drivers/keyboard/keyboard.c index 8ef5da52..654645f1 100644 --- a/mentos/src/drivers/keyboard/keyboard.c +++ b/mentos/src/drivers/keyboard/keyboard.c @@ -43,6 +43,9 @@ spinlock_t scancodes_lock; #define KBD_LEFT_ALT (1 << 7) ///< Flag which identifies the left alt. #define KBD_RIGHT_ALT (1 << 8) ///< Flag which identifies the right alt. +/// @brief Returns the keypad number associated with the scancode. +/// @param scancode the scan code we transform to number. +/// @return the number it is associated with. static inline int get_keypad_number(unsigned int scancode) { if (scancode == KEY_KP0) { return 0; } @@ -58,6 +61,8 @@ static inline int get_keypad_number(unsigned int scancode) return -1; } +/// @brief Pushes the character in the scancode ring buffer. +/// @param c the char we push inside the ring buffer. static inline void keyboard_push_front(unsigned int c) { spinlock_lock(&scancodes_lock); @@ -65,6 +70,8 @@ static inline void keyboard_push_front(unsigned int c) spinlock_unlock(&scancodes_lock); } +/// @brief Pops a value from the ring buffer. +/// @return the value we removed from the ring buffer. int keyboard_pop_back(void) { int c; diff --git a/mentos/src/elf/elf.c b/mentos/src/elf/elf.c index 7bdb928c..6f690d7d 100644 --- a/mentos/src/elf/elf.c +++ b/mentos/src/elf/elf.c @@ -125,6 +125,10 @@ static inline const char *elf_get_symbol_name(elf_header_t *header, elf_section_ // SEARCH FUNCTIONS // ============================================================================ +/// @brief Finds the section header with the given name. +/// @param header a pointer to the ELF header. +/// @param name the name of the section we are looking for. +/// @return a pointer to the section header. static inline elf_section_header_t *elf_find_section_header(elf_header_t *header, const char *name) { for (unsigned i = 0; i < header->shnum; ++i) { @@ -142,6 +146,10 @@ static inline elf_section_header_t *elf_find_section_header(elf_header_t *header return NULL; } +/// @brief Finds the symbol with the given name. +/// @param header a pointer to the ELF header. +/// @param name the name of the symbol we are looking for. +/// @return a pointer to the symbol. static inline elf_symbol_t *elf_find_symbol(elf_header_t *header, const char *name) { for (unsigned i = 0; i < header->shnum; ++i) { @@ -175,6 +183,8 @@ static inline elf_symbol_t *elf_find_symbol(elf_header_t *header, const char *na // DUMP FUNCTIONS // ============================================================================ +/// @brief Dumps the information about the sections. +/// @param header a pointer to the ELF header. static inline void elf_dump_section_headers(elf_header_t *header) { pr_debug("[Nr] Name Type Addr Off Size ES Flg Lk Inf Al\n"); @@ -192,6 +202,8 @@ static inline void elf_dump_section_headers(elf_header_t *header) } } +/// @brief Dumps the information about the symbols. +/// @param header a pointer to the ELF header. static inline void elf_dump_symbol_table(elf_header_t *header) { for (unsigned i = 0; i < header->shnum; ++i) { @@ -228,9 +240,8 @@ static inline void elf_dump_symbol_table(elf_header_t *header) // ============================================================================ /// @brief Loads an ELF executable. -/// @param task The task for which we load the ELF. -/// @param file The ELF file. /// @param header The header of the ELF file. +/// @param task The task for which we load the ELF. /// @return The ELF entry. static inline int elf_load_exec(elf_header_t *header, task_struct *task) { diff --git a/mentos/src/fs/ext2.c b/mentos/src/fs/ext2.c index 67ae93c3..55093473 100644 --- a/mentos/src/fs/ext2.c +++ b/mentos/src/fs/ext2.c @@ -449,6 +449,9 @@ static const char *ext2_file_type_to_string(ext2_file_type_t ext2_type) return "UNK"; } +/// @brief Turns the EXT2 file type to OS standard file types. +/// @param ext2_type the EXT2 file type. +/// @return the OS standard file types. static int ext2_file_type_to_vfs_file_type(int ext2_type) { if (ext2_type == ext2_file_type_regular_file) { return DT_REG; } @@ -536,6 +539,7 @@ static void ext2_dump_group_descriptor(ext2_group_descriptor_t *gd) } /// @brief Dumps on debugging output the inode. +/// @param fs a pointer to the filesystem. /// @param inode the object to dump. static void ext2_dump_inode(ext2_filesystem_t *fs, ext2_inode_t *inode) { @@ -766,6 +770,7 @@ static int __valid_x_permission(task_struct *task, ext2_inode_t *inode) /// @param fs the ext2 filesystem structure. /// @param cache the cache from which we read the bgdt data. /// @param group_offset the output variable where we store the linear indes to the free inode. +/// @param skip_reserved should we skip reserved inodes. /// @return 1 if we found a free inode, 0 otherwise. static inline int ext2_find_free_inode_in_group( ext2_filesystem_t *fs, @@ -792,6 +797,7 @@ static inline int ext2_find_free_inode_in_group( /// @param cache the cache from which we read the bgdt data. /// @param group_index the output variable where we store the group index. /// @param group_offset the output variable where we store the linear indes to the free inode. +/// @param preferred_group we accept a preferred group, but only if available. /// @return 1 if we found a free inode, 0 otherwise. static inline int ext2_find_free_inode( ext2_filesystem_t *fs, @@ -832,7 +838,6 @@ static inline int ext2_find_free_inode( /// @brief Searches for a free block inside the group data loaded inside the cache. /// @param fs the ext2 filesystem structure. /// @param cache the cache from which we read the bgdt data. -/// @param group_index the output variable where we store the group index. /// @param block_offset the output variable where we store the linear indes to the free block. /// @return 1 if we found a free block, 0 otherwise. static inline int ext2_find_free_block_in_group(ext2_filesystem_t *fs, uint8_t *cache, uint32_t *block_offset) @@ -849,6 +854,7 @@ static inline int ext2_find_free_block_in_group(ext2_filesystem_t *fs, uint8_t * /// @brief Searches for a free block. /// @param fs the ext2 filesystem structure. /// @param cache the cache from which we read the bgdt data. +/// @param group_index the output variable where we store the group index. /// @param block_offset the output variable where we store the linear indes to the free block. /// @return 1 if we found a free block, 0 otherwise. static inline int ext2_find_free_block( @@ -1166,7 +1172,6 @@ static uint32_t ext2_allocate_block(ext2_filesystem_t *fs) /// @brief Frees a block. /// @param fs the filesystem. /// @param block_index the index of the block we are freeing. -/// @return 0 on failure, or the index of the new block on success. static void ext2_free_block(ext2_filesystem_t *fs, uint32_t block_index) { uint32_t group_index = ext2_block_index_to_group_index(fs, block_index); @@ -1205,6 +1210,11 @@ static void ext2_free_block(ext2_filesystem_t *fs, uint32_t block_index) } } +/// @brief Frees the given inode. +/// @param fs a pointer to the filesystem. +/// @param inode the inode we free. +/// @param inode_index its index. +/// @return 0 on success, otherwise it is a failure. static int ext2_free_inode(ext2_filesystem_t *fs, ext2_inode_t *inode, uint32_t inode_index) { // Retrieve the group index. @@ -1315,6 +1325,7 @@ static int __ext2_read_and_allocate_indexing_block( /// @brief Sets the real block index based on the block index inside an inode. /// @param fs the filesystem. /// @param inode the inode which we are working with. +/// @param inode_index thwe inode index. /// @param block_index the block index inside the inode. /// @param real_index the real block number. /// @return 0 on success, a negative value on failure. @@ -1785,6 +1796,11 @@ void ext2_direntry_iterator_next(ext2_direntry_iterator_t *iterator) iterator->direntry = ext2_direntry_iterator_get(iterator); } +/// @brief Checks if the directory is empty. +/// @param fs a pointer to the filesystem. +/// @param cache used for reading. +/// @param inode the inode of the directory. +/// @return 1 if empty, 0 if not empty. static inline int ext2_directory_is_empty(ext2_filesystem_t *fs, uint8_t *cache, ext2_inode_t *inode) { ext2_direntry_iterator_t it = ext2_direntry_iterator_begin(fs, cache, inode); @@ -1796,6 +1812,11 @@ static inline int ext2_directory_is_empty(ext2_filesystem_t *fs, uint8_t *cache, return 1; } +/// @brief Cleans the inode content. +/// @param fs a pointer to the filesystem. +/// @param inode the inode. +/// @param inode_index the inode index. +/// @return 0 on success, 1 on failure. static int ext2_clean_inode_content(ext2_filesystem_t *fs, ext2_inode_t *inode, uint32_t inode_index) { // Check the type of operation. @@ -1832,6 +1853,9 @@ static int ext2_clean_inode_content(ext2_filesystem_t *fs, ext2_inode_t *inode, // Directory Entry Management Functions // ============================================================================ +/// @brief Returns the rec_len from the given name. +/// @param name the name we use to compute the rec_len. +/// @return the rec_len value. static inline uint32_t ext2_get_rec_len_from_name(const char *name) { unsigned int rec_len = sizeof(ext2_dirent_t) + strlen(name) - EXT2_NAME_LEN; @@ -1839,6 +1863,9 @@ static inline uint32_t ext2_get_rec_len_from_name(const char *name) return rec_len; } +/// @brief Returns the rec_len from the given direntry. +/// @param direntry the direntry we use to compute the rec_len. +/// @return the rec_len value. static inline uint32_t ext2_get_rec_len_from_direntry(const ext2_dirent_t *direntry) { unsigned int rec_len = sizeof(ext2_dirent_t) + direntry->name_len - EXT2_NAME_LEN; @@ -1846,6 +1873,13 @@ static inline uint32_t ext2_get_rec_len_from_direntry(const ext2_dirent_t *diren return rec_len; } +/// @brief Allocates a directory entry. +/// @param fs a pointer to the filesystem. +/// @param parent_inode_index the inode index of the parent. +/// @param inode_index the inode index of the new entry. +/// @param name the name of the new entry. +/// @param file_type the type of file. +/// @return 0 on success, a negative value on failure. static int ext2_allocate_direntry( ext2_filesystem_t *fs, uint32_t parent_inode_index, @@ -1965,7 +1999,8 @@ static int ext2_allocate_direntry( } /// @brief Finds the entry with the given `name` inside the `directory`. -/// @param directory the directory in which we perform the search. +/// @param fs a pointer to the filesystem. +/// @param ino the inodex of the directory entry. /// @param name the name of the entry we are looking for. /// @param search the output variable where we save the info about the entry. /// @return 0 on success, -errno on failure. @@ -2051,7 +2086,7 @@ static int ext2_find_direntry(ext2_filesystem_t *fs, ino_t ino, const char *name /// @param directory the directory from which we start performing the search. /// @param path the path of the entry we are looking for, it can be a relative path. /// @param search the output variable where we save the entry information. -/// @return 0 on success, -1 on failure. +/// @return 0 on success, -errno on failure. static int ext2_resolve_path(vfs_file_t *directory, char *path, ext2_direntry_search_t *search) { // Check the pointers. @@ -2127,6 +2162,14 @@ static ext2_filesystem_t *get_ext2_filesystem(const char *absolute_path) return fs; } +/// @brief Initializes the VFS file. +/// @param fs a pointer to the filesystem. +/// @param file the file we want to initialize. +/// @param inode the inode we use to initialize the VFS file. +/// @param inode_index the inode index. +/// @param name the name of the file. +/// @param name_len the length of the name. +/// @return 0 on success, -errno on failure. static int ext2_init_vfs_file( ext2_filesystem_t *fs, vfs_file_t *file, @@ -2191,6 +2234,10 @@ static int ext2_init_vfs_file( return 0; } +/// @brief Finds the VFS file that is associated with the given inode index. +/// @param fs a pointer to the fileystem. +/// @param inode the inode index. +/// @return a pointer to the VFS file. static vfs_file_t *ext2_find_vfs_file_with_inode(ext2_filesystem_t *fs, ino_t inode) { vfs_file_t *file = NULL; @@ -2214,6 +2261,7 @@ static vfs_file_t *ext2_find_vfs_file_with_inode(ext2_filesystem_t *fs, ino_t in /// @brief Creates and initializes a new inode. /// @param fs the filesystem. /// @param inode the inode we use to initialize the root of the filesystem. +/// @param mode the creat mode. /// @param preferred_group the preferred group where the inode should be allocated. /// @return the inode index on success, -1 on failure. static int ext2_create_inode( @@ -2482,6 +2530,9 @@ static vfs_file_t *ext2_open(const char *path, int flags, mode_t mode) return file; } +/// @brief Delete a name and possibly the file it refers to. +/// @param path The path to the file. +/// @return 0 on success, -errno on failure. static int ext2_unlink(const char *path) { pr_debug("ext2_unlink(%s)\n", path); @@ -2570,6 +2621,7 @@ static int ext2_unlink(const char *path) /// @brief Closes the given file. /// @param file The file structure. +/// @return 0 on success, -errno on failure. static int ext2_close(vfs_file_t *file) { // Get the filesystem. @@ -2746,6 +2798,12 @@ static int ext2_fstat(vfs_file_t *file, stat_t *stat) return __ext2_stat(&inode, stat); } +/// @brief Perform the I/O control operation specified by REQUEST on FD. One +/// argument may follow; its presence and type depend on REQUEST. +/// @param file the file on which we perform the operations. +/// @param request the device-dependent request code +/// @param data an untyped pointer to memory. +/// @return Return value depends on REQUEST. Usually -1 indicates error. static int ext2_ioctl(vfs_file_t *file, int request, void *data) { return -1; @@ -2809,6 +2867,12 @@ static ssize_t ext2_getdents(vfs_file_t *file, dirent_t *dirp, off_t doff, size_ return written; } +/// @brief Read the symbolic link, if present. +/// @param path the file for which we want to read the symbolic link information. +/// @param buffer the buffer where we will store the symbolic link path. +/// @param bufsize the size of the buffer. +/// @return The number of read characters on success, -1 otherwise and errno is +/// set to indicate the error. static ssize_t ext2_readlink(vfs_file_t *file, char *buffer, size_t bufsize) { // Get the filesystem. @@ -2831,6 +2895,10 @@ static ssize_t ext2_readlink(vfs_file_t *file, char *buffer, size_t bufsize) return nbytes; } +/// @brief Creates a new directory at the given path. +/// @param path The path of the new directory. +/// @param mode The permission of the new directory. +/// @return Returns a negative value on failure. static int ext2_mkdir(const char *path, mode_t permission) { pr_debug("\next2_mkdir(%s, %d)\n", path, permission); @@ -2926,6 +2994,9 @@ static int ext2_mkdir(const char *path, mode_t permission) return 0; } +/// @brief Removes the given directory. +/// @param path The path to the directory to remove. +/// @return Returns a negative value on failure. static int ext2_rmdir(const char *path) { pr_debug("ext2_unlink(%s)\n", path); @@ -3061,7 +3132,7 @@ static int ext2_stat(const char *path, stat_t *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. +/// @param attr The structure where the attributes are stored. /// @return 0 if success. static int __ext2_setattr(ext2_inode_t *inode, struct iattr *attr) { @@ -3086,6 +3157,9 @@ static int __ext2_setattr(ext2_inode_t *inode, struct iattr *attr) return 0; } +/// @brief Checks the attributes permission. +/// @param file_owner the file owner we are checking against. +/// @return 1 if it has permission, 0 otherwise. static int __ext2_check_setattr_permission(uid_t file_owner) { task_struct *task = scheduler_get_current_process(); @@ -3094,7 +3168,7 @@ static int __ext2_check_setattr_permission(uid_t 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. +/// @param attr The structure where the attributes are stored. /// @return 0 if success. static int ext2_fsetattr(vfs_file_t *file, struct iattr *attr) { @@ -3120,7 +3194,7 @@ static int ext2_fsetattr(vfs_file_t *file, struct iattr *attr) /// @brief Set attributes of a file /// @param path The path where the file resides. -/// @param stat The structure where the information are stored. +/// @param attr The structure where the information are stored. /// @return 0 if success. static int ext2_setattr(const char *path, struct iattr *attr) { @@ -3163,6 +3237,7 @@ static int ext2_setattr(const char *path, struct iattr *attr) /// @brief Mounts the block device as an EXT2 filesystem. /// @param block_device the block device formatted as EXT2. +/// @param path location where we mount the filesystem. /// @return the VFS root node of the EXT2 filesystem. static vfs_file_t *ext2_mount(vfs_file_t *block_device, const char *path) { @@ -3308,6 +3383,11 @@ static vfs_file_t *ext2_mount(vfs_file_t *block_device, const char *path) // Initialization Functions // ============================================================================ +/// @brief The mount call-back, which prepares everything and calls the actual +/// EXT2 mount function. +/// @param path the path where the filesystem should be mounted. +/// @param device the device we mount. +/// @return the VFS file of the filesystem. static vfs_file_t *ext2_mount_callback(const char *path, const char *device) { // Allocate a variable for the path. From ccda10891e417ef946c39178b20d7ab9c7d209ca Mon Sep 17 00:00:00 2001 From: "Enrico Fraccaroli (Galfurian)" Date: Tue, 9 Apr 2024 13:54:41 +0200 Subject: [PATCH 04/40] Add all missing comments. --- libc/inc/sys/mman.h | 24 +++++++++++++ mentos/inc/fs/namei.h | 10 +++--- mentos/src/fs/ext2.c | 4 +-- mentos/src/fs/namei.c | 36 ++++++++++---------- mentos/src/fs/procfs.c | 28 ++++++++++----- mentos/src/fs/vfs.c | 6 ++++ mentos/src/hardware/timer.c | 12 +++++-- mentos/src/io/debug.c | 8 +++++ mentos/src/io/proc_running.c | 2 ++ mentos/src/io/proc_system.c | 58 ++++++++++++++++++++++--------- mentos/src/io/proc_video.c | 6 ++++ mentos/src/io/vga/vga.c | 26 ++++++++++---- mentos/src/ipc/msg.c | 20 ++++++++++- mentos/src/ipc/sem.c | 12 +++++++ mentos/src/kernel/sys.c | 1 + mentos/src/klib/hashmap.c | 11 ++++++ mentos/src/klib/list.c | 22 ++++++++++-- mentos/src/klib/ndtree.c | 22 ++++++++++++ mentos/src/klib/rbtree.c | 44 ++++++++++++++++++++---- mentos/src/klib/time.c | 13 ++++--- mentos/src/klib/vscanf.c | 6 ++++ mentos/src/klib/vsprintf.c | 43 ++++++++++++++++++++++- mentos/src/mem/buddysystem.c | 12 +++++++ mentos/src/mem/kheap.c | 16 +++++++++ mentos/src/mem/paging.c | 17 ++++++++++ mentos/src/mem/vmem_map.c | 3 ++ mentos/src/mem/zone_allocator.c | 3 ++ mentos/src/process/process.c | 11 ++++++ mentos/src/process/scheduler.c | 6 ++++ mentos/src/process/wait.c | 6 ++++ mentos/src/sys/utsname.c | 9 ++++- mentos/src/system/panic.c | 1 + mentos/src/system/signal.c | 60 ++++++++++++++++++++++++++++++--- 33 files changed, 477 insertions(+), 81 deletions(-) diff --git a/libc/inc/sys/mman.h b/libc/inc/sys/mman.h index 4759b569..15772d96 100644 --- a/libc/inc/sys/mman.h +++ b/libc/inc/sys/mman.h @@ -17,14 +17,38 @@ #ifndef __KERNEL__ +/// @brief creates a new mapping in the virtual address space of the calling process. +/// @param addr the starting address for the new mapping. +/// @param length specifies the length of the mapping (which must be greater than 0). +/// @param prot describes the desired memory protection of the mapping (and must not conflict with the open mode of the file). +/// @param flags determines whether updates to the mapping are visible to other processes mapping the same region. +/// @param fd in case of file mapping, the file descriptor to use. +/// @param offset offset in the file, which must be a multiple of the page size PAGE_SIZE. +/// @return returns a pointer to the mapped area, -1 and errno is set. void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); +/// @brief deletes the mappings for the specified address range. +/// @param addr the starting address. +/// @param length the length of the mapped area. +/// @return 0 on success, -1 on falure and errno is set. int munmap(void *addr, size_t length); #else +/// @brief creates a new mapping in the virtual address space of the calling process. +/// @param addr the starting address for the new mapping. +/// @param length specifies the length of the mapping (which must be greater than 0). +/// @param prot describes the desired memory protection of the mapping (and must not conflict with the open mode of the file). +/// @param flags determines whether updates to the mapping are visible to other processes mapping the same region. +/// @param fd in case of file mapping, the file descriptor to use. +/// @param offset offset in the file, which must be a multiple of the page size PAGE_SIZE. +/// @return returns a pointer to the mapped area, -1 and errno is set. void *sys_mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); +/// @brief deletes the mappings for the specified address range. +/// @param addr the starting address. +/// @param length the length of the mapped area. +/// @return 0 on success, -1 on falure and errno is set. int sys_munmap(void *addr, size_t length); #endif diff --git a/mentos/inc/fs/namei.h b/mentos/inc/fs/namei.h index ff692014..3a89d3aa 100644 --- a/mentos/inc/fs/namei.h +++ b/mentos/inc/fs/namei.h @@ -8,13 +8,13 @@ #include "stddef.h" #define REMOVE_TRAILING_SLASH 1 << 0 -#define FOLLOW_LINKS 1 << 1 -#define CREAT_LAST_COMPONENT 1 << 2 +#define FOLLOW_LINKS 1 << 1 +#define CREAT_LAST_COMPONENT 1 << 2 /// @brief Resolve the path by following all symbolic links. /// @param path The path to resolve. -/// @param resolved_path The buffer where the resolved path is stored. -/// @param size The size of the provided resolved_path buffer. +/// @param buffer The buffer where the resolved path is stored. +/// @param buflen The size of the provided resolved_path buffer. /// @param flags The flags controlling how the path is resolved. /// @return -errno on fail, 1 on success. -int resolve_path(const char *path, char *resolved_path, size_t size, int flags); +int resolve_path(const char *path, char *buffer, size_t buflen, int flags); diff --git a/mentos/src/fs/ext2.c b/mentos/src/fs/ext2.c index 55093473..ef0728ea 100644 --- a/mentos/src/fs/ext2.c +++ b/mentos/src/fs/ext2.c @@ -2868,7 +2868,7 @@ static ssize_t ext2_getdents(vfs_file_t *file, dirent_t *dirp, off_t doff, size_ } /// @brief Read the symbolic link, if present. -/// @param path the file for which we want to read the symbolic link information. +/// @param file the file for which we want to read the symbolic link information. /// @param buffer the buffer where we will store the symbolic link path. /// @param bufsize the size of the buffer. /// @return The number of read characters on success, -1 otherwise and errno is @@ -2897,7 +2897,7 @@ static ssize_t ext2_readlink(vfs_file_t *file, char *buffer, size_t bufsize) /// @brief Creates a new directory at the given path. /// @param path The path of the new directory. -/// @param mode The permission of the new directory. +/// @param permission The permission of the new directory. /// @return Returns a negative value on failure. static int ext2_mkdir(const char *path, mode_t permission) { diff --git a/mentos/src/fs/namei.c b/mentos/src/fs/namei.c index b22acbfc..1afcb55c 100644 --- a/mentos/src/fs/namei.c +++ b/mentos/src/fs/namei.c @@ -3,9 +3,9 @@ /// @copyright (c) 2014-2024 This file is distributed under the MIT License. /// See LICENSE.md for details. +#include "fs/namei.h" #include "assert.h" #include "limits.h" -#include "fs/namei.h" #include "fcntl.h" #include "fs/vfs.h" #include "io/debug.h" @@ -13,6 +13,24 @@ #include "sys/errno.h" #include "string.h" +/// Appends the path with a "/" as separator. +#define APPEND_PATH_SEP_OR_FAIL(b, remaining) \ +{ \ + strncat(b, "/", remaining); \ + remaining--; \ + if (remaining < 0) \ + return -ENAMETOOLONG; \ +} + +/// Appends the path with a "/" as separator. +#define APPEND_PATH_OR_FAIL(b, path, remaining) \ +{ \ + strncat(b, path, remaining); \ + remaining -= strlen(path); \ + if (remaining < 0) \ + return -ENAMETOOLONG; \ +} + int sys_unlink(const char *path) { return vfs_unlink(path); @@ -81,22 +99,6 @@ char *realpath(const char *path, char *buffer, size_t buflen) { return buffer; } -#define APPEND_PATH_SEP_OR_FAIL(b, remaining) \ -{ \ - strncat(b, "/", remaining); \ - remaining--; \ - if (remaining < 0) \ - return -ENAMETOOLONG; \ -} - -#define APPEND_PATH_OR_FAIL(b, path, remaining) \ -{ \ - strncat(b, path, remaining); \ - remaining -= strlen(path); \ - if (remaining < 0) \ - return -ENAMETOOLONG; \ -} - int resolve_path(const char *path, char *buffer, size_t buflen, int flags) { assert(path && "Provided null path."); diff --git a/mentos/src/fs/procfs.c b/mentos/src/fs/procfs.c index bf817399..38657ae8 100644 --- a/mentos/src/fs/procfs.c +++ b/mentos/src/fs/procfs.c @@ -200,6 +200,8 @@ static inline int procfs_find_inode(const char *path) return -1; } +/// @brief Finds a free inode. +/// @return the free inode index, or -1 on failure. static inline int procfs_get_free_inode(void) { for (int inode = 1; inode < PROCFS_MAX_FILES; ++inode) { @@ -534,6 +536,7 @@ static vfs_file_t *procfs_open(const char *path, int flags, mode_t mode) /// @brief Closes the given file. /// @param file The file structure. +/// @return 0 on success, -errno on failure. static int procfs_close(vfs_file_t *file) { assert(file && "Received null file."); @@ -583,13 +586,13 @@ static inline int procfs_unlink(const char *path) /// @param offset Offset from which we start reading from the file. /// @param nbyte The number of bytes to read. /// @return The number of red bytes. -static ssize_t procfs_read(vfs_file_t *file, char *buf, off_t offset, size_t nbyte) +static ssize_t procfs_read(vfs_file_t *file, char *buffer, off_t offset, size_t nbyte) { if (file) { procfs_file_t *procfs_file = procfs_find_entry_inode(file->ino); if (procfs_file && procfs_file->dir_entry.fs_operations) { if (procfs_file->dir_entry.fs_operations->read_f) { - return procfs_file->dir_entry.fs_operations->read_f(file, buf, offset, nbyte); + return procfs_file->dir_entry.fs_operations->read_f(file, buffer, offset, nbyte); } } } @@ -602,13 +605,13 @@ static ssize_t procfs_read(vfs_file_t *file, char *buf, off_t offset, size_t nby /// @param offset Offset from which we start writing in the file. /// @param nbyte The number of bytes to write. /// @return The number of written bytes. -static ssize_t procfs_write(vfs_file_t *file, const void *buf, off_t offset, size_t nbyte) +static ssize_t procfs_write(vfs_file_t *file, const void *buffer, off_t offset, size_t nbyte) { if (file) { procfs_file_t *procfs_file = procfs_find_entry_inode(file->ino); if (procfs_file && procfs_file->dir_entry.fs_operations) { if (procfs_file->dir_entry.fs_operations->write_f) { - return procfs_file->dir_entry.fs_operations->write_f(file, buf, offset, nbyte); + return procfs_file->dir_entry.fs_operations->write_f(file, buffer, offset, nbyte); } } } @@ -643,7 +646,7 @@ off_t procfs_lseek(vfs_file_t *file, off_t offset, int whence) } /// @brief Saves the information concerning the file. -/// @param inode The inode containing the data. +/// @param file The file containing the data. /// @param stat The structure where the information are stored. /// @return 0 if success. static int __procfs_stat(procfs_file_t *file, stat_t *stat) @@ -712,6 +715,12 @@ static int procfs_stat(const char *path, stat_t *stat) return -1; } +/// @brief Perform the I/O control operation specified by REQUEST on FD. One +/// argument may follow; its presence and type depend on REQUEST. +/// @param file the file on which we perform the operations. +/// @param request the device-dependent request code +/// @param data an untyped pointer to memory. +/// @return Return value depends on REQUEST. Usually -1 indicates error. static int procfs_ioctl(vfs_file_t *file, int request, void *data) { if (file) { @@ -811,10 +820,11 @@ static inline ssize_t procfs_getdents(vfs_file_t *file, dirent_t *dirp, off_t do return written_size; } -/// @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. -static vfs_file_t *ext2_mount(vfs_file_t *block_device, const char *path) +/// @brief Mounts the block device as a procfs filesystem. +/// @param block_device the block device formatted as procfs. +/// @param path location where we mount the filesystem. +/// @return the VFS root node of the procfs filesystem. +static vfs_file_t *procfs_mount(vfs_file_t *block_device, const char *path) { return NULL; } diff --git a/mentos/src/fs/vfs.c b/mentos/src/fs/vfs.c index e604b2d9..f7a3d008 100644 --- a/mentos/src/fs/vfs.c +++ b/mentos/src/fs/vfs.c @@ -686,6 +686,12 @@ int sys_dup(int fd) return fd; } +/// @brief Checks the valid open permission. +/// @param mask the mask we need to check against. +/// @param flags the flags we want to check. +/// @param read the read permissions we want to check. +/// @param write the write permissions we want to check. +/// @return 0 on falure, success otherwise. static inline int __valid_open_permissions( const mode_t mask, const int flags, diff --git a/mentos/src/hardware/timer.c b/mentos/src/hardware/timer.c index e12318cf..ed0f8061 100644 --- a/mentos/src/hardware/timer.c +++ b/mentos/src/hardware/timer.c @@ -174,6 +174,8 @@ static inline void __print_vector_base(tvec_base_t *base) #endif } +/// @brief Initializes the tvec_base. +/// @param base the base to initialize. static inline void __tvec_base_init(tvec_base_t *base) { spinlock_init(&base->lock); @@ -221,7 +223,9 @@ static inline list_head *__timer_get_target_vector(tvec_base_t *base, struct tim return base->tvn[3] + ((expires >> TIMER_TICKS_BITS(3)) & TVN_MASK); } -/// Move all timers from tv up one level +/// @brief Move all timers from tv up one level. +/// @param base the base that contains the vector we want to cascate. +/// @param current_vector the vector we want to cascate. static inline void __timer_cascate_vector(tvec_base_t *base, list_head *current_vector) { list_head *target_vector; @@ -556,7 +560,7 @@ static inline void sleep_timeout(unsigned long data) /// @brief Function executed when the real_timer of a process expires, sends /// SIGALRM to process. -/// @param pid PID of the process whos associated timer has expired. +/// @param task_ptr pointer to the process whos associated timer has expired. static inline void alarm_timeout(unsigned long task_ptr) { // Get the task fromt the argument. @@ -567,7 +571,9 @@ static inline void alarm_timeout(unsigned long task_ptr) task->real_timer = NULL; } -// Real timer interval timemout +/// @brief Function executed when the real_timer of a process expires, sends +/// SIGALRM to process. +/// @param task_ptr pointer to the process whos associated timer has expired. static inline void real_timer_timeout(unsigned long task_ptr) { // Get the task fromt the argument. diff --git a/mentos/src/io/debug.c b/mentos/src/io/debug.c index 1a34178b..f052b293 100644 --- a/mentos/src/io/debug.c +++ b/mentos/src/io/debug.c @@ -29,6 +29,12 @@ void dbg_puts(const char *s) } } +/// @brief Prints the correct header for the given debug level. +/// @param file the file origin of the debug message. +/// @param fun the function where the debug message was called. +/// @param line the line in the file where debug message was called. +/// @param log_level the log level. +/// @param header the header we want to show. static inline void __debug_print_header(const char *file, const char *fun, int line, short log_level, char *header) { // "EMERG ", "ALERT ", "CRIT ", "ERR ", "WARNING", "NOTICE ", "INFO ", "DEBUG ", "DEFAULT", @@ -160,6 +166,8 @@ const char *dec_to_binary(unsigned long value, unsigned length) return buffer; } +/// @brief Prints the registers. +/// @param frame the registers to print. void dbg_print_regs(pt_regs *frame) { pr_debug("Interrupt stack frame:\n"); diff --git a/mentos/src/io/proc_running.c b/mentos/src/io/proc_running.c index f6396de1..9533ace4 100644 --- a/mentos/src/io/proc_running.c +++ b/mentos/src/io/proc_running.c @@ -14,6 +14,8 @@ #include "sys/errno.h" /// @brief Returns the character identifying the process state. +/// @param state the process state. +/// @return a character describing the state. /// @details /// R Running /// S Sleeping in an interruptible wait diff --git a/mentos/src/io/proc_system.c b/mentos/src/io/proc_system.c index ad9761c3..93aadc54 100644 --- a/mentos/src/io/proc_system.c +++ b/mentos/src/io/proc_system.c @@ -24,6 +24,12 @@ static ssize_t procs_do_meminfo(char *buffer, size_t bufsize); static ssize_t procs_do_stat(char *buffer, size_t bufsize); +/// @brief Read function for the proc system. +/// @param file The file. +/// @param buf Buffer where the read content must be placed. +/// @param offset Offset from which we start reading from the file. +/// @param nbyte The number of bytes to read. +/// @return The number of red bytes. static ssize_t __procs_read(vfs_file_t *file, char *buf, off_t offset, size_t nbyte) { if (!file) { @@ -157,33 +163,51 @@ int procs_module_init(void) return 0; } +/// @brief Write the uptime inside the buffer. +/// @param buffer the buffer. +/// @param bufsize the buffer size. +/// @return the amount we wrote. static ssize_t procs_do_uptime(char *buffer, size_t bufsize) { - sprintf(buffer, "%d", timer_get_seconds()); - return 0; + return sprintf(buffer, "%d", timer_get_seconds()); } +/// @brief Write the version inside the buffer. +/// @param buffer the buffer. +/// @param bufsize the buffer size. +/// @return the amount we wrote. static ssize_t procs_do_version(char *buffer, size_t bufsize) { - sprintf(buffer, - "%s version %s (site: %s) (email: %s)", - OS_NAME, - OS_VERSION, - OS_SITEURL, - OS_REF_EMAIL); - return 0; + return sprintf(buffer, + "%s version %s (site: %s) (email: %s)", + OS_NAME, + OS_VERSION, + OS_SITEURL, + OS_REF_EMAIL); } +/// @brief Write the list of mount points inside the buffer. +/// @param buffer the buffer. +/// @param bufsize the buffer size. +/// @return the amount we wrote. static ssize_t procs_do_mounts(char *buffer, size_t bufsize) { return 0; } +/// @brief Write the cpu information inside the buffer. +/// @param buffer the buffer. +/// @param bufsize the buffer size. +/// @return the amount we wrote. static ssize_t procs_do_cpuinfo(char *buffer, size_t bufsize) { return 0; } +/// @brief Write the memory information inside the buffer. +/// @param buffer the buffer. +/// @param bufsize the buffer size. +/// @return the amount we wrote. static ssize_t procs_do_meminfo(char *buffer, size_t bufsize) { double total_space = get_zone_total_space(GFP_KERNEL) + @@ -193,20 +217,22 @@ static ssize_t procs_do_meminfo(char *buffer, size_t bufsize) cached_space = get_zone_cached_space(GFP_KERNEL) + get_zone_cached_space(GFP_USER), used_space = total_space - free_space; - total_space /= (double)K; - free_space /= (double)K; - cached_space /= (double)K; - used_space /= (double)K; - sprintf( + return sprintf( buffer, "MemTotal : %12.2f Kb\n" "MemFree : %12.2f Kb\n" "MemUsed : %12.2f Kb\n" "Cached : %12.2f Kb\n", - total_space, free_space, used_space, cached_space); - return 0; + total_space / (double)K, + free_space / (double)K, + used_space / (double)K, + cached_space / (double)K); } +/// @brief Write the process statistics inside the buffer. +/// @param buffer the buffer. +/// @param bufsize the buffer size. +/// @return the amount we wrote. static ssize_t procs_do_stat(char *buffer, size_t bufsize) { return 0; diff --git a/mentos/src/io/proc_video.c b/mentos/src/io/proc_video.c index 6fff3c7a..913efdce 100644 --- a/mentos/src/io/proc_video.c +++ b/mentos/src/io/proc_video.c @@ -34,6 +34,12 @@ void print_rb(fs_rb_scancode_t *rb) } } +/// @brief Read function for the proc video system. +/// @param file The file. +/// @param buf Buffer where the read content must be placed. +/// @param offset Offset from which we start reading from the file. +/// @param nbyte The number of bytes to read. +/// @return The number of red bytes. static ssize_t procv_read(vfs_file_t *file, char *buf, off_t offset, size_t nbyte) { // Stop if the buffer is invalid. diff --git a/mentos/src/io/vga/vga.c b/mentos/src/io/vga/vga.c index 0614eea5..0f3f88c1 100644 --- a/mentos/src/io/vga/vga.c +++ b/mentos/src/io/vga/vga.c @@ -225,6 +225,7 @@ static unsigned char __read_byte(unsigned int offset) /// @brief Writes onto the video memory. /// @param offset where we are going to write. +/// @param value the value to write. static void __write_byte(unsigned int offset, unsigned char value) { *(char *)(driver->address + offset) = value; @@ -456,7 +457,7 @@ static inline unsigned __read_pixel_2(unsigned x, unsigned y) /// @brief Writes a pixel. /// @param x x coordinates. /// @param y y coordinates. -/// @param c color. +/// @param color the color. static inline void __write_pixel_4(int x, int y, unsigned char color) { unsigned off, mask, plane, pmask; @@ -489,7 +490,7 @@ static inline unsigned __read_pixel_4(int x, int y) /// @brief Writes a pixel. /// @param x x coordinates. /// @param y y coordinates. -/// @param c color. +/// @param color the color. static inline void __write_pixel_8(int x, int y, unsigned char color) { __set_plane(x); @@ -664,6 +665,7 @@ void vga_run_test(void) // == MODEs and DRIVERs ======================================================= +/// @brief Operations for 720*480, and 16-bit color video. static vga_ops_t ops_720_480_16 = { .write_pixel = __write_pixel_4, .read_pixel = __read_pixel_4, @@ -671,6 +673,7 @@ static vga_ops_t ops_720_480_16 = { .fill_rect = NULL, }; +/// @brief Operations for 640*480, and 16-bit color video. static vga_ops_t ops_640_480_16 = { .write_pixel = __write_pixel_4, .read_pixel = __read_pixel_4, @@ -678,6 +681,7 @@ static vga_ops_t ops_640_480_16 = { .fill_rect = NULL, }; +/// @brief Operations for 320*200, and 256-bit color video. static vga_ops_t ops_320_200_256 = { .write_pixel = __write_pixel_8, .read_pixel = __read_pixel_8, @@ -685,36 +689,42 @@ static vga_ops_t ops_320_200_256 = { .fill_rect = NULL, }; +/// @brief 4x6 font. static vga_font_t font_4x6 = { .font = arr_4x6_font, .width = 4, .height = 6, }; +/// @brief 5x6 font. static vga_font_t font_5x6 = { .font = arr_5x6_font, .width = 5, .height = 6, }; +/// @brief 8x8 font. static vga_font_t font_8x8 = { .font = arr_8x8_font, .width = 8, .height = 8, }; +/// @brief 8x14 font. static vga_font_t font_8x14 = { .font = arr_8x14_font, .width = 8, .height = 14, }; +/// @brief 8x16 font. static vga_font_t font_8x16 = { .font = arr_8x16_font, .width = 8, .height = 16, }; +/// @brief Drivers for 720*480, and 16-bit color video. static vga_driver_t driver_720_480_16 = { .width = 720, .height = 480, @@ -723,6 +733,7 @@ static vga_driver_t driver_720_480_16 = { .ops = &ops_720_480_16, }; +/// @brief Drivers for 640*480, and 16-bit color video. static vga_driver_t driver_640_480_16 = { .width = 640, .height = 480, @@ -731,6 +742,7 @@ static vga_driver_t driver_640_480_16 = { .ops = &ops_640_480_16, }; +/// @brief Drivers for 320*200, and 16-bit color video. static vga_driver_t driver_320_200_256 = { .width = 320, .height = 200, @@ -796,11 +808,12 @@ void vga_finalize(void) vga_enable = false; } -static int _x = 0; -static int _y = 0; -static unsigned char _color = 7; -static int _cursor_state = 0; +static int _x = 0; ///< Current x coordinate of the cursor. +static int _y = 0; ///< Current y coordinate of the cursor. +static unsigned char _color = 7; ///< Current color. +static int _cursor_state = 0; ///< Current state of the cursor. +/// @brief Clears the character at the cursor. inline static void __vga_clear_cursor(void) { for (unsigned cy = 0; cy < driver->font->height; ++cy) { @@ -810,6 +823,7 @@ inline static void __vga_clear_cursor(void) } } +/// @brief Draws the cursor. inline static void __vga_draw_cursor(void) { unsigned char color = (_cursor_state = (_cursor_state == 0)) * _color; diff --git a/mentos/src/ipc/msg.c b/mentos/src/ipc/msg.c index bbff7bb6..77b48b03 100644 --- a/mentos/src/ipc/msg.c +++ b/mentos/src/ipc/msg.c @@ -50,7 +50,7 @@ list_head msq_list; /// @brief Allocates the memory for message queue structure. /// @param key IPC_KEY associated with message queue. -/// @param msgflg flags used to create message queue. +/// @param msqflg flags used to create message queue. /// @return a pointer to the allocated message queue structure. static inline msq_info_t *__msq_info_alloc(key_t key, int msqflg) { @@ -141,6 +141,8 @@ static inline msq_info_t *__list_find_msq_info_by_key(key_t key) return NULL; } +/// @brief Adds the structure to the global list. +/// @param msq_info the structure to add. static inline void __list_add_msq_info(msq_info_t *msq_info) { assert(msq_info && "Received a NULL pointer."); @@ -148,6 +150,8 @@ static inline void __list_add_msq_info(msq_info_t *msq_info) list_head_insert_before(&msq_info->list, &msq_list); } +/// @brief Removes the structure from the global list. +/// @param msq_info the structure to remove. static inline void __list_remove_msq_info(msq_info_t *msq_info) { assert(msq_info && "Received a NULL pointer."); @@ -155,6 +159,9 @@ static inline void __list_remove_msq_info(msq_info_t *msq_info) list_head_remove(&msq_info->list); } +/// @brief Pushes a messages inside the message queue. +/// @param msq_info the structure that will contain the message. +/// @param message the message to push. static inline void __msq_info_push_message(msq_info_t *msq_info, struct msg *message) { assert(msq_info && "Received a NULL pointer."); @@ -172,6 +179,9 @@ static inline void __msq_info_push_message(msq_info_t *msq_info, struct msg *mes } } +/// @brief Removes the message from the message queue. +/// @param msq_info the structure that contains the message. +/// @param message the message to remove. static inline void __msq_info_remove_message(msq_info_t *msq_info, struct msg *message) { assert(msq_info && "Received a NULL pointer."); @@ -201,6 +211,8 @@ static inline void __msq_info_remove_message(msq_info_t *msq_info, struct msg *m // SYSTEM FUNCTIONS // ============================================================================ +/// @brief Iinitializes the message queue system. +/// @return 0 on success, 1 on failure. int msq_init(void) { list_head_init(&msq_list); @@ -535,6 +547,12 @@ int sys_msgctl(int msqid, int cmd, struct msqid_ds *buf) // PROCFS FUNCTIONS // ============================================================================ +/// @brief Read function for the proc system. +/// @param file The file. +/// @param buf Buffer where the read content must be placed. +/// @param offset Offset from which we start reading from the file. +/// @param nbyte The number of bytes to read. +/// @return The number of red bytes. ssize_t procipc_msg_read(vfs_file_t *file, char *buf, off_t offset, size_t nbyte) { if (!file) { diff --git a/mentos/src/ipc/sem.c b/mentos/src/ipc/sem.c index 4109160a..70803d60 100644 --- a/mentos/src/ipc/sem.c +++ b/mentos/src/ipc/sem.c @@ -161,6 +161,8 @@ static inline sem_info_t *__list_find_sem_info_by_key(key_t key) return NULL; } +/// @brief Adds the structure to the global list. +/// @param sem_info the structure to add. static inline void __list_add_sem_info(sem_info_t *sem_info) { assert(sem_info && "Received a NULL pointer."); @@ -168,6 +170,8 @@ static inline void __list_add_sem_info(sem_info_t *sem_info) list_head_insert_before(&sem_info->list, &semaphores_list); } +/// @brief Removes the structure from the global list. +/// @param sem_info the structure to remove. static inline void __list_remove_sem_info(sem_info_t *sem_info) { assert(sem_info && "Received a NULL pointer."); @@ -179,6 +183,8 @@ static inline void __list_remove_sem_info(sem_info_t *sem_info) // SYSTEM FUNCTIONS // ============================================================================ +/// @brief Iinitializes the semaphore system. +/// @return 0 on success, 1 on failure. int sem_init(void) { list_head_init(&semaphores_list); @@ -495,6 +501,12 @@ long sys_semctl(int semid, int semnum, int cmd, union semun *arg) // PROCFS FUNCTIONS // ============================================================================ +/// @brief Read function for the proc system. +/// @param file The file. +/// @param buf Buffer where the read content must be placed. +/// @param offset Offset from which we start reading from the file. +/// @param nbyte The number of bytes to read. +/// @return The number of red bytes. ssize_t procipc_sem_read(vfs_file_t *file, char *buf, off_t offset, size_t nbyte) { if (!file) { diff --git a/mentos/src/kernel/sys.c b/mentos/src/kernel/sys.c index 3e1e442a..c54ed0c5 100644 --- a/mentos/src/kernel/sys.c +++ b/mentos/src/kernel/sys.c @@ -9,6 +9,7 @@ #include "sys/errno.h" #include "sys/reboot.h" +/// @brief Powers off the machine. static void machine_power_off(void) { while (1) { diff --git a/mentos/src/klib/hashmap.c b/mentos/src/klib/hashmap.c index d9f27dec..b9bfd5bc 100644 --- a/mentos/src/klib/hashmap.c +++ b/mentos/src/klib/hashmap.c @@ -34,6 +34,8 @@ struct hashmap_t { hashmap_entry_t **entries; }; +/// @brief Allocates the memory for an hasmap. +/// @return the newly allocated hashmap. static inline hashmap_t *__alloc_hashmap(void) { hashmap_t *hashmap = kmalloc(sizeof(hashmap_t)); @@ -41,6 +43,8 @@ static inline hashmap_t *__alloc_hashmap(void) return hashmap; } +/// @brief Allocates the memory for an entry of the hasmap. +/// @return the newly allocated entry of the hashmap. static inline hashmap_entry_t *__alloc_entry(void) { hashmap_entry_t *entry = kmalloc(sizeof(hashmap_entry_t)); @@ -48,12 +52,17 @@ static inline hashmap_entry_t *__alloc_entry(void) return entry; } +/// @brief Frees the memory of an entry of the hasmap. +/// @param entry the entry we destroy. static inline void __dealloc_entry(hashmap_entry_t *entry) { assert(entry && "Invalid pointer to an entry."); kfree(entry); } +/// @brief Allocates the memory for a number of entries in the hasmap. +/// @param size the number of entries. +/// @return the newly allocated vector of entries in the hashmap. static inline hashmap_entry_t **__alloc_entries(unsigned int size) { hashmap_entry_t **entries = kmalloc(sizeof(hashmap_entry_t *) * size); @@ -61,6 +70,8 @@ static inline hashmap_entry_t **__alloc_entries(unsigned int size) return entries; } +/// @brief Frees the memory of a vector of entries. +/// @param entries the vector of entries. static inline void __dealloc_entries(hashmap_entry_t **entries) { assert(entries && "Invalid pointer to entries."); diff --git a/mentos/src/klib/list.c b/mentos/src/klib/list.c index cc37b868..2747fe1a 100644 --- a/mentos/src/klib/list.c +++ b/mentos/src/klib/list.c @@ -8,6 +8,8 @@ #include "mem/slab.h" #include "string.h" +/// @brief Allocates the memory for a node. +/// @return a pointer to the newly allocated node. static inline listnode_t *__node_alloc(void) { listnode_t *node = kmalloc(sizeof(listnode_t)); @@ -15,12 +17,28 @@ static inline listnode_t *__node_alloc(void) return node; } +/// @brief Frees the memory of a node. +/// @param node the new we want to free. static inline void __node_dealloc(listnode_t *node) { assert(node && "Invalid pointer to node."); kfree(node); } +/// @brief Allocates the memory for a list. +/// @return a pointer to the newly allocated list. +static inline list_t *__list_alloc() +{ + // Allocate the list. + list_t *list = kmalloc(sizeof(list_t)); + assert(list && "Failed to allocate memory for a list."); + // Clear the memory of the list. + memset(list, 0, sizeof(list_t)); + return list; +} + +/// @brief Frees the memory of a list. +/// @param list the list we want to free. static inline void __list_dealloc(list_t *list) { assert(list && "Invalid pointer to list."); @@ -29,9 +47,7 @@ static inline void __list_dealloc(list_t *list) list_t *list_create(void) { - list_t *list = kmalloc(sizeof(list_t)); - memset(list, 0, sizeof(list_t)); - return list; + return __list_alloc(); } unsigned int list_size(list_t *list) diff --git a/mentos/src/klib/ndtree.c b/mentos/src/klib/ndtree.c index a63b1fd1..483a4af5 100644 --- a/mentos/src/klib/ndtree.c +++ b/mentos/src/klib/ndtree.c @@ -46,6 +46,12 @@ struct ndtree_iter_t { // ============================================================================ // Default Comparison functions. + +/// @brief Default comparison function. +/// @param self the ndtree. +/// @param a the first element. +/// @param b the second element. +/// @return comparison between the elements. static inline int __ndtree_tree_node_cmp_ptr_cb(ndtree_t *self, void *a, void *b) { return (a > b) - (a < b); @@ -165,6 +171,10 @@ ndtree_t *ndtree_tree_init(ndtree_t *tree, ndtree_tree_cmp_f node_cmp_cb) return tree; } +/// @brief Recursive deallocation of the memory of the tree. +/// @param tree the tree. +/// @param node the node to deallocate. +/// @param node_cb the callback to call before freeing the memory of the node. static void __ndtree_tree_dealloc_rec(ndtree_t *tree, ndtree_node_t *node, ndtree_tree_node_f node_cb) { if (node && node_cb) { @@ -192,6 +202,12 @@ void ndtree_tree_dealloc(ndtree_t *tree, ndtree_tree_node_f node_cb) kfree(tree); } +/// @brief Recursive search in the tree. +/// @param tree the tree. +/// @param cmp the comparison function. +/// @param value the value to compare against. +/// @param node the current node. +/// @return the node we found, NULL otherwise. static ndtree_node_t *__ndtree_tree_find_rec(ndtree_t *tree, ndtree_tree_cmp_f cmp, void *value, ndtree_node_t *node) { ndtree_node_t *result = NULL; @@ -363,6 +379,12 @@ ndtree_node_t *ndtree_iter_prev(ndtree_iter_t *iter) // ============================================================================ // Tree debugging functions. + +/// @brief A visitor function. +/// @param tree the tree. +/// @param node the current node. +/// @param enter_fun the enter function. +/// @param exit_fun the exit function. static void __ndtree_tree_visitor_iter(ndtree_t *tree, ndtree_node_t *node, ndtree_tree_node_f enter_fun, diff --git a/mentos/src/klib/rbtree.c b/mentos/src/klib/rbtree.c index 6cae50aa..0c9b7d32 100644 --- a/mentos/src/klib/rbtree.c +++ b/mentos/src/klib/rbtree.c @@ -76,11 +76,18 @@ void rbtree_node_dealloc(rbtree_node_t *node) } } +/// @brief Checks if the node is red. +/// @param node the node to check. +/// @return 1 if the node is red, 0 otherwise. static int rbtree_node_is_red(const rbtree_node_t *node) { return node ? node->red : 0; } +/// @brief Performs a node rotation. +/// @param node the node. +/// @param dir the direction of the rotation (0: left, 1: right). +/// @return the result of the rotate operation. static rbtree_node_t *rbtree_node_rotate(rbtree_node_t *node, int dir) { rbtree_node_t *result = NULL; @@ -94,6 +101,12 @@ static rbtree_node_t *rbtree_node_rotate(rbtree_node_t *node, int dir) return result; } +/// @brief Performs a double rotation. +/// @param node the node. +/// @param dir the direction of the rotation (0: left, 1: right). +/// @return the result of the rotate operation. +/// @details Suppose U has a parent V and a grandparent W. Then two successive +/// rotations on U will ensure that V and W are descendents of U. static rbtree_node_t *rbtree_node_rotate2(rbtree_node_t *node, int dir) { rbtree_node_t *result = NULL; @@ -106,6 +119,11 @@ static rbtree_node_t *rbtree_node_rotate2(rbtree_node_t *node, int dir) // rbtree_t - default callbacks +/// @brief Peforms a comparison between the pointers of two elements. +/// @param tree the tree. +/// @param a the first element. +/// @param b the second element. +/// @return result of the comparison. static int rbtree_tree_node_cmp_ptr_cb( rbtree_t *tree, rbtree_node_t *a, @@ -115,12 +133,13 @@ static int rbtree_tree_node_cmp_ptr_cb( return (a->value > b->value) - (a->value < b->value); } +/// @brief Default deallocation callback. +/// @param tree the tree. +/// @param node the node. static void rbtree_tree_node_dealloc_cb(rbtree_t *tree, rbtree_node_t *node) { - if (tree) { - if (node) { - rbtree_node_dealloc(node); - } + if (tree && node) { + rbtree_node_dealloc(node); } } @@ -435,8 +454,12 @@ void rbtree_iter_dealloc(rbtree_iter_t *iter) } } -// Internal function, init traversal object, dir determines whether -// to begin traversal at the smallest or largest valued node. +/// @brief Internal function, init traversal object, dir determines whether +/// to begin traversal at the smallest or largest valued node. +/// @param iter the iterator. +/// @param tree the tree. +/// @param dir the direction. +/// @return result of the iteration. static void *rbtree_iter_start(rbtree_iter_t *iter, rbtree_t *tree, int dir) { void *result = NULL; @@ -458,7 +481,10 @@ static void *rbtree_iter_start(rbtree_iter_t *iter, rbtree_t *tree, int dir) return result; } -// Traverse a red black tree in the user-specified direction (0 asc, 1 desc) +/// @brief Traverse a red black tree in the user-specified direction (0 asc, 1 desc) +/// @param iter the iterator. +/// @param dir the direction. +/// @return result of the iteration. static void *rbtree_iter_move(rbtree_iter_t *iter, int dir) { if (iter->node->link[dir] != NULL) { @@ -544,6 +570,10 @@ int rbtree_tree_test(rbtree_t *tree, rbtree_node_t *root) return 0; } +/// @brief Prints the tree using a user-defined function. +/// @param tree the tree. +/// @param node the current node. +/// @param fun the print function. static void rbtree_tree_print_iter(rbtree_t *tree, rbtree_node_t *node, rbtree_tree_node_f fun) diff --git a/mentos/src/klib/time.c b/mentos/src/klib/time.c index ce02750c..ea4b1890 100644 --- a/mentos/src/klib/time.c +++ b/mentos/src/klib/time.c @@ -11,12 +11,15 @@ #include "stdio.h" #include "time.h" -static const char *str_weekdays[] = { "Sunday", "Monday", "Tuesday", "Wednesday", - "Thursday", "Friday", "Saturday" }; +/// @brief List of week days. +static const char *str_weekdays[] = { + "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" +}; -static const char *str_months[] = { "January", "February", "March", "April", - "May", "June", "July", "August", - "September", "October", "November", "December" }; +/// @brief List of months. +static const char *str_months[] = { + "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" +}; time_t sys_time(time_t *time) { diff --git a/mentos/src/klib/vscanf.c b/mentos/src/klib/vscanf.c index b35208f5..b4f34cf7 100644 --- a/mentos/src/klib/vscanf.c +++ b/mentos/src/klib/vscanf.c @@ -9,6 +9,12 @@ #include "stdio.h" #include "string.h" +/// @brief Read formatted data from string. +/// @param buf String processed as source to retrieve the data. +/// @param s Format string, following the same specifications as printf. +/// @param ap The list of arguments where the values are stored. +/// @return On success, the function returns the number of items of the +/// argument list successfully filled. EOF otherwise. static int vsscanf(const char *buf, const char *s, va_list ap) { int count = 0, noassign = 0, width = 0, base = 0; diff --git a/mentos/src/klib/vsprintf.c b/mentos/src/klib/vsprintf.c index 7775e56e..7fded041 100644 --- a/mentos/src/klib/vsprintf.c +++ b/mentos/src/klib/vsprintf.c @@ -31,6 +31,8 @@ static char *_digits = "0123456789abcdefghijklmnopqrstuvwxyz"; static char *_upper_digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; /// @brief Returns the index of the first non-integer character. +/// @param s the string. +/// @return the index of the first non-integer character. static inline int skip_atoi(const char **s) { int i = 0; @@ -40,6 +42,14 @@ static inline int skip_atoi(const char **s) return i; } +/// @brief Places the number inside the string. +/// @param str the string where the number will end up in. +/// @param num the number. +/// @param base the base used to transform the number. +/// @param size the size available for storing the number. +/// @param precision the precision. +/// @param flags support flags. +/// @return the string itself, or NULL. static char *number(char *str, long num, int base, int size, int32_t precision, unsigned flags) { char c, tmp[66] = { 0 }; @@ -52,7 +62,7 @@ static char *number(char *str, long num, int base, int size, int32_t precision, flags &= ~FLAGS_ZEROPAD; } if (base < 2 || base > 36) { - return 0; + return NULL; } c = (flags & FLAGS_ZEROPAD) ? '0' : ' '; @@ -130,6 +140,13 @@ static char *number(char *str, long num, int base, int size, int32_t precision, return str; } +/// @brief Prints a MAC address. +/// @param str the string where we store the address. +/// @param addr the address we need to store. +/// @param size the size available in str. +/// @param precision the precision to use. +/// @param flags support flags. +/// @return a pointer to str itself, or NULL. static char *eaddr(char *str, unsigned char *addr, int size, int precision, unsigned flags) { (void)precision; @@ -167,6 +184,13 @@ static char *eaddr(char *str, unsigned char *addr, int size, int precision, unsi return str; } +/// @brief Prints an internet address. +/// @param str the string where we store the address. +/// @param addr the address we need to store. +/// @param size the size available in str. +/// @param precision the precision to use. +/// @param flags support flags. +/// @return a pointer to str itself, or NULL. static char *iaddr(char *str, unsigned char *addr, int size, int precision, unsigned flags) { (void)precision; @@ -214,6 +238,11 @@ static char *iaddr(char *str, unsigned char *addr, int size, int precision, unsi return str; } +/// @brief Prints a floating point value. +/// @param value the value to print. +/// @param buffer the buffer where the value is stored. +/// @param fmt the format. +/// @param precision the precision. static void cfltcvt(double value, char *buffer, char fmt, int precision) { int decpt, sign, exp, pos; @@ -314,6 +343,8 @@ static void cfltcvt(double value, char *buffer, char fmt, int precision) *buffer = '\0'; } +/// @brief Should we force the decimal point. +/// @param buffer the buffer where we force the decimal point. static void forcdecpt(char *buffer) { while (*buffer) { @@ -340,6 +371,8 @@ static void forcdecpt(char *buffer) } } +/// @brief Crop zero unless '#' given. +/// @param buffer the buffer to work on. static void cropzeros(char *buffer) { char *stop; @@ -363,6 +396,14 @@ static void cropzeros(char *buffer) } } +/// @brief Transforms a floating point value to string. +/// @param str the string where the floating point value should be stored. +/// @param num the number to store. +/// @param size the size available for storing the floating point value. +/// @param precision the precision. +/// @param fmt the format. +/// @param flags the support flags. +/// @return a pointer to str itself. static char *flt(char *str, double num, int size, int precision, char fmt, unsigned flags) { char tmp[80]; diff --git a/mentos/src/mem/buddysystem.c b/mentos/src/mem/buddysystem.c index bd36ca59..ab11f2d8 100644 --- a/mentos/src/mem/buddysystem.c +++ b/mentos/src/mem/buddysystem.c @@ -382,6 +382,9 @@ unsigned long buddy_system_get_cached_space(bb_instance_t *instance) return size; } +/// @brief Extenmds the cache of the given amount. +/// @param instance the cache instance. +/// @param count the amount to extend to. static void __cache_extend(bb_instance_t *instance, int count) { for (int i = 0; i < count; i++) { @@ -391,6 +394,9 @@ static void __cache_extend(bb_instance_t *instance, int count) } } +/// @brief Shrinks the cache. +/// @param instance the cache instance. +/// @param count the amount to shrink. static void __cache_shrink(bb_instance_t *instance, int count) { for (int i = 0; i < count; i++) { @@ -401,6 +407,9 @@ static void __cache_shrink(bb_instance_t *instance, int count) } } +/// @brief Allocate memory using the given cache. +/// @param instance the cache instance. +/// @return a pointer to the allocated page. static bb_page_t *__cached_alloc(bb_instance_t *instance) { if (instance->free_pages_cache_size < LOW_WATERMARK_LEVEL) { @@ -413,6 +422,9 @@ static bb_page_t *__cached_alloc(bb_instance_t *instance) return page; } +/// @brief Frees the memory of the allocated page. +/// @param instance the cache instance. +/// @param page a pointer to the allocated page. static void __cached_free(bb_instance_t *instance, bb_page_t *page) { list_head_insert_after(&page->location.cache, &instance->free_pages_cache_list); diff --git a/mentos/src/mem/kheap.c b/mentos/src/mem/kheap.c index 47b506b9..65e05b9e 100644 --- a/mentos/src/mem/kheap.c +++ b/mentos/src/mem/kheap.c @@ -92,6 +92,8 @@ static inline const char *__block_to_string(block_t *block) return buffer; } +/// @brief Dumpts debug information about the heap. +/// @param header the heap header. static inline void __blkmngr_dump(heap_header_t *header) { #if __DEBUG_LEVEL__ == LOGLEVEL_DEBUG @@ -162,6 +164,9 @@ static inline block_t *__blkmngr_find_best_fitting(heap_header_t *header, uint32 } /// @brief Given a block, finds its previous block. +/// @param header the heap header. +/// @param block the block. +/// @return a pointer to the previous block. static inline block_t *__blkmngr_get_previous_block(heap_header_t *header, block_t *block) { assert(header && "Received a NULL heap header."); @@ -174,6 +179,9 @@ static inline block_t *__blkmngr_get_previous_block(heap_header_t *header, block } /// @brief Given a block, finds its next block. +/// @param header the heap header. +/// @param block the block. +/// @return a pointer to the next block. static inline block_t *__blkmngr_get_next_block(heap_header_t *header, block_t *block) { assert(header && "Received a NULL heap header."); @@ -207,6 +215,10 @@ static inline int __blkmngr_is_next_block(block_t *block, block_t *next) return block->list.next == &next->list; } +/// @brief Splits a block in two blocks, provided the size of the first one. +/// @param header the heap header. +/// @param block the block to split. +/// @param size the size of the first of the two new blocks. static inline void __blkmngr_split_block(heap_header_t *header, block_t *block, uint32_t size) { assert(block && "Received NULL block."); @@ -232,6 +244,10 @@ static inline void __blkmngr_split_block(heap_header_t *header, block_t *block, pr_debug("And %s\n", __block_to_string(split)); } +/// @brief Merges two blocks, into the first block. +/// @param header the heap header. +/// @param block the first block. +/// @param other the second block, which is lost in the process. static inline void __blkmngr_merge_blocks(heap_header_t *header, block_t *block, block_t *other) { assert(block && "Received NULL first block."); diff --git a/mentos/src/mem/paging.c b/mentos/src/mem/paging.c index d953df0e..2d375d54 100644 --- a/mentos/src/mem/paging.c +++ b/mentos/src/mem/paging.c @@ -276,11 +276,15 @@ inline int find_free_vm_area(mm_struct_t *mm, size_t length, uintptr_t *vm_start return 1; } +/// @brief Initializes the page directory. +/// @param pdir the page directory to initialize. static void __init_pagedir(page_directory_t *pdir) { *pdir = (page_directory_t){ { 0 } }; } +/// @brief Initializes the page table. +/// @param ptable the page table to initialize. static void __init_pagetable(page_table_t *ptable) { *ptable = (page_table_t){ { 0 } }; @@ -319,6 +323,9 @@ void paging_init(boot_info_t *info) #define ERR_RESERVED 0x08 ///< Overwrote reserved bit. #define ERR_INST 0x10 ///< Instruction fetch. +/// @brief Sets the given page table flags. +/// @param table the page table. +/// @param flags the flags to set. static inline void __set_pg_table_flags(page_table_entry_t *table, uint32_t flags) { table->rw = (flags & MM_RW) != 0; @@ -371,6 +378,9 @@ static void __page_fault_panic(pt_regs *f, uint32_t addr) __asm__ __volatile__("cli"); } +/// @brief Handles the copy-on-write. +/// @param entry the entry to manage. +/// @return 0 on success, 1 on error. static int __page_handle_cow(page_table_entry_t *entry) { // Check if the page is Copy On Write (COW). @@ -397,6 +407,10 @@ static int __page_handle_cow(page_table_entry_t *entry) return 1; } +/// @brief Allocates memory for a page table entry. +/// @param entry the entry for which we allocate memory. +/// @param flags the flags to control the allocation. +/// @return a pointer to the page table entry. static page_table_t *__mem_pg_entry_alloc(page_dir_entry_t *entry, uint32_t flags) { if (!entry->present) { @@ -424,6 +438,9 @@ static page_table_t *__mem_pg_entry_alloc(page_dir_entry_t *entry, uint32_t flag get_page_from_physical_address(((uint32_t)entry->frame) << 12U)); } +/// @brief Sets the frame attribute of a page table entry. +/// @param entry the entry. +/// @param table the page table. static inline void __set_pg_entry_frame(page_dir_entry_t *entry, page_table_t *table) { page_t *table_page = get_lowmem_page_from_address((uint32_t)table); diff --git a/mentos/src/mem/vmem_map.c b/mentos/src/mem/vmem_map.c index 35b74a6a..ed427614 100644 --- a/mentos/src/mem/vmem_map.c +++ b/mentos/src/mem/vmem_map.c @@ -78,6 +78,9 @@ void virt_init(void) } } +/// @brief Allocates a virtual page, given the page frame count. +/// @param pfn_count the page frame count. +/// @return pointer to the virtual page. static virt_map_page_t *_alloc_virt_pages(uint32_t pfn_count) { unsigned order = find_nearest_order_greater(0, pfn_count << 12); diff --git a/mentos/src/mem/zone_allocator.c b/mentos/src/mem/zone_allocator.c index 8ba80909..61a3ddbe 100644 --- a/mentos/src/mem/zone_allocator.c +++ b/mentos/src/mem/zone_allocator.c @@ -102,6 +102,9 @@ static zone_t *get_zone_from_flags(gfp_t gfp_mask) } } +/// @brief Checks if the memory is clean. +/// @param gfp_mask the mask which specifies the zone we are interested in. +/// @return 1 if clean, 0 on error. static int is_memory_clean(gfp_t gfp_mask) { // Get the corresponding zone. diff --git a/mentos/src/process/process.c b/mentos/src/process/process.c index 8c629d5f..c1ea84dd 100644 --- a/mentos/src/process/process.c +++ b/mentos/src/process/process.c @@ -81,6 +81,9 @@ static inline char **__push_args_on_stack(uintptr_t *stack, char *args[]) return (char **)(*stack); } +/// @brief Resets the process. +/// @param task the process to reset. +/// @return 0 on failure, 1 otherwise. static int __reset_process(task_struct *task) { pr_debug("__reset_process(%p `%s`)\n", task, task->name); @@ -111,6 +114,9 @@ static int __reset_process(task_struct *task) return 1; } +/// @brief Checks if the file starts with a shebang. +/// @param file the file to check. +/// @return 1 if it contains a shebang, 0 otherwise. static int __has_shebang(vfs_file_t *file) { char buf[2]; vfs_read(file, buf, 0, sizeof(buf)); @@ -213,6 +219,11 @@ static int __load_executable(const char *path, task_struct *task, uint32_t *entr return ret; } +/// @brief Allocates the memory for a task. +/// @param source the source task we use for the copy. +/// @param parent the parent process. +/// @param name the name of the new process. +/// @return pointer to the newly allocated task. static inline task_struct *__alloc_task(task_struct *source, task_struct *parent, const char *name) { // Create a new task_struct. diff --git a/mentos/src/process/scheduler.c b/mentos/src/process/scheduler.c index b5c03018..bc1c5144 100644 --- a/mentos/src/process/scheduler.c +++ b/mentos/src/process/scheduler.c @@ -376,6 +376,7 @@ int sys_setpgid(pid_t pid, pid_t pgid) return 0; } +/// Returns the attributes of the runnign process. #define RETURN_PROCESS_ATTR_OR_EPERM(attr) \ if (runqueue.curr) { return runqueue.curr->attr; } \ return -EPERM; @@ -398,25 +399,30 @@ gid_t sys_getegid(void) RETURN_PROCESS_ATTR_OR_EPERM(gid); } +/// Checks the given ID. #define FAIL_ON_INV_ID(id) \ if (id < 0) { return -EINVAL; } +/// Checks the ID, and if there is a running process. #define FAIL_ON_INV_ID_OR_PROC(id) \ FAIL_ON_INV_ID(id) \ if (!runqueue.curr) { return -EPERM; } +/// If the process is ROOT, set the attribute and return 0. #define IF_PRIVILEGED_SET_ALL_AND_RETURN(attr) \ if (runqueue.curr->uid == 0) { \ runqueue.curr->r##attr = runqueue.curr->attr = attr; \ return 0; \ } +/// Checks the attributes, resets them, and returns 0. #define IF_RESET_SET_AND_RETURN(attr) \ if (runqueue.curr->r##attr == attr) { \ runqueue.curr->attr = attr; \ return 0; \ } +/// If the process is ROOT set the attribute, otherwise return failure. #define SET_IF_PRIVILEGED_OR_FAIL(attr) \ if (runqueue.curr->uid == 0) { \ runqueue.curr->attr = attr; \ diff --git a/mentos/src/process/wait.c b/mentos/src/process/wait.c index 7566c9ff..be84788e 100644 --- a/mentos/src/process/wait.c +++ b/mentos/src/process/wait.c @@ -14,11 +14,17 @@ #include "assert.h" #include "string.h" +/// @brief Adds the entry to the wait queue. +/// @param head the wait queue. +/// @param wq the entry. static inline void __add_wait_queue(wait_queue_head_t *head, wait_queue_entry_t *wq) { list_head_insert_before(&wq->task_list, &head->task_list); } +/// @brief Removes the entry from the wait queue. +/// @param head the wait queue. +/// @param wq the entry. static inline void __remove_wait_queue(wait_queue_head_t *head, wait_queue_entry_t *wq) { list_head_remove(&wq->task_list); diff --git a/mentos/src/sys/utsname.c b/mentos/src/sys/utsname.c index 2cfa3f95..746441e4 100644 --- a/mentos/src/sys/utsname.c +++ b/mentos/src/sys/utsname.c @@ -16,6 +16,10 @@ #include "sys/utsname.h" #include "version.h" +/// @brief Returns the hostname. +/// @param name where the hostname is stored. +/// @param len the length of the buffer. +/// @return 0 on success, a negative value on failure. static inline int __gethostname(char *name, size_t len) { // Check if name is an invalid address. @@ -54,7 +58,10 @@ int sys_uname(utsname_t *buf) strcpy(buf->sysname, OS_NAME); strcpy(buf->version, OS_VERSION); strcpy(buf->release, OS_VERSION); - __gethostname(buf->nodename, SYS_LEN); strcpy(buf->machine, "i686"); + int ret = __gethostname(buf->nodename, SYS_LEN); + if (ret != 0) { + return ret; + } return 0; } diff --git a/mentos/src/system/panic.c b/mentos/src/system/panic.c index c6c230ca..52447bf8 100644 --- a/mentos/src/system/panic.c +++ b/mentos/src/system/panic.c @@ -7,6 +7,7 @@ #include "io/debug.h" #include "io/port_io.h" +/// Shutdown port for qemu. #define SHUTDOWN_PORT 0x604 extern int runtests; diff --git a/mentos/src/system/signal.c b/mentos/src/system/signal.c index 2adf7350..bd25b4eb 100644 --- a/mentos/src/system/signal.c +++ b/mentos/src/system/signal.c @@ -19,6 +19,7 @@ #include "sys/errno.h" #include "system/signal.h" +/// @brief Extracts the exit status. #define GET_EXIT_STATUS(status) (((status) & 0x00FF) << 8) /// SLAB caches for signal bits. @@ -27,6 +28,7 @@ static kmem_cache_t *sigqueue_cachep; /// Contains all stopped process waiting for a continue signal static struct wait_queue_head_t stopped_queue; +/// @brief The list of signal names. static const char *sys_siglist[] = { "HUP", "INT", @@ -62,44 +64,67 @@ static const char *sys_siglist[] = { NULL, }; +/// @brief Copies the sigaction. +/// @param to the target. +/// @param from the source. static inline void __copy_sigaction(sigaction_t *to, const sigaction_t *from) { memcpy(to, from, sizeof(sigaction_t)); } +/// @brief Copies a signal set. +/// @param to the target. +/// @param from the source. static inline void __copy_sigset(sigset_t *to, const sigset_t *from) { memcpy(to, from, sizeof(sigset_t)); } +/// @brief Copies a signal information structure. +/// @param to the target. +/// @param from the source. static inline void __copy_siginfo(siginfo_t *to, const siginfo_t *from) { memcpy(to, from, sizeof(siginfo_t)); } +/// @brief Clears the memory of a signal information structure. +/// @param info the signal information structure. static inline void __clear_siginfo(siginfo_t *info) { memset(info, 0, sizeof(siginfo_t)); } +/// @brief Locks the signal handling of a given task. +/// @param t the task. static inline void __lock_task_sighand(struct task_struct *t) { assert(t && "Null task struct."); spinlock_lock(&t->sighand.siglock); } +/// @brief Unlocks the signal handling of a given task. +/// @param t the task. static inline void __unlock_task_sighand(struct task_struct *t) { assert(t && "Null task struct."); spinlock_unlock(&t->sighand.siglock); } +/// @brief Returns the handler for a given signal, for a given task. +/// @param t the task. +/// @param sig the signal index. +/// @return a pointer to the handler. static sighandler_t __get_handler(struct task_struct *t, int sig) { assert(t && "Null task struct."); return t->sighand.action[sig - 1].sa_handler; } +/// @brief Checks if the given signal is ignored. +/// @param t the task. +/// @param sig the signal to check. +/// @return 0 if not ignored, 1 if ignored. static int __sig_is_ignored(struct task_struct *t, int sig) { // Blocked signals are never ignored, since the @@ -121,6 +146,7 @@ static int __sig_is_ignored(struct task_struct *t, int sig) /// @param t The task to which the signal belongs. /// @param sig The signal to set. /// @param flags Flags identifying from where we are going to take the memory. +/// @return a pointer to the newly allocated signal queue. static inline sigqueue_t *__sigqueue_alloc(struct task_struct *t, int sig, gfp_t flags) { sigqueue_t *sigqueue = kmem_cache_alloc(sigqueue_cachep, flags); @@ -132,18 +158,20 @@ static inline sigqueue_t *__sigqueue_alloc(struct task_struct *t, int sig, gfp_t return sigqueue; } -static inline void __sigqueue_free(sigqueue_t *sigqueue) +/// @brief Freest the memory of a signal queue. +/// @param sigqueue the signal queue to free. +static inline void __sigqueue_dealloc(sigqueue_t *sigqueue) { if (sigqueue) { kmem_cache_free(sigqueue); } } -/// @brief +/// @brief Sends a signal. /// @param sig Signal to be sent. /// @param info The signal info /// @param t The process to which we send the signal. -/// @return +/// @return 0 on success, a negative value on failure. static int __send_signal(int sig, siginfo_t *info, struct task_struct *t) { // Lock the signal handling for the given task. @@ -181,6 +209,10 @@ static int __send_signal(int sig, siginfo_t *info, struct task_struct *t) return 0; } +/// @brief Gets the next signal that abides by the given mask. +/// @param pending the list of pending signals. +/// @param mask the mask we are checking against. +/// @return index of the next signal to handle. static inline int __next_signal(sigpending_t *pending, sigset_t *mask) { pr_debug("__next_signal(%p, %p)\n", pending, mask); @@ -198,6 +230,10 @@ static inline int __next_signal(sigpending_t *pending, sigset_t *mask) return 0; } +/// @brief Collects the signals from the list. +/// @param sig the signal. +/// @param list the list of pending signals. +/// @param info the where we store the signal information. static inline void __collect_signal(int sig, sigpending_t *list, siginfo_t *info) { pr_debug("__collect_signal(%2d:%s, %p, %p)\n", sig, strsignal(sig), list, info); @@ -240,7 +276,7 @@ static inline void __collect_signal(int sig, sigpending_t *list, siginfo_t *info // Copy the details about the entry inside the info structure. __copy_siginfo(info, &queue_entry->info); // Free the memory for the queue entry. - __sigqueue_free(queue_entry); + __sigqueue_dealloc(queue_entry); } else { pr_debug("__collect_signal(%2d:%s, %p, %p) : Cannot find the signal in the queue.\n", sig, strsignal(sig), list, info); // Ok, it wasn't in the queue, zero out the info. @@ -262,6 +298,11 @@ static inline void __collect_signal(int sig, sigpending_t *list, siginfo_t *info } } +/// @brief Dequeues a signal that abides by the mask. +/// @param pending the list of pending signals. +/// @param mask the mask used to select the signals. +/// @param info the signal information, where we store the information of the dequeued signal. +/// @return the signal index on success, a negative value on failure. static inline int __dequeue_signal(sigpending_t *pending, sigset_t *mask, siginfo_t *info) { pr_debug("__dequeue_signal(%p, %p, %p)\n", pending, mask, info); @@ -275,6 +316,12 @@ static inline int __dequeue_signal(sigpending_t *pending, sigset_t *mask, siginf return sig; } +/// @brief Handels the signals for the current process. +/// @param signr the signal number. +/// @param info the signal information. +/// @param ka the action associated with the signal. +/// @param regs the current registers. +/// @return 1 on success, 0 on failure. static inline int __handle_signal(int signr, siginfo_t *info, sigaction_t *ka, struct pt_regs *regs) { pr_debug("__handle_signal(%d, %p, %p, %p)\n", signr, info, ka, regs); @@ -340,7 +387,10 @@ long sys_sigreturn(struct pt_regs *f) return 0; } -// Send signal to parent +/// @brief Send signal to parent. +/// @param current the current task. +/// @param signr the signal number. +/// @return the result of the operation. static int __notify_parent(struct task_struct *current, int signr) { siginfo_t info; From 50d2cfbd59f62448a0e6400f0d756d761b61897c Mon Sep 17 00:00:00 2001 From: "Enrico Fraccaroli (Galfurian)" Date: Tue, 16 Jul 2024 15:30:44 -0400 Subject: [PATCH 05/40] - Split directory management into several smaller functions; - Properly manage block indexing when dealing with directory entries; - Fix mkdir directory creation; --- mentos/src/fs/ext2.c | 496 +++++++++++++++++++++++++++---------------- 1 file changed, 318 insertions(+), 178 deletions(-) diff --git a/mentos/src/fs/ext2.c b/mentos/src/fs/ext2.c index ef0728ea..63f012a2 100644 --- a/mentos/src/fs/ext2.c +++ b/mentos/src/fs/ext2.c @@ -4,10 +4,10 @@ /// See LICENSE.md for details. // Setup the logging for this file (do this before any other include). -#include "sys/kernel_levels.h" // Include kernel log levels. -#define __DEBUG_HEADER__ "[EXT2 ]" ///< Change header. -#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE ///< Set log level. -#include "io/debug.h" // Include debugging functions. +#include "sys/kernel_levels.h" // Include kernel log levels. +#define __DEBUG_HEADER__ "[EXT2 ]" ///< Change header. +#define __DEBUG_LEVEL__ LOGLEVEL_DEBUG ///< Set log level. +#include "io/debug.h" // Include debugging functions. #include "assert.h" #include "fcntl.h" @@ -665,6 +665,52 @@ static void ext2_dump_filesystem(ext2_filesystem_t *fs) // EXT2 Core Functions // ============================================================================ +/// @brief Allocate cache for EXT2 operations. +/// @param fs file system we are working with. +/// @return a pointer to the cache. +static inline uint8_t *ext2_alloc_cache(ext2_filesystem_t *fs) +{ + // Allocate the cache. + uint8_t *cache = kmem_cache_alloc(fs->ext2_buffer_cache, GFP_KERNEL); + // Clean the cache. + memset(cache, 0, fs->ext2_buffer_cache->size); + // Check the cache. + assert(cache && "Failed to allocate cache for EXT2 operations."); + return cache; +} + +/// @brief Free the cache. +/// @param cache pointer to the cache. +static inline void ext2_dealloc_cache(uint8_t *cache) +{ + // Check the cache. + assert(cache && "Received invalid EXT2 cache."); + // Free the cache. + kmem_cache_free(cache); + // Clean pointer. + *cache = 0; +} + +/// @brief Returns the rec_len from the given name. +/// @param name the name we use to compute the rec_len. +/// @return the rec_len value. +static inline uint32_t ext2_get_rec_len_from_name(const char *name) +{ + uint32_t rec_len = sizeof(ext2_dirent_t) + strlen(name) + 1; + rec_len += (rec_len % 4) ? (4 - (rec_len % 4)) : 0; + return rec_len; +} + +/// @brief Returns the rec_len from the given direntry. +/// @param direntry the direntry we use to compute the rec_len. +/// @return the rec_len value. +static inline uint32_t ext2_get_rec_len_from_direntry(const ext2_dirent_t *direntry) +{ + uint32_t rec_len = sizeof(ext2_dirent_t) + direntry->name_len + 1; + rec_len += (rec_len % 4) ? (4 - (rec_len % 4)) : 0; + return rec_len; +} + /// @brief Cheks if the bit at the given linear index is free. /// @param buffer the buffer containing the bitmap /// @param offset the linear index we want to check. @@ -987,8 +1033,8 @@ static int ext2_read_inode(ext2_filesystem_t *fs, ext2_inode_t *inode, uint32_t block_index = ext2_inode_index_to_block_index(fs, inode_index); // Log the address to the inode. - pr_debug("Read inode (inode_index:%4u, group_index:%4u, group_offset:%4u, block_index:%4u)\n", - inode_index, group_index, group_offset, block_index); + // pr_debug("Read inode (inode_index:%4u, group_index:%4u, group_offset:%4u, block_index:%4u)\n", + // inode_index, group_index, group_offset, block_index); // Check for error. if (group_index > fs->block_groups_count) { @@ -999,15 +1045,13 @@ static int ext2_read_inode(ext2_filesystem_t *fs, ext2_inode_t *inode, uint32_t // Get the real inode offset inside the block. group_offset %= fs->inodes_per_block_count; // Allocate the cache. - uint8_t *cache = kmem_cache_alloc(fs->ext2_buffer_cache, GFP_KERNEL); - // Clean the cache. - memset(cache, 0, fs->ext2_buffer_cache->size); + uint8_t *cache = ext2_alloc_cache(fs); // Read the block containing the inode table. ext2_read_block(fs, fs->block_groups[group_index].inode_table + block_index, cache); // Save the inode content. memcpy(inode, (ext2_inode_t *)((uintptr_t)cache + (group_offset * fs->superblock.inode_size)), sizeof(ext2_inode_t)); // Free the cache. - kmem_cache_free(cache); + ext2_dealloc_cache(cache); return 0; } @@ -1030,8 +1074,8 @@ static int ext2_write_inode(ext2_filesystem_t *fs, ext2_inode_t *inode, uint32_t // Get the block offest. block_index = ext2_inode_index_to_block_index(fs, inode_index); - pr_debug("Write inode (inode_index:%4u, group_index:%4u, group_offset:%4u, block_index:%4u)\n", - inode_index, group_index, group_offset, block_index); + // pr_debug("Write inode (inode_index:%4u, group_index:%4u, group_offset:%4u, block_index:%4u)\n", + // inode_index, group_index, group_offset, block_index); // Check for error. if (group_index > fs->block_groups_count) { @@ -1042,9 +1086,7 @@ static int ext2_write_inode(ext2_filesystem_t *fs, ext2_inode_t *inode, uint32_t // Get the real inode offset inside the block. group_offset %= fs->inodes_per_block_count; // Allocate the cache. - uint8_t *cache = kmem_cache_alloc(fs->ext2_buffer_cache, GFP_KERNEL); - // Clean the cache. - memset(cache, 0, fs->ext2_buffer_cache->size); + uint8_t *cache = ext2_alloc_cache(fs); // Read the block containing the inode table. ext2_read_block(fs, fs->block_groups[group_index].inode_table + block_index, cache); // Write the inode. @@ -1052,7 +1094,7 @@ static int ext2_write_inode(ext2_filesystem_t *fs, ext2_inode_t *inode, uint32_t // Write back the block. ext2_write_block(fs, fs->block_groups[group_index].inode_table + block_index, cache); // Free the cache. - kmem_cache_free(cache); + ext2_dealloc_cache(cache); return 0; } @@ -1071,16 +1113,14 @@ static int ext2_allocate_inode(ext2_filesystem_t *fs, unsigned preferred_group) // Lock the filesystem. spinlock_lock(&fs->spinlock); // Allocate the cache. - uint8_t *cache = kmem_cache_alloc(fs->ext2_buffer_cache, GFP_KERNEL); - // Clean the cache. - memset(cache, 0, fs->ext2_buffer_cache->size); + uint8_t *cache = ext2_alloc_cache(fs); // Search for a free inode. if (!ext2_find_free_inode(fs, cache, &group_index, &group_offset, preferred_group)) { pr_err("Failed to find a free inode.\n"); // Unlock the filesystem. spinlock_unlock(&fs->spinlock); // Free the cache. - kmem_cache_free(cache); + ext2_dealloc_cache(cache); return 0; } // Compute the inode index. @@ -1094,7 +1134,7 @@ static int ext2_allocate_inode(ext2_filesystem_t *fs, unsigned preferred_group) pr_err("We failed to write back the block_bitmap.\n"); } // Free the cache. - kmem_cache_free(cache); + ext2_dealloc_cache(cache); // Reduce the number of free inodes. fs->block_groups[group_index].free_inodes_count--; // Reduce the number of inodes inside the superblock. @@ -1122,16 +1162,14 @@ static uint32_t ext2_allocate_block(ext2_filesystem_t *fs) // Lock the filesystem. spinlock_lock(&fs->spinlock); // Allocate the cache. - uint8_t *cache = kmem_cache_alloc(fs->ext2_buffer_cache, GFP_KERNEL); - // Clean the cache. - memset(cache, 0, fs->ext2_buffer_cache->size); + uint8_t *cache = ext2_alloc_cache(fs); // Search for a free block. if (!ext2_find_free_block(fs, cache, &group_index, &group_offset)) { pr_err("Failed to find a free block.\n"); // Unlock the filesystem. spinlock_unlock(&fs->spinlock); // Free the cache. - kmem_cache_free(cache); + ext2_dealloc_cache(cache); return 0; } // Compute the block index. @@ -1163,7 +1201,7 @@ static uint32_t ext2_allocate_block(ext2_filesystem_t *fs) pr_err("We failed to clean the content of the newly allocated block.\n"); } // Free the cache. - kmem_cache_free(cache); + ext2_dealloc_cache(cache); // Unlock the spinlock. spinlock_unlock(&fs->spinlock); return block_index; @@ -1182,9 +1220,7 @@ static void ext2_free_block(ext2_filesystem_t *fs, uint32_t block_index) pr_debug("Free block (block_index:%u, group_index:%4u, group_offset:%4u)\n", block_index, group_index, group_offset); // Allocate the cache. - uint8_t *cache = kmem_cache_alloc(fs->ext2_buffer_cache, GFP_KERNEL); - // Clean the cache. - memset(cache, 0, fs->ext2_buffer_cache->size); + uint8_t *cache = ext2_alloc_cache(fs); // Read the bitmap. ext2_read_block(fs, block_bitmap, cache); // Set it as free. @@ -1194,7 +1230,7 @@ static void ext2_free_block(ext2_filesystem_t *fs, uint32_t block_index) pr_err("We failed to write back the block_bitmap.\n"); } // Free the cache. - kmem_cache_free(cache); + ext2_dealloc_cache(cache); // Increase the number of free blocks inside the superblock. fs->superblock.free_blocks_count++; @@ -1240,9 +1276,7 @@ static int ext2_free_inode(ext2_filesystem_t *fs, ext2_inode_t *inode, uint32_t } // Allocate the cache. - uint8_t *cache = kmem_cache_alloc(fs->ext2_buffer_cache, GFP_KERNEL); - // Clean the cache. - memset(cache, 0, fs->ext2_buffer_cache->size); + uint8_t *cache = ext2_alloc_cache(fs); // Read the bitmap. ext2_read_block(fs, inode_bitmap, cache); // Set it as free. @@ -1252,7 +1286,7 @@ static int ext2_free_inode(ext2_filesystem_t *fs, ext2_inode_t *inode, uint32_t pr_err("We failed to write back the inode_bitmap.\n"); } // Free the cache. - kmem_cache_free(cache); + ext2_dealloc_cache(cache); // Increase the number of inodes inside the superblock. fs->superblock.free_inodes_count++; @@ -1346,9 +1380,7 @@ static int ext2_set_real_block_index( int ret = 0; // Allocate the cache. - uint8_t *cache = kmem_cache_alloc(fs->ext2_buffer_cache, GFP_KERNEL); - // Clean the cache. - memset(cache, 0, fs->ext2_buffer_cache->size); + uint8_t *cache = ext2_alloc_cache(fs); // Are we setting a DIRECT block pointer. a = ((int)block_index) - EXT2_DIRECT_BLOCKS; @@ -1437,7 +1469,7 @@ static int ext2_set_real_block_index( } early_exit: // Free the cache. - kmem_cache_free(cache); + ext2_dealloc_cache(cache); return ret; } @@ -1456,9 +1488,7 @@ static uint32_t ext2_get_real_block_index(ext2_filesystem_t *fs, ext2_inode_t *i uint32_t real_index = 0; // Allocate the cache. - uint8_t *cache = kmem_cache_alloc(fs->ext2_buffer_cache, GFP_KERNEL); - // Clean the cache. - memset(cache, 0, fs->ext2_buffer_cache->size); + uint8_t *cache = ext2_alloc_cache(fs); // Check if the index is among the DIRECT blocks. a = block_index - EXT2_DIRECT_BLOCKS; @@ -1510,7 +1540,7 @@ static uint32_t ext2_get_real_block_index(ext2_filesystem_t *fs, ext2_inode_t *i } } // Free the cache. - kmem_cache_free(cache); + ext2_dealloc_cache(cache); return real_index; } @@ -1522,7 +1552,7 @@ static uint32_t ext2_get_real_block_index(ext2_filesystem_t *fs, ext2_inode_t *i /// @return 0 on success, -1 on failure. static int ext2_allocate_inode_block(ext2_filesystem_t *fs, ext2_inode_t *inode, uint32_t inode_index, uint32_t block_index) { - pr_debug("Allocating block with index `%d` for inode with index `%d`.\n", block_index, inode_index); + pr_debug("Allocating block `%d` for inode `%d`.\n", block_index, inode_index); // Allocate the block. int real_index = ext2_allocate_block(fs); if (real_index == -1) { @@ -1543,6 +1573,7 @@ static int ext2_allocate_inode_block(ext2_filesystem_t *fs, ext2_inode_t *inode, if (ext2_write_inode(fs, inode, inode_index) == -1) { return -1; } + pr_debug("Succesfully allocated block `%d` for inode `%d`.\n", block_index, inode_index); return 0; } @@ -1563,7 +1594,7 @@ static ssize_t ext2_read_inode_block(ext2_filesystem_t *fs, ext2_inode_t *inode, return -1; } // Log the address to the inode block. - pr_debug("Read inode block (block_index:%4u, real_index:%4u)\n", block_index, real_index); + // pr_debug("Read inode block (block_index:%4u, real_index:%4u)\n", block_index, real_index); // Read the block. return ext2_read_block(fs, real_index, buffer); } @@ -1591,7 +1622,7 @@ static ssize_t ext2_write_inode_block(ext2_filesystem_t *fs, ext2_inode_t *inode return -1; } // Log the address to the inode block. - pr_debug("Write inode block (block_index:%4u, real_index:%4u, inode_index:%4u)\n", block_index, real_index, inode_index); + // pr_debug("Write inode block (block_index:%4u, real_index:%4u, inode_index:%4u)\n", block_index, real_index, inode_index); // Write the block. return ext2_write_block(fs, real_index, buffer); } @@ -1617,9 +1648,7 @@ static ssize_t ext2_read_inode_data(ext2_filesystem_t *fs, ext2_inode_t *inode, uint32_t end_size = end_offset - end_block * fs->block_size; // Allocate the cache. - uint8_t *cache = kmem_cache_alloc(fs->ext2_buffer_cache, GFP_KERNEL); - // Clean the cache. - memset(cache, 0, fs->ext2_buffer_cache->size); + uint8_t *cache = ext2_alloc_cache(fs); uint32_t curr_off = 0, left, right, ret = end_offset - offset; for (uint32_t block_index = start_block; block_index <= end_block; ++block_index) { @@ -1643,7 +1672,7 @@ static ssize_t ext2_read_inode_data(ext2_filesystem_t *fs, ext2_inode_t *inode, curr_off += (right - left + 1); } // Free the cache. - kmem_cache_free(cache); + ext2_dealloc_cache(cache); return ret; } @@ -1675,9 +1704,7 @@ static ssize_t ext2_write_inode_data(ext2_filesystem_t *fs, ext2_inode_t *inode, uint32_t end_size = end_offset - end_block * fs->block_size; // Allocate the cache. - uint8_t *cache = kmem_cache_alloc(fs->ext2_buffer_cache, GFP_KERNEL); - // Clean the cache. - memset(cache, 0, fs->ext2_buffer_cache->size); + uint8_t *cache = ext2_alloc_cache(fs); uint32_t curr_off = 0, left, right, ret = end_offset - offset; for (uint32_t block_index = start_block; block_index <= end_block; ++block_index) { @@ -1702,7 +1729,7 @@ static ssize_t ext2_write_inode_data(ext2_filesystem_t *fs, ext2_inode_t *inode, } } // Free the cache. - kmem_cache_free(cache); + ext2_dealloc_cache(cache); return ret; } @@ -1825,11 +1852,9 @@ static int ext2_clean_inode_content(ext2_filesystem_t *fs, ext2_inode_t *inode, return 1; } // Allocate the cache. - uint8_t *cache = kmem_cache_alloc(fs->ext2_buffer_cache, GFP_KERNEL); + uint8_t *cache = ext2_alloc_cache(fs); // Get the cache size. size_t cache_size = fs->ext2_buffer_cache->size; - // Clean the cache. - memset(cache, 0, cache_size); // int ret = 0; for (ssize_t offset = 0, to_write; offset < inode->size;) { @@ -1845,7 +1870,7 @@ static int ext2_clean_inode_content(ext2_filesystem_t *fs, ext2_inode_t *inode, offset += written; } // Free the cache. - kmem_cache_free(cache); + ext2_dealloc_cache(cache); return ret; } @@ -1853,55 +1878,235 @@ static int ext2_clean_inode_content(ext2_filesystem_t *fs, ext2_inode_t *inode, // Directory Entry Management Functions // ============================================================================ -/// @brief Returns the rec_len from the given name. -/// @param name the name we use to compute the rec_len. -/// @return the rec_len value. -static inline uint32_t ext2_get_rec_len_from_name(const char *name) +/// @brief Initializes a directory entry. +/// @param direntry a pointer to the directory entry we want to initialize. +/// @param name the name of the new entry. +/// @param inode_index its inode index. +/// @param rec_len the length of the new entry. +/// @param file_type its file type. +static inline void ext2_initialize_direntry( + ext2_dirent_t *direntry, + const char *name, + ino_t inode_index, + uint32_t rec_len, + uint8_t file_type) { - unsigned int rec_len = sizeof(ext2_dirent_t) + strlen(name) - EXT2_NAME_LEN; - rec_len += (rec_len % 4) ? (4 - (rec_len % 4)) : 0; - return rec_len; + // Initialize the new directory entry. + direntry->inode = inode_index; + direntry->rec_len = rec_len; + direntry->name_len = strlen(name); + direntry->file_type = file_type; + strncpy(direntry->name, name, direntry->name_len); } -/// @brief Returns the rec_len from the given direntry. -/// @param direntry the direntry we use to compute the rec_len. -/// @return the rec_len value. -static inline uint32_t ext2_get_rec_len_from_direntry(const ext2_dirent_t *direntry) +/// @brief Dumps the directory entries inside the parent directory. +/// @param fs a pointer to the filesystem. +/// @param parent_inode the parent inode. +/// @param cache cache for memory EXT2 operations. +static inline void ext2_dump_direntries(ext2_filesystem_t *fs, ext2_inode_t *parent_inode, uint8_t *cache) { - unsigned int rec_len = sizeof(ext2_dirent_t) + direntry->name_len - EXT2_NAME_LEN; - rec_len += (rec_len % 4) ? (4 - (rec_len % 4)) : 0; - return rec_len; + ext2_direntry_iterator_t it = ext2_direntry_iterator_begin(fs, cache, parent_inode); + // Iterate the directory entries. + while (ext2_direntry_iterator_valid(&it)) { + // Dump the entry. + ext2_dump_dirent(it.direntry); + // Move to next entry. + ext2_direntry_iterator_next(&it); + } +} + +/// @brief Searches for a free unused directory entry (inode == 0). +/// @param fs a pointer to the filesystem. +/// @param parent_inode the parent inode. +/// @param parent_inode_index the parent inode index. +/// @param cache cache for memory EXT2 operations. +/// @param name the name of the new entry. +/// @param inode_index its inode index. +/// @param file_type its file type. +/// @return 1 on success, 0 on failure. +static inline int ext2_get_free_direntry( + ext2_filesystem_t *fs, + ext2_inode_t *parent_inode, + uint32_t parent_inode_index, + uint8_t *cache, + const char *name, + ino_t inode_index, + uint8_t file_type) +{ + // Get the rec_len; + uint32_t rec_len = ext2_get_rec_len_from_name(name); + // Prepare iterator. + ext2_direntry_iterator_t it = ext2_direntry_iterator_begin(fs, cache, parent_inode); + // Iterate the directory entries. + while (ext2_direntry_iterator_valid(&it)) { + // If we hit a direntry with an empty inode, that is a free direntry. + // Then, we check that the rec_len of the free direntry is big enough. + if ((it.direntry->inode == 0) && (rec_len <= it.direntry->rec_len)) { + // Initialize the new directory entry. + ext2_initialize_direntry(it.direntry, name, inode_index, rec_len, file_type); + // Update the inode block. + if (ext2_write_inode_block(fs, parent_inode, parent_inode_index, it.block_index, cache) == -1) { + pr_err("Failed to update the block of the father directory.\n"); + return 0; + } + pr_debug("\nFound free directory entry:\n"); + ext2_dump_dirent(it.direntry); + pr_debug("\n"); + return 1; + } + // Move to next entry. + ext2_direntry_iterator_next(&it); + } + return 0; +} + +/// @brief Appends the new directory entry at the end of the last used block, if +/// there is enough space. +/// @param fs a pointer to the filesystem. +/// @param parent_inode the parent inode. +/// @param parent_inode_index the parent inode index. +/// @param cache cache for memory EXT2 operations. +/// @param name the name of the new entry. +/// @param inode_index its inode index. +/// @param file_type its file type. +/// @return 1 on success, 0 on failure. +static inline int ext2_append_new_direntry( + ext2_filesystem_t *fs, + ext2_inode_t *parent_inode, + uint32_t parent_inode_index, + uint8_t *cache, + const char *name, + ino_t inode_index, + uint8_t file_type) +{ + // Get the rec_len; + uint32_t rec_len = ext2_get_rec_len_from_name(name); + // Prepare iterator. + ext2_direntry_iterator_t it = ext2_direntry_iterator_begin(fs, cache, parent_inode); + // Iterate the directory entries. + while (ext2_direntry_iterator_valid(&it)) { + // Compute the real rec_len of the entry. + uint32_t real_rec_len = ext2_get_rec_len_from_direntry(it.direntry); + // Check if we reached the last directory entry, if that's the case, we + // check if the remaining space is big enough. + if ((it.direntry->rec_len != real_rec_len) && ((it.block_offset + rec_len) <= fs->block_size)) { + // Fix the rec_len of the entry. + it.direntry->rec_len = real_rec_len; + // Move the block offset correctly. + it.block_offset += real_rec_len; + // Move the total offset correctly. + it.total_offset += real_rec_len; + // Set the iterator pointer to the new free location. + it.direntry = ext2_direntry_iterator_get(&it); + // Initialize the new directory entry. + ext2_initialize_direntry(it.direntry, name, inode_index, fs->block_size - it.block_offset, file_type); + // Update the inode block. + if (ext2_write_inode_block(fs, parent_inode, parent_inode_index, it.block_index, cache) == -1) { + pr_err("Failed to update the block of the father directory.\n"); + return 0; + } + pr_debug("\nAppended new directory entry:\n"); + ext2_dump_dirent(it.direntry); + pr_debug("\n"); + return 1; + } + // Move to next entry. + ext2_direntry_iterator_next(&it); + } + return 0; +} + +/// @brief Allocates a new block, and creates a new directory entry inside that +/// new block. +/// @param fs a pointer to the filesystem. +/// @param parent_inode the parent inode. +/// @param parent_inode_index the parent inode index. +/// @param cache cache for memory EXT2 operations. +/// @param name the name of the new entry. +/// @param inode_index its inode index. +/// @param file_type its file type. +/// @return 1 on success, 0 on failure. +static inline int ext2_create_new_direntry( + ext2_filesystem_t *fs, + ext2_inode_t *parent_inode, + uint32_t parent_inode_index, + uint8_t *cache, + const char *name, + ino_t inode_index, + uint8_t file_type) +{ + // Get the rec_len; + uint32_t rec_len = ext2_get_rec_len_from_name(name); + // Prepare iterator. + ext2_direntry_iterator_t it = ext2_direntry_iterator_begin(fs, cache, parent_inode); + // Find the last entry. + while (ext2_direntry_iterator_valid(&it)) { ext2_direntry_iterator_next(&it); } + // Allocate a new block. + if (ext2_allocate_inode_block(fs, parent_inode, parent_inode_index, it.block_index) == -1) { + pr_err("Failed to allocate a new block for an inode.\n"); + return 0; + } + // Update the inode block. + if (ext2_write_inode_block(fs, parent_inode, parent_inode_index, it.block_index, cache) == -1) { + pr_err("Failed to update the block of the father directory.\n"); + return 0; + } + // Move to new block inted. + it.block_index += 1; + // Update the inode size. + parent_inode->size = it.block_index * fs->block_size; + // Update the inode. + if (ext2_write_inode(fs, parent_inode, parent_inode_index) == -1) { + pr_err("Failed to update the inode of the father directory.\n"); + return 0; + } + // Initialize the iterato once again, with the new block.. + it = ext2_direntry_iterator_begin(fs, cache, parent_inode); + // Move back at the beginning of the block. + it.block_offset = 0; + // Set the iterator pointer to the new free location. + it.direntry = ext2_direntry_iterator_get(&it); + // Initialize the new directory entry. + ext2_initialize_direntry(it.direntry, name, inode_index, fs->block_size - it.block_offset, file_type); + // Update the inode block. + if (ext2_write_inode_block(fs, parent_inode, parent_inode_index, it.block_index, cache) == -1) { + pr_err("Failed to update the block of the father directory.\n"); + return 0; + } + pr_debug("\nCreated new directory entry:\n"); + ext2_dump_dirent(it.direntry); + pr_debug("\n"); + return 1; } /// @brief Allocates a directory entry. /// @param fs a pointer to the filesystem. /// @param parent_inode_index the inode index of the parent. -/// @param inode_index the inode index of the new entry. +/// @param direntry_inode_index the inode index of the new entry. /// @param name the name of the new entry. /// @param file_type the type of file. /// @return 0 on success, a negative value on failure. static int ext2_allocate_direntry( ext2_filesystem_t *fs, uint32_t parent_inode_index, - uint32_t inode_index, + uint32_t direntry_inode_index, const char *name, uint8_t file_type) { + ext2_inode_t parent_inode, direntry_inode; // Get the inode associated with the new directory entry. - ext2_inode_t inode; - if (ext2_read_inode(fs, &inode, inode_index) == -1) { - pr_err("Failed to read the inode of the directory entry (%d).\n", inode_index); + if (ext2_read_inode(fs, &direntry_inode, direntry_inode_index) == -1) { + pr_err("Failed to read the inode of the directory entry (%d).\n", direntry_inode_index); return -1; } // Update the number of links to the inode. - inode.links_count += 1; + direntry_inode.links_count += 1; // Write the inode back. - if (ext2_write_inode(fs, &inode, inode_index) == -1) { - pr_err("Failed to update the inode of the directory entry.\n"); + if (ext2_write_inode(fs, &direntry_inode, direntry_inode_index) == -1) { + pr_err("Failed to update the inode of the directory entry (%d).\n", direntry_inode_index); return -1; } // Get the inode associated with the parent directory. - ext2_inode_t parent_inode; if (ext2_read_inode(fs, &parent_inode, parent_inode_index) == -1) { pr_err("Failed to read the parent inode (%d).\n", parent_inode_index); return -1; @@ -1911,91 +2116,28 @@ static int ext2_allocate_direntry( pr_err("The parent inode is not a directory (ino: %d, mode: %d).\n", parent_inode_index, parent_inode.mode); return -1; } - pr_debug("ext2_allocate_direntry(parent: %d, name: \"%s\", inode: %d)\n", parent_inode_index, name, inode_index); - // Compute the rec_len for the name of the new direntry. Remember, the name - // is not actually 256 chars long as specified in EXT2_NAME_LEN, that is - // just a maximum. - unsigned int rec_len = ext2_get_rec_len_from_name(name); // Allocate the cache. - uint8_t *cache = kmem_cache_alloc(fs->ext2_buffer_cache, GFP_KERNEL); - // Clean the cache. - memset(cache, 0, fs->ext2_buffer_cache->size); - // Iterate the directory entries. - ext2_direntry_iterator_t it = ext2_direntry_iterator_begin(fs, cache, &parent_inode); - for (; ext2_direntry_iterator_valid(&it); ext2_direntry_iterator_next(&it)) { - // If we hit a direntry with an empty inode, that is a free direntry. - if (it.direntry->inode == 0) { - if (rec_len <= it.direntry->rec_len) { - break; + uint8_t *cache = ext2_alloc_cache(fs); + + ext2_dump_direntries(fs, &parent_inode, cache); + + // Get free directory entry. + if (!ext2_get_free_direntry(fs, &parent_inode, parent_inode_index, cache, name, direntry_inode_index, file_type)) { + if (!ext2_append_new_direntry(fs, &parent_inode, parent_inode_index, cache, name, direntry_inode_index, file_type)) { + if (!ext2_create_new_direntry(fs, &parent_inode, parent_inode_index, cache, name, direntry_inode_index, file_type)) { + pr_err("Failed to place directory entry.\n"); + // Free the cache. + ext2_dealloc_cache(cache); + return -1; } } - // Compute the real rec_len of the entry. - uint32_t real_rec_len = ext2_get_rec_len_from_direntry(it.direntry); - // If the previous direntry has a wrong rec_len (wrong because it identifies the last). - if ((it.direntry->rec_len != real_rec_len) && (it.total_offset + it.direntry->rec_len == parent_inode.size)) { - // Fix the rec_len of the entry. - it.direntry->rec_len = real_rec_len; - // Move the block offset correctly. - it.block_offset += real_rec_len; - // Move the total offset correctly. - it.total_offset += real_rec_len; - // Clean the pointer to the direntry inside the iterator. - it.direntry = NULL; - // Stop here. - break; - } } - if (it.direntry) { - // Clean the previous name. - memset(it.direntry->name, 0, it.direntry->name_len); - // Set the inode. - it.direntry->inode = inode_index; - // Set the new name length, - it.direntry->name_len = strlen(name); - // Set the new name. - memcpy(it.direntry->name, name, it.direntry->name_len); - // Set the file type. - it.direntry->file_type = file_type; - - if (ext2_write_inode_block(fs, &parent_inode, parent_inode_index, it.block_index, cache) == -1) { - pr_err("Failed to update the block of the father directory.\n"); - goto free_cache_return_error; - } - goto free_cache_return_success; - } else if ((it.block_offset + rec_len) >= fs->block_size) { - it.block_index += 1; - if (ext2_allocate_inode_block(fs, &parent_inode, parent_inode_index, it.block_index) == -1) { - pr_err("Failed to allocate a new block for an inode.\n"); - goto free_cache_return_error; - } - it.block_offset = 0; - parent_inode.size += fs->block_size; - if (ext2_write_inode(fs, &parent_inode, parent_inode_index) == -1) { - pr_err("Failed to update the inode of the father directory.\n"); - goto free_cache_return_error; - } - } - ext2_dirent_t *new_direntry = (ext2_dirent_t *)((uintptr_t)cache + it.block_offset); - new_direntry->inode = inode_index; - new_direntry->rec_len = fs->block_size - it.block_offset; - new_direntry->name_len = strlen(name); - new_direntry->file_type = file_type; - memcpy(new_direntry->name, name, new_direntry->name_len); - if (ext2_write_inode_block(fs, &parent_inode, parent_inode_index, it.block_index, cache) == -1) { - pr_err("Failed to update the block of the father directory.\n"); - goto free_cache_return_error; - } + ext2_dump_direntries(fs, &parent_inode, cache); -free_cache_return_success: // Free the cache. - kmem_cache_free(cache); + ext2_dealloc_cache(cache); return 0; - -free_cache_return_error: - // Free the cache. - kmem_cache_free(cache); - return -1; } /// @brief Finds the entry with the given `name` inside the `directory`. @@ -2037,9 +2179,9 @@ static int ext2_find_direntry(ext2_filesystem_t *fs, ino_t ino, const char *name } // Allocate the cache. - uint8_t *cache = kmem_cache_alloc(fs->ext2_buffer_cache, GFP_KERNEL); - // Clean the cache. - memset(cache, 0, fs->ext2_buffer_cache->size); + uint8_t *cache = ext2_alloc_cache(fs); + + // Prepare iterator. ext2_direntry_iterator_t it = ext2_direntry_iterator_begin(fs, cache, &inode); for (; ext2_direntry_iterator_valid(&it); ext2_direntry_iterator_next(&it)) { // Skip unused inode. @@ -2074,11 +2216,11 @@ static int ext2_find_direntry(ext2_filesystem_t *fs, ino_t ino, const char *name // Copy the offset of the direntry inside the block. search->block_offset = it.block_offset; // Free the cache. - kmem_cache_free(cache); + ext2_dealloc_cache(cache); return 0; free_cache_return_error: // Free the cache. - kmem_cache_free(cache); + ext2_dealloc_cache(cache); return -1; } @@ -2122,6 +2264,8 @@ static int ext2_resolve_path(vfs_file_t *directory, char *path, ext2_direntry_se } token = strtok_r(NULL, "/", &saveptr); } + pr_debug("ext2_resolve_path(directory: %s, path: %s) -> (%s, %d)\n", + directory->name, path, search->direntry.name, search->direntry.inode); return 0; } @@ -2569,9 +2713,9 @@ static int ext2_unlink(const char *path) pr_err("ext2_stat(%s): Failed to read the inode of parent of `%s`.\n", path, search.direntry.name); return -ENOENT; } - // Allocate the cache and clean it. - uint8_t *cache = kmem_cache_alloc(fs->ext2_buffer_cache, GFP_KERNEL); - memset(cache, 0, fs->ext2_buffer_cache->size); + // Allocate the cache. + uint8_t *cache = ext2_alloc_cache(fs); + // Read the block where the direntry resides. if (ext2_read_inode_block(fs, &parent_inode, search.block_index, cache) == -1) { pr_err("Failed to read the parent inode block `%d`\n", search.block_index); @@ -2611,11 +2755,11 @@ static int ext2_unlink(const char *path) } // Free the cache. - kmem_cache_free(cache); + ext2_dealloc_cache(cache); return 0; free_cache_return_error: // Free the cache. - kmem_cache_free(cache); + ext2_dealloc_cache(cache); return -1; } @@ -2835,9 +2979,8 @@ static ssize_t ext2_getdents(vfs_file_t *file, dirent_t *dirp, off_t doff, size_ uint32_t current = 0; ssize_t written = 0; // Allocate the cache. - uint8_t *cache = kmem_cache_alloc(fs->ext2_buffer_cache, GFP_KERNEL); - // Clean the cache. - memset(cache, 0, fs->ext2_buffer_cache->size); + uint8_t *cache = ext2_alloc_cache(fs); + // Initialize the iterator. ext2_direntry_iterator_t it = ext2_direntry_iterator_begin(fs, cache, &inode); for (; ext2_direntry_iterator_valid(&it) && (written < count); ext2_direntry_iterator_next(&it)) { @@ -2863,7 +3006,7 @@ static ssize_t ext2_getdents(vfs_file_t *file, dirent_t *dirp, off_t doff, size_ ++dirp; } // Free the cache. - kmem_cache_free(cache); + ext2_dealloc_cache(cache); return written; } @@ -2953,8 +3096,6 @@ static int ext2_mkdir(const char *path, mode_t permission) vfs_close(parent); return -ENOENT; } - // Initialize the size of the inode to the block size. - inode.size = fs->block_size; // Increase the number of directories inside the group. fs->block_groups[group_index].used_dirs_count += 1; // Update the bgdt. @@ -3035,8 +3176,7 @@ static int ext2_rmdir(const char *path) } // Allocate the cache and clean it. - uint8_t *cache = kmem_cache_alloc(fs->ext2_buffer_cache, GFP_KERNEL); - memset(cache, 0, fs->ext2_buffer_cache->size); + uint8_t *cache = ext2_alloc_cache(fs); // Read the inode of the direntry we want to unlink. ext2_inode_t inode; @@ -3047,7 +3187,7 @@ static int ext2_rmdir(const char *path) // Check if the directory is empty, if it enters the loop then it means it is not empty. if (!ext2_directory_is_empty(fs, cache, &inode)) { pr_err("The directory is not empty `%s`.\n", search.direntry.name); - kmem_cache_free(cache); + ext2_dealloc_cache(cache); return -ENOTEMPTY; } // Reduce the number of links to the inode. @@ -3080,11 +3220,11 @@ static int ext2_rmdir(const char *path) } // Free the cache. - kmem_cache_free(cache); + ext2_dealloc_cache(cache); return 0; free_cache_return_error: // Free the cache. - kmem_cache_free(cache); + ext2_dealloc_cache(cache); return -1; } From 3d2a163fbd4b15dad614bf89ee08fcf72dea925c Mon Sep 17 00:00:00 2001 From: "Enrico Fraccaroli (Galfurian)" Date: Tue, 16 Jul 2024 15:32:13 -0400 Subject: [PATCH 06/40] Just some minor inconsequential fixes, because the compiler is complaining. --- mentos/inc/process/wait.h | 2 +- mentos/src/hardware/timer.c | 4 ++-- mentos/src/klib/list.c | 2 +- mentos/src/process/wait.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mentos/inc/process/wait.h b/mentos/inc/process/wait.h index d02c33db..4d88b13f 100644 --- a/mentos/inc/process/wait.h +++ b/mentos/inc/process/wait.h @@ -82,7 +82,7 @@ typedef struct wait_queue_entry_t { /// @brief Allocates the memory for a wait_queue_entry. /// @return a pointer to the allocated wait_queue_entry. -wait_queue_entry_t * wait_queue_entry_alloc(); +wait_queue_entry_t * wait_queue_entry_alloc(void); /// @brief Frees the memory of a wait_queue_entry. /// @param wait_queue_entry pointer to the wait_queue_entry. diff --git a/mentos/src/hardware/timer.c b/mentos/src/hardware/timer.c index ed0f8061..96fa87fd 100644 --- a/mentos/src/hardware/timer.c +++ b/mentos/src/hardware/timer.c @@ -279,7 +279,7 @@ static inline void __timer_cascate_base(tvec_base_t *base) /// @brief Allocates the memory for timer. /// @return a pointer to the allocated timer. -static inline struct timer_list *__timer_list_alloc() +static inline struct timer_list *__timer_list_alloc(void) { // Allocate the memory. struct timer_list *timer = (struct timer_list *)kmalloc(sizeof(struct timer_list)); @@ -363,7 +363,7 @@ typedef struct sleep_data_t { /// @brief Allocates the memory for sleep_data. /// @return a pointer to the allocated sleep_data. -static inline struct sleep_data_t *__sleep_data_alloc() +static inline struct sleep_data_t *__sleep_data_alloc(void) { // Allocate the memory. sleep_data_t *sleep_data = (sleep_data_t *)kmalloc(sizeof(sleep_data_t)); diff --git a/mentos/src/klib/list.c b/mentos/src/klib/list.c index 2747fe1a..75cb5c5c 100644 --- a/mentos/src/klib/list.c +++ b/mentos/src/klib/list.c @@ -27,7 +27,7 @@ static inline void __node_dealloc(listnode_t *node) /// @brief Allocates the memory for a list. /// @return a pointer to the newly allocated list. -static inline list_t *__list_alloc() +static inline list_t *__list_alloc(void) { // Allocate the list. list_t *list = kmalloc(sizeof(list_t)); diff --git a/mentos/src/process/wait.c b/mentos/src/process/wait.c index be84788e..b0352d8c 100644 --- a/mentos/src/process/wait.c +++ b/mentos/src/process/wait.c @@ -30,7 +30,7 @@ static inline void __remove_wait_queue(wait_queue_head_t *head, wait_queue_entry list_head_remove(&wq->task_list); } -wait_queue_entry_t *wait_queue_entry_alloc() +wait_queue_entry_t *wait_queue_entry_alloc(void) { // Allocate the memory. wait_queue_entry_t *wait_queue_entry = (wait_queue_entry_t *)kmalloc(sizeof(wait_queue_entry_t)); From 5c34af6d030a2a438e5344824fd7116fcff41248 Mon Sep 17 00:00:00 2001 From: "Enrico Fraccaroli (Galfurian)" Date: Thu, 18 Jul 2024 10:13:22 -0400 Subject: [PATCH 07/40] User real path in cd command. --- programs/shell.c | 65 +++++++++++++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 26 deletions(-) diff --git a/programs/shell.c b/programs/shell.c index 0b17c6ab..cdadff7c 100644 --- a/programs/shell.c +++ b/programs/shell.c @@ -52,7 +52,8 @@ static char status_buf[4] = { 0 }; static sigset_t oldmask; -static void __block_sigchld(void) { +static void __block_sigchld(void) +{ sigset_t mask; //sigmask functions only fail on invalid inputs -> no exception handling needed sigemptyset(&mask); @@ -60,7 +61,8 @@ static void __block_sigchld(void) { sigprocmask(SIG_BLOCK, &mask, &oldmask); } -static void __unblock_sigchld(void) { +static void __unblock_sigchld(void) +{ sigprocmask(SIG_SETMASK, &oldmask, NULL); } @@ -179,7 +181,8 @@ static inline void __prompt_print(void) USER, HOSTNAME, timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, CWD); } -static char* __getenv(const char* var) { +static char *__getenv(const char *var) +{ if (strlen(var) > 1) { return getenv(var); } @@ -192,7 +195,7 @@ static char* __getenv(const char* var) { // TODO: implement access to argv /* int arg = strtol(var, NULL, 10); */ /* if (arg < argc) { */ - /* return argv[arg]; */ + /* return argv[arg]; */ /* } */ return NULL; @@ -344,13 +347,20 @@ static int __cd(int argc, char *argv[]) return 1; } } - int fd = open(path, O_RDONLY | O_DIRECTORY, S_IXUSR); + // Get the real path. + char real_path[PATH_MAX]; + if (realpath(path, real_path, PATH_MAX) != real_path) { + printf("cd: Failed to resolve directory.\n"); + return 1; + } + // Open the given directory. + int fd = open(real_path, O_RDONLY | O_DIRECTORY, S_IXUSR); if (fd == -1) { - printf("cd: %s: %s\n", path, strerror(errno)); + printf("cd: %s: %s\n", real_path, strerror(errno)); return 1; } // Set current working directory. - chdir(path); + chdir(real_path); close(fd); // Get the updated working directory. char cwd[PATH_MAX]; @@ -498,7 +508,8 @@ static inline void __cmd_sug(dirent_t *suggestion, size_t starting_position) } } -static void __cmd_complete(void) { +static void __cmd_complete(void) +{ // Get the lenght of the command. size_t cmd_len = strlen(cmd); // Count the number of words. @@ -581,12 +592,14 @@ static void __cmd_complete(void) { } } -static void __move_cursor_back(int n) { +static void __move_cursor_back(int n) +{ printf("\033[%dD", n); cmd_cursor_index -= n; } -static void __move_cursor_forward(int n) { +static void __move_cursor_forward(int n) +{ printf("\033[%dC", n); cmd_cursor_index += n; } @@ -704,16 +717,16 @@ static void __alloc_argv(char *command, int *argc, char ***argv) if ((*argc) == 0) { return; } - (*argv) = (char **)malloc(sizeof(char *) * ((*argc) + 1)); - bool_t inword = false; - char *cit = command; - char *argStart = command; - size_t argcIt = 0; + (*argv) = (char **)malloc(sizeof(char *) * ((*argc) + 1)); + bool_t inword = false; + char *cit = command; + char *argStart = command; + size_t argcIt = 0; do { if (!__is_separator(*cit)) { if (!inword) { argStart = cit; - inword = true; + inword = true; } continue; } @@ -723,7 +736,7 @@ static void __alloc_argv(char *command, int *argc, char ***argv) // Expand possible environment variables in the current argument char expand_env_buf[BUFSIZ]; ___expand_env(argStart, expand_env_buf, BUFSIZ, cit - argStart, true); - (*argv)[argcIt] = (char*)malloc(strlen(expand_env_buf) + 1); + (*argv)[argcIt] = (char *)malloc(strlen(expand_env_buf) + 1); strcpy((*argv)[argcIt++], expand_env_buf); } } while (*cit++); @@ -738,12 +751,13 @@ static inline void __free_argv(int argc, char **argv) free(argv); } -static void __setup_redirects(int *argcp, char ***argvp) { +static void __setup_redirects(int *argcp, char ***argvp) +{ char **argv = *argvp; - int argc = *argcp; + int argc = *argcp; - char* path; - int flags = O_CREAT | O_WRONLY; + char *path; + int flags = O_CREAT | O_WRONLY; mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; bool_t rd_stdout, rd_stderr; @@ -757,7 +771,7 @@ static void __setup_redirects(int *argcp, char ***argvp) { path = argv[i + 1]; // Determine stream to redirect - switch(*argv[i]) { + switch (*argv[i]) { case '&': rd_stdout = rd_stderr = true; break; @@ -782,8 +796,8 @@ static void __setup_redirects(int *argcp, char ***argvp) { *argcp -= 2; free(argv[i]); (*argvp)[i] = 0; - free(argv[i+1]); - (*argvp)[i+1] = 0; + free(argv[i + 1]); + (*argvp)[i + 1] = 0; int fd = open(path, flags, mode); if (fd < 0) { @@ -805,7 +819,7 @@ static void __setup_redirects(int *argcp, char ***argvp) { } } -static int __execute_cmd(char* command, bool_t add_to_history) +static int __execute_cmd(char *command, bool_t add_to_history) { int _status = 0; // Retrieve the options from the command. @@ -920,7 +934,6 @@ static void __interactive_mode(void) #pragma clang diagnostic pop } - void wait_for_child(int signum) { wait(NULL); From a5d8b3bef3feeecf6ec1a40119e3916f3459b606 Mon Sep 17 00:00:00 2001 From: "Enrico Fraccaroli (Galfurian)" Date: Thu, 18 Jul 2024 10:16:30 -0400 Subject: [PATCH 08/40] Simplify rec_len computation. --- mentos/src/fs/ext2.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/mentos/src/fs/ext2.c b/mentos/src/fs/ext2.c index 63f012a2..b35e6832 100644 --- a/mentos/src/fs/ext2.c +++ b/mentos/src/fs/ext2.c @@ -696,9 +696,7 @@ static inline void ext2_dealloc_cache(uint8_t *cache) /// @return the rec_len value. static inline uint32_t ext2_get_rec_len_from_name(const char *name) { - uint32_t rec_len = sizeof(ext2_dirent_t) + strlen(name) + 1; - rec_len += (rec_len % 4) ? (4 - (rec_len % 4)) : 0; - return rec_len; + return round_up(sizeof(ext2_dirent_t) + strlen(name) + 1, 4); } /// @brief Returns the rec_len from the given direntry. @@ -706,9 +704,16 @@ static inline uint32_t ext2_get_rec_len_from_name(const char *name) /// @return the rec_len value. static inline uint32_t ext2_get_rec_len_from_direntry(const ext2_dirent_t *direntry) { - uint32_t rec_len = sizeof(ext2_dirent_t) + direntry->name_len + 1; - rec_len += (rec_len % 4) ? (4 - (rec_len % 4)) : 0; - return rec_len; + return round_up(sizeof(ext2_dirent_t) + direntry->name_len + 1, 4); +} + +/// @brief If the real rec_len is different from the on in attribute rec_len, +/// this is the last directory entry. +/// @param direntry the directory entry to check. +/// @return 1 if it is the last, 0 otherwise. +static inline uint32_t ext2_is_last_directory_entry(const ext2_dirent_t *direntry) +{ + return direntry->rec_len != ext2_get_rec_len_from_direntry(direntry); } /// @brief Cheks if the bit at the given linear index is free. From bd5d6617e222e8ba1dafe4013ab2bf089d0b9ac1 Mon Sep 17 00:00:00 2001 From: "Enrico Fraccaroli (Galfurian)" Date: Thu, 18 Jul 2024 10:17:08 -0400 Subject: [PATCH 09/40] Do not recompute rec_len. --- mentos/src/fs/ext2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mentos/src/fs/ext2.c b/mentos/src/fs/ext2.c index b35e6832..a3b8061c 100644 --- a/mentos/src/fs/ext2.c +++ b/mentos/src/fs/ext2.c @@ -1802,8 +1802,8 @@ void ext2_direntry_iterator_next(ext2_direntry_iterator_t *iterator) // Get the current rec_len. uint32_t rec_len = ext2_direntry_iterator_get(iterator)->rec_len; // Advance the offsets. - iterator->block_offset += rec_len; - iterator->total_offset += rec_len; + iterator->block_offset += iterator->direntry->rec_len; + iterator->total_offset += iterator->direntry->rec_len; // If we reached the end of the inode, stop. if (iterator->total_offset >= iterator->inode->size) { // The iterator is not valid anymore. From 9cd06bc77cf9a94a2eeddc6774c56bd7837975b1 Mon Sep 17 00:00:00 2001 From: "Enrico Fraccaroli (Galfurian)" Date: Thu, 18 Jul 2024 10:17:47 -0400 Subject: [PATCH 10/40] Do not recompute rec_len. --- mentos/src/fs/ext2.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/mentos/src/fs/ext2.c b/mentos/src/fs/ext2.c index a3b8061c..100f5911 100644 --- a/mentos/src/fs/ext2.c +++ b/mentos/src/fs/ext2.c @@ -1799,8 +1799,6 @@ ext2_direntry_iterator_t ext2_direntry_iterator_begin(ext2_filesystem_t *fs, uin /// @param iterator the iterator. void ext2_direntry_iterator_next(ext2_direntry_iterator_t *iterator) { - // Get the current rec_len. - uint32_t rec_len = ext2_direntry_iterator_get(iterator)->rec_len; // Advance the offsets. iterator->block_offset += iterator->direntry->rec_len; iterator->total_offset += iterator->direntry->rec_len; From 0d50ff678a5078819919657f25ba72d02b20893b Mon Sep 17 00:00:00 2001 From: "Enrico Fraccaroli (Galfurian)" Date: Thu, 18 Jul 2024 10:18:21 -0400 Subject: [PATCH 11/40] Add function that initializes a new direntry block. --- mentos/src/fs/ext2.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/mentos/src/fs/ext2.c b/mentos/src/fs/ext2.c index 100f5911..07d9a255 100644 --- a/mentos/src/fs/ext2.c +++ b/mentos/src/fs/ext2.c @@ -1902,6 +1902,40 @@ static inline void ext2_initialize_direntry( strncpy(direntry->name, name, direntry->name_len); } +static inline int ext2_initialize_new_direntry_block( + ext2_filesystem_t *fs, + ext2_inode_t *inode, + uint32_t inode_index, + uint32_t block_index) +{ + // Allocate a new block. + if (ext2_allocate_inode_block(fs, inode, inode_index, block_index) == -1) { + pr_err("Failed to allocate a new block for an inode.\n"); + return 0; + } + // Update the inode size. + inode->size = (block_index + 1) * fs->block_size; + // Update the inode. + if (ext2_write_inode(fs, inode, inode_index) == -1) { + pr_err("Failed to update the inode of directory.\n"); + return 0; + } + // Create a cache. + uint8_t *cache = ext2_alloc_cache(fs); + // Get the first non-initizlied direntry. + ext2_dirent_t *direntry = (ext2_dirent_t *)cache; + // Initialize the new directory entry. + ext2_initialize_direntry(direntry, "", 0, fs->block_size, ext2_file_type_unknown); + // Update the inode block. + if (ext2_write_inode_block(fs, inode, inode_index, block_index, cache) == -1) { + pr_err("Failed to update the block of the father directory.\n"); + ext2_dealloc_cache(cache); + return 0; + } + ext2_dealloc_cache(cache); + return 1; +} + /// @brief Dumps the directory entries inside the parent directory. /// @param fs a pointer to the filesystem. /// @param parent_inode the parent inode. From e36c6017bd3411442d61a7fcc0f359a352f1de62 Mon Sep 17 00:00:00 2001 From: "Enrico Fraccaroli (Galfurian)" Date: Thu, 18 Jul 2024 10:19:54 -0400 Subject: [PATCH 12/40] Allocate new direntry block during mkdir. Fix how new directory entries are inserted. --- mentos/src/fs/ext2.c | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/mentos/src/fs/ext2.c b/mentos/src/fs/ext2.c index 07d9a255..1d4ac4ba 100644 --- a/mentos/src/fs/ext2.c +++ b/mentos/src/fs/ext2.c @@ -1943,9 +1943,11 @@ static inline int ext2_initialize_new_direntry_block( static inline void ext2_dump_direntries(ext2_filesystem_t *fs, ext2_inode_t *parent_inode, uint8_t *cache) { ext2_direntry_iterator_t it = ext2_direntry_iterator_begin(fs, cache, parent_inode); + pr_debug("Directory entries:\n"); // Iterate the directory entries. while (ext2_direntry_iterator_valid(&it)) { // Dump the entry. + pr_debug(" [%2u, %4u]", it.block_index, it.block_offset); ext2_dump_dirent(it.direntry); // Move to next entry. ext2_direntry_iterator_next(&it); @@ -1980,15 +1982,18 @@ static inline int ext2_get_free_direntry( // Then, we check that the rec_len of the free direntry is big enough. if ((it.direntry->inode == 0) && (rec_len <= it.direntry->rec_len)) { // Initialize the new directory entry. + if (ext2_is_last_directory_entry(it.direntry)) { + assert(fs->block_size > it.block_offset); + rec_len = fs->block_size - it.block_offset; + } ext2_initialize_direntry(it.direntry, name, inode_index, rec_len, file_type); // Update the inode block. if (ext2_write_inode_block(fs, parent_inode, parent_inode_index, it.block_index, cache) == -1) { pr_err("Failed to update the block of the father directory.\n"); return 0; } - pr_debug("\nFound free directory entry:\n"); + pr_debug("Found free directory entry:\n"); ext2_dump_dirent(it.direntry); - pr_debug("\n"); return 1; } // Move to next entry. @@ -2017,34 +2022,34 @@ static inline int ext2_append_new_direntry( uint8_t file_type) { // Get the rec_len; - uint32_t rec_len = ext2_get_rec_len_from_name(name); + uint32_t rec_len = ext2_get_rec_len_from_name(name), real_rec_len; // Prepare iterator. ext2_direntry_iterator_t it = ext2_direntry_iterator_begin(fs, cache, parent_inode); // Iterate the directory entries. while (ext2_direntry_iterator_valid(&it)) { - // Compute the real rec_len of the entry. - uint32_t real_rec_len = ext2_get_rec_len_from_direntry(it.direntry); // Check if we reached the last directory entry, if that's the case, we // check if the remaining space is big enough. - if ((it.direntry->rec_len != real_rec_len) && ((it.block_offset + rec_len) <= fs->block_size)) { + if (ext2_is_last_directory_entry(it.direntry) && ((it.block_offset + rec_len) <= fs->block_size)) { + pr_debug("Found last directory entry (offset: %u):\n", it.block_offset); + ext2_dump_dirent(it.direntry); + // Compute the real rec_len of the entry. + real_rec_len = ext2_get_rec_len_from_direntry(it.direntry); // Fix the rec_len of the entry. it.direntry->rec_len = real_rec_len; - // Move the block offset correctly. + // Move the block offsets correctly. it.block_offset += real_rec_len; - // Move the total offset correctly. it.total_offset += real_rec_len; // Set the iterator pointer to the new free location. it.direntry = ext2_direntry_iterator_get(&it); // Initialize the new directory entry. ext2_initialize_direntry(it.direntry, name, inode_index, fs->block_size - it.block_offset, file_type); + pr_debug("Appended new directory entry (offset: %u -> %u):\n", it.block_offset - real_rec_len, it.block_offset); + ext2_dump_dirent(it.direntry); // Update the inode block. if (ext2_write_inode_block(fs, parent_inode, parent_inode_index, it.block_index, cache) == -1) { pr_err("Failed to update the block of the father directory.\n"); return 0; } - pr_debug("\nAppended new directory entry:\n"); - ext2_dump_dirent(it.direntry); - pr_debug("\n"); return 1; } // Move to next entry. @@ -2110,9 +2115,8 @@ static inline int ext2_create_new_direntry( pr_err("Failed to update the block of the father directory.\n"); return 0; } - pr_debug("\nCreated new directory entry:\n"); + pr_debug("Created new directory entry:\n"); ext2_dump_dirent(it.direntry); - pr_debug("\n"); return 1; } @@ -2156,6 +2160,7 @@ static int ext2_allocate_direntry( // Allocate the cache. uint8_t *cache = ext2_alloc_cache(fs); + pr_debug("[Before] "); ext2_dump_direntries(fs, &parent_inode, cache); // Get free directory entry. @@ -2170,6 +2175,7 @@ static int ext2_allocate_direntry( } } + pr_debug("[After ] "); ext2_dump_direntries(fs, &parent_inode, cache); // Free the cache. @@ -3153,6 +3159,11 @@ static int ext2_mkdir(const char *path, mode_t permission) vfs_close(parent); return -ENOENT; } + // Allocate a new block. + if (!ext2_initialize_new_direntry_block(fs, &inode, inode_index, 0)) { + pr_err("Failed to allocate a new block for an inode.\n"); + return 0; + } // Create a directory entry, inside the new directory, pointing to itself. if (ext2_allocate_direntry(fs, inode_index, inode_index, ".", ext2_file_type_directory) == -1) { pr_err("Failed to allocate a new direntry for the inode.\n"); From 37413ba49987f44bf1420733d502801187dab206 Mon Sep 17 00:00:00 2001 From: "Enrico Fraccaroli (Galfurian)" Date: Thu, 18 Jul 2024 13:15:15 -0400 Subject: [PATCH 13/40] Get most recent version of inode info before using it. Fix inode link counter. --- mentos/src/fs/ext2.c | 98 +++++++++++++++++++++++++------------------- 1 file changed, 55 insertions(+), 43 deletions(-) diff --git a/mentos/src/fs/ext2.c b/mentos/src/fs/ext2.c index 1d4ac4ba..b0a43467 100644 --- a/mentos/src/fs/ext2.c +++ b/mentos/src/fs/ext2.c @@ -1904,19 +1904,23 @@ static inline void ext2_initialize_direntry( static inline int ext2_initialize_new_direntry_block( ext2_filesystem_t *fs, - ext2_inode_t *inode, uint32_t inode_index, uint32_t block_index) { + ext2_inode_t inode; + if (ext2_read_inode(fs, &inode, inode_index) == -1) { + pr_err("Failed to read the inode of `%u`.\n", inode_index); + return 0; + } // Allocate a new block. - if (ext2_allocate_inode_block(fs, inode, inode_index, block_index) == -1) { + if (ext2_allocate_inode_block(fs, &inode, inode_index, block_index) == -1) { pr_err("Failed to allocate a new block for an inode.\n"); return 0; } // Update the inode size. - inode->size = (block_index + 1) * fs->block_size; + inode.size = (block_index + 1) * fs->block_size; // Update the inode. - if (ext2_write_inode(fs, inode, inode_index) == -1) { + if (ext2_write_inode(fs, &inode, inode_index) == -1) { pr_err("Failed to update the inode of directory.\n"); return 0; } @@ -1927,7 +1931,7 @@ static inline int ext2_initialize_new_direntry_block( // Initialize the new directory entry. ext2_initialize_direntry(direntry, "", 0, fs->block_size, ext2_file_type_unknown); // Update the inode block. - if (ext2_write_inode_block(fs, inode, inode_index, block_index, cache) == -1) { + if (ext2_write_inode_block(fs, &inode, inode_index, block_index, cache) == -1) { pr_err("Failed to update the block of the father directory.\n"); ext2_dealloc_cache(cache); return 0; @@ -1938,9 +1942,12 @@ static inline int ext2_initialize_new_direntry_block( /// @brief Dumps the directory entries inside the parent directory. /// @param fs a pointer to the filesystem. -/// @param parent_inode the parent inode. /// @param cache cache for memory EXT2 operations. -static inline void ext2_dump_direntries(ext2_filesystem_t *fs, ext2_inode_t *parent_inode, uint8_t *cache) +/// @param parent_inode the parent inode. +static inline void ext2_dump_direntries( + ext2_filesystem_t *fs, + uint8_t *cache, + ext2_inode_t *parent_inode) { ext2_direntry_iterator_t it = ext2_direntry_iterator_begin(fs, cache, parent_inode); pr_debug("Directory entries:\n"); @@ -1956,26 +1963,30 @@ static inline void ext2_dump_direntries(ext2_filesystem_t *fs, ext2_inode_t *par /// @brief Searches for a free unused directory entry (inode == 0). /// @param fs a pointer to the filesystem. -/// @param parent_inode the parent inode. -/// @param parent_inode_index the parent inode index. /// @param cache cache for memory EXT2 operations. +/// @param parent_inode_index the parent inode index. /// @param name the name of the new entry. /// @param inode_index its inode index. /// @param file_type its file type. /// @return 1 on success, 0 on failure. static inline int ext2_get_free_direntry( ext2_filesystem_t *fs, - ext2_inode_t *parent_inode, - uint32_t parent_inode_index, uint8_t *cache, + ino_t parent_inode_index, const char *name, ino_t inode_index, uint8_t file_type) { + // Read the parent inode. + ext2_inode_t parent_inode; + if (ext2_read_inode(fs, &parent_inode, parent_inode_index) == -1) { + pr_err("Failed to read the parent inode `%u`.\n", parent_inode_index); + return 0; + } // Get the rec_len; uint32_t rec_len = ext2_get_rec_len_from_name(name); // Prepare iterator. - ext2_direntry_iterator_t it = ext2_direntry_iterator_begin(fs, cache, parent_inode); + ext2_direntry_iterator_t it = ext2_direntry_iterator_begin(fs, cache, &parent_inode); // Iterate the directory entries. while (ext2_direntry_iterator_valid(&it)) { // If we hit a direntry with an empty inode, that is a free direntry. @@ -1988,7 +1999,7 @@ static inline int ext2_get_free_direntry( } ext2_initialize_direntry(it.direntry, name, inode_index, rec_len, file_type); // Update the inode block. - if (ext2_write_inode_block(fs, parent_inode, parent_inode_index, it.block_index, cache) == -1) { + if (ext2_write_inode_block(fs, &parent_inode, parent_inode_index, it.block_index, cache) == -1) { pr_err("Failed to update the block of the father directory.\n"); return 0; } @@ -2005,26 +2016,30 @@ static inline int ext2_get_free_direntry( /// @brief Appends the new directory entry at the end of the last used block, if /// there is enough space. /// @param fs a pointer to the filesystem. -/// @param parent_inode the parent inode. -/// @param parent_inode_index the parent inode index. /// @param cache cache for memory EXT2 operations. +/// @param parent_inode_index the parent inode index. /// @param name the name of the new entry. /// @param inode_index its inode index. /// @param file_type its file type. /// @return 1 on success, 0 on failure. static inline int ext2_append_new_direntry( ext2_filesystem_t *fs, - ext2_inode_t *parent_inode, - uint32_t parent_inode_index, uint8_t *cache, + ino_t parent_inode_index, const char *name, ino_t inode_index, uint8_t file_type) { + // Read the parent inode. + ext2_inode_t parent_inode; + if (ext2_read_inode(fs, &parent_inode, parent_inode_index) == -1) { + pr_err("Failed to read the parent inode `%u`.\n", parent_inode_index); + return 0; + } // Get the rec_len; uint32_t rec_len = ext2_get_rec_len_from_name(name), real_rec_len; // Prepare iterator. - ext2_direntry_iterator_t it = ext2_direntry_iterator_begin(fs, cache, parent_inode); + ext2_direntry_iterator_t it = ext2_direntry_iterator_begin(fs, cache, &parent_inode); // Iterate the directory entries. while (ext2_direntry_iterator_valid(&it)) { // Check if we reached the last directory entry, if that's the case, we @@ -2046,7 +2061,7 @@ static inline int ext2_append_new_direntry( pr_debug("Appended new directory entry (offset: %u -> %u):\n", it.block_offset - real_rec_len, it.block_offset); ext2_dump_dirent(it.direntry); // Update the inode block. - if (ext2_write_inode_block(fs, parent_inode, parent_inode_index, it.block_index, cache) == -1) { + if (ext2_write_inode_block(fs, &parent_inode, parent_inode_index, it.block_index, cache) == -1) { pr_err("Failed to update the block of the father directory.\n"); return 0; } @@ -2061,49 +2076,51 @@ static inline int ext2_append_new_direntry( /// @brief Allocates a new block, and creates a new directory entry inside that /// new block. /// @param fs a pointer to the filesystem. -/// @param parent_inode the parent inode. -/// @param parent_inode_index the parent inode index. /// @param cache cache for memory EXT2 operations. +/// @param parent_inode_index the parent inode index. /// @param name the name of the new entry. /// @param inode_index its inode index. /// @param file_type its file type. /// @return 1 on success, 0 on failure. static inline int ext2_create_new_direntry( ext2_filesystem_t *fs, - ext2_inode_t *parent_inode, - uint32_t parent_inode_index, uint8_t *cache, + ino_t parent_inode_index, const char *name, ino_t inode_index, uint8_t file_type) { - // Get the rec_len; - uint32_t rec_len = ext2_get_rec_len_from_name(name); + // Read the parent inode. + ext2_inode_t parent_inode; + if (ext2_read_inode(fs, &parent_inode, parent_inode_index) == -1) { + pr_err("Failed to read the parent inode `%u`.\n", parent_inode_index); + return 0; + } // Prepare iterator. - ext2_direntry_iterator_t it = ext2_direntry_iterator_begin(fs, cache, parent_inode); + ext2_direntry_iterator_t it = ext2_direntry_iterator_begin(fs, cache, &parent_inode); // Find the last entry. while (ext2_direntry_iterator_valid(&it)) { ext2_direntry_iterator_next(&it); } // Allocate a new block. - if (ext2_allocate_inode_block(fs, parent_inode, parent_inode_index, it.block_index) == -1) { + if (ext2_allocate_inode_block(fs, &parent_inode, parent_inode_index, it.block_index) == -1) { pr_err("Failed to allocate a new block for an inode.\n"); return 0; } // Update the inode block. - if (ext2_write_inode_block(fs, parent_inode, parent_inode_index, it.block_index, cache) == -1) { + if (ext2_write_inode_block(fs, &parent_inode, parent_inode_index, it.block_index, cache) == -1) { pr_err("Failed to update the block of the father directory.\n"); return 0; } // Move to new block inted. it.block_index += 1; // Update the inode size. - parent_inode->size = it.block_index * fs->block_size; + parent_inode.size = it.block_index * fs->block_size; // Update the inode. - if (ext2_write_inode(fs, parent_inode, parent_inode_index) == -1) { + if (ext2_write_inode(fs, &parent_inode, parent_inode_index) == -1) { pr_err("Failed to update the inode of the father directory.\n"); return 0; } // Initialize the iterato once again, with the new block.. - it = ext2_direntry_iterator_begin(fs, cache, parent_inode); + it = ext2_direntry_iterator_begin(fs, cache, &parent_inode); // Move back at the beginning of the block. it.block_offset = 0; // Set the iterator pointer to the new free location. @@ -2111,7 +2128,7 @@ static inline int ext2_create_new_direntry( // Initialize the new directory entry. ext2_initialize_direntry(it.direntry, name, inode_index, fs->block_size - it.block_offset, file_type); // Update the inode block. - if (ext2_write_inode_block(fs, parent_inode, parent_inode_index, it.block_index, cache) == -1) { + if (ext2_write_inode_block(fs, &parent_inode, parent_inode_index, it.block_index, cache) == -1) { pr_err("Failed to update the block of the father directory.\n"); return 0; } @@ -2134,8 +2151,8 @@ static int ext2_allocate_direntry( const char *name, uint8_t file_type) { - ext2_inode_t parent_inode, direntry_inode; // Get the inode associated with the new directory entry. + ext2_inode_t direntry_inode; if (ext2_read_inode(fs, &direntry_inode, direntry_inode_index) == -1) { pr_err("Failed to read the inode of the directory entry (%d).\n", direntry_inode_index); return -1; @@ -2148,6 +2165,7 @@ static int ext2_allocate_direntry( return -1; } // Get the inode associated with the parent directory. + ext2_inode_t parent_inode; if (ext2_read_inode(fs, &parent_inode, parent_inode_index) == -1) { pr_err("Failed to read the parent inode (%d).\n", parent_inode_index); return -1; @@ -2160,13 +2178,10 @@ static int ext2_allocate_direntry( // Allocate the cache. uint8_t *cache = ext2_alloc_cache(fs); - pr_debug("[Before] "); - ext2_dump_direntries(fs, &parent_inode, cache); - // Get free directory entry. - if (!ext2_get_free_direntry(fs, &parent_inode, parent_inode_index, cache, name, direntry_inode_index, file_type)) { - if (!ext2_append_new_direntry(fs, &parent_inode, parent_inode_index, cache, name, direntry_inode_index, file_type)) { - if (!ext2_create_new_direntry(fs, &parent_inode, parent_inode_index, cache, name, direntry_inode_index, file_type)) { + if (!ext2_get_free_direntry(fs, cache, parent_inode_index, name, direntry_inode_index, file_type)) { + if (!ext2_append_new_direntry(fs, cache, parent_inode_index, name, direntry_inode_index, file_type)) { + if (!ext2_create_new_direntry(fs, cache, parent_inode_index, name, direntry_inode_index, file_type)) { pr_err("Failed to place directory entry.\n"); // Free the cache. ext2_dealloc_cache(cache); @@ -2175,9 +2190,6 @@ static int ext2_allocate_direntry( } } - pr_debug("[After ] "); - ext2_dump_direntries(fs, &parent_inode, cache); - // Free the cache. ext2_dealloc_cache(cache); return 0; @@ -3160,7 +3172,7 @@ static int ext2_mkdir(const char *path, mode_t permission) return -ENOENT; } // Allocate a new block. - if (!ext2_initialize_new_direntry_block(fs, &inode, inode_index, 0)) { + if (!ext2_initialize_new_direntry_block(fs, inode_index, 0)) { pr_err("Failed to allocate a new block for an inode.\n"); return 0; } From ba29901bb16c702bd81b8d384916e626c53ebbf2 Mon Sep 17 00:00:00 2001 From: "Enrico Fraccaroli (Galfurian)" Date: Thu, 18 Jul 2024 13:15:25 -0400 Subject: [PATCH 14/40] Add error check. --- programs/stat.c | 55 +++++++++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/programs/stat.c b/programs/stat.c index ebcda026..f5834231 100644 --- a/programs/stat.c +++ b/programs/stat.c @@ -26,19 +26,20 @@ #define S_IFCHR 0x2000 ///< Character device #define S_IFIFO 0x1000 ///< Fifo -static void __print_time(const char* prefix, time_t *time) { +static void __print_time(const char *prefix, time_t *time) +{ tm_t *timeinfo = localtime(time); printf("%s%d-%d-%d %d:%d:%d\n", - prefix, - timeinfo->tm_year, - timeinfo->tm_mon, - timeinfo->tm_mday, - timeinfo->tm_hour, - timeinfo->tm_min, - timeinfo->tm_sec); + prefix, + timeinfo->tm_year, + timeinfo->tm_mon, + timeinfo->tm_mday, + timeinfo->tm_hour, + timeinfo->tm_min, + timeinfo->tm_sec); } -int main(int argc, char** argv) +int main(int argc, char **argv) { if (argc != 2) { printf("%s: missing operand.\n", argv[0]); @@ -47,28 +48,27 @@ int main(int argc, char** argv) } if (strcmp(argv[1], "--help") == 0) { printf("Usage: %s FILE\n", argv[0]); - printf( "Display file status.\n"); + printf("Display file status.\n"); exit(0); } stat_t statbuf; - if(stat(argv[1], &statbuf) == -1) { + if (stat(argv[1], &statbuf) == -1) { printf("%s: cannot stat '%s': %s\n", argv[0], argv[1], strerror(errno)); exit(1); } - printf("File: %s\n", argv[1]); printf("Size: %s\n", to_human_size(statbuf.st_size)); printf("File type: "); switch (statbuf.st_mode & S_IFMT) { - case S_IFBLK: printf("block device\n"); break; - case S_IFCHR: printf("character device\n"); break; - case S_IFDIR: printf("directory\n"); break; - case S_IFIFO: printf("FIFO/pipe\n"); break; - case S_IFLNK: printf("symlink\n"); break; - case S_IFREG: printf("regular file\n"); break; - case S_IFSOCK: printf("socket\n"); break; - default: printf("unknown?\n"); break; + case S_IFBLK : printf("block device\n"); break; + case S_IFCHR : printf("character device\n"); break; + case S_IFDIR : printf("directory\n"); break; + case S_IFIFO : printf("FIFO/pipe\n"); break; + case S_IFLNK : printf("symlink\n"); break; + case S_IFREG : printf("regular file\n"); break; + case S_IFSOCK: printf("socket\n"); break; + default : printf("unknown?\n"); break; } printf("Access: (%.4o/", statbuf.st_mode & 0xFFF); // Print the access permissions. @@ -83,11 +83,16 @@ int main(int argc, char** argv) putchar(bitmask_check(statbuf.st_mode, S_IXOTH) ? 'x' : '-'); passwd_t *user = getpwuid(statbuf.st_uid); - group_t *grp = getgrgid(statbuf.st_gid); - - printf(") Uid: (%d/%s) Gid: (%d/%s)\n", - statbuf.st_uid, user->pw_name, - statbuf.st_gid, grp->gr_name); + if (!user) { + printf("%s: failed to retrieve uid '%u'.\n", argv[0], statbuf.st_uid); + exit(1); + } + group_t *group = getgrgid(statbuf.st_gid); + if (!group) { + printf("%s: failed to retrieve gid '%u'.\n", argv[0], statbuf.st_gid); + exit(1); + } + printf(") Uid: (%d/%s) Gid: (%d/%s)\n", statbuf.st_uid, user->pw_name, statbuf.st_gid, group->gr_name); __print_time("Access: ", &statbuf.st_atime); __print_time("Modify: ", &statbuf.st_mtime); From 7d60bd2806772167591546b0f251faea705c72bb Mon Sep 17 00:00:00 2001 From: "Enrico Fraccaroli (Galfurian)" Date: Thu, 18 Jul 2024 13:15:46 -0400 Subject: [PATCH 15/40] Minor change to clang formatting for switches. --- .clang-format | 710 +++++++++++++++++++++++++------------------------- 1 file changed, 357 insertions(+), 353 deletions(-) diff --git a/.clang-format b/.clang-format index dfa07a04..0bdf33a8 100644 --- a/.clang-format +++ b/.clang-format @@ -18,7 +18,7 @@ AlignConsecutiveMacros: true AlignOperands: AlignAfterOperator AlignTrailingComments: true AllowAllParametersOfDeclarationOnNextLine: false -AllowShortCaseLabelsOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: true AllowShortFunctionsOnASingleLine: None AllowShortIfStatementsOnASingleLine: Always AllowShortLoopsOnASingleLine: true @@ -54,7 +54,7 @@ BreakConstructorInitializersBeforeComma: false BreakAfterJavaFieldAnnotations: false BreakStringLiterals: false ColumnLimit: 0 -CommentPragmas: '^ IWYU pragma:' +CommentPragmas: "^ IWYU pragma:" #CompactNamespaces: false # Unknown to clang-format-4.0 ConstructorInitializerAllOnOneLineOrOnePerLine: false ConstructorInitializerIndentWidth: 4 @@ -70,366 +70,371 @@ ExperimentalAutoDetectBinPacking: false # | sed "s,^#define \([^[:space:]]*for_each[^[:space:]]*\)(.*$, - '\1'," \ # | sort | uniq ForEachMacros: - - 'apei_estatus_for_each_section' - - 'ata_for_each_dev' - - 'ata_for_each_link' - - '__ata_qc_for_each' - - 'ata_qc_for_each' - - 'ata_qc_for_each_raw' - - 'ata_qc_for_each_with_internal' - - 'ax25_for_each' - - 'ax25_uid_for_each' - - 'bio_for_each_integrity_vec' - - '__bio_for_each_segment' - - 'bio_for_each_segment' - - 'bio_for_each_segment_all' - - 'bio_list_for_each' - - 'bip_for_each_vec' - - 'blkg_for_each_descendant_post' - - 'blkg_for_each_descendant_pre' - - 'blk_queue_for_each_rl' - - 'bond_for_each_slave' - - 'bond_for_each_slave_rcu' - - 'bpf_for_each_spilled_reg' - - 'btree_for_each_safe128' - - 'btree_for_each_safe32' - - 'btree_for_each_safe64' - - 'btree_for_each_safel' - - 'card_for_each_dev' - - 'cgroup_taskset_for_each' - - 'cgroup_taskset_for_each_leader' - - 'cpufreq_for_each_entry' - - 'cpufreq_for_each_entry_idx' - - 'cpufreq_for_each_valid_entry' - - 'cpufreq_for_each_valid_entry_idx' - - 'css_for_each_child' - - 'css_for_each_descendant_post' - - 'css_for_each_descendant_pre' - - 'device_for_each_child_node' - - 'drm_atomic_crtc_for_each_plane' - - 'drm_atomic_crtc_state_for_each_plane' - - 'drm_atomic_crtc_state_for_each_plane_state' - - 'drm_atomic_for_each_plane_damage' - - 'drm_connector_for_each_possible_encoder' - - 'drm_for_each_connector_iter' - - 'drm_for_each_crtc' - - 'drm_for_each_encoder' - - 'drm_for_each_encoder_mask' - - 'drm_for_each_fb' - - 'drm_for_each_legacy_plane' - - 'drm_for_each_plane' - - 'drm_for_each_plane_mask' - - 'drm_mm_for_each_hole' - - 'drm_mm_for_each_node' - - 'drm_mm_for_each_node_in_range' - - 'drm_mm_for_each_node_safe' - - 'for_each_active_drhd_unit' - - 'for_each_active_iommu' - - 'for_each_available_child_of_node' - - 'for_each_bio' - - 'for_each_board_func_rsrc' - - 'for_each_bvec' - - 'for_each_card_components' - - 'for_each_card_links' - - 'for_each_card_links_safe' - - 'for_each_card_prelinks' - - 'for_each_card_rtds' - - 'for_each_card_rtds_safe' - - 'for_each_cgroup_storage_type' - - 'for_each_child_of_node' - - 'for_each_clear_bit' - - 'for_each_clear_bit_from' - - 'for_each_cmsghdr' - - 'for_each_compatible_node' - - 'for_each_component_dais' - - 'for_each_component_dais_safe' - - 'for_each_comp_order' - - 'for_each_console' - - 'for_each_cpu' - - 'for_each_cpu_and' - - 'for_each_cpu_not' - - 'for_each_cpu_wrap' - - 'for_each_dev_addr' - - 'for_each_dma_cap_mask' - - 'for_each_dpcm_be' - - 'for_each_dpcm_be_rollback' - - 'for_each_dpcm_be_safe' - - 'for_each_dpcm_fe' - - 'for_each_drhd_unit' - - 'for_each_dss_dev' - - 'for_each_efi_memory_desc' - - 'for_each_efi_memory_desc_in_map' - - 'for_each_endpoint_of_node' - - 'for_each_evictable_lru' - - 'for_each_fib6_node_rt_rcu' - - 'for_each_fib6_walker_rt' - - 'for_each_free_mem_range' - - 'for_each_free_mem_range_reverse' - - 'for_each_func_rsrc' - - 'for_each_hstate' - - 'for_each_if' - - 'for_each_iommu' - - 'for_each_ip_tunnel_rcu' - - 'for_each_irq_nr' - - 'for_each_link_codecs' - - 'for_each_lru' - - 'for_each_matching_node' - - 'for_each_matching_node_and_match' - - 'for_each_memblock' - - 'for_each_memblock_type' - - 'for_each_memcg_cache_index' - - 'for_each_mem_pfn_range' - - 'for_each_mem_range' - - 'for_each_mem_range_rev' - - 'for_each_migratetype_order' - - 'for_each_msi_entry' - - 'for_each_msi_entry_safe' - - 'for_each_net' - - 'for_each_netdev' - - 'for_each_netdev_continue' - - 'for_each_netdev_continue_rcu' - - 'for_each_netdev_feature' - - 'for_each_netdev_in_bond_rcu' - - 'for_each_netdev_rcu' - - 'for_each_netdev_reverse' - - 'for_each_netdev_safe' - - 'for_each_net_rcu' - - 'for_each_new_connector_in_state' - - 'for_each_new_crtc_in_state' - - 'for_each_new_plane_in_state' - - 'for_each_new_private_obj_in_state' - - 'for_each_node' - - 'for_each_node_by_name' - - 'for_each_node_by_type' - - 'for_each_node_mask' - - 'for_each_node_state' - - 'for_each_node_with_cpus' - - 'for_each_node_with_property' - - 'for_each_of_allnodes' - - 'for_each_of_allnodes_from' - - 'for_each_of_cpu_node' - - 'for_each_of_pci_range' - - 'for_each_old_connector_in_state' - - 'for_each_old_crtc_in_state' - - 'for_each_oldnew_connector_in_state' - - 'for_each_oldnew_crtc_in_state' - - 'for_each_oldnew_plane_in_state' - - 'for_each_oldnew_plane_in_state_reverse' - - 'for_each_oldnew_private_obj_in_state' - - 'for_each_old_plane_in_state' - - 'for_each_old_private_obj_in_state' - - 'for_each_online_cpu' - - 'for_each_online_node' - - 'for_each_online_pgdat' - - 'for_each_pci_bridge' - - 'for_each_pci_dev' - - 'for_each_pci_msi_entry' - - 'for_each_populated_zone' - - 'for_each_possible_cpu' - - 'for_each_present_cpu' - - 'for_each_prime_number' - - 'for_each_prime_number_from' - - 'for_each_process' - - 'for_each_process_thread' - - 'for_each_property_of_node' - - 'for_each_registered_fb' - - 'for_each_reserved_mem_region' - - 'for_each_rtd_codec_dai' - - 'for_each_rtd_codec_dai_rollback' - - 'for_each_rtdcom' - - 'for_each_rtdcom_safe' - - 'for_each_set_bit' - - 'for_each_set_bit_from' - - 'for_each_sg' - - 'for_each_sg_dma_page' - - 'for_each_sg_page' - - 'for_each_sibling_event' - - '__for_each_thread' - - 'for_each_thread' - - 'for_each_zone' - - 'for_each_zone_zonelist' - - 'for_each_zone_zonelist_nodemask' - - 'fwnode_for_each_available_child_node' - - 'fwnode_for_each_child_node' - - 'fwnode_graph_for_each_endpoint' - - 'gadget_for_each_ep' - - 'hash_for_each' - - 'hash_for_each_possible' - - 'hash_for_each_possible_rcu' - - 'hash_for_each_possible_rcu_notrace' - - 'hash_for_each_possible_safe' - - 'hash_for_each_rcu' - - 'hash_for_each_safe' - - 'hctx_for_each_ctx' - - 'hlist_bl_for_each_entry' - - 'hlist_bl_for_each_entry_rcu' - - 'hlist_bl_for_each_entry_safe' - - 'hlist_for_each' - - 'hlist_for_each_entry' - - 'hlist_for_each_entry_continue' - - 'hlist_for_each_entry_continue_rcu' - - 'hlist_for_each_entry_continue_rcu_bh' - - 'hlist_for_each_entry_from' - - 'hlist_for_each_entry_from_rcu' - - 'hlist_for_each_entry_rcu' - - 'hlist_for_each_entry_rcu_bh' - - 'hlist_for_each_entry_rcu_notrace' - - 'hlist_for_each_entry_safe' - - '__hlist_for_each_rcu' - - 'hlist_for_each_safe' - - 'hlist_nulls_for_each_entry' - - 'hlist_nulls_for_each_entry_from' - - 'hlist_nulls_for_each_entry_rcu' - - 'hlist_nulls_for_each_entry_safe' - - 'i3c_bus_for_each_i2cdev' - - 'i3c_bus_for_each_i3cdev' - - 'ide_host_for_each_port' - - 'ide_port_for_each_dev' - - 'ide_port_for_each_present_dev' - - 'idr_for_each_entry' - - 'idr_for_each_entry_continue' - - 'idr_for_each_entry_ul' - - 'inet_bind_bucket_for_each' - - 'inet_lhash2_for_each_icsk_rcu' - - 'key_for_each' - - 'key_for_each_safe' - - 'klp_for_each_func' - - 'klp_for_each_object' - - 'kvm_for_each_memslot' - - 'kvm_for_each_vcpu' - - 'list_for_each' - - 'list_for_each_codec' - - 'list_for_each_codec_safe' - - 'list_for_each_entry' - - 'list_for_each_entry_continue' - - 'list_for_each_entry_continue_rcu' - - 'list_for_each_entry_continue_reverse' - - 'list_for_each_entry_from' - - 'list_for_each_entry_from_rcu' - - 'list_for_each_entry_from_reverse' - - 'list_for_each_entry_lockless' - - 'list_for_each_entry_rcu' - - 'list_for_each_entry_reverse' - - 'list_for_each_entry_safe' - - 'list_for_each_entry_safe_continue' - - 'list_for_each_entry_safe_from' - - 'list_for_each_entry_safe_reverse' - - 'list_for_each_prev' - - 'list_for_each_prev_safe' - - 'list_for_each_safe' - - 'llist_for_each' - - 'llist_for_each_entry' - - 'llist_for_each_entry_safe' - - 'llist_for_each_safe' - - 'media_device_for_each_entity' - - 'media_device_for_each_intf' - - 'media_device_for_each_link' - - 'media_device_for_each_pad' - - 'nanddev_io_for_each_page' - - 'netdev_for_each_lower_dev' - - 'netdev_for_each_lower_private' - - 'netdev_for_each_lower_private_rcu' - - 'netdev_for_each_mc_addr' - - 'netdev_for_each_uc_addr' - - 'netdev_for_each_upper_dev_rcu' - - 'netdev_hw_addr_list_for_each' - - 'nft_rule_for_each_expr' - - 'nla_for_each_attr' - - 'nla_for_each_nested' - - 'nlmsg_for_each_attr' - - 'nlmsg_for_each_msg' - - 'nr_neigh_for_each' - - 'nr_neigh_for_each_safe' - - 'nr_node_for_each' - - 'nr_node_for_each_safe' - - 'of_for_each_phandle' - - 'of_property_for_each_string' - - 'of_property_for_each_u32' - - 'pci_bus_for_each_resource' - - 'ping_portaddr_for_each_entry' - - 'plist_for_each' - - 'plist_for_each_continue' - - 'plist_for_each_entry' - - 'plist_for_each_entry_continue' - - 'plist_for_each_entry_safe' - - 'plist_for_each_safe' - - 'pnp_for_each_card' - - 'pnp_for_each_dev' - - 'protocol_for_each_card' - - 'protocol_for_each_dev' - - 'queue_for_each_hw_ctx' - - 'radix_tree_for_each_slot' - - 'radix_tree_for_each_tagged' - - 'rbtree_postorder_for_each_entry_safe' - - 'rdma_for_each_port' - - 'resource_list_for_each_entry' - - 'resource_list_for_each_entry_safe' - - 'rhl_for_each_entry_rcu' - - 'rhl_for_each_rcu' - - 'rht_for_each' - - 'rht_for_each_continue' - - 'rht_for_each_entry' - - 'rht_for_each_entry_continue' - - 'rht_for_each_entry_rcu' - - 'rht_for_each_entry_rcu_continue' - - 'rht_for_each_entry_safe' - - 'rht_for_each_rcu' - - 'rht_for_each_rcu_continue' - - '__rq_for_each_bio' - - 'rq_for_each_segment' - - 'scsi_for_each_prot_sg' - - 'scsi_for_each_sg' - - 'sctp_for_each_hentry' - - 'sctp_skb_for_each' - - 'shdma_for_each_chan' - - '__shost_for_each_device' - - 'shost_for_each_device' - - 'sk_for_each' - - 'sk_for_each_bound' - - 'sk_for_each_entry_offset_rcu' - - 'sk_for_each_from' - - 'sk_for_each_rcu' - - 'sk_for_each_safe' - - 'sk_nulls_for_each' - - 'sk_nulls_for_each_from' - - 'sk_nulls_for_each_rcu' - - 'snd_array_for_each' - - 'snd_pcm_group_for_each_entry' - - 'snd_soc_dapm_widget_for_each_path' - - 'snd_soc_dapm_widget_for_each_path_safe' - - 'snd_soc_dapm_widget_for_each_sink_path' - - 'snd_soc_dapm_widget_for_each_source_path' - - 'tb_property_for_each' - - 'tcf_exts_for_each_action' - - 'udp_portaddr_for_each_entry' - - 'udp_portaddr_for_each_entry_rcu' - - 'usb_hub_for_each_child' - - 'v4l2_device_for_each_subdev' - - 'v4l2_m2m_for_each_dst_buf' - - 'v4l2_m2m_for_each_dst_buf_safe' - - 'v4l2_m2m_for_each_src_buf' - - 'v4l2_m2m_for_each_src_buf_safe' - - 'virtio_device_for_each_vq' - - 'xa_for_each' - - 'xas_for_each' - - 'xas_for_each_conflict' - - 'xas_for_each_marked' - - 'zorro_for_each_dev' + - "apei_estatus_for_each_section" + - "ata_for_each_dev" + - "ata_for_each_link" + - "__ata_qc_for_each" + - "ata_qc_for_each" + - "ata_qc_for_each_raw" + - "ata_qc_for_each_with_internal" + - "ax25_for_each" + - "ax25_uid_for_each" + - "bio_for_each_integrity_vec" + - "__bio_for_each_segment" + - "bio_for_each_segment" + - "bio_for_each_segment_all" + - "bio_list_for_each" + - "bip_for_each_vec" + - "blkg_for_each_descendant_post" + - "blkg_for_each_descendant_pre" + - "blk_queue_for_each_rl" + - "bond_for_each_slave" + - "bond_for_each_slave_rcu" + - "bpf_for_each_spilled_reg" + - "btree_for_each_safe128" + - "btree_for_each_safe32" + - "btree_for_each_safe64" + - "btree_for_each_safel" + - "card_for_each_dev" + - "cgroup_taskset_for_each" + - "cgroup_taskset_for_each_leader" + - "cpufreq_for_each_entry" + - "cpufreq_for_each_entry_idx" + - "cpufreq_for_each_valid_entry" + - "cpufreq_for_each_valid_entry_idx" + - "css_for_each_child" + - "css_for_each_descendant_post" + - "css_for_each_descendant_pre" + - "device_for_each_child_node" + - "drm_atomic_crtc_for_each_plane" + - "drm_atomic_crtc_state_for_each_plane" + - "drm_atomic_crtc_state_for_each_plane_state" + - "drm_atomic_for_each_plane_damage" + - "drm_connector_for_each_possible_encoder" + - "drm_for_each_connector_iter" + - "drm_for_each_crtc" + - "drm_for_each_encoder" + - "drm_for_each_encoder_mask" + - "drm_for_each_fb" + - "drm_for_each_legacy_plane" + - "drm_for_each_plane" + - "drm_for_each_plane_mask" + - "drm_mm_for_each_hole" + - "drm_mm_for_each_node" + - "drm_mm_for_each_node_in_range" + - "drm_mm_for_each_node_safe" + - "for_each_active_drhd_unit" + - "for_each_active_iommu" + - "for_each_available_child_of_node" + - "for_each_bio" + - "for_each_board_func_rsrc" + - "for_each_bvec" + - "for_each_card_components" + - "for_each_card_links" + - "for_each_card_links_safe" + - "for_each_card_prelinks" + - "for_each_card_rtds" + - "for_each_card_rtds_safe" + - "for_each_cgroup_storage_type" + - "for_each_child_of_node" + - "for_each_clear_bit" + - "for_each_clear_bit_from" + - "for_each_cmsghdr" + - "for_each_compatible_node" + - "for_each_component_dais" + - "for_each_component_dais_safe" + - "for_each_comp_order" + - "for_each_console" + - "for_each_cpu" + - "for_each_cpu_and" + - "for_each_cpu_not" + - "for_each_cpu_wrap" + - "for_each_dev_addr" + - "for_each_dma_cap_mask" + - "for_each_dpcm_be" + - "for_each_dpcm_be_rollback" + - "for_each_dpcm_be_safe" + - "for_each_dpcm_fe" + - "for_each_drhd_unit" + - "for_each_dss_dev" + - "for_each_efi_memory_desc" + - "for_each_efi_memory_desc_in_map" + - "for_each_endpoint_of_node" + - "for_each_evictable_lru" + - "for_each_fib6_node_rt_rcu" + - "for_each_fib6_walker_rt" + - "for_each_free_mem_range" + - "for_each_free_mem_range_reverse" + - "for_each_func_rsrc" + - "for_each_hstate" + - "for_each_if" + - "for_each_iommu" + - "for_each_ip_tunnel_rcu" + - "for_each_irq_nr" + - "for_each_link_codecs" + - "for_each_lru" + - "for_each_matching_node" + - "for_each_matching_node_and_match" + - "for_each_memblock" + - "for_each_memblock_type" + - "for_each_memcg_cache_index" + - "for_each_mem_pfn_range" + - "for_each_mem_range" + - "for_each_mem_range_rev" + - "for_each_migratetype_order" + - "for_each_msi_entry" + - "for_each_msi_entry_safe" + - "for_each_net" + - "for_each_netdev" + - "for_each_netdev_continue" + - "for_each_netdev_continue_rcu" + - "for_each_netdev_feature" + - "for_each_netdev_in_bond_rcu" + - "for_each_netdev_rcu" + - "for_each_netdev_reverse" + - "for_each_netdev_safe" + - "for_each_net_rcu" + - "for_each_new_connector_in_state" + - "for_each_new_crtc_in_state" + - "for_each_new_plane_in_state" + - "for_each_new_private_obj_in_state" + - "for_each_node" + - "for_each_node_by_name" + - "for_each_node_by_type" + - "for_each_node_mask" + - "for_each_node_state" + - "for_each_node_with_cpus" + - "for_each_node_with_property" + - "for_each_of_allnodes" + - "for_each_of_allnodes_from" + - "for_each_of_cpu_node" + - "for_each_of_pci_range" + - "for_each_old_connector_in_state" + - "for_each_old_crtc_in_state" + - "for_each_oldnew_connector_in_state" + - "for_each_oldnew_crtc_in_state" + - "for_each_oldnew_plane_in_state" + - "for_each_oldnew_plane_in_state_reverse" + - "for_each_oldnew_private_obj_in_state" + - "for_each_old_plane_in_state" + - "for_each_old_private_obj_in_state" + - "for_each_online_cpu" + - "for_each_online_node" + - "for_each_online_pgdat" + - "for_each_pci_bridge" + - "for_each_pci_dev" + - "for_each_pci_msi_entry" + - "for_each_populated_zone" + - "for_each_possible_cpu" + - "for_each_present_cpu" + - "for_each_prime_number" + - "for_each_prime_number_from" + - "for_each_process" + - "for_each_process_thread" + - "for_each_property_of_node" + - "for_each_registered_fb" + - "for_each_reserved_mem_region" + - "for_each_rtd_codec_dai" + - "for_each_rtd_codec_dai_rollback" + - "for_each_rtdcom" + - "for_each_rtdcom_safe" + - "for_each_set_bit" + - "for_each_set_bit_from" + - "for_each_sg" + - "for_each_sg_dma_page" + - "for_each_sg_page" + - "for_each_sibling_event" + - "__for_each_thread" + - "for_each_thread" + - "for_each_zone" + - "for_each_zone_zonelist" + - "for_each_zone_zonelist_nodemask" + - "fwnode_for_each_available_child_node" + - "fwnode_for_each_child_node" + - "fwnode_graph_for_each_endpoint" + - "gadget_for_each_ep" + - "hash_for_each" + - "hash_for_each_possible" + - "hash_for_each_possible_rcu" + - "hash_for_each_possible_rcu_notrace" + - "hash_for_each_possible_safe" + - "hash_for_each_rcu" + - "hash_for_each_safe" + - "hctx_for_each_ctx" + - "hlist_bl_for_each_entry" + - "hlist_bl_for_each_entry_rcu" + - "hlist_bl_for_each_entry_safe" + - "hlist_for_each" + - "hlist_for_each_entry" + - "hlist_for_each_entry_continue" + - "hlist_for_each_entry_continue_rcu" + - "hlist_for_each_entry_continue_rcu_bh" + - "hlist_for_each_entry_from" + - "hlist_for_each_entry_from_rcu" + - "hlist_for_each_entry_rcu" + - "hlist_for_each_entry_rcu_bh" + - "hlist_for_each_entry_rcu_notrace" + - "hlist_for_each_entry_safe" + - "__hlist_for_each_rcu" + - "hlist_for_each_safe" + - "hlist_nulls_for_each_entry" + - "hlist_nulls_for_each_entry_from" + - "hlist_nulls_for_each_entry_rcu" + - "hlist_nulls_for_each_entry_safe" + - "i3c_bus_for_each_i2cdev" + - "i3c_bus_for_each_i3cdev" + - "ide_host_for_each_port" + - "ide_port_for_each_dev" + - "ide_port_for_each_present_dev" + - "idr_for_each_entry" + - "idr_for_each_entry_continue" + - "idr_for_each_entry_ul" + - "inet_bind_bucket_for_each" + - "inet_lhash2_for_each_icsk_rcu" + - "key_for_each" + - "key_for_each_safe" + - "klp_for_each_func" + - "klp_for_each_object" + - "kvm_for_each_memslot" + - "kvm_for_each_vcpu" + - "list_for_each" + - "list_for_each_codec" + - "list_for_each_codec_safe" + - "list_for_each_entry" + - "list_for_each_entry_continue" + - "list_for_each_entry_continue_rcu" + - "list_for_each_entry_continue_reverse" + - "list_for_each_entry_from" + - "list_for_each_entry_from_rcu" + - "list_for_each_entry_from_reverse" + - "list_for_each_entry_lockless" + - "list_for_each_entry_rcu" + - "list_for_each_entry_reverse" + - "list_for_each_entry_safe" + - "list_for_each_entry_safe_continue" + - "list_for_each_entry_safe_from" + - "list_for_each_entry_safe_reverse" + - "list_for_each_prev" + - "list_for_each_prev_safe" + - "list_for_each_safe" + - "llist_for_each" + - "llist_for_each_entry" + - "llist_for_each_entry_safe" + - "llist_for_each_safe" + - "media_device_for_each_entity" + - "media_device_for_each_intf" + - "media_device_for_each_link" + - "media_device_for_each_pad" + - "nanddev_io_for_each_page" + - "netdev_for_each_lower_dev" + - "netdev_for_each_lower_private" + - "netdev_for_each_lower_private_rcu" + - "netdev_for_each_mc_addr" + - "netdev_for_each_uc_addr" + - "netdev_for_each_upper_dev_rcu" + - "netdev_hw_addr_list_for_each" + - "nft_rule_for_each_expr" + - "nla_for_each_attr" + - "nla_for_each_nested" + - "nlmsg_for_each_attr" + - "nlmsg_for_each_msg" + - "nr_neigh_for_each" + - "nr_neigh_for_each_safe" + - "nr_node_for_each" + - "nr_node_for_each_safe" + - "of_for_each_phandle" + - "of_property_for_each_string" + - "of_property_for_each_u32" + - "pci_bus_for_each_resource" + - "ping_portaddr_for_each_entry" + - "plist_for_each" + - "plist_for_each_continue" + - "plist_for_each_entry" + - "plist_for_each_entry_continue" + - "plist_for_each_entry_safe" + - "plist_for_each_safe" + - "pnp_for_each_card" + - "pnp_for_each_dev" + - "protocol_for_each_card" + - "protocol_for_each_dev" + - "queue_for_each_hw_ctx" + - "radix_tree_for_each_slot" + - "radix_tree_for_each_tagged" + - "rbtree_postorder_for_each_entry_safe" + - "rdma_for_each_port" + - "resource_list_for_each_entry" + - "resource_list_for_each_entry_safe" + - "rhl_for_each_entry_rcu" + - "rhl_for_each_rcu" + - "rht_for_each" + - "rht_for_each_continue" + - "rht_for_each_entry" + - "rht_for_each_entry_continue" + - "rht_for_each_entry_rcu" + - "rht_for_each_entry_rcu_continue" + - "rht_for_each_entry_safe" + - "rht_for_each_rcu" + - "rht_for_each_rcu_continue" + - "__rq_for_each_bio" + - "rq_for_each_segment" + - "scsi_for_each_prot_sg" + - "scsi_for_each_sg" + - "sctp_for_each_hentry" + - "sctp_skb_for_each" + - "shdma_for_each_chan" + - "__shost_for_each_device" + - "shost_for_each_device" + - "sk_for_each" + - "sk_for_each_bound" + - "sk_for_each_entry_offset_rcu" + - "sk_for_each_from" + - "sk_for_each_rcu" + - "sk_for_each_safe" + - "sk_nulls_for_each" + - "sk_nulls_for_each_from" + - "sk_nulls_for_each_rcu" + - "snd_array_for_each" + - "snd_pcm_group_for_each_entry" + - "snd_soc_dapm_widget_for_each_path" + - "snd_soc_dapm_widget_for_each_path_safe" + - "snd_soc_dapm_widget_for_each_sink_path" + - "snd_soc_dapm_widget_for_each_source_path" + - "tb_property_for_each" + - "tcf_exts_for_each_action" + - "udp_portaddr_for_each_entry" + - "udp_portaddr_for_each_entry_rcu" + - "usb_hub_for_each_child" + - "v4l2_device_for_each_subdev" + - "v4l2_m2m_for_each_dst_buf" + - "v4l2_m2m_for_each_dst_buf_safe" + - "v4l2_m2m_for_each_src_buf" + - "v4l2_m2m_for_each_src_buf_safe" + - "virtio_device_for_each_vq" + - "xa_for_each" + - "xas_for_each" + - "xas_for_each_conflict" + - "xas_for_each_marked" + - "zorro_for_each_dev" #IncludeBlocks: Preserve # Unknown to clang-format-5.0 IncludeCategories: - - Regex: '.*' + - Regex: ".*" Priority: 1 -IncludeIsMainRegex: '(Test)?$' -IndentCaseLabels: false +IncludeIsMainRegex: "(Test)?$" +IndentCaseBlocks: true +AlignConsecutiveShortCaseStatements: + Enabled: true + AcrossEmptyLines: true + AcrossComments: true + AlignCaseColons: true #IndentPPDirectives: None # Unknown to clang-format-5.0 IndentWidth: 4 IndentWrappedFunctionNames: false JavaScriptQuotes: Leave JavaScriptWrapImports: true KeepEmptyLinesAtTheStartOfBlocks: false -MacroBlockBegin: '' -MacroBlockEnd: '' +MacroBlockBegin: "" +MacroBlockEnd: "" MaxEmptyLinesToKeep: 1 NamespaceIndentation: Inner #ObjCBinPackProtocolList: Auto # Unknown to clang-format-5.0 @@ -467,4 +472,3 @@ SpacesInSquareBrackets: false Standard: Auto TabWidth: 4 UseTab: Never -... From f3e48cfde834d364c886cc17ffd8aec7829edd3a Mon Sep 17 00:00:00 2001 From: "Enrico Fraccaroli (Galfurian)" Date: Thu, 18 Jul 2024 13:16:52 -0400 Subject: [PATCH 16/40] Set debug level to notice. --- mentos/src/fs/ext2.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mentos/src/fs/ext2.c b/mentos/src/fs/ext2.c index b0a43467..0b2545d6 100644 --- a/mentos/src/fs/ext2.c +++ b/mentos/src/fs/ext2.c @@ -4,10 +4,10 @@ /// See LICENSE.md for details. // Setup the logging for this file (do this before any other include). -#include "sys/kernel_levels.h" // Include kernel log levels. -#define __DEBUG_HEADER__ "[EXT2 ]" ///< Change header. -#define __DEBUG_LEVEL__ LOGLEVEL_DEBUG ///< Set log level. -#include "io/debug.h" // Include debugging functions. +#include "sys/kernel_levels.h" // Include kernel log levels. +#define __DEBUG_HEADER__ "[EXT2 ]" ///< Change header. +#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE ///< Set log level. +#include "io/debug.h" // Include debugging functions. #include "assert.h" #include "fcntl.h" From a30467e1d8fcb67edc9ae96771fec3db61f1b65a Mon Sep 17 00:00:00 2001 From: Florian Fischer Date: Sat, 20 Jul 2024 11:38:05 +0200 Subject: [PATCH 17/40] grp: match group name literally Since strncmp only compares up to strlen(name) bytes, "r" and "root" are considered the same group name because only the first byte is compared. This is fixed by assuring that the byte after the name must be the delimiter ':'. --- libc/src/grp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libc/src/grp.c b/libc/src/grp.c index 6203fa71..f69816cc 100644 --- a/libc/src/grp.c +++ b/libc/src/grp.c @@ -74,7 +74,7 @@ static inline int __search_entry(int fd, char *buf, size_t buflen, const char *n buf[pos] = 0; // Check the entry. if (name) { - if (strncmp(buf, name, strlen(name)) == 0) { + if (strncmp(buf, name, strlen(name)) == 0 && buf[strlen(name)] == ':') { return 1; } } else { From 9c4f2ce0d215fbc01a954ac5778e092f0fe5b1ba Mon Sep 17 00:00:00 2001 From: Florian Fischer Date: Sat, 20 Jul 2024 11:41:35 +0200 Subject: [PATCH 18/40] pwd: match user name literally Since strncmp only compares up to strlen(name) bytes, "r" and "root" are considered the same user name because only the first byte is compared. This is fixed by assuring that both the stored user name and the user name to look up are equally long. --- libc/src/pwd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libc/src/pwd.c b/libc/src/pwd.c index 87a8d2bf..9fcbe0c4 100644 --- a/libc/src/pwd.c +++ b/libc/src/pwd.c @@ -72,7 +72,8 @@ static inline char *__search_entry(int fd, char *buffer, int buflen, const char char *name_end = strchr(buffer, ':'); if (name_end) { *name_end = '\0'; - if (strncmp(buffer, name, strlen(name)) == 0) { + if (strlen(name) == strlen(buffer) && + strncmp(buffer, name, strlen(name)) == 0) { *name_end = ':'; return buffer; } From c465b004f3a2cedc635884fb0b5978de566002aa Mon Sep 17 00:00:00 2001 From: Florian Fischer Date: Sat, 20 Jul 2024 11:43:44 +0200 Subject: [PATCH 19/40] add simple tests for pwd.h and grp.h function Test that we do match group and user names literally. --- programs/runtests.c | 2 ++ programs/tests/CMakeLists.txt | 2 ++ programs/tests/t_grp.c | 35 +++++++++++++++++++++++++++++++++++ programs/tests/t_pwd.c | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 74 insertions(+) create mode 100644 programs/tests/t_grp.c create mode 100644 programs/tests/t_pwd.c diff --git a/programs/runtests.c b/programs/runtests.c index 615fae67..6459631d 100644 --- a/programs/runtests.c +++ b/programs/runtests.c @@ -40,6 +40,7 @@ static char *all_tests[] = { "t_exec execvpe", "t_fork 10", "t_gid", + "t_grp", "t_groups", "t_itimer", "t_kill", @@ -49,6 +50,7 @@ static char *all_tests[] = { /* "t_periodic1", */ /* "t_periodic2", */ /* "t_periodic3", */ + "t_pwd", "t_schedfb", "t_semflg", "t_semget", diff --git a/programs/tests/CMakeLists.txt b/programs/tests/CMakeLists.txt index 4ce7804e..1c4c373e 100644 --- a/programs/tests/CMakeLists.txt +++ b/programs/tests/CMakeLists.txt @@ -1,5 +1,7 @@ # List of programs. set(TEST_LIST + t_grp.c + t_pwd.c t_mkdir.c t_dup.c t_creat.c diff --git a/programs/tests/t_grp.c b/programs/tests/t_grp.c new file mode 100644 index 00000000..53deebea --- /dev/null +++ b/programs/tests/t_grp.c @@ -0,0 +1,35 @@ +/// @file t_pwd.c +/// @brief Test the libc grp.h interface +/// @copyright (c) 2014-2024 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include +#include +#include +#include +#include +#include +#include + +static void __test_getgrnam(void) { + // Test that getpwnam matches the whole group name literally + if (getgrnam("r") != NULL) + errx(EXIT_FAILURE, "Group entry for non-existent group \"r\" found"); + + if (getgrnam("root") == NULL) + errx(EXIT_FAILURE, "Group entry for root group not found"); +} + +static void __test_getgrgid(void) { + if (getgrgid(1337) != NULL) + errx(EXIT_FAILURE, "Group entry for non-existent gid 1337 found"); + + if (getgrgid(0) == NULL) + errx(EXIT_FAILURE, "Group entry for gid 0 not found"); +} + +int main(int argc, char *argv[]) +{ + __test_getgrnam(); + __test_getgrgid(); +} diff --git a/programs/tests/t_pwd.c b/programs/tests/t_pwd.c new file mode 100644 index 00000000..09efdb16 --- /dev/null +++ b/programs/tests/t_pwd.c @@ -0,0 +1,35 @@ +/// @file t_pwd.c +/// @brief Test the libc pwd.h interface +/// @copyright (c) 2014-2024 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#include +#include +#include +#include +#include +#include +#include + +static void __test_getpwnam(void) { + // Test that getpwnam matches the whole user name literally + if (getpwnam("r") != NULL) + errx(EXIT_FAILURE, "Password entry for non-existent user \"r\" found"); + + if (getpwnam("root") == NULL) + errx(EXIT_FAILURE, "Password entry for root user not found"); +} + +static void __test_getpwuid(void) { + if (getpwuid(1337) != NULL) + errx(EXIT_FAILURE, "Password entry for non-existent uid 1337 found"); + + if (getpwuid(0) == NULL) + errx(EXIT_FAILURE, "Password entry for uid 0 not found"); +} + +int main(int argc, char *argv[]) +{ + __test_getpwnam(); + __test_getpwuid(); +} From 3c004e18d2aabc0e334b6ffefad4fa125c963558 Mon Sep 17 00:00:00 2001 From: Florian Fischer Date: Sat, 20 Jul 2024 18:47:29 +0200 Subject: [PATCH 20/40] end the user group entry line with a newline The function getgrgid failed, because the second line in the /etc/group file, defining the group user with gid=1000, was not terminated by '\n'. --- files/etc/group | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/etc/group b/files/etc/group index 1fb11d46..38ffec88 100644 --- a/files/etc/group +++ b/files/etc/group @@ -1,2 +1,2 @@ root:x:0:user,root,marco -user:x:1000:banana,marco \ No newline at end of file +user:x:1000:banana,marco From bd50e03d493b06df30d5dc19825e26a23701b43a Mon Sep 17 00:00:00 2001 From: Florian Fischer Date: Sat, 20 Jul 2024 20:17:46 +0200 Subject: [PATCH 21/40] fix listing big directories Now we only print the entries returned by getdents. Previously, if a directory contained 13 entries the entries 2-12 would be printed twice, because they remain in the dents buffer. --- programs/ls.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/programs/ls.c b/programs/ls.c index e65362ec..2f251444 100644 --- a/programs/ls.c +++ b/programs/ls.c @@ -117,13 +117,15 @@ static void print_ls(int fd, const char *path, unsigned int flags) memset(&dents, 0, DENTS_NUM * sizeof(dirent_t)); size_t total_size = 0; - while (getdents(fd, dents, sizeof(dents))) { - for (size_t i = 0; i < DENTS_NUM; ++i) { - if (dents[i].d_ino != 0) { - print_dir_entry(&dents[i], path, flags, &total_size); - } + ssize_t bytes_read = 0; + while ((bytes_read = getdents(fd, dents, sizeof(dents))) > 0) { + for (size_t i = 0; i < bytes_read / sizeof(dirent_t); ++i) { + print_dir_entry(&dents[i], path, flags, &total_size); } } + if (bytes_read < 0) { + perror("getdents failed"); + } printf("\n"); if (bitmask_check(flags, FLAG_L)) { From 50b30e239798eda84f4946d9fdc63e472b81eb63 Mon Sep 17 00:00:00 2001 From: Florian Fischer Date: Sat, 20 Jul 2024 20:21:04 +0200 Subject: [PATCH 22/40] close the file after executing it --- programs/shell.c | 1 + 1 file changed, 1 insertion(+) diff --git a/programs/shell.c b/programs/shell.c index cdadff7c..41b08efe 100644 --- a/programs/shell.c +++ b/programs/shell.c @@ -910,6 +910,7 @@ static int __execute_file(char *path) } } + close(fd); return status; } From 584495ab49682637fd114f75c2e3cbe476fc93aa Mon Sep 17 00:00:00 2001 From: Florian Fischer Date: Wed, 24 Jul 2024 20:16:37 +0200 Subject: [PATCH 23/40] test getgrgid for both gids 0 and 1000 --- programs/tests/t_grp.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/programs/tests/t_grp.c b/programs/tests/t_grp.c index 53deebea..de842c01 100644 --- a/programs/tests/t_grp.c +++ b/programs/tests/t_grp.c @@ -24,8 +24,11 @@ static void __test_getgrgid(void) { if (getgrgid(1337) != NULL) errx(EXIT_FAILURE, "Group entry for non-existent gid 1337 found"); - if (getgrgid(0) == NULL) - errx(EXIT_FAILURE, "Group entry for gid 0 not found"); + int gids[] = {0, 1000}; + for (int i = 0; i < sizeof(gids) / sizeof(int); i++) { + if (getgrgid(gids[i]) == NULL) + errx(EXIT_FAILURE, "Group entry for gid %d not found", gids[i]); + } } int main(int argc, char *argv[]) From 99c978b8a87f505f569c2290176a6352aea9257c Mon Sep 17 00:00:00 2001 From: Florian Fischer Date: Sun, 28 Jul 2024 11:01:47 +0200 Subject: [PATCH 24/40] add man pages for passwd and shadow files The manual pages are greatly inspired by the ones provided by the shadow-utils upstream project https://github.com/shadow-maint/shadow. --- files/usr/share/man/passwd.man | 28 ++++++++++++++++++++++++++++ files/usr/share/man/shadow.man | 22 ++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 files/usr/share/man/passwd.man create mode 100644 files/usr/share/man/shadow.man diff --git a/files/usr/share/man/passwd.man b/files/usr/share/man/passwd.man new file mode 100644 index 00000000..4cb60045 --- /dev/null +++ b/files/usr/share/man/passwd.man @@ -0,0 +1,28 @@ +NAME + passwd - the password file + +DESCRIPTION + /etc/passwd contains one line for each user account, with seven fields + delimited by colons (":"). + + These fields are: + * login name + * optional encrypted password + * numerical user ID + * numerical group ID + * user name or comment field + * user home directory + * optional user command interpreter + + If the password field is a lower-case "x", then the encrypted password is + actually stored in the shadow file instead; there must be a corresponding + line in the /etc/shadow file, or else the user account is invalid. + + The home directory field provides the name of the initial working directory. + The login program uses this information to set the value of the $HOME + environmental variable. + + The command interpreter field provides the name of the user's command + language interpreter, or the name of the initial program to execute. + The login program uses this information to set the value of the $SHELL + environmental variable. diff --git a/files/usr/share/man/shadow.man b/files/usr/share/man/shadow.man new file mode 100644 index 00000000..b61d0bcb --- /dev/null +++ b/files/usr/share/man/shadow.man @@ -0,0 +1,22 @@ +NAME + shadow - shadowed password file + +DESCRIPTION + shadow is a file which contains the password information for the + system's accounts. + + This file must not be readable by regular users if password security is to + be maintained. + + Each line of this file contains 9 fields, separated by colons (“:”), in the + following order: + + * login name + * encrypted password + * date of last password change + * minimum password age + * maximum password age + * password warning period + * password inactivity period + * account expiration date + * reserved field From 8211f4fb2e2c5b09605cf18bfe96629f65f2338f Mon Sep 17 00:00:00 2001 From: Florian Fischer Date: Tue, 30 Jul 2024 15:21:58 +0200 Subject: [PATCH 25/40] ata: set proper file attributes for ATA devices --- mentos/src/drivers/ata.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/mentos/src/drivers/ata.c b/mentos/src/drivers/ata.c index b317d0d5..bca28c74 100644 --- a/mentos/src/drivers/ata.c +++ b/mentos/src/drivers/ata.c @@ -1138,12 +1138,12 @@ static int _ata_stat(const ata_device_t *dev, stat_t *stat) pr_debug("_ata_stat(%p, %p)\n", dev, stat); stat->st_dev = 0; stat->st_ino = 0; - stat->st_mode = 0; - stat->st_uid = 0; - stat->st_gid = 0; - stat->st_atime = sys_time(NULL); - stat->st_mtime = sys_time(NULL); - stat->st_ctime = sys_time(NULL); + stat->st_mode = dev->fs_root->mask; + stat->st_uid = dev->fs_root->uid; + stat->st_gid = dev->fs_root->gid; + stat->st_atime = dev->fs_root->atime; + stat->st_mtime = dev->fs_root->mtime; + stat->st_ctime = dev->fs_root->ctime; stat->st_size = dev->fs_root->length; } return 0; @@ -1208,6 +1208,12 @@ static vfs_file_t *ata_device_create(ata_device_t *dev) } // Set the device name. memcpy(file->name, dev->name, NAME_MAX); + file->uid = 0; + file->gid = 0; + file->mask = 0x2000 | 0600; + file->atime = sys_time(NULL); + file->mtime = sys_time(NULL); + file->ctime = sys_time(NULL); // Set the device. file->device = dev; // Re-set the flags. From 9f78f44ac5c7bd17d28f4e2d34444a064467e502 Mon Sep 17 00:00:00 2001 From: Florian Fischer Date: Tue, 30 Jul 2024 17:38:12 +0200 Subject: [PATCH 26/40] procfs: add function to set the file mask for procfs entries The procfs_file_t struct contains a mask member which was never used. Use the mask member in __procfs_stat and allow to set it using proc_entry_set_mask via the contained procfs entry. --- mentos/inc/fs/procfs.h | 6 ++++++ mentos/src/fs/procfs.c | 12 ++++++++++++ 2 files changed, 18 insertions(+) diff --git a/mentos/inc/fs/procfs.h b/mentos/inc/fs/procfs.h index 7ef3eefa..84a60cec 100644 --- a/mentos/inc/fs/procfs.h +++ b/mentos/inc/fs/procfs.h @@ -57,6 +57,12 @@ proc_dir_entry_t *proc_create_entry(const char *name, proc_dir_entry_t *parent); /// @return 0 if succeed, or -errno in case of error. int proc_destroy_entry(const char *name, proc_dir_entry_t *parent); +/// @brief Sets the mask of a given procfs entry. +/// @param entry Pointer to the entry. +/// @param mask The mask to set. +/// @return 0 if succeed, or -errno in case of error. +int proc_entry_set_mask(proc_dir_entry_t *entry, mode_t mask); + /// @brief Create the entire procfs entry tree for the give process. /// @param entry Pointer to the task_struct of the process. /// @return 0 if succeed, or -errno in case of error. diff --git a/mentos/src/fs/procfs.c b/mentos/src/fs/procfs.c index 38657ae8..f5db354d 100644 --- a/mentos/src/fs/procfs.c +++ b/mentos/src/fs/procfs.c @@ -668,6 +668,7 @@ static int __procfs_stat(procfs_file_t *file, stat_t *stat) } else { return -ENOENT; } + stat->st_mode = stat->st_mode | file->mask; stat->st_uid = file->uid; stat->st_gid = file->gid; stat->st_dev = 0; @@ -1019,3 +1020,14 @@ int proc_destroy_entry(const char *name, proc_dir_entry_t *parent) } return 0; } + +int proc_entry_set_mask(proc_dir_entry_t *entry, mode_t mask) +{ + procfs_file_t *procfs_file = container_of(entry, procfs_file_t, dir_entry); + if (procfs_file == NULL) { + pr_err("proc_destroy_entry(%s): Cannot find proc entry.\n", entry->name); + return -ENOENT; + } + procfs_file->mask = mask; + return 0; +} From 2476d916057b1655bbbd983422fe2c39c33912aa Mon Sep 17 00:00:00 2001 From: Florian Fischer Date: Tue, 30 Jul 2024 17:40:46 +0200 Subject: [PATCH 27/40] proc/ipc: set correct masks for ipc entries The directory /proc/ipc has the permissions r-xr-xr-x. Set the permissions of all entries in /proc/ipc to r--r--r--. Use a loop to create all entries removing code duplication. --- mentos/src/io/proc_ipc.c | 41 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/mentos/src/io/proc_ipc.c b/mentos/src/io/proc_ipc.c index d69b9f21..4c1a3077 100644 --- a/mentos/src/io/proc_ipc.c +++ b/mentos/src/io/proc_ipc.c @@ -71,6 +71,7 @@ static vfs_file_operations_t procipc_shm_fs_operations = { int procipc_module_init(void) { + int err = 0; proc_dir_entry_t *folder = NULL, *entry = NULL; // First, we need to create the `/proc/ipc` folder. @@ -79,31 +80,27 @@ int procipc_module_init(void) return 1; } - // Create the `/proc/ipc/msg` entry. - if ((entry = proc_create_entry("msg", folder)) == NULL) { - pr_err("Cannot create the `/proc/ipc/msg` file.\n"); - return 1; + if ((err = proc_entry_set_mask(folder, 0555))) { + pr_err("Cannot set mask of `/proc/ipc` directory.\n"); + return err; } - // Set the specific operations. - entry->sys_operations = &procipc_sys_operations; - entry->fs_operations = &procipc_msg_fs_operations; - // Create the `/proc/ipc/sem` entry. - if ((entry = proc_create_entry("sem", folder)) == NULL) { - pr_err("Cannot create the `/proc/ipc/sem` file.\n"); - return 1; - } - // Set the specific operations. - entry->sys_operations = &procipc_sys_operations; - entry->fs_operations = &procipc_sem_fs_operations; + char *entry_names[] = {"msg", "sem", "shm"}; + for (int i = 0; i < count_of(entry_names); i++) { + char *entry_name = entry_names[i]; + // Create the `/proc/ipc/` entry. + if ((entry = proc_create_entry(entry_name, folder)) == NULL) { + pr_err("Cannot create the `/proc/ipc/%s` file.\n", entry_name); + return 1; + } + // Set the specific operations. + entry->sys_operations = &procipc_sys_operations; + entry->fs_operations = &procipc_msg_fs_operations; - // Create the `/proc/ipc/shm` entry. - if ((entry = proc_create_entry("shm", folder)) == NULL) { - pr_err("Cannot create the `/proc/ipc/shm` file.\n"); - return 1; + if ((err = proc_entry_set_mask(entry, 0444))) { + pr_err("Cannot set mask of `/proc/ipc/%s` file.\n", entry_name); + return err; + } } - // Set the specific operations. - entry->sys_operations = &procipc_sys_operations; - entry->fs_operations = &procipc_shm_fs_operations; return 0; } From d97e6b095f7403e1276e1bd3dc201aa97b90a619 Mon Sep 17 00:00:00 2001 From: Florian Fischer Date: Tue, 30 Jul 2024 17:43:24 +0200 Subject: [PATCH 28/40] proc/system: set the mask for the system proc entries to 0444 Remove the duplicated code by using a loop to create the entries. --- mentos/src/io/proc_system.c | 74 ++++++++----------------------------- 1 file changed, 16 insertions(+), 58 deletions(-) diff --git a/mentos/src/io/proc_system.c b/mentos/src/io/proc_system.c index 93aadc54..5acf039d 100644 --- a/mentos/src/io/proc_system.c +++ b/mentos/src/io/proc_system.c @@ -101,65 +101,23 @@ static vfs_file_operations_t procs_fs_operations = { int procs_module_init(void) { proc_dir_entry_t *system_entry; - // == /proc/uptime ======================================================== - if ((system_entry = proc_create_entry("uptime", NULL)) == NULL) { - pr_err("Cannot create `/proc/uptime`.\n"); - return 1; - } - pr_debug("Created `/proc/uptime` (%p)\n", system_entry); - // Set the specific operations. - system_entry->sys_operations = &procs_sys_operations; - system_entry->fs_operations = &procs_fs_operations; - - // == /proc/version ======================================================== - if ((system_entry = proc_create_entry("version", NULL)) == NULL) { - pr_err("Cannot create `/proc/version`.\n"); - return 1; - } - pr_debug("Created `/proc/version` (%p)\n", system_entry); - // Set the specific operations. - system_entry->sys_operations = &procs_sys_operations; - system_entry->fs_operations = &procs_fs_operations; - - // == /proc/mounts ======================================================== - if ((system_entry = proc_create_entry("mounts", NULL)) == NULL) { - pr_err("Cannot create `/proc/mounts`.\n"); - return 1; - } - pr_debug("Created `/proc/mounts` (%p)\n", system_entry); - // Set the specific operations. - system_entry->sys_operations = &procs_sys_operations; - system_entry->fs_operations = &procs_fs_operations; - - // == /proc/cpuinfo ======================================================== - if ((system_entry = proc_create_entry("cpuinfo", NULL)) == NULL) { - pr_err("Cannot create `/proc/cpuinfo`.\n"); - return 1; - } - pr_debug("Created `/proc/cpuinfo` (%p)\n", system_entry); - // Set the specific operations. - system_entry->sys_operations = &procs_sys_operations; - system_entry->fs_operations = &procs_fs_operations; - - // == /proc/meminfo ======================================================== - if ((system_entry = proc_create_entry("meminfo", NULL)) == NULL) { - pr_err("Cannot create `/proc/meminfo`.\n"); - return 1; - } - pr_debug("Created `/proc/meminfo` (%p)\n", system_entry); - // Set the specific operations. - system_entry->sys_operations = &procs_sys_operations; - system_entry->fs_operations = &procs_fs_operations; - - // == /proc/stat ======================================================== - if ((system_entry = proc_create_entry("stat", NULL)) == NULL) { - pr_err("Cannot create `/proc/stat`.\n"); - return 1; + char* entry_names[] = {"uptime", "version", "mounts", "cpuinfo", "meminfo", "stat"}; + for (int i = 0; i < count_of(entry_names); i++) { + char *entry_name = entry_names[i]; + if ((system_entry = proc_create_entry(entry_name, NULL)) == NULL) { + pr_err("Cannot create `/proc/%s`.\n", entry_name); + return 1; + } + pr_debug("Created `/proc/%s` (%p)\n", entry_name, system_entry); + // Set the specific operations. + system_entry->sys_operations = &procs_sys_operations; + system_entry->fs_operations = &procs_fs_operations; + if (proc_entry_set_mask(system_entry, 0444) < 0) { + pr_err("Cannot set mask of `/proc/%s`.\n", entry_name); + return 1; + } } - pr_debug("Created `/proc/stat` (%p)\n", system_entry); - // Set the specific operations. - system_entry->sys_operations = &procs_sys_operations; - system_entry->fs_operations = &procs_fs_operations; + return 0; } From ee7d9ced1ca34708168c70939def5d29141080d7 Mon Sep 17 00:00:00 2001 From: Florian Fischer Date: Tue, 30 Jul 2024 17:44:59 +0200 Subject: [PATCH 29/40] proc/feedback: set the file permissions to 0444 --- mentos/src/io/proc_feedback.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mentos/src/io/proc_feedback.c b/mentos/src/io/proc_feedback.c index b46ba95a..95fb2f52 100644 --- a/mentos/src/io/proc_feedback.c +++ b/mentos/src/io/proc_feedback.c @@ -56,5 +56,9 @@ int procfb_module_init(void) // Set the specific operations. file->sys_operations = &procfb_sys_operations; file->fs_operations = &procfb_fs_operations; + if (proc_entry_set_mask(file, 0444) < 0) { + pr_err("Cannot set mask of `/proc/feedback`.\n"); + return 1; + } return 0; } From 34741a862befa664e290ad0da35db0add5078324 Mon Sep 17 00:00:00 2001 From: Florian Fischer Date: Tue, 30 Jul 2024 17:52:02 +0200 Subject: [PATCH 30/40] prov/video: use the procfs_file_t mask and the common procfs stat --- mentos/src/io/proc_video.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/mentos/src/io/proc_video.c b/mentos/src/io/proc_video.c index 913efdce..96e71684 100644 --- a/mentos/src/io/proc_video.c +++ b/mentos/src/io/proc_video.c @@ -194,18 +194,6 @@ static ssize_t procv_write(vfs_file_t *file, const void *buf, off_t offset, size } return nbyte; } - -static int procv_fstat(vfs_file_t *file, stat_t *stat) -{ - stat->st_dev = 0; - stat->st_mode = 0666; - stat->st_uid = 0; - stat->st_gid = 0; - stat->st_size = 0; - stat->st_mtime = sys_time(NULL); - return 0; -} - static int procv_ioctl(vfs_file_t *file, int request, void *data) { task_struct *process = scheduler_get_current_process(); @@ -239,7 +227,7 @@ static vfs_file_operations_t procv_fs_operations = { .read_f = procv_read, .write_f = procv_write, .lseek_f = NULL, - .stat_f = procv_fstat, + .stat_f = NULL, .ioctl_f = procv_ioctl, .getdents_f = NULL, .readlink_f = NULL, @@ -256,5 +244,11 @@ int procv_module_init(void) // Set the specific operations. video->sys_operations = &procv_sys_operations; video->fs_operations = &procv_fs_operations; + + if (proc_entry_set_mask(video, 0666) < 0) { + pr_err("Cannot set mask for `/proc/video`.\n"); + return 1; + } + return 0; } From acef9624ab3b005aa6a5615bf35f7debd4523cd5 Mon Sep 17 00:00:00 2001 From: Florian Fischer Date: Fri, 29 Mar 2024 18:52:40 +0100 Subject: [PATCH 31/40] process: fix interpreter support Previously, the argv array was not altered. However, this does not work when the script was executed using execp. When executing an executable from the path the interpreter has no way to determine what file it should load. Now we do the correct thing and add the path to the executed file as second argument shifting everything else to the right. TODO: Pass the path to the interpreter as first argument. --- mentos/src/process/process.c | 40 +++++++++++++++++++++++++++++++++++- programs/shell.c | 2 +- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/mentos/src/process/process.c b/mentos/src/process/process.c index c1ea84dd..b569493c 100644 --- a/mentos/src/process/process.c +++ b/mentos/src/process/process.c @@ -127,7 +127,7 @@ static int __has_shebang(vfs_file_t *file) { /// @param path the path to the executable to load. /// @param task the task to laod the exectuable. /// @param entry -/// @return -errno or 0 on failure, 1 on success +/// @return -errno or 0 on failure, 1 on success, 2 if a interpreter was loaded static int __load_executable(const char *path, task_struct *task, uint32_t *entry) { // Return code variable. @@ -211,6 +211,7 @@ static int __load_executable(const char *path, task_struct *task, uint32_t *entr if (interpreter_loop) { // Free interpreter buffer kfree((void*)path); + ret = 2; } close_and_return: @@ -530,6 +531,7 @@ int sys_execve(pt_regs *f) char **origin_argv, **saved_argv, **final_argv; char **origin_envp, **saved_envp, **final_envp; char name_buffer[NAME_MAX]; + char saved_filename[PATH_MAX]; // Get the filename. char *filename = (char *)f->ebx; @@ -557,6 +559,8 @@ int sys_execve(pt_regs *f) // Save the name of the process. strcpy(name_buffer, origin_argv[0]); + // Save the filename. + strcpy(saved_filename, filename); // == COPY PROGRAM ARGUMENTS ============================================== // Copy argv and envp to kernel memory, because all the old process memory will be discarded. @@ -590,6 +594,40 @@ int sys_execve(pt_regs *f) // Free the temporary args memory. kfree(args_mem); return ret; + } else if (ret == 2) { // An interpreter was loaded. + // We need to modify the argv array passed to the interpreter process. + // The original file name must be passed as second argument and the rest + // is shifted to the right. + // Prepare a new argv array. + char **int_argv = kmalloc((argc + 2) * sizeof(char*)); + if (!int_argv) { + pr_err("Failed to allocate memory for interpreter argv array.\n"); + return -1; + } + int_argv[0] = saved_argv[0]; // TODO: pass the path to the interpreter. + int_argv[1] = saved_filename; + for (int i = 1; i <= argc; i++) { + int_argv[i+1] = saved_argv[i]; + } + argc++; + + // Rebuild the saved argv and envp pointers. + int int_argv_bytes = __count_args_bytes(int_argv); + void *int_args_mem = kmalloc(int_argv_bytes); + if (!int_args_mem) { + pr_err("Failed to allocate memory for interpreter arguments and environment %d (%d + %d).\n", + int_argv_bytes + envp_bytes, int_argv_bytes, envp_bytes); + return -1; + } + // Copy the arguments. + uint32_t int_args_mem_ptr = (uint32_t)int_args_mem + (int_argv_bytes + envp_bytes); + saved_argv = __push_args_on_stack(&int_args_mem_ptr, int_argv); + saved_envp = __push_args_on_stack(&int_args_mem_ptr, saved_envp); + // Check the memory pointer. + assert(int_args_mem_ptr == (uint32_t)int_args_mem); + // Free the old argument and environ memory block. + kfree(args_mem); + args_mem = int_args_mem; } // ------------------------------------------------------------------------ diff --git a/programs/shell.c b/programs/shell.c index 41b08efe..2ed0abba 100644 --- a/programs/shell.c +++ b/programs/shell.c @@ -971,7 +971,7 @@ int main(int argc, char *argv[]) // We have been executed as script interpreter if (!strstr(argv[0], "shell")) { - return __execute_file(argv[0]); + return __execute_file(argv[1]); } // Interactive From 61de914e1bcb34ff54b899592b5f24031ce2197d Mon Sep 17 00:00:00 2001 From: Florian Fischer Date: Tue, 30 Jul 2024 18:19:53 +0200 Subject: [PATCH 32/40] proc/system: fix read always returning 0 Since all the proc_system read functions use the return value of sprintf, none of them actually return 0 on success. Fix the wrong success detection by considering anything >= 0 a success. FIXES: b01eccca2ef1a36dc4a7b54f531e282cc491a282 --- mentos/src/io/proc_system.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mentos/src/io/proc_system.c b/mentos/src/io/proc_system.c index 93aadc54..016c2f15 100644 --- a/mentos/src/io/proc_system.c +++ b/mentos/src/io/proc_system.c @@ -61,7 +61,7 @@ static ssize_t __procs_read(vfs_file_t *file, char *buf, off_t offset, size_t nb } // Perform read. ssize_t it = 0; - if (ret == 0) { + if (ret >= 0) { size_t name_len = strlen(buffer); size_t read_pos = offset; if (read_pos < name_len) { From 06935e5aab32ad588707afb26690e119fbf4c503 Mon Sep 17 00:00:00 2001 From: Florian Fischer Date: Tue, 30 Jul 2024 18:29:43 +0200 Subject: [PATCH 33/40] bump the version used in the code to 0.7.1 --- files/README | 2 +- mentos/inc/version.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/files/README b/files/README index 99390ef4..7f9f5752 100644 --- a/files/README +++ b/files/README @@ -1,4 +1,4 @@ -MentOS 0.6.0 +MentOS 0.7.1 Welcome to the MentOS, the Mentoring Operating System. diff --git a/mentos/inc/version.h b/mentos/inc/version.h index c2a4a338..0fced4f8 100644 --- a/mentos/inc/version.h +++ b/mentos/inc/version.h @@ -18,10 +18,10 @@ #define OS_MAJOR_VERSION 0 /// Minor version of the operating system. -#define OS_MINOR_VERSION 6 +#define OS_MINOR_VERSION 7 /// Micro version of the operating system. -#define OS_MICRO_VERSION 0 +#define OS_MICRO_VERSION 1 /// Helper to transform the given argument into a string. #define OS_STR_HELPER(x) #x From 63a183256864cb73a562836a5f956d6735cf8414 Mon Sep 17 00:00:00 2001 From: Florian Fischer Date: Tue, 30 Jul 2024 18:52:31 +0200 Subject: [PATCH 34/40] man: correct and extend the file system hierarchy manual page Fix the explanation for /usr/share duplicated from /usr/srv. Add descriptions for the /var subtree. --- files/usr/share/man/hier.man | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/files/usr/share/man/hier.man b/files/usr/share/man/hier.man index cf2f647c..90ccad39 100644 --- a/files/usr/share/man/hier.man +++ b/files/usr/share/man/hier.man @@ -29,7 +29,13 @@ DESCRIPTION Contains the source code used to build the system. /usr/share - Contains the source code used to build the system. + Contains subdirectories with specific application data, that can be shared + among different architectures of the same OS. /usr/share/man Manual pages go here. + + /var Contains files which may change in size. + + /var/lib + Variable state information for programs. From aa9f679d016072c30e1018bd835de193606f503c Mon Sep 17 00:00:00 2001 From: "Enrico Fraccaroli (Galfurian)" Date: Wed, 14 Aug 2024 15:09:44 -0400 Subject: [PATCH 35/40] Properly upate link number, and directory count when deleting a directory. Extend mkdir and rmdir test. --- mentos/src/fs/ext2.c | 169 ++++++++++++++++++++++++++------------- programs/tests/t_mkdir.c | 115 ++++++++++++++------------ 2 files changed, 177 insertions(+), 107 deletions(-) diff --git a/mentos/src/fs/ext2.c b/mentos/src/fs/ext2.c index 0b2545d6..7242247f 100644 --- a/mentos/src/fs/ext2.c +++ b/mentos/src/fs/ext2.c @@ -1797,19 +1797,39 @@ ext2_direntry_iterator_t ext2_direntry_iterator_begin(ext2_filesystem_t *fs, uin /// @brief Moves to the next direntry, and moves to the next block if necessary. /// @param iterator the iterator. -void ext2_direntry_iterator_next(ext2_direntry_iterator_t *iterator) +void ext2_direntry_iterator_next(ext2_direntry_iterator_t *iterator, uint32_t inode_index) { // Advance the offsets. iterator->block_offset += iterator->direntry->rec_len; iterator->total_offset += iterator->direntry->rec_len; // If we reached the end of the inode, stop. if (iterator->total_offset >= iterator->inode->size) { + if (inode_index > 0) { + pr_crit("Update block!\n"); + // Read the new block. + if (ext2_write_inode_block(iterator->fs, iterator->inode, inode_index, iterator->block_index, iterator->cache) < 0) { + pr_err("Failed to write the inode block `%d` while iterating.\n", iterator->block_index); + // The iterator is not valid anymore. + iterator->direntry = NULL; + return; + } + } // The iterator is not valid anymore. iterator->direntry = NULL; return; } // If we exceed the size of a block, move to the next block. if (iterator->block_offset >= iterator->fs->block_size) { + if (inode_index > 0) { + pr_crit("Update block!\n"); + // Read the new block. + if (ext2_write_inode_block(iterator->fs, iterator->inode, inode_index, iterator->block_index, iterator->cache) < 0) { + pr_err("Failed to write the inode block `%d` while iterating.\n", iterator->block_index); + // The iterator is not valid anymore. + iterator->direntry = NULL; + return; + } + } // Increase the block index. iterator->block_index += 1; // Remove the exceeding size, so that we start correctly in the new block. @@ -1834,7 +1854,10 @@ void ext2_direntry_iterator_next(ext2_direntry_iterator_t *iterator) static inline int ext2_directory_is_empty(ext2_filesystem_t *fs, uint8_t *cache, ext2_inode_t *inode) { ext2_direntry_iterator_t it = ext2_direntry_iterator_begin(fs, cache, inode); - for (; ext2_direntry_iterator_valid(&it); ext2_direntry_iterator_next(&it)) { + for (; ext2_direntry_iterator_valid(&it); ext2_direntry_iterator_next(&it, 0)) { + if (!strncmp(it.direntry->name, ".", 1) || !strncmp(it.direntry->name, "..", 2)) { + continue; + } if (it.direntry->inode != 0) { return 0; } @@ -1957,7 +1980,7 @@ static inline void ext2_dump_direntries( pr_debug(" [%2u, %4u]", it.block_index, it.block_offset); ext2_dump_dirent(it.direntry); // Move to next entry. - ext2_direntry_iterator_next(&it); + ext2_direntry_iterator_next(&it, 0); } } @@ -2008,7 +2031,7 @@ static inline int ext2_get_free_direntry( return 1; } // Move to next entry. - ext2_direntry_iterator_next(&it); + ext2_direntry_iterator_next(&it, 0); } return 0; } @@ -2068,7 +2091,7 @@ static inline int ext2_append_new_direntry( return 1; } // Move to next entry. - ext2_direntry_iterator_next(&it); + ext2_direntry_iterator_next(&it, 0); } return 0; } @@ -2099,7 +2122,7 @@ static inline int ext2_create_new_direntry( // Prepare iterator. ext2_direntry_iterator_t it = ext2_direntry_iterator_begin(fs, cache, &parent_inode); // Find the last entry. - while (ext2_direntry_iterator_valid(&it)) { ext2_direntry_iterator_next(&it); } + while (ext2_direntry_iterator_valid(&it)) { ext2_direntry_iterator_next(&it, 0); } // Allocate a new block. if (ext2_allocate_inode_block(fs, &parent_inode, parent_inode_index, it.block_index) == -1) { pr_err("Failed to allocate a new block for an inode.\n"); @@ -2195,6 +2218,82 @@ static int ext2_allocate_direntry( return 0; } +/// @brief Destroys a directory entry. +/// @param fs a pointer to the filesystem. +/// @param parent_inode_index the inode index of the parent. +/// @param direntry_inode_index the inode index of the new entry. +/// @param name the name of the new entry. +/// @param file_type the type of file. +/// @return 0 on success, a negative value on failure. +static int ext2_destroy_direntry( + ext2_filesystem_t *fs, + ext2_inode_t parent, + ext2_inode_t inode, + uint32_t parent_index, + uint32_t inode_index, + uint32_t block_index, + uint32_t block_offset) +{ + // Allocate the cache and clean it. + uint8_t *cache = ext2_alloc_cache(fs); + // Check if the directory is empty, if it enters the loop then it means it is not empty. + if (!ext2_directory_is_empty(fs, cache, &inode)) { + pr_err("The directory is not empty `%d`.\n", inode_index); + ext2_dealloc_cache(cache); + return -ENOTEMPTY; + } + // Get the group index of the parent. + uint32_t group_index = ext2_inode_index_to_group_index(fs, parent_index); + // Increase the number of directories inside the group. + fs->block_groups[group_index].used_dirs_count -= 1; + // Reduce the number of links to the parent directory. + parent.links_count--; + if (ext2_write_inode(fs, &parent, parent_index) < 0) { + pr_err("Failed to update the inode of `%d`.\n", parent_index); + ext2_dealloc_cache(cache); + return 1; + } + // Reduce the number of links to the directory. + inode.links_count = 0; + // Update the delete time. + inode.dtime = sys_time(NULL); + if (ext2_write_inode(fs, &inode, inode_index) < 0) { + pr_err("Failed to update the inode of `%d`.\n", inode_index); + ext2_dealloc_cache(cache); + return 1; + } + // Free the inode. + if (ext2_free_inode(fs, &inode, inode_index) < 0) { + pr_err("Failed to free the inode of `%d`.\n", inode_index); + ext2_dealloc_cache(cache); + return 1; + } + // Read the block where the direntry resides. + if (ext2_read_inode_block(fs, &parent, block_index, cache) == -1) { + pr_err("Failed to read the parent inode block `%d`\n", block_index); + ext2_dealloc_cache(cache); + return 1; + } + // Get a pointer to the direntry. + ext2_dirent_t *dirent = (ext2_dirent_t *)((uintptr_t)cache + block_offset); + if (dirent == NULL) { + pr_err("We found a NULL ext2_dirent_t\n"); + ext2_dealloc_cache(cache); + return 1; + } + // Set the inode to zero. + dirent->inode = 0; + // Write back the parent directory block. + if (!ext2_write_inode_block(fs, &parent, parent_index, block_index, cache)) { + pr_err("Failed to write the inode block `%d`\n", block_index); + ext2_dealloc_cache(cache); + return 1; + } + // Free the cache. + ext2_dealloc_cache(cache); + return 0; +} + /// @brief Finds the entry with the given `name` inside the `directory`. /// @param fs a pointer to the filesystem. /// @param ino the inodex of the directory entry. @@ -2238,7 +2337,7 @@ static int ext2_find_direntry(ext2_filesystem_t *fs, ino_t ino, const char *name // Prepare iterator. ext2_direntry_iterator_t it = ext2_direntry_iterator_begin(fs, cache, &inode); - for (; ext2_direntry_iterator_valid(&it); ext2_direntry_iterator_next(&it)) { + for (; ext2_direntry_iterator_valid(&it); ext2_direntry_iterator_next(&it, 0)) { // Skip unused inode. if (it.direntry->inode == 0) { continue; @@ -3038,7 +3137,7 @@ static ssize_t ext2_getdents(vfs_file_t *file, dirent_t *dirp, off_t doff, size_ // Initialize the iterator. ext2_direntry_iterator_t it = ext2_direntry_iterator_begin(fs, cache, &inode); - for (; ext2_direntry_iterator_valid(&it) && (written < count); ext2_direntry_iterator_next(&it)) { + for (; ext2_direntry_iterator_valid(&it) && (written < count); ext2_direntry_iterator_next(&it, 0)) { // Skip unused inode. if (it.direntry->inode == 0) { continue; @@ -3228,64 +3327,20 @@ static int ext2_rmdir(const char *path) pr_err("Failed to resolve path `%s`.\n", absolute_path); return -ENOENT; } + // Get the inode associated with the parent directory entry. - ext2_inode_t parent_inode; - if (ext2_read_inode(fs, &parent_inode, search.parent_inode) == -1) { + ext2_inode_t parent; + if (ext2_read_inode(fs, &parent, search.parent_inode) == -1) { pr_err("ext2_stat(%s): Failed to read the inode of parent of `%s`.\n", path, search.direntry.name); return -ENOENT; } - - // Allocate the cache and clean it. - uint8_t *cache = ext2_alloc_cache(fs); - // Read the inode of the direntry we want to unlink. ext2_inode_t inode; if (ext2_read_inode(fs, &inode, search.direntry.inode) == -1) { pr_err("Failed to read the inode of `%s`.\n", search.direntry.name); - goto free_cache_return_error; - } - // Check if the directory is empty, if it enters the loop then it means it is not empty. - if (!ext2_directory_is_empty(fs, cache, &inode)) { - pr_err("The directory is not empty `%s`.\n", search.direntry.name); - ext2_dealloc_cache(cache); - return -ENOTEMPTY; - } - // Reduce the number of links to the inode. - if (inode.links_count > 0) { - inode.links_count--; - // Update the inode. - if (ext2_write_inode(fs, &inode, search.direntry.inode) == -1) { - pr_err("Failed to update the inode of `%s`.\n", search.direntry.name); - goto free_cache_return_error; - } - } - - // Read the block where the direntry resides. - if (ext2_read_inode_block(fs, &parent_inode, search.block_index, cache) == -1) { - pr_err("Failed to read the parent inode block `%d`\n", search.block_index); - goto free_cache_return_error; - } - // Get a pointer to the direntry. - ext2_dirent_t *actual_dirent = (ext2_dirent_t *)((uintptr_t)cache + search.block_offset); - if (actual_dirent == NULL) { - pr_err("We found a NULL ext2_dirent_t\n"); - goto free_cache_return_error; - } - // Set the inode to zero. - actual_dirent->inode = 0; - // Write back the parent directory block. - if (!ext2_write_inode_block(fs, &parent_inode, search.parent_inode, search.block_index, cache)) { - pr_err("Failed to write the inode block `%d`\n", search.block_index); - goto free_cache_return_error; + return -ENOENT; } - - // Free the cache. - ext2_dealloc_cache(cache); - return 0; -free_cache_return_error: - // Free the cache. - ext2_dealloc_cache(cache); - return -1; + return ext2_destroy_direntry(fs, parent, inode, search.parent_inode, search.direntry.inode, search.block_index, search.block_offset); } /// @brief Retrieves information concerning the file at the given position. diff --git a/programs/tests/t_mkdir.c b/programs/tests/t_mkdir.c index ae7ce3a9..d44a4ac2 100644 --- a/programs/tests/t_mkdir.c +++ b/programs/tests/t_mkdir.c @@ -6,84 +6,99 @@ #include #include #include +#include #include #include #include #include #include -#define BASEDIR "/t_mkdir" - -int create_dir(const char *pathname, mode_t mode) +int create_dir(const char *parent_directory, const char *directory_name, mode_t mode) { - int ret = mkdir(pathname, mode); - if (ret < 0) { - printf("Failed to create dir %s: %s\n", pathname, strerror(errno)); + char path[PATH_MAX]; + memset(path, 0, PATH_MAX); + strcat(path, parent_directory); + strcat(path, directory_name); + pr_notice("Creating directory `%s`...\n", path); + if (mkdir(path, mode) < 0) { + pr_err("Failed to create directory %s: %s\n", path, strerror(errno)); return EXIT_FAILURE; } return EXIT_SUCCESS; } -int test_consecutive_dirs(void) +int remove_dir(const char *parent_directory, const char *directory_name) { - int ret = EXIT_SUCCESS; - if (create_dir(BASEDIR "/outer", 0777) == EXIT_FAILURE) { + char path[PATH_MAX]; + memset(path, 0, PATH_MAX); + strcat(path, parent_directory); + strcat(path, directory_name); + pr_notice("Removing directory `%s`...\n", path); + if (rmdir(path) < 0) { + pr_err("Failed to remove directory %s: %s\n", path, strerror(errno)); return EXIT_FAILURE; } - if (create_dir(BASEDIR "/outer/inner", 0777) == EXIT_FAILURE) { - ret = EXIT_FAILURE; - goto clean_outer; - } + return EXIT_SUCCESS; +} - // Check if both directories are present - int fd = open(BASEDIR "/outer", O_RDONLY | O_DIRECTORY, 0); - if (fd == -1) { - ret = EXIT_FAILURE; - printf("failed to open dir %s: %s\n", BASEDIR "/outer", strerror(errno)); - goto clean_inner; +int check_dir(const char *parent_directory, const char *directory_name) +{ + char path[PATH_MAX]; + memset(path, 0, PATH_MAX); + strcat(path, parent_directory); + strcat(path, directory_name); + pr_notice("Checking directory `%s`...\n", path); + stat_t buffer; + stat(path, &buffer); + if (!S_ISDIR(buffer.st_mode)) { + pr_err("Failed to check directory `%s` : %s.\n", path, strerror(errno)); + return EXIT_FAILURE; } + return EXIT_SUCCESS; +} - dirent_t dent; - ssize_t read_bytes = getdents(fd, &dent, sizeof(dirent_t)); - // We reached the end of the folder. - if (read_bytes <= 0) { - ret = EXIT_FAILURE; - // We encountered an error. - if (read_bytes == -1) { - printf("failed to read outer dir: %s\n", strerror(errno)); - } else { // There was nothing to read - printf("dir outer does not contain any entries\n"); +int test_consecutive_dirs(const char *parent_directory) +{ + int ret; + if (create_dir(parent_directory, "/t_mkdir", 0777) == EXIT_FAILURE) { + return EXIT_FAILURE; + } + if (create_dir(parent_directory, "/t_mkdir/outer", 0777) == EXIT_FAILURE) { + remove_dir(parent_directory, "/t_mkdir"); + return EXIT_FAILURE; + } + if (create_dir(parent_directory, "/t_mkdir/outer/inner", 0777) == EXIT_FAILURE) { + remove_dir(parent_directory, "/t_mkdir/outer"); + remove_dir(parent_directory, "/t_mkdir"); + return EXIT_FAILURE; + } + // Check if both directories are present. + if ((ret = check_dir(parent_directory, "/t_mkdir")) == EXIT_SUCCESS) { + if ((ret = check_dir(parent_directory, "/t_mkdir/outer")) == EXIT_SUCCESS) { + ret = check_dir(parent_directory, "/t_mkdir/outer/inner"); } - goto clean_inner; } - - if (strcmp(dent.d_name, "outer") != 0) { - ret = EXIT_FAILURE; - printf("outer expected, %s found\n", dent.d_name); + // Remove the directories. + if (remove_dir(parent_directory, "/t_mkdir/outer/inner") == EXIT_FAILURE) { + return EXIT_FAILURE; + } + if (remove_dir(parent_directory, "/t_mkdir/outer") == EXIT_FAILURE) { + return EXIT_FAILURE; + } + if (remove_dir(parent_directory, "/t_mkdir") == EXIT_FAILURE) { + return EXIT_FAILURE; } - -clean_inner: - rmdir(BASEDIR "/outer/inner"); -clean_outer: - rmdir(BASEDIR "/outer"); return ret; } int main(int argc, char *argv[]) { - int ret = mkdir(BASEDIR, 0777); - if (ret == -1) { - err(EXIT_FAILURE, "Failed to create base dir %s", BASEDIR); - } - printf("Running `test_consecutive_dirs`...\n"); - if (test_consecutive_dirs()) { + pr_notice("Running `test_consecutive_dirs`...\n"); + if (test_consecutive_dirs("/home/user")) { return EXIT_FAILURE; } - - ret = rmdir(BASEDIR); - if (ret == -1) { - err(EXIT_FAILURE, "Failed to remove base dir %s", BASEDIR); + if (test_consecutive_dirs("")) { + return EXIT_FAILURE; } - return EXIT_SUCCESS; } From 6dbce6341f02348c7c36f45be48c2d5911e2d53d Mon Sep 17 00:00:00 2001 From: "Enrico Fraccaroli (Galfurian)" Date: Thu, 22 Aug 2024 10:51:06 -0400 Subject: [PATCH 36/40] Extend mkdir and rmdir test. --- programs/tests/t_mkdir.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/programs/tests/t_mkdir.c b/programs/tests/t_mkdir.c index d44a4ac2..4003bdff 100644 --- a/programs/tests/t_mkdir.c +++ b/programs/tests/t_mkdir.c @@ -59,7 +59,7 @@ int check_dir(const char *parent_directory, const char *directory_name) int test_consecutive_dirs(const char *parent_directory) { - int ret; + int ret = EXIT_SUCCESS; if (create_dir(parent_directory, "/t_mkdir", 0777) == EXIT_FAILURE) { return EXIT_FAILURE; } @@ -94,10 +94,10 @@ int test_consecutive_dirs(const char *parent_directory) int main(int argc, char *argv[]) { pr_notice("Running `test_consecutive_dirs`...\n"); - if (test_consecutive_dirs("/home/user")) { + if (test_consecutive_dirs("")) { return EXIT_FAILURE; } - if (test_consecutive_dirs("")) { + if (test_consecutive_dirs("/home/user")) { return EXIT_FAILURE; } return EXIT_SUCCESS; From 2875dadeefc3b1e5a9922bffebc9fcb051e1a5f2 Mon Sep 17 00:00:00 2001 From: "Enrico Fraccaroli (Galfurian)" Date: Thu, 22 Aug 2024 10:51:30 -0400 Subject: [PATCH 37/40] Fix mkdir and rmdir functions. --- mentos/src/fs/ext2.c | 268 +++++++++++++++++++------------------------ 1 file changed, 115 insertions(+), 153 deletions(-) diff --git a/mentos/src/fs/ext2.c b/mentos/src/fs/ext2.c index 7242247f..d21ed4f0 100644 --- a/mentos/src/fs/ext2.c +++ b/mentos/src/fs/ext2.c @@ -4,10 +4,10 @@ /// See LICENSE.md for details. // Setup the logging for this file (do this before any other include). -#include "sys/kernel_levels.h" // Include kernel log levels. -#define __DEBUG_HEADER__ "[EXT2 ]" ///< Change header. -#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE ///< Set log level. -#include "io/debug.h" // Include debugging functions. +#include "sys/kernel_levels.h" // Include kernel log levels. +#define __DEBUG_HEADER__ "[EXT2 ]" ///< Change header. +#define __DEBUG_LEVEL__ LOGLEVEL_DEBUG ///< Set log level. +#include "io/debug.h" // Include debugging functions. #include "assert.h" #include "fcntl.h" @@ -704,7 +704,7 @@ static inline uint32_t ext2_get_rec_len_from_name(const char *name) /// @return the rec_len value. static inline uint32_t ext2_get_rec_len_from_direntry(const ext2_dirent_t *direntry) { - return round_up(sizeof(ext2_dirent_t) + direntry->name_len + 1, 4); + return round_up(sizeof(ext2_dirent_t) + direntry->name_len, 4); } /// @brief If the real rec_len is different from the on in attribute rec_len, @@ -1131,7 +1131,7 @@ static int ext2_allocate_inode(ext2_filesystem_t *fs, unsigned preferred_group) // Compute the inode index. inode_index = (group_index * fs->superblock.inodes_per_group) + group_offset + 1U; // Log the allocation of the inode. - pr_debug("Allocate inode (inode_index:%u, group_index:%4u, group_offset:%4u)\n", inode_index, group_index, group_offset); + pr_debug("Allocate inode, inode_index:%u, group_index:%4u, group_offset:%4u\n", inode_index, group_index, group_offset); // Set the inode as occupied. ext2_bitmap_set(cache, group_offset); // Write back the inode bitmap. @@ -1241,14 +1241,14 @@ static void ext2_free_block(ext2_filesystem_t *fs, uint32_t block_index) fs->superblock.free_blocks_count++; // Increase the number of free blocks inside the BGDT entry. fs->block_groups[group_index].free_blocks_count++; - // Update the superblock. - if (ext2_write_superblock(fs) < 0) { - pr_warning("Failed to write superblock.\n"); - } // Update the BGDT. if (ext2_write_bgdt(fs) < 0) { pr_warning("Failed to write BGDT.\n"); } + // Update the superblock. + if (ext2_write_superblock(fs) < 0) { + pr_warning("Failed to write superblock.\n"); + } } /// @brief Frees the given inode. @@ -1614,7 +1614,7 @@ static ssize_t ext2_read_inode_block(ext2_filesystem_t *fs, ext2_inode_t *inode, static ssize_t ext2_write_inode_block(ext2_filesystem_t *fs, ext2_inode_t *inode, uint32_t inode_index, uint32_t block_index, uint8_t *buffer) { while (block_index >= (inode->blocks_count / fs->blocks_per_block_count)) { - pr_debug("ext2_write_inode_block: %u >= %u (%u / %u)\n", + pr_debug("Write inode block: %u >= %u (%u / %u)\n", block_index, inode->blocks_count / fs->blocks_per_block_count, inode->blocks_count, fs->blocks_per_block_count); if (ext2_allocate_inode_block(fs, inode, inode_index, (inode->blocks_count / fs->blocks_per_block_count)) < 0) { @@ -1754,19 +1754,19 @@ typedef struct ext2_direntry_iterator_t { } ext2_direntry_iterator_t; /// @brief Returns the ext2_dirent_t pointed by the iterator. -/// @param iterator the iterator. +/// @param it the iterator. /// @return pointer to the ext2_dirent_t -ext2_dirent_t *ext2_direntry_iterator_get(ext2_direntry_iterator_t *iterator) +ext2_dirent_t *ext2_direntry_iterator_get(ext2_direntry_iterator_t *it) { - return (ext2_dirent_t *)((uintptr_t)iterator->cache + iterator->block_offset); + return (ext2_dirent_t *)((uintptr_t)it->cache + it->block_offset); } /// @brief Check if the iterator is valid. -/// @param iterator the iterator to check. +/// @param it the iterator to check. /// @return 1 if valid, 0 otherwise. -int ext2_direntry_iterator_valid(ext2_direntry_iterator_t *iterator) +int ext2_direntry_iterator_valid(ext2_direntry_iterator_t *it) { - return iterator->direntry != NULL; + return it->direntry != NULL; } /// @brief Initializes the iterator and reads the first block. @@ -1797,53 +1797,31 @@ ext2_direntry_iterator_t ext2_direntry_iterator_begin(ext2_filesystem_t *fs, uin /// @brief Moves to the next direntry, and moves to the next block if necessary. /// @param iterator the iterator. -void ext2_direntry_iterator_next(ext2_direntry_iterator_t *iterator, uint32_t inode_index) +void ext2_direntry_iterator_next(ext2_direntry_iterator_t *it) { // Advance the offsets. - iterator->block_offset += iterator->direntry->rec_len; - iterator->total_offset += iterator->direntry->rec_len; + it->block_offset += it->direntry->rec_len; + it->total_offset += it->direntry->rec_len; // If we reached the end of the inode, stop. - if (iterator->total_offset >= iterator->inode->size) { - if (inode_index > 0) { - pr_crit("Update block!\n"); - // Read the new block. - if (ext2_write_inode_block(iterator->fs, iterator->inode, inode_index, iterator->block_index, iterator->cache) < 0) { - pr_err("Failed to write the inode block `%d` while iterating.\n", iterator->block_index); - // The iterator is not valid anymore. - iterator->direntry = NULL; - return; - } - } + if (it->total_offset >= it->inode->size) { // The iterator is not valid anymore. - iterator->direntry = NULL; + it->direntry = NULL; return; } // If we exceed the size of a block, move to the next block. - if (iterator->block_offset >= iterator->fs->block_size) { - if (inode_index > 0) { - pr_crit("Update block!\n"); - // Read the new block. - if (ext2_write_inode_block(iterator->fs, iterator->inode, inode_index, iterator->block_index, iterator->cache) < 0) { - pr_err("Failed to write the inode block `%d` while iterating.\n", iterator->block_index); - // The iterator is not valid anymore. - iterator->direntry = NULL; - return; - } - } - // Increase the block index. - iterator->block_index += 1; - // Remove the exceeding size, so that we start correctly in the new block. - iterator->block_offset -= iterator->fs->block_size; + if (it->block_offset >= it->fs->block_size) { + // Increase the block index, and reset the block offset. + it->block_index += 1, it->block_offset = 0; // Read the new block. - if (ext2_read_inode_block(iterator->fs, iterator->inode, iterator->block_index, iterator->cache) == -1) { - pr_err("Failed to read the inode block `%d`\n", iterator->block_index); + if (ext2_read_inode_block(it->fs, it->inode, it->block_index, it->cache) == -1) { + pr_err("Failed to read the inode block `%d`.\n", it->block_index); // The iterator is not valid anymore. - iterator->direntry = NULL; + it->direntry = NULL; return; } } // Read the direntry. - iterator->direntry = ext2_direntry_iterator_get(iterator); + it->direntry = ext2_direntry_iterator_get(it); } /// @brief Checks if the directory is empty. @@ -1854,7 +1832,7 @@ void ext2_direntry_iterator_next(ext2_direntry_iterator_t *iterator, uint32_t in static inline int ext2_directory_is_empty(ext2_filesystem_t *fs, uint8_t *cache, ext2_inode_t *inode) { ext2_direntry_iterator_t it = ext2_direntry_iterator_begin(fs, cache, inode); - for (; ext2_direntry_iterator_valid(&it); ext2_direntry_iterator_next(&it, 0)) { + for (; ext2_direntry_iterator_valid(&it); ext2_direntry_iterator_next(&it)) { if (!strncmp(it.direntry->name, ".", 1) || !strncmp(it.direntry->name, "..", 2)) { continue; } @@ -1922,6 +1900,7 @@ static inline void ext2_initialize_direntry( direntry->rec_len = rec_len; direntry->name_len = strlen(name); direntry->file_type = file_type; + memset(direntry->name, 0, direntry->name_len + 1); strncpy(direntry->name, name, direntry->name_len); } @@ -1973,14 +1952,11 @@ static inline void ext2_dump_direntries( ext2_inode_t *parent_inode) { ext2_direntry_iterator_t it = ext2_direntry_iterator_begin(fs, cache, parent_inode); - pr_debug("Directory entries:\n"); // Iterate the directory entries. - while (ext2_direntry_iterator_valid(&it)) { + for (; ext2_direntry_iterator_valid(&it); ext2_direntry_iterator_next(&it)) { // Dump the entry. - pr_debug(" [%2u, %4u]", it.block_index, it.block_offset); + pr_debug(" [%2u, %4u] ", it.block_index, it.block_offset); ext2_dump_dirent(it.direntry); - // Move to next entry. - ext2_direntry_iterator_next(&it, 0); } } @@ -2011,7 +1987,7 @@ static inline int ext2_get_free_direntry( // Prepare iterator. ext2_direntry_iterator_t it = ext2_direntry_iterator_begin(fs, cache, &parent_inode); // Iterate the directory entries. - while (ext2_direntry_iterator_valid(&it)) { + for (; ext2_direntry_iterator_valid(&it); ext2_direntry_iterator_next(&it)) { // If we hit a direntry with an empty inode, that is a free direntry. // Then, we check that the rec_len of the free direntry is big enough. if ((it.direntry->inode == 0) && (rec_len <= it.direntry->rec_len)) { @@ -2030,8 +2006,6 @@ static inline int ext2_get_free_direntry( ext2_dump_dirent(it.direntry); return 1; } - // Move to next entry. - ext2_direntry_iterator_next(&it, 0); } return 0; } @@ -2064,11 +2038,15 @@ static inline int ext2_append_new_direntry( // Prepare iterator. ext2_direntry_iterator_t it = ext2_direntry_iterator_begin(fs, cache, &parent_inode); // Iterate the directory entries. - while (ext2_direntry_iterator_valid(&it)) { + for (; ext2_direntry_iterator_valid(&it); ext2_direntry_iterator_next(&it)) { // Check if we reached the last directory entry, if that's the case, we // check if the remaining space is big enough. if (ext2_is_last_directory_entry(it.direntry) && ((it.block_offset + rec_len) <= fs->block_size)) { - pr_debug("Found last directory entry (offset: %u):\n", it.block_offset); + pr_debug("Found last directory entry (offset: %u, %u != round(%u+%u+1):\n", + it.block_offset, + it.direntry->rec_len, + sizeof(ext2_dirent_t), it.direntry->name_len); + ext2_dump_dirent(it.direntry); // Compute the real rec_len of the entry. real_rec_len = ext2_get_rec_len_from_direntry(it.direntry); @@ -2090,8 +2068,6 @@ static inline int ext2_append_new_direntry( } return 1; } - // Move to next entry. - ext2_direntry_iterator_next(&it, 0); } return 0; } @@ -2122,7 +2098,7 @@ static inline int ext2_create_new_direntry( // Prepare iterator. ext2_direntry_iterator_t it = ext2_direntry_iterator_begin(fs, cache, &parent_inode); // Find the last entry. - while (ext2_direntry_iterator_valid(&it)) { ext2_direntry_iterator_next(&it, 0); } + while (ext2_direntry_iterator_valid(&it)) { ext2_direntry_iterator_next(&it); } // Allocate a new block. if (ext2_allocate_inode_block(fs, &parent_inode, parent_inode_index, it.block_index) == -1) { pr_err("Failed to allocate a new block for an inode.\n"); @@ -2201,6 +2177,10 @@ static int ext2_allocate_direntry( // Allocate the cache. uint8_t *cache = ext2_alloc_cache(fs); + // pr_debug("BEFORE:\n"); + // ext2_dump_direntries(fs, cache, &parent_inode); + // pr_debug("\n"); + // Get free directory entry. if (!ext2_get_free_direntry(fs, cache, parent_inode_index, name, direntry_inode_index, file_type)) { if (!ext2_append_new_direntry(fs, cache, parent_inode_index, name, direntry_inode_index, file_type)) { @@ -2213,6 +2193,10 @@ static int ext2_allocate_direntry( } } + // pr_debug("AFTER:\n"); + // ext2_dump_direntries(fs, cache, &parent_inode); + // pr_debug("\n"); + // Free the cache. ext2_dealloc_cache(cache); return 0; @@ -2234,6 +2218,7 @@ static int ext2_destroy_direntry( uint32_t block_index, uint32_t block_offset) { + pr_debug("destroy_direntry(parent: %u, entry: %u)\n", parent_index, inode_index); // Allocate the cache and clean it. uint8_t *cache = ext2_alloc_cache(fs); // Check if the directory is empty, if it enters the loop then it means it is not empty. @@ -2251,7 +2236,7 @@ static int ext2_destroy_direntry( if (ext2_write_inode(fs, &parent, parent_index) < 0) { pr_err("Failed to update the inode of `%d`.\n", parent_index); ext2_dealloc_cache(cache); - return 1; + return -1; } // Reduce the number of links to the directory. inode.links_count = 0; @@ -2260,26 +2245,26 @@ static int ext2_destroy_direntry( if (ext2_write_inode(fs, &inode, inode_index) < 0) { pr_err("Failed to update the inode of `%d`.\n", inode_index); ext2_dealloc_cache(cache); - return 1; + return -1; } // Free the inode. if (ext2_free_inode(fs, &inode, inode_index) < 0) { pr_err("Failed to free the inode of `%d`.\n", inode_index); ext2_dealloc_cache(cache); - return 1; + return -1; } // Read the block where the direntry resides. if (ext2_read_inode_block(fs, &parent, block_index, cache) == -1) { pr_err("Failed to read the parent inode block `%d`\n", block_index); ext2_dealloc_cache(cache); - return 1; + return -1; } // Get a pointer to the direntry. ext2_dirent_t *dirent = (ext2_dirent_t *)((uintptr_t)cache + block_offset); if (dirent == NULL) { pr_err("We found a NULL ext2_dirent_t\n"); ext2_dealloc_cache(cache); - return 1; + return -1; } // Set the inode to zero. dirent->inode = 0; @@ -2287,7 +2272,7 @@ static int ext2_destroy_direntry( if (!ext2_write_inode_block(fs, &parent, parent_index, block_index, cache)) { pr_err("Failed to write the inode block `%d`\n", block_index); ext2_dealloc_cache(cache); - return 1; + return -1; } // Free the cache. ext2_dealloc_cache(cache); @@ -2337,7 +2322,7 @@ static int ext2_find_direntry(ext2_filesystem_t *fs, ino_t ino, const char *name // Prepare iterator. ext2_direntry_iterator_t it = ext2_direntry_iterator_begin(fs, cache, &inode); - for (; ext2_direntry_iterator_valid(&it); ext2_direntry_iterator_next(&it, 0)) { + for (; ext2_direntry_iterator_valid(&it); ext2_direntry_iterator_next(&it)) { // Skip unused inode. if (it.direntry->inode == 0) { continue; @@ -2418,7 +2403,7 @@ static int ext2_resolve_path(vfs_file_t *directory, char *path, ext2_direntry_se } token = strtok_r(NULL, "/", &saveptr); } - pr_debug("ext2_resolve_path(directory: %s, path: %s) -> (%s, %d)\n", + pr_debug("resolve_path(directory: %s, path: %s) -> (%s, %d)\n", directory->name, path, search->direntry.name, search->direntry.inode); return 0; } @@ -2645,7 +2630,7 @@ static int ext2_create_inode( /// It is equivalent to: open(path, O_WRONLY|O_CREAT|O_TRUNC, mode) static vfs_file_t *ext2_creat(const char *path, mode_t mode) { - pr_debug("ext2_creat(path: \"%s\", mode: %d)\n", path, mode); + pr_debug("creat(path: \"%s\", mode: %d)\n", path, mode); // Get the name of the directory. char parent_path[PATH_MAX]; if (!dirname(path, parent_path, sizeof(parent_path))) { @@ -2746,7 +2731,7 @@ static vfs_file_t *ext2_creat(const char *path, mode_t mode) /// @return The file descriptor of the opened file, otherwise returns -1. static vfs_file_t *ext2_open(const char *path, int flags, mode_t mode) { - pr_debug("ext2_open(path: \"%s\", flags: %d, mode: %d)\n", path, flags, mode); + pr_debug("open(path: \"%s\", flags: %d, mode: %d)\n", path, flags, mode); // Get the absolute path. char absolute_path[PATH_MAX]; // If the first character is not the '/' then get the absolute path. @@ -2833,7 +2818,7 @@ static vfs_file_t *ext2_open(const char *path, int flags, mode_t mode) /// @return 0 on success, -errno on failure. static int ext2_unlink(const char *path) { - pr_debug("ext2_unlink(%s)\n", path); + pr_debug("unlink(%s)\n", path); // Get the absolute path. char absolute_path[PATH_MAX]; // If the first character is not the '/' then get the absolute path. @@ -2864,7 +2849,7 @@ static int ext2_unlink(const char *path) // Get the inode associated with the parent directory entry. ext2_inode_t parent_inode; if (ext2_read_inode(fs, &parent_inode, search.parent_inode) == -1) { - pr_err("ext2_stat(%s): Failed to read the inode of parent of `%s`.\n", path, search.direntry.name); + pr_err("stat(%s): Failed to read the inode of parent of `%s`.\n", path, search.direntry.name); return -ENOENT; } // Allocate the cache. @@ -2932,7 +2917,7 @@ static int ext2_close(vfs_file_t *file) if (file == fs->root) { return -1; } - pr_debug("ext2_close(ino: %d, file: \"%s\")\n", file->ino, file->name); + pr_debug("close(ino: %d, file: \"%s\")\n", file->ino, file->name); // Remove the file from the list of opened files. list_head_remove(&file->siblings); // Free the cache. @@ -2948,7 +2933,7 @@ static int ext2_close(vfs_file_t *file) /// @return The number of red bytes. static ssize_t ext2_read(vfs_file_t *file, char *buffer, off_t offset, size_t nbyte) { - //pr_debug("ext2_read(%s, %p, %d, %d)\n", file->name, buffer, offset, nbyte); + //pr_debug("read(%s, %p, %d, %d)\n", file->name, buffer, offset, nbyte); // Get the filesystem. ext2_filesystem_t *fs = (ext2_filesystem_t *)file->device; if (fs == NULL) { @@ -3117,7 +3102,7 @@ static int ext2_ioctl(vfs_file_t *file, int request, void *data) /// @return The number of written bytes in the buffer. static ssize_t ext2_getdents(vfs_file_t *file, dirent_t *dirp, off_t doff, size_t count) { - pr_debug("ext2_getdents(%s, %p, %d, %d)\n", file->name, dirp, doff, count); + pr_debug("getdents(%s, %p, %d, %d)\n", file->name, dirp, doff, count); // Get the filesystem. ext2_filesystem_t *fs = (ext2_filesystem_t *)file->device; if (fs == NULL) { @@ -3137,7 +3122,7 @@ static ssize_t ext2_getdents(vfs_file_t *file, dirent_t *dirp, off_t doff, size_ // Initialize the iterator. ext2_direntry_iterator_t it = ext2_direntry_iterator_begin(fs, cache, &inode); - for (; ext2_direntry_iterator_valid(&it) && (written < count); ext2_direntry_iterator_next(&it, 0)) { + for (; ext2_direntry_iterator_valid(&it) && (written < count); ext2_direntry_iterator_next(&it)) { // Skip unused inode. if (it.direntry->inode == 0) { continue; @@ -3198,99 +3183,79 @@ static ssize_t ext2_readlink(vfs_file_t *file, char *buffer, size_t bufsize) /// @return Returns a negative value on failure. static int ext2_mkdir(const char *path, mode_t permission) { - pr_debug("\next2_mkdir(%s, %d)\n", path, permission); + pr_debug("mkdir(%s, %d)\n", path, permission); // 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); + pr_err("mkdir(%s): Cannot get the absolute path.\n", path); + return -ENOENT; + } + // Get the parent directory. + char parent_path[PATH_MAX]; + if (!dirname(absolute_path, parent_path, sizeof(parent_path))) { + return -ENOENT; + } + // Check the parent path. + if (strcmp(parent_path, absolute_path) == 0) { + pr_err("mkdir(%s): Failed to properly get the parent directory (%s == %s).\n", path, parent_path, absolute_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); + pr_err("mkdir(%s): Failed to get the EXT2 filesystem for absolute path `%s`.\n", path, absolute_path); return -ENOENT; } // Prepare the structure for the search. ext2_direntry_search_t search; - // Prepare an inode, it will come in handy either way. - ext2_inode_t inode; // Search if the entry already exists. if (!ext2_resolve_path(fs->root, absolute_path, &search)) { - pr_err("Directory already exists.\n"); + pr_err("mkdir(%s): Directory already exists.\n", absolute_path); return -EEXIST; } - // Get the parent directory. - char parent_path[PATH_MAX]; - if (!dirname(path, parent_path, sizeof(parent_path))) { - return -ENOENT; - } - // Check the parent path. - if (strcmp(parent_path, path) == 0) { - pr_err("Failed to properly get the parent directory (%s == %s).\n", parent_path, path); - return -ENOENT; - } // Set the inode mode. uint32_t mode = EXT2_S_IFDIR; mode |= 0xFFF & permission; - // Get the parent VFS node. - vfs_file_t *parent = vfs_open(parent_path, O_RDONLY, mode); - if (parent == NULL) { - pr_err("Failed to open parent directory (%s).\n", parent_path); - return -ENOENT; - } // Get the group index of the parent. - uint32_t group_index = ext2_inode_index_to_group_index(fs, parent->ino); + uint32_t group_index = ext2_inode_index_to_group_index(fs, search.parent_inode); + // Prepare an inode, it will come in handy either way. + ext2_inode_t inode; // Create and initialize the new inode. int inode_index = ext2_create_inode(fs, &inode, mode, group_index); if (inode_index == -1) { - pr_err("Failed to create a new inode inside `%s` (group index: %d).\n", parent->name, group_index); - // Close the parent directory. - vfs_close(parent); + pr_err("mkdir(%s): Failed to create a new inode (group index: %d).\n", path, group_index); return -ENOENT; } // Increase the number of directories inside the group. fs->block_groups[group_index].used_dirs_count += 1; - // Update the bgdt. - if (ext2_write_bgdt(fs) < 0) { - pr_warning("Failed to write BGDT.\n"); - } // Write the inode. if (ext2_write_inode(fs, &inode, inode_index) == -1) { pr_err("Failed to write the newly created inode.\n"); - // Close the parent directory. - vfs_close(parent); return -ENOENT; } + // Get the directory name. + const char *directory_name = basename(path); // Create a directory entry for the directory. - if (ext2_allocate_direntry(fs, parent->ino, inode_index, basename(path), ext2_file_type_directory) == -1) { - pr_err("Failed to allocate a new direntry for the inode.\n"); - // Close the parent directory. - vfs_close(parent); + if (ext2_allocate_direntry(fs, search.parent_inode, inode_index, directory_name, ext2_file_type_directory) == -1) { + pr_err("mkdir(%s): Failed to allocate the new direntry `%s` for the inode.\n", path, directory_name); return -ENOENT; } // Allocate a new block. if (!ext2_initialize_new_direntry_block(fs, inode_index, 0)) { - pr_err("Failed to allocate a new block for an inode.\n"); + pr_err("mkdir(%s): Failed to allocate a new block for an inode.\n", path); return 0; } // Create a directory entry, inside the new directory, pointing to itself. if (ext2_allocate_direntry(fs, inode_index, inode_index, ".", ext2_file_type_directory) == -1) { - pr_err("Failed to allocate a new direntry for the inode.\n"); - // Close the parent directory. - vfs_close(parent); + pr_err("mkdir(%s): Failed to allocate a new direntry for the inode.\n", path); return -ENOENT; } // Create a directory entry, inside the new directory, pointing to its parent. - if (ext2_allocate_direntry(fs, inode_index, parent->ino, "..", ext2_file_type_directory) == -1) { - pr_err("Failed to allocate a new direntry for the inode.\n"); - // Close the parent directory. - vfs_close(parent); + if (ext2_allocate_direntry(fs, inode_index, search.parent_inode, "..", ext2_file_type_directory) == -1) { + pr_err("mkdir(%s): Failed to allocate a new direntry for the inode.\n", path); return -ENOENT; } - // Close the parent directory. - vfs_close(parent); return 0; } @@ -3299,24 +3264,24 @@ static int ext2_mkdir(const char *path, mode_t permission) /// @return Returns a negative value on failure. static int ext2_rmdir(const char *path) { - pr_debug("ext2_unlink(%s)\n", path); + pr_debug("rmdir(%s)\n", path); // 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); + pr_err("rmdir(%s): Cannot get the absolute path.\n", path); return -ENOENT; } // Get the name of the entry we want to unlink. const char *name = basename(absolute_path); if (name == NULL) { - pr_err("Cannot get the basename from the absolute path `%s`.\n", absolute_path); + pr_err("rmdir(%s): Cannot get the basename from the absolute path `%s`.\n", path, absolute_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); + pr_err("rmdir(%s): Failed to get the EXT2 filesystem for absolute path `%s`.\n", path, absolute_path); return -ENOENT; } // Prepare the structure for the search. @@ -3324,20 +3289,20 @@ static int ext2_rmdir(const char *path) memset(&search, 0, sizeof(ext2_direntry_search_t)); // Resolve the path to the directory entry. if (ext2_resolve_path(fs->root, absolute_path, &search)) { - pr_err("Failed to resolve path `%s`.\n", absolute_path); + pr_err("rmdir(%s): Failed to resolve path `%s`.\n", path, absolute_path); return -ENOENT; } // Get the inode associated with the parent directory entry. ext2_inode_t parent; if (ext2_read_inode(fs, &parent, search.parent_inode) == -1) { - pr_err("ext2_stat(%s): Failed to read the inode of parent of `%s`.\n", path, search.direntry.name); + pr_err("rmdir(%s): Failed to read the inode of parent of `%s`.\n", path, search.direntry.name); return -ENOENT; } // Read the inode of the direntry we want to unlink. ext2_inode_t inode; if (ext2_read_inode(fs, &inode, search.direntry.inode) == -1) { - pr_err("Failed to read the inode of `%s`.\n", search.direntry.name); + pr_err("rmdir(%s): Failed to read the inode of `%s`.\n", path, search.direntry.name); return -ENOENT; } return ext2_destroy_direntry(fs, parent, inode, search.parent_inode, search.direntry.inode, search.block_index, search.block_offset); @@ -3349,18 +3314,18 @@ static int ext2_rmdir(const char *path) /// @return 0 if success. static int ext2_stat(const char *path, stat_t *stat) { - pr_debug("ext2_stat(%s, %p)\n", path, stat); + pr_debug("stat(%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); + pr_err("stat(%s): Cannot get the absolute path.\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); + pr_err("stat(%s): Failed to get the EXT2 filesystem for absolute path `%s`.\n", path, absolute_path); return -ENOENT; } // Prepare the structure for the search. @@ -3368,13 +3333,13 @@ static int ext2_stat(const char *path, stat_t *stat) memset(&search, 0, sizeof(ext2_direntry_search_t)); // Resolve the path. if (ext2_resolve_path(fs->root, absolute_path, &search)) { - pr_err("Failed to resolve path `%s`.\n", path); + pr_err("stat(%s): Failed to resolve path `%s`.\n", path, absolute_path); return -ENOENT; } // Get the inode associated with the directory entry. ext2_inode_t inode; if (ext2_read_inode(fs, &inode, search.direntry.inode) == -1) { - pr_err("ext2_stat(%s): Failed to read the inode of `%s`.\n", path, search.direntry.name); + pr_err("stat(%s): Failed to read the inode of `%s`.\n", path, search.direntry.name); return -ENOENT; } /// ID of device containing file. @@ -3433,16 +3398,15 @@ static int ext2_fsetattr(vfs_file_t *file, struct iattr *attr) // 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); + pr_err("fsetattr(%s): The file does not belong to an EXT2 filesystem.\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); + pr_err("fsetattr(%s): Failed to read the inode.\n", file->name); return -ENOENT; } - __ext2_setattr(&inode, attr); return ext2_write_inode(fs, &inode, file->ino); } @@ -3453,18 +3417,18 @@ static int ext2_fsetattr(vfs_file_t *file, struct iattr *attr) /// @return 0 if success. static int ext2_setattr(const char *path, struct iattr *attr) { - pr_debug("ext2_setattr(%s, %p)\n", path, attr); + pr_debug("setattr(%s, %p)\n", path, attr); // 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); + pr_err("setattr(%s): Cannot get the absolute path.\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); + pr_err("setattr(%s): Failed to get the EXT2 filesystem for absolute path `%s`.\n", path, absolute_path); return -ENOENT; } // Prepare the structure for the search. @@ -3472,20 +3436,18 @@ static int ext2_setattr(const char *path, struct iattr *attr) memset(&search, 0, sizeof(ext2_direntry_search_t)); // Resolve the path. if (ext2_resolve_path(fs->root, absolute_path, &search)) { - pr_err("Failed to resolve path `%s`.\n", absolute_path); + pr_err("setattr(%s): Failed to resolve path `%s`.\n", path, absolute_path); return -ENOENT; } // Get the inode associated with the directory entry. ext2_inode_t inode; if (ext2_read_inode(fs, &inode, search.direntry.inode) == -1) { - pr_err("ext2_stat(%s): Failed to read the inode of `%s`.\n", path, search.direntry.name); + pr_err("setattr(%s): Failed to read the inode of `%s`.\n", path, search.direntry.name); return -ENOENT; } - if (!__ext2_check_setattr_permission(inode.uid)) { return -EPERM; } - __ext2_setattr(&inode, attr); return ext2_write_inode(fs, &inode, search.direntry.inode); } @@ -3649,21 +3611,21 @@ static vfs_file_t *ext2_mount_callback(const char *path, const char *device) char absolute_path[PATH_MAX]; // If the first character is not the '/' then get the absolute path. if (!realpath(device, absolute_path, sizeof(absolute_path))) { - pr_err("ext2_mount_callback(%s, %s): Cannot get the absolute path.", path, device); + pr_err("mount_callback(%s, %s): Cannot get the absolute path.", path, device); return NULL; } super_block_t *sb = vfs_get_superblock(absolute_path); if (sb == NULL) { - pr_err("ext2_mount_callback(%s, %s): Cannot find the superblock at absolute path `%s`!\n", path, device, absolute_path); + pr_err("mount_callback(%s, %s): Cannot find the superblock at absolute path `%s`!\n", path, device, absolute_path); return NULL; } vfs_file_t *block_device = sb->root; if (block_device == NULL) { - pr_err("ext2_mount_callback(%s, %s): Cannot find the superblock root.", path, device); + pr_err("mount_callback(%s, %s): Cannot find the superblock root.", path, device); return NULL; } if (block_device->flags != DT_BLK) { - pr_err("ext2_mount_callback(%s, %s): The device is not a block device.\n", path, device); + pr_err("mount_callback(%s, %s): The device is not a block device.\n", path, device); return NULL; } return ext2_mount(block_device, path); From 6b35ebe1ce21feac823803f82439fcb9fb6ce8b7 Mon Sep 17 00:00:00 2001 From: "Enrico Fraccaroli (Galfurian)" Date: Thu, 22 Aug 2024 11:27:44 -0400 Subject: [PATCH 38/40] Add sanity checks to list_head functions. --- libc/inc/sys/list_head.h | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/libc/inc/sys/list_head.h b/libc/inc/sys/list_head.h index 4e61c4cf..f13244a3 100644 --- a/libc/inc/sys/list_head.h +++ b/libc/inc/sys/list_head.h @@ -6,6 +6,7 @@ #pragma once #include "stddef.h" +#include "assert.h" /// @brief Structure used to implement the list_head data structure. typedef struct list_head { @@ -73,6 +74,7 @@ static inline void list_head_init(list_head *head) /// @return 1 if empty, 0 otherwise. static inline int list_head_empty(const list_head *head) { + assert(head && "Variable head is NULL."); return head->next == head; } @@ -93,6 +95,8 @@ static inline unsigned list_head_size(const list_head *head) /// @param location the element after which we insert. static inline void list_head_insert_after(list_head *new_entry, list_head *location) { + assert(new_entry && "Variable new_entry is NULL."); + assert(location && "Variable location is NULL."); // We store the old `next` element. list_head *old_next = location->next; // We insert our element. @@ -110,6 +114,8 @@ static inline void list_head_insert_after(list_head *new_entry, list_head *locat /// @param location the element after which we insert. static inline void list_head_insert_before(list_head *new_entry, list_head *location) { + assert(new_entry && "Variable new_entry is NULL."); + assert(location && "Variable location is NULL."); // We store the old `previous` element. list_head *old_prev = location->prev; // We link the old `previous` element to our new entry. @@ -128,6 +134,8 @@ static inline void list_head_remove(list_head *entry) { // Check if the element is actually in a list. if (!list_head_empty(entry)) { + assert(entry->prev && "Attribute entry->prev is NULL."); + assert(entry->next && "Attribute entry->next is NULL."); // We link the `previous` element to the `next` one. entry->prev->next = entry->next; // We link the `next` element to the `previous` one. @@ -162,16 +170,17 @@ static inline void list_head_append(list_head *main, list_head *secondary) { // Check that both lists are actually filled with entries. if (!list_head_empty(main) && !list_head_empty(secondary)) { + assert(main->prev && "Attribute main->prev is NULL."); + assert(secondary->next && "Attribute secondary->next is NULL."); + assert(secondary->prev && "Attribute secondary->prev is NULL."); // Connect the last element of the main list to the first one of the secondary list. main->prev->next = secondary->next; // Connect the first element of the secondary list to the last one of the main list. secondary->next->prev = main->prev; - // Connect the last element of the secondary list to our main. secondary->prev->next = main; // Connect our main to the last element of the secondary list. main->prev = secondary->prev; - // Re-initialize the secondary list. list_head_init(secondary); } @@ -184,6 +193,8 @@ static inline void list_head_replace(list_head *entry1, list_head *entry2) { // First we need to remove the second entry. list_head_remove(entry2); + assert(entry2->next && "Attribute entry2->next is NULL."); + assert(entry2->prev && "Attribute entry2->prev is NULL."); // Then, we can place second entry where the first entry is. entry2->next = entry1->next; entry2->next->prev = entry2; From 1955c7bd224da79d86c293b1608712363a828d9a Mon Sep 17 00:00:00 2001 From: "Enrico Fraccaroli (Galfurian)" Date: Thu, 22 Aug 2024 11:29:16 -0400 Subject: [PATCH 39/40] Disable debug messages in ext2 --- mentos/src/fs/ext2.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mentos/src/fs/ext2.c b/mentos/src/fs/ext2.c index d21ed4f0..320d26ba 100644 --- a/mentos/src/fs/ext2.c +++ b/mentos/src/fs/ext2.c @@ -4,10 +4,10 @@ /// See LICENSE.md for details. // Setup the logging for this file (do this before any other include). -#include "sys/kernel_levels.h" // Include kernel log levels. -#define __DEBUG_HEADER__ "[EXT2 ]" ///< Change header. -#define __DEBUG_LEVEL__ LOGLEVEL_DEBUG ///< Set log level. -#include "io/debug.h" // Include debugging functions. +#include "sys/kernel_levels.h" // Include kernel log levels. +#define __DEBUG_HEADER__ "[EXT2 ]" ///< Change header. +#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE ///< Set log level. +#include "io/debug.h" // Include debugging functions. #include "assert.h" #include "fcntl.h" From 4dd80ede9cb95be66503fc7827cdf9137801e9fc Mon Sep 17 00:00:00 2001 From: "Enrico Fraccaroli (Galfurian)" Date: Thu, 22 Aug 2024 11:38:04 -0400 Subject: [PATCH 40/40] Update version numbers. --- files/README | 2 +- mentos/inc/version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/files/README b/files/README index 7f9f5752..b3572567 100644 --- a/files/README +++ b/files/README @@ -1,4 +1,4 @@ -MentOS 0.7.1 +MentOS 0.7.2 Welcome to the MentOS, the Mentoring Operating System. diff --git a/mentos/inc/version.h b/mentos/inc/version.h index 0fced4f8..042f8a6b 100644 --- a/mentos/inc/version.h +++ b/mentos/inc/version.h @@ -21,7 +21,7 @@ #define OS_MINOR_VERSION 7 /// Micro version of the operating system. -#define OS_MICRO_VERSION 1 +#define OS_MICRO_VERSION 2 /// Helper to transform the given argument into a string. #define OS_STR_HELPER(x) #x