From 45957a4a2998b060bc0507fa19bef84e87be3b8f Mon Sep 17 00:00:00 2001 From: "Enrico Fraccaroli (Galfurian)" Date: Fri, 23 Aug 2024 09:34:25 -0400 Subject: [PATCH 01/18] Move file types related macros from fcntl to sys/stat --- libc/inc/fcntl.h | 30 ---------------- libc/inc/sys/stat.h | 45 ++++++++++++++++++++++++ libc/src/string.c | 2 +- mentos/src/fs/ext2.c | 45 +++++++++--------------- mentos/src/fs/namei.c | 3 ++ mentos/src/fs/procfs.c | 1 + mentos/src/fs/vfs.c | 1 + mentos/src/ipc/ipc.c | 1 + mentos/src/klib/string.c | 2 +- mentos/src/process/process.c | 1 + programs/ls.c | 14 ++++++-- programs/stat.c | 67 +++++++++++++++++------------------- programs/tests/t_dup.c | 1 + programs/tests/t_msgget.c | 17 ++++----- programs/tests/t_semflg.c | 15 ++++---- programs/tests/t_semget.c | 15 ++++---- programs/tests/t_semop.c | 17 ++++----- programs/touch.c | 1 + 18 files changed, 151 insertions(+), 127 deletions(-) diff --git a/libc/inc/fcntl.h b/libc/inc/fcntl.h index c3700fd5..991f527b 100644 --- a/libc/inc/fcntl.h +++ b/libc/inc/fcntl.h @@ -15,33 +15,3 @@ #define O_APPEND 00002000U ///< Set append mode. #define O_NONBLOCK 00004000U ///< No delay. #define O_DIRECTORY 00200000U ///< If file exists has no effect. Otherwise, the file is created. - -/// @defgroup ModeBitsAccessPermission Mode Bits for Access Permission -/// @brief The file modes. -/// @{ - -#define S_ISUID 0x0800 ///< Set user id on execution -#define S_ISGID 0x0400 ///< Set group id on execution -#define S_ISVTX 0x0200 ///< Save swapped text even after use (Sticky Bit) -#define S_IRWXU 0x01C0 ///< rwx------ : User can read/write/execute -#define S_IRUSR 0x0100 ///< r-------- : User can read -#define S_IWUSR 0x0080 ///< -w------- : User can write -#define S_IXUSR 0x0040 ///< --x------ : User can execute -#define S_IRWXG 0x0038 ///< ---rwx--- : Group can read/write/execute -#define S_IRGRP 0x0020 ///< ---r----- : Group can read -#define S_IWGRP 0x0010 ///< ----w---- : Group can write -#define S_IXGRP 0x0008 ///< -----x--- : Group can execute -#define S_IRWXO 0x0007 ///< ------rwx : Others can read/write/execute -#define S_IROTH 0x0004 ///< ------r-- : Others can read -#define S_IWOTH 0x0002 ///< -------w- : Others can write -#define S_IXOTH 0x0001 ///< --------x : Others can execute - -#define S_ISDIR(m) (((m)&0170000) == 0040000) ///< directory. -#define S_ISCHR(m) (((m)&0170000) == 0020000) ///< char special -#define S_ISBLK(m) (((m)&0170000) == 0060000) ///< block special -#define S_ISREG(m) (((m)&0170000) == 0100000) ///< regular file -#define S_ISFIFO(m) (((m)&0170000) == 0010000) ///< fifo -#define S_ISLNK(m) (((m)&0170000) == 0120000) ///< symbolic link -#define S_ISSOCK(m) (((m)&0170000) == 0140000) ///< socket - -/// @} diff --git a/libc/inc/sys/stat.h b/libc/inc/sys/stat.h index 3b29421b..1b99b1ec 100644 --- a/libc/inc/sys/stat.h +++ b/libc/inc/sys/stat.h @@ -10,6 +10,51 @@ #include "stddef.h" #include "time.h" +/// @defgroup FileTypes File Types Macros +/// @brief These constants allow to identify file types. +/// @{ +#define S_IFMT 0xF000 ///< Format mask +#define S_IFSOCK 0xC000 ///< Socket +#define S_IFLNK 0xA000 ///< Symbolic link +#define S_IFREG 0x8000 ///< Regular file +#define S_IFBLK 0x6000 ///< Block device +#define S_IFDIR 0x4000 ///< Directory +#define S_IFCHR 0x2000 ///< Character device +#define S_IFIFO 0x1000 ///< Fifo +/// @} + +/// @defgroup FileTypeTest File Type Test Macros +/// @brief These macros allows to easily identify file types. +/// @{ +#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) ///< Check if the input values identifies a socket. +#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) ///< Check if the input values identifies a symbolic link. +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) ///< Check if the input values identifies a regular file. +#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) ///< Check if the input values identifies a block special. +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) ///< Check if the input values identifies a directory. +#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) ///< Check if the input values identifies a char special. +#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) ///< Check if the input values identifies a fifo. +/// @} + +/// @defgroup ModeBitsAccessPermission Mode Bits for Access Permission +/// @brief These constants allow to control access permission for files. +/// @{ +#define S_ISUID 0x0800 ///< Set user id on execution +#define S_ISGID 0x0400 ///< Set group id on execution +#define S_ISVTX 0x0200 ///< Save swapped text even after use (Sticky Bit) +#define S_IRWXU 0x01C0 ///< rwx------ : User can read/write/execute +#define S_IRUSR 0x0100 ///< r-------- : User can read +#define S_IWUSR 0x0080 ///< -w------- : User can write +#define S_IXUSR 0x0040 ///< --x------ : User can execute +#define S_IRWXG 0x0038 ///< ---rwx--- : Group can read/write/execute +#define S_IRGRP 0x0020 ///< ---r----- : Group can read +#define S_IWGRP 0x0010 ///< ----w---- : Group can write +#define S_IXGRP 0x0008 ///< -----x--- : Group can execute +#define S_IRWXO 0x0007 ///< ------rwx : Others can read/write/execute +#define S_IROTH 0x0004 ///< ------r-- : Others can read +#define S_IWOTH 0x0002 ///< -------w- : Others can write +#define S_IXOTH 0x0001 ///< --------x : Others can execute +/// @} + /// @brief Retrieves information about the file at the given location. /// @param path The path to the file that is being inquired. /// @param buf A structure where data about the file will be stored. diff --git a/libc/src/string.c b/libc/src/string.c index 14cc4209..d3a396fd 100644 --- a/libc/src/string.c +++ b/libc/src/string.c @@ -5,9 +5,9 @@ #include "string.h" #include "ctype.h" -#include "fcntl.h" #include "stdio.h" #include "stdlib.h" +#include "sys/stat.h" #ifdef __KERNEL__ #include "mem/kheap.h" diff --git a/mentos/src/fs/ext2.c b/mentos/src/fs/ext2.c index 320d26ba..bb9021c5 100644 --- a/mentos/src/fs/ext2.c +++ b/mentos/src/fs/ext2.c @@ -6,7 +6,7 @@ // 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. +#define __DEBUG_LEVEL__ LOGLEVEL_DEBUG ///< Set log level. #include "io/debug.h" // Include debugging functions. #include "assert.h" @@ -21,6 +21,7 @@ #include "stdio.h" #include "string.h" #include "sys/errno.h" +#include "sys/stat.h" #define EXT2_SUPERBLOCK_MAGIC 0xEF53 ///< Magic value used to identify an ext2 filesystem. #define EXT2_DIRECT_BLOCKS 12 ///< Amount of indirect blocks in an inode. @@ -28,16 +29,6 @@ #define EXT2_MAX_SYMLINK_COUNT 8 ///< Maximum nesting of symlinks, used to prevent a loop. #define EXT2_NAME_LEN 255 ///< The lenght of names inside directory entries. -// File types. -#define EXT2_S_IFMT 0xF000 ///< Format mask -#define EXT2_S_IFSOCK 0xC000 ///< Socket -#define EXT2_S_IFLNK 0xA000 ///< Symbolic link -#define EXT2_S_IFREG 0x8000 ///< Regular file -#define EXT2_S_IFBLK 0x6000 ///< Block device -#define EXT2_S_IFDIR 0x4000 ///< Directory -#define EXT2_S_IFCHR 0x2000 ///< Character device -#define EXT2_S_IFIFO 0x1000 ///< Fifo - // Permissions bit. #define EXT2_S_ISUID 0x0800 ///< SUID #define EXT2_S_ISGID 0x0400 ///< SGID @@ -1851,7 +1842,7 @@ static inline int ext2_directory_is_empty(ext2_filesystem_t *fs, uint8_t *cache, static int ext2_clean_inode_content(ext2_filesystem_t *fs, ext2_inode_t *inode, uint32_t inode_index) { // Check the type of operation. - if ((inode->mode & EXT2_S_IFREG) != EXT2_S_IFREG) { + if ((inode->mode & S_IFREG) != S_IFREG) { pr_alert("Trying to clean the content of a non-regular file.\n"); return 1; } @@ -2170,7 +2161,7 @@ static int ext2_allocate_direntry( return -1; } // Check that the parent is a directory. - if (!bitmask_check(parent_inode.mode, EXT2_S_IFDIR)) { + if (!bitmask_check(parent_inode.mode, S_IFDIR)) { pr_err("The parent inode is not a directory (ino: %d, mode: %d).\n", parent_inode_index, parent_inode.mode); return -1; } @@ -2306,7 +2297,7 @@ static int ext2_find_direntry(ext2_filesystem_t *fs, ino_t ino, const char *name return -1; } // Check that the parent is a directory. - if (!bitmask_check(inode.mode, EXT2_S_IFDIR)) { + if (!bitmask_check(inode.mode, S_IFDIR)) { pr_err("The parent inode is not a directory (ino: %d, mode: %d).\n", ino, inode.mode); return -1; } @@ -2473,22 +2464,22 @@ static int ext2_init_vfs_file( file->gid = inode->gid; // Set the VFS specific flags. file->flags = 0; - if ((inode->mode & EXT2_S_IFREG) == EXT2_S_IFREG) { + if ((inode->mode & S_IFREG) == S_IFREG) { file->flags |= DT_REG; } - if ((inode->mode & EXT2_S_IFDIR) == EXT2_S_IFDIR) { + if ((inode->mode & S_IFDIR) == S_IFDIR) { file->flags |= DT_DIR; } - if ((inode->mode & EXT2_S_IFBLK) == EXT2_S_IFBLK) { + if ((inode->mode & S_IFBLK) == S_IFBLK) { file->flags |= DT_BLK; } - if ((inode->mode & EXT2_S_IFCHR) == EXT2_S_IFCHR) { + if ((inode->mode & S_IFCHR) == S_IFCHR) { file->flags |= DT_CHR; } - if ((inode->mode & EXT2_S_IFIFO) == EXT2_S_IFIFO) { + if ((inode->mode & S_IFIFO) == S_IFIFO) { file->flags |= DT_FIFO; } - if ((inode->mode & EXT2_S_IFLNK) == EXT2_S_IFLNK) { + if ((inode->mode & S_IFLNK) == S_IFLNK) { file->flags |= DT_LNK; } // Set the inode. @@ -2682,7 +2673,7 @@ static vfs_file_t *ext2_creat(const char *path, mode_t mode) return file; } // Set the inode mode. - mode = EXT2_S_IFREG | (0xFFF & mode); + mode = S_IFREG | (0xFFF & mode); // Get the group index of the parent. uint32_t group_index = ext2_inode_index_to_group_index(fs, parent->ino); // Create and initialize the new inode. @@ -2768,9 +2759,6 @@ static vfs_file_t *ext2_open(const char *path, int flags, mode_t mode) errno = ENOENT; return NULL; } - if (search.direntry.file_type == ext2_file_type_symbolic_link) { - pr_alert("Beware, it is a symbolic link.\n"); - } // Prepare the structure for the inode. ext2_inode_t inode; memset(&inode, 0, sizeof(ext2_inode_t)); @@ -2787,7 +2775,7 @@ static vfs_file_t *ext2_open(const char *path, int flags, mode_t mode) } // Check if the file is a regular file, and the user wants to write and truncate. - if (bitmask_exact(inode.mode, EXT2_S_IFREG) && (bitmask_exact(flags, O_RDWR | O_TRUNC) || bitmask_exact(flags, O_RDONLY | O_TRUNC))) { + if (bitmask_exact(inode.mode, S_IFREG) && (bitmask_exact(flags, O_RDWR | O_TRUNC) || bitmask_exact(flags, O_RDONLY | O_TRUNC))) { // Clean the content of the newly created file. if (ext2_clean_inode_content(fs, &inode, search.direntry.inode) < 0) { pr_err("Failed to clean the content of the newly created inode.\n"); @@ -2947,7 +2935,7 @@ static ssize_t ext2_read(vfs_file_t *file, char *buffer, off_t offset, size_t nb return -1; } // Disallow reading directories using read - if ((inode.mode & EXT2_S_IFDIR) == EXT2_S_IFDIR) { + if ((inode.mode & S_IFDIR) == S_IFDIR) { pr_err("Reading a directory `%s` is not allowed.\n", file->name); return -EISDIR; } @@ -3173,6 +3161,7 @@ static ssize_t ext2_readlink(vfs_file_t *file, char *buffer, size_t bufsize) ssize_t nbytes = min(strlen(inode.data.symlink), bufsize); // Copy the symlink information. strncpy(buffer, inode.data.symlink, nbytes); + pr_emerg("LINK: %d `%s`\n", file->ino, inode.data.symlink); // Return how much we read. return nbytes; } @@ -3215,7 +3204,7 @@ static int ext2_mkdir(const char *path, mode_t permission) return -EEXIST; } // Set the inode mode. - uint32_t mode = EXT2_S_IFDIR; + uint32_t mode = S_IFDIR; mode |= 0xFFF & permission; // Get the group index of the parent. uint32_t group_index = ext2_inode_index_to_group_index(fs, search.parent_inode); @@ -3552,7 +3541,7 @@ static vfs_file_t *ext2_mount(vfs_file_t *block_device, const char *path) // Free the block_buffer, the block_groups and the filesystem. goto free_block_buffer; } - if ((root_inode.mode & EXT2_S_IFDIR) != EXT2_S_IFDIR) { + if ((root_inode.mode & S_IFDIR) != S_IFDIR) { pr_err("The root is not a directory.\n"); // Free the block_buffer, the block_groups and the filesystem. goto free_block_buffer; diff --git a/mentos/src/fs/namei.c b/mentos/src/fs/namei.c index 21b845e9..cad82d60 100644 --- a/mentos/src/fs/namei.c +++ b/mentos/src/fs/namei.c @@ -7,6 +7,7 @@ #include "assert.h" #include "limits.h" #include "fcntl.h" +#include "sys/stat.h" #include "fs/vfs.h" #include "io/debug.h" #include "process/scheduler.h" @@ -77,12 +78,14 @@ int sys_symlink(const char *linkname, const char *path) int sys_readlink(const char *path, char *buffer, size_t bufsize) { + pr_crit("Open...\n"); // Try to open the file. vfs_file_t *file = vfs_open(path, O_RDONLY, 0); if (file == NULL) { return -errno; } // Read the link. + pr_crit("Readlink...\n"); ssize_t nbytes = vfs_readlink(file, buffer, bufsize); // Close the file. vfs_close(file); diff --git a/mentos/src/fs/procfs.c b/mentos/src/fs/procfs.c index f5db354d..126d0fd3 100644 --- a/mentos/src/fs/procfs.c +++ b/mentos/src/fs/procfs.c @@ -11,6 +11,7 @@ #include "assert.h" #include "fcntl.h" +#include "sys/stat.h" #include "fs/procfs.h" #include "fs/vfs.h" #include "libgen.h" diff --git a/mentos/src/fs/vfs.c b/mentos/src/fs/vfs.c index 4620bccc..907f1392 100644 --- a/mentos/src/fs/vfs.c +++ b/mentos/src/fs/vfs.c @@ -10,6 +10,7 @@ #include "io/debug.h" // Include debugging functions. #include "fcntl.h" +#include "sys/stat.h" #include "assert.h" #include "fs/procfs.h" #include "fs/namei.h" diff --git a/mentos/src/ipc/ipc.c b/mentos/src/ipc/ipc.c index 03862443..6076bbfd 100644 --- a/mentos/src/ipc/ipc.c +++ b/mentos/src/ipc/ipc.c @@ -6,6 +6,7 @@ #include "ipc/ipc.h" #include "assert.h" +#include "sys/stat.h" #include "fcntl.h" #include "io/debug.h" #include "process/scheduler.h" diff --git a/mentos/src/klib/string.c b/mentos/src/klib/string.c index 7579da94..37ec3eb2 100644 --- a/mentos/src/klib/string.c +++ b/mentos/src/klib/string.c @@ -5,7 +5,7 @@ #include "string.h" #include "ctype.h" -#include "fcntl.h" +#include "sys/stat.h" #include "stdio.h" #include "stdlib.h" diff --git a/mentos/src/process/process.c b/mentos/src/process/process.c index b569493c..49015d7a 100644 --- a/mentos/src/process/process.c +++ b/mentos/src/process/process.c @@ -12,6 +12,7 @@ #include "assert.h" #include "elf/elf.h" #include "fcntl.h" +#include "sys/stat.h" #include "fs/vfs.h" #include "hardware/timer.h" #include "klib/stack_helper.h" diff --git a/programs/ls.c b/programs/ls.c index 2f251444..b5a6ae17 100644 --- a/programs/ls.c +++ b/programs/ls.c @@ -83,7 +83,7 @@ static inline void print_dir_entry(dirent_t *dirent, const char *path, unsigned // Add a space. putchar(' '); // Print the rest. - printf("%4d %4d %11s %02d/%02d %02d:%02d %s\n", + printf("%4d %4d %11s %02d/%02d %02d:%02d %s", dstat.st_uid, dstat.st_gid, to_human_size(dstat.st_size), @@ -92,6 +92,16 @@ static inline void print_dir_entry(dirent_t *dirent, const char *path, unsigned timeinfo->tm_hour, timeinfo->tm_min, dirent->d_name); + if (S_ISLNK(dstat.st_mode)) { + char link_buffer[PATH_MAX]; + ssize_t len; + pr_emerg("Read link...\n"); + if ((len = readlink(relative_path, link_buffer, sizeof(link_buffer))) != -1) { + link_buffer[len] = '\0'; + printf(" -> %s\n", link_buffer); + } + } + putchar('\n'); (*total_size) += dstat.st_size; } else { // Print the inode if required. @@ -116,7 +126,7 @@ static void print_ls(int fd, const char *path, unsigned int flags) dirent_t dents[DENTS_NUM]; memset(&dents, 0, DENTS_NUM * sizeof(dirent_t)); - size_t total_size = 0; + size_t total_size = 0; 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) { diff --git a/programs/stat.c b/programs/stat.c index f5834231..f1dacec0 100644 --- a/programs/stat.c +++ b/programs/stat.c @@ -15,17 +15,6 @@ #include #include -// Copied from mentos/src/fs/ext2.c -// File types. -#define S_IFMT 0xF000 ///< Format mask -#define S_IFSOCK 0xC000 ///< Socket -#define S_IFLNK 0xA000 ///< Symbolic link -#define S_IFREG 0x8000 ///< Regular file -#define S_IFBLK 0x6000 ///< Block device -#define S_IFDIR 0x4000 ///< Directory -#define S_IFCHR 0x2000 ///< Character device -#define S_IFIFO 0x1000 ///< Fifo - static void __print_time(const char *prefix, time_t *time) { tm_t *timeinfo = localtime(time); @@ -51,51 +40,59 @@ int main(int argc, char **argv) printf("Display file status.\n"); exit(0); } - stat_t statbuf; - if (stat(argv[1], &statbuf) == -1) { + stat_t dstat; + if (stat(argv[1], &dstat) == -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)); + if (S_ISLNK(dstat.st_mode)) { + char link_buffer[PATH_MAX]; + ssize_t len; + if ((len = readlink(argv[1], link_buffer, sizeof(link_buffer))) != -1) { + link_buffer[len] = '\0'; + printf(" -> %s\n", link_buffer); + } + } + printf("Size: %s\n", to_human_size(dstat.st_size)); printf("File type: "); - switch (statbuf.st_mode & S_IFMT) { + switch (dstat.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_IFIFO : printf("fifo/pipe\n"); break; + case S_IFLNK : printf("symbolic link\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); + printf("Access: (%.4o/", dstat.st_mode & 0xFFF); // Print the access permissions. - putchar(bitmask_check(statbuf.st_mode, S_IRUSR) ? 'r' : '-'); - putchar(bitmask_check(statbuf.st_mode, S_IWUSR) ? 'w' : '-'); - putchar(bitmask_check(statbuf.st_mode, S_IXUSR) ? 'x' : '-'); - putchar(bitmask_check(statbuf.st_mode, S_IRGRP) ? 'r' : '-'); - putchar(bitmask_check(statbuf.st_mode, S_IWGRP) ? 'w' : '-'); - putchar(bitmask_check(statbuf.st_mode, S_IXGRP) ? 'x' : '-'); - putchar(bitmask_check(statbuf.st_mode, S_IROTH) ? 'r' : '-'); - putchar(bitmask_check(statbuf.st_mode, S_IWOTH) ? 'w' : '-'); - putchar(bitmask_check(statbuf.st_mode, S_IXOTH) ? 'x' : '-'); + putchar(bitmask_check(dstat.st_mode, S_IRUSR) ? 'r' : '-'); + putchar(bitmask_check(dstat.st_mode, S_IWUSR) ? 'w' : '-'); + putchar(bitmask_check(dstat.st_mode, S_IXUSR) ? 'x' : '-'); + putchar(bitmask_check(dstat.st_mode, S_IRGRP) ? 'r' : '-'); + putchar(bitmask_check(dstat.st_mode, S_IWGRP) ? 'w' : '-'); + putchar(bitmask_check(dstat.st_mode, S_IXGRP) ? 'x' : '-'); + putchar(bitmask_check(dstat.st_mode, S_IROTH) ? 'r' : '-'); + putchar(bitmask_check(dstat.st_mode, S_IWOTH) ? 'w' : '-'); + putchar(bitmask_check(dstat.st_mode, S_IXOTH) ? 'x' : '-'); - passwd_t *user = getpwuid(statbuf.st_uid); + passwd_t *user = getpwuid(dstat.st_uid); if (!user) { - printf("%s: failed to retrieve uid '%u'.\n", argv[0], statbuf.st_uid); + printf("%s: failed to retrieve uid '%u'.\n", argv[0], dstat.st_uid); exit(1); } - group_t *group = getgrgid(statbuf.st_gid); + group_t *group = getgrgid(dstat.st_gid); if (!group) { - printf("%s: failed to retrieve gid '%u'.\n", argv[0], statbuf.st_gid); + printf("%s: failed to retrieve gid '%u'.\n", argv[0], dstat.st_gid); exit(1); } - printf(") Uid: (%d/%s) Gid: (%d/%s)\n", statbuf.st_uid, user->pw_name, statbuf.st_gid, group->gr_name); + printf(") Uid: (%d/%s) Gid: (%d/%s)\n", dstat.st_uid, user->pw_name, dstat.st_gid, group->gr_name); - __print_time("Access: ", &statbuf.st_atime); - __print_time("Modify: ", &statbuf.st_mtime); - __print_time("Change: ", &statbuf.st_ctime); + __print_time("Access: ", &dstat.st_atime); + __print_time("Modify: ", &dstat.st_mtime); + __print_time("Change: ", &dstat.st_ctime); return 0; } diff --git a/programs/tests/t_dup.c b/programs/tests/t_dup.c index 9681e1e8..f53bc87a 100644 --- a/programs/tests/t_dup.c +++ b/programs/tests/t_dup.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include diff --git a/programs/tests/t_msgget.c b/programs/tests/t_msgget.c index 1d3e9331..e4f2e5bb 100644 --- a/programs/tests/t_msgget.c +++ b/programs/tests/t_msgget.c @@ -3,14 +3,15 @@ /// @copyright (c) 2014-2024 This file is distributed under the MIT License. /// See LICENSE.md for details. -#include "string.h" -#include "sys/unistd.h" -#include "sys/errno.h" -#include "sys/msg.h" -#include "sys/ipc.h" -#include "stdlib.h" -#include "fcntl.h" -#include "stdio.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include #define MESSAGE_LEN 100 diff --git a/programs/tests/t_semflg.c b/programs/tests/t_semflg.c index bb42b22e..a20822ab 100644 --- a/programs/tests/t_semflg.c +++ b/programs/tests/t_semflg.c @@ -3,13 +3,14 @@ /// @copyright (c) 2014-2024 This file is distributed under the MIT License. /// See LICENSE.md for details. -#include "sys/unistd.h" -#include "sys/errno.h" -#include "sys/sem.h" -#include "sys/ipc.h" -#include "stdlib.h" -#include "fcntl.h" -#include "stdio.h" +#include +#include +#include +#include +#include +#include +#include +#include int main(int argc, char *argv[]) { diff --git a/programs/tests/t_semget.c b/programs/tests/t_semget.c index ccfc81e2..a38e546c 100644 --- a/programs/tests/t_semget.c +++ b/programs/tests/t_semget.c @@ -5,13 +5,14 @@ /// @copyright (c) 2014-2024 This file is distributed under the MIT License. /// See LICENSE.md for details. -#include "sys/unistd.h" -#include "sys/errno.h" -#include "sys/sem.h" -#include "sys/ipc.h" -#include "stdlib.h" -#include "fcntl.h" -#include "stdio.h" +#include +#include +#include +#include +#include +#include +#include +#include int main(int argc, char *argv[]) { diff --git a/programs/tests/t_semop.c b/programs/tests/t_semop.c index 23606fe2..022cdc48 100644 --- a/programs/tests/t_semop.c +++ b/programs/tests/t_semop.c @@ -3,14 +3,15 @@ /// @copyright (c) 2014-2024 This file is distributed under the MIT License. /// See LICENSE.md for details. -#include "sys/sem.h" -#include "stdio.h" -#include "sys/ipc.h" -#include "sys/errno.h" -#include "sys/wait.h" -#include "stdlib.h" -#include "sys/unistd.h" -#include "fcntl.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include int main(int argc, char *argv[]) { diff --git a/programs/touch.c b/programs/touch.c index 3eeb623d..eae2ec27 100644 --- a/programs/touch.c +++ b/programs/touch.c @@ -8,6 +8,7 @@ #include #include #include +#include #include int main(int argc, char** argv) From 11229aa4d72cec030f39b5cd92d5a4708523bfda Mon Sep 17 00:00:00 2001 From: "Enrico Fraccaroli (Galfurian)" Date: Fri, 23 Aug 2024 09:54:38 -0400 Subject: [PATCH 02/18] Correctly open symlinks when using readlink function --- mentos/src/fs/ext2.c | 3 +-- mentos/src/fs/namei.c | 57 ++++++++++++++++++++++++------------------- mentos/src/fs/vfs.c | 1 + programs/ls.c | 56 +++++++++++++++++++++++++----------------- programs/stat.c | 5 ++-- 5 files changed, 70 insertions(+), 52 deletions(-) diff --git a/mentos/src/fs/ext2.c b/mentos/src/fs/ext2.c index bb9021c5..9faf0690 100644 --- a/mentos/src/fs/ext2.c +++ b/mentos/src/fs/ext2.c @@ -6,7 +6,7 @@ // 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. +#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE ///< Set log level. #include "io/debug.h" // Include debugging functions. #include "assert.h" @@ -3161,7 +3161,6 @@ static ssize_t ext2_readlink(vfs_file_t *file, char *buffer, size_t bufsize) ssize_t nbytes = min(strlen(inode.data.symlink), bufsize); // Copy the symlink information. strncpy(buffer, inode.data.symlink, nbytes); - pr_emerg("LINK: %d `%s`\n", file->ino, inode.data.symlink); // Return how much we read. return nbytes; } diff --git a/mentos/src/fs/namei.c b/mentos/src/fs/namei.c index cad82d60..77142348 100644 --- a/mentos/src/fs/namei.c +++ b/mentos/src/fs/namei.c @@ -16,21 +16,21 @@ /// Appends the path with a "/" as separator. #define APPEND_PATH_SEP_OR_FAIL(b, remaining) \ -{ \ - strncat(b, "/", remaining); \ - remaining--; \ - if (remaining < 0) \ - return -ENAMETOOLONG; \ -} + { \ + 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; \ -} + { \ + strncat(b, path, remaining); \ + remaining -= strlen(path); \ + if (remaining < 0) \ + return -ENAMETOOLONG; \ + } int sys_unlink(const char *path) { @@ -65,7 +65,7 @@ int sys_creat(const char *path, mode_t mode) // Set the file descriptor id. task->fd_list[fd].file_struct = file; - task->fd_list[fd].flags_mask = O_WRONLY|O_CREAT|O_TRUNC; + task->fd_list[fd].flags_mask = O_WRONLY | O_CREAT | O_TRUNC; // Return the file descriptor and increment it. return fd; @@ -78,14 +78,21 @@ int sys_symlink(const char *linkname, const char *path) int sys_readlink(const char *path, char *buffer, size_t bufsize) { - pr_crit("Open...\n"); + // Allocate a variable for the path. + char absolute_path[PATH_MAX]; + // Resolve the path. + int ret = resolve_path(path, absolute_path, sizeof(absolute_path), 0); + if (ret < 0) { + pr_err("sys_readlink(%s): Cannot resolve path!\n", path); + return ret; + } // Try to open the file. - vfs_file_t *file = vfs_open(path, O_RDONLY, 0); + vfs_file_t *file = vfs_open_abspath(absolute_path, O_RDONLY, 0); if (file == NULL) { + pr_err("sys_readlink(%s): Cannot open file!\n", path); return -errno; } // Read the link. - pr_crit("Readlink...\n"); ssize_t nbytes = vfs_readlink(file, buffer, bufsize); // Close the file. vfs_close(file); @@ -93,7 +100,8 @@ int sys_readlink(const char *path, char *buffer, size_t bufsize) return nbytes; } -char *realpath(const char *path, char *buffer, size_t buflen) { +char *realpath(const char *path, char *buffer, size_t buflen) +{ int ret = resolve_path(path, buffer, buflen, REMOVE_TRAILING_SLASH); if (ret < 0) { errno = -ret; @@ -110,7 +118,7 @@ int resolve_path(const char *path, char *buffer, size_t buflen, int flags) // Buffer used to build up the absolute path char abspath[buflen]; // Null-terminate our work buffer - memset(abspath,0, buflen); + memset(abspath, 0, buflen); int remaining = buflen - 1; // Track the resolved symlinks to ensure we do not end up in a loop @@ -158,7 +166,7 @@ int resolve_path(const char *path, char *buffer, size_t buflen, int flags) buffer[pathidx++] = abspath[absidx++]; // Find the next separator after the current path component - char* sep_after_cur = strchr(abspath + absidx, '/'); + char *sep_after_cur = strchr(abspath + absidx, '/'); if (sep_after_cur) { // Null-terminate work buffer to properly open the current component *sep_after_cur = 0; @@ -187,7 +195,7 @@ int resolve_path(const char *path, char *buffer, size_t buflen, int flags) if (symlinks > SYMLOOP_MAX) { return -ELOOP; } char link[PATH_MAX]; - vfs_file_t* link_file = vfs_open_abspath(abspath, O_RDONLY, 0); + vfs_file_t *link_file = vfs_open_abspath(abspath, O_RDONLY, 0); if (link_file == NULL) { return -errno; } ssize_t nbytes = vfs_readlink(link_file, link, sizeof(link)); vfs_close(link_file); @@ -208,7 +216,7 @@ int resolve_path(const char *path, char *buffer, size_t buflen, int flags) strncpy(abspath, link, remaining); remaining -= strlen(link); - if (remaining < 0) { return -ENAMETOOLONG; } + if (remaining < 0) { return -ENAMETOOLONG; } // This is not the last component, therefore it must be a directory if (sep_after_cur) { @@ -217,7 +225,7 @@ int resolve_path(const char *path, char *buffer, size_t buflen, int flags) APPEND_PATH_OR_FAIL(abspath, buffer, remaining); } goto resolve_abspath; - // Link is relative, add it and continue + // Link is relative, add it and continue } else { // Recalculate the remaining space in the working buffer remaining = buflen - absidx - 1; @@ -239,11 +247,10 @@ int resolve_path(const char *path, char *buffer, size_t buflen, int flags) } // Copy the path component else { -copy_path_component: + copy_path_component: do { buffer[pathidx++] = abspath[absidx++]; - } - while (abspath[absidx] && abspath[absidx] != '/'); + } while (abspath[absidx] && abspath[absidx] != '/'); } } } diff --git a/mentos/src/fs/vfs.c b/mentos/src/fs/vfs.c index 907f1392..c49c26fd 100644 --- a/mentos/src/fs/vfs.c +++ b/mentos/src/fs/vfs.c @@ -358,6 +358,7 @@ ssize_t vfs_readlink(vfs_file_t *file, char *buffer, size_t bufsize) pr_err("vfs_readlink(%s): Function not supported in current filesystem.", file->name); return -ENOSYS; } + pr_debug("vfs_readlink(file: %s, ino:%d)\n", file->name, file->ino); // Perform the read. return file->fs_operations->readlink_f(file, buffer, bufsize); } diff --git a/programs/ls.c b/programs/ls.c index b5a6ae17..cccf4fef 100644 --- a/programs/ls.c +++ b/programs/ls.c @@ -15,19 +15,40 @@ #include #include #include +#include #define FLAG_L (1U << 0U) #define FLAG_A (1U << 1U) #define FLAG_I (1U << 2U) #define FLAG_1 (1U << 3U) -#define FG_BRIGHT_GREEN "\033[92m" -#define FG_BRIGHT_CYAN "\033[96m" -#define FG_BRIGHT_WHITE "\033[97m" -#define FG_BRIGHT_YELLOW "\033[93m" - #define DENTS_NUM 12 +static inline void print_dir_entry_name(const char *name, mode_t st_mode) +{ + if (S_ISSOCK(st_mode)) { + printf(FG_YELLOW "%s" FG_RESET, name); + } + if (S_ISLNK(st_mode)) { + printf(FG_CYAN "%s" FG_RESET, name); + } + if (S_ISREG(st_mode)) { + printf(FG_WHITE "%s" FG_RESET, name); + } + if (S_ISBLK(st_mode)) { + printf(FG_GREEN "%s" FG_RESET, name); + } + if (S_ISDIR(st_mode)) { + printf(FG_BLUE "%s" FG_RESET, name); + } + if (S_ISCHR(st_mode)) { + printf(FG_YELLOW "%s" FG_RESET, name); + } + if (S_ISFIFO(st_mode)) { + printf(FG_YELLOW "%s" FG_RESET, name); + } +} + static inline void print_dir_entry(dirent_t *dirent, const char *path, unsigned int flags, size_t *total_size) { static char relative_path[PATH_MAX]; @@ -51,15 +72,6 @@ static inline void print_dir_entry(dirent_t *dirent, const char *path, unsigned return; } - // Deal with the coloring. - if ((dirent->d_type == DT_REG) && bitmask_check(dstat.st_mode, S_IXUSR)) { - puts(FG_BRIGHT_YELLOW); - } else if (dirent->d_type == DT_DIR) { - puts(FG_BRIGHT_CYAN); - } else if (dirent->d_type == DT_BLK) { - puts(FG_BRIGHT_GREEN); - } - // Deal with the -l. if (bitmask_check(flags, FLAG_L)) { // Get the broken down time from the creation time of the file. @@ -83,22 +95,23 @@ static inline void print_dir_entry(dirent_t *dirent, const char *path, unsigned // Add a space. putchar(' '); // Print the rest. - printf("%4d %4d %11s %02d/%02d %02d:%02d %s", + printf("%4d %4d %11s %02d/%02d %02d:%02d ", dstat.st_uid, dstat.st_gid, to_human_size(dstat.st_size), timeinfo->tm_mon, timeinfo->tm_mday, timeinfo->tm_hour, - timeinfo->tm_min, - dirent->d_name); + timeinfo->tm_min); + + print_dir_entry_name(dirent->d_name, dstat.st_mode); + if (S_ISLNK(dstat.st_mode)) { char link_buffer[PATH_MAX]; ssize_t len; - pr_emerg("Read link...\n"); if ((len = readlink(relative_path, link_buffer, sizeof(link_buffer))) != -1) { link_buffer[len] = '\0'; - printf(" -> %s\n", link_buffer); + printf(" -> %s", link_buffer); } } putchar('\n'); @@ -108,7 +121,7 @@ static inline void print_dir_entry(dirent_t *dirent, const char *path, unsigned if (bitmask_check(flags, FLAG_I)) { printf("%d ", dirent->d_ino); } - puts(dirent->d_name); + print_dir_entry_name(dirent->d_name, dstat.st_mode); // Print in 1 column if requested. if (bitmask_check(flags, FLAG_1)) { putchar('\n'); @@ -116,9 +129,6 @@ static inline void print_dir_entry(dirent_t *dirent, const char *path, unsigned putchar(' '); } } - - // Reset the color. - puts(FG_BRIGHT_WHITE); } static void print_ls(int fd, const char *path, unsigned int flags) diff --git a/programs/stat.c b/programs/stat.c index f1dacec0..0de79dec 100644 --- a/programs/stat.c +++ b/programs/stat.c @@ -46,15 +46,16 @@ int main(int argc, char **argv) exit(1); } - printf("File: %s\n", argv[1]); + printf("File: %s", argv[1]); if (S_ISLNK(dstat.st_mode)) { char link_buffer[PATH_MAX]; ssize_t len; if ((len = readlink(argv[1], link_buffer, sizeof(link_buffer))) != -1) { link_buffer[len] = '\0'; - printf(" -> %s\n", link_buffer); + printf(" -> %s", link_buffer); } } + putchar('\n'); printf("Size: %s\n", to_human_size(dstat.st_size)); printf("File type: "); switch (dstat.st_mode & S_IFMT) { From 69dae6b6057c0f74723acc7b2704652821bcefc5 Mon Sep 17 00:00:00 2001 From: "Enrico Fraccaroli (Galfurian)" Date: Fri, 23 Aug 2024 10:05:03 -0400 Subject: [PATCH 03/18] Fix video ANSI coloring --- mentos/src/io/video.c | 22 ++++++++++++---------- programs/shell.c | 2 +- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/mentos/src/io/video.c b/mentos/src/io/video.c index 90235498..5fd8abb7 100644 --- a/mentos/src/io/video.c +++ b/mentos/src/io/video.c @@ -7,6 +7,7 @@ #include "ctype.h" #include "io/vga/vga.h" #include "io/video.h" +#include "io/debug.h" #include "stdbool.h" #include "stdio.h" #include "string.h" @@ -27,6 +28,8 @@ struct ansi_color_map_t { } /// @brief The mapping. ansi_color_map[] = { + { 0, 7 }, + { 30, 0 }, { 31, 4 }, { 32, 2 }, @@ -61,9 +64,7 @@ ansi_color_map[] = { { 104, 9 }, { 105, 13 }, { 106, 11 }, - { 107, 15 }, - - { 0, 0 } + { 107, 15 } }; /// Pointer to a position of the screen writer. @@ -111,17 +112,18 @@ static inline void __draw_char(char c) /// @param ansi_code The ansi code describing background and foreground color. static inline void __set_color(uint8_t ansi_code) { - struct ansi_color_map_t *it = ansi_color_map; - while (it->ansi_color != 0) { - if (ansi_code == it->ansi_color) { - if (((ansi_code >= 30) && (ansi_code <= 37)) || ((ansi_code >= 90) && (ansi_code <= 97))) { - color = (color & 0xF0U) | it->video_color; + for (size_t i = 0; i < count_of(ansi_color_map); ++i) { + if (ansi_code == ansi_color_map[i].ansi_color) { + if ( + (ansi_code == 0) || + ((ansi_code >= 30) && (ansi_code <= 37)) || + ((ansi_code >= 90) && (ansi_code <= 97))) { + color = (color & 0xF0U) | ansi_color_map[i].video_color; } else { - color = (color & 0x0FU) | (it->video_color << 4U); + color = (color & 0x0FU) | (ansi_color_map[i].video_color << 4U); } break; } - ++it; } } diff --git a/programs/shell.c b/programs/shell.c index 2ed0abba..4a68f42e 100644 --- a/programs/shell.c +++ b/programs/shell.c @@ -177,7 +177,7 @@ static inline void __prompt_print(void) } else { HOSTNAME = buffer.nodename; } - printf(FG_GREEN "%s" FG_WHITE "@" FG_CYAN "%s " FG_BLUE_BRIGHT "[%02d:%02d:%02d]" FG_WHITE " [%s] " FG_WHITE_BRIGHT "\n-> %% ", + printf(FG_GREEN "%s" FG_WHITE "@" FG_CYAN "%s " FG_BLUE_BRIGHT "[%02d:%02d:%02d]" FG_WHITE " [%s] " FG_RESET "\n-> %% ", USER, HOSTNAME, timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, CWD); } From e57ddadf2afdacb3794ad636473c7152bc8649ca Mon Sep 17 00:00:00 2001 From: "Enrico Fraccaroli (Galfurian)" Date: Fri, 23 Aug 2024 10:18:17 -0400 Subject: [PATCH 04/18] Fix cd to a symbolik link directory --- programs/shell.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/programs/shell.c b/programs/shell.c index 4a68f42e..7025e9a8 100644 --- a/programs/shell.c +++ b/programs/shell.c @@ -353,6 +353,28 @@ static int __cd(int argc, char *argv[]) printf("cd: Failed to resolve directory.\n"); return 1; } + // Stat the directory. + stat_t dstat; + if (stat(real_path, &dstat) == -1) { + printf("cd: cannot stat '%s': %s\n", real_path, strerror(errno)); + return 1; + } + // Check if the directory is actually a symbolic link. + if (S_ISLNK(dstat.st_mode)) { + char link_buffer[PATH_MAX]; + ssize_t len; + // First, read the link. + if ((len = readlink(real_path, link_buffer, sizeof(link_buffer))) < 0) { + printf("cd: Failed to read symlink.\n"); + return 1; + } + link_buffer[len] = '\0'; + // Resolve the link, it might still be a relative path. + if (realpath(link_buffer, real_path, PATH_MAX) != real_path) { + printf("cd: Failed to resolve symlink to directory.\n"); + return 1; + } + } // Open the given directory. int fd = open(real_path, O_RDONLY | O_DIRECTORY, S_IXUSR); if (fd == -1) { From bdf95a693484bdf0d505c2437a2b58bab61a9607 Mon Sep 17 00:00:00 2001 From: "Enrico Fraccaroli (Galfurian)" Date: Mon, 26 Aug 2024 11:51:29 -0400 Subject: [PATCH 05/18] In procfs fix call to unregister filesystem. --- mentos/src/fs/procfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mentos/src/fs/procfs.c b/mentos/src/fs/procfs.c index 126d0fd3..a7e28b01 100644 --- a/mentos/src/fs/procfs.c +++ b/mentos/src/fs/procfs.c @@ -879,7 +879,7 @@ int procfs_cleanup_module(void) // Destroy the cache. kmem_cache_destroy(fs.procfs_file_cache); // Unregister the filesystem. - vfs_register_filesystem(&procfs_file_system_type); + vfs_unregister_filesystem(&procfs_file_system_type); return 0; } From 92ff0a9bd5030eeb159b76102579dd1bf8a3cc98 Mon Sep 17 00:00:00 2001 From: "Enrico Fraccaroli (Galfurian)" Date: Mon, 26 Aug 2024 11:52:37 -0400 Subject: [PATCH 06/18] Replace old `vfs_mount` with `do_mount`. Register superblocks for null and ATA devices. --- mentos/inc/fs/vfs.h | 29 +++------ mentos/src/drivers/ata.c | 37 ++++++++--- mentos/src/drivers/mem.c | 89 +++++++++++++++++---------- mentos/src/fs/vfs.c | 129 ++++++++++++++++++--------------------- mentos/src/kernel.c | 4 +- 5 files changed, 158 insertions(+), 130 deletions(-) diff --git a/mentos/inc/fs/vfs.h b/mentos/inc/fs/vfs.h index b84003c4..19c1c718 100644 --- a/mentos/inc/fs/vfs.h +++ b/mentos/inc/fs/vfs.h @@ -19,11 +19,6 @@ extern kmem_cache_t *vfs_file_cache; /// @brief Forward declaration of task_struct. struct task_struct; -/// @brief Searches for the mountpoint of the given path. -/// @param absolute_path Path for which we want to search the mountpoint. -/// @return Pointer to the vfs_file of the mountpoint. -super_block_t *vfs_get_superblock(const char *absolute_path); - /// @brief Initialize the Virtual File System (VFS). void vfs_init(void); @@ -37,6 +32,15 @@ int vfs_register_filesystem(file_system_type *fs); /// @return The outcome of the operation, 0 if fails. int vfs_unregister_filesystem(file_system_type *fs); +int vfs_register_superblock(const char *name, const char *path, file_system_type *type, vfs_file_t *root); + +int vfs_unregister_superblock(super_block_t *sb); + +/// @brief Searches for the mountpoint of the given path. +/// @param absolute_path Path for which we want to search the mountpoint. +/// @return Pointer to the vfs_file of the mountpoint. +super_block_t *vfs_get_superblock(const char *absolute_path); + /// @brief Given an absolute path to a file, vfs_open_abspath() returns a file struct, used to access the file. /// @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. @@ -151,24 +155,12 @@ int vfs_stat(const char *path, stat_t *buf); /// @return 0 on success, -errno on failure. int vfs_fstat(vfs_file_t *file, stat_t *buf); -/// @brief Mount a file system to the specified path. -/// @param path Path where we want to map the filesystem. -/// @param fs_root Root node of the filesystem. -/// @return 1 on success, 0 on fail. -/// @details -/// For example, if we have an EXT2 filesystem with a root node -/// of ext2_root and we want to mount it to /, we would run -/// vfs_mount("/", ext2_root); - or, if we have a procfs node, -/// we could mount that to /dev/procfs. Individual files can also -/// be mounted. -int vfs_mount(const char *path, vfs_file_t *fs_root); - /// @brief Mount the path as a filesystem of the given type. /// @param type The type of filesystem /// @param path The path to where it should be mounter. /// @param args The arguments passed to the filesystem mount callback. /// @return 0 on success, a negative number if fails and errno is set. -int do_mount(const char *type, const char *path, const char *args); +int vfs_mount(const char *type, const char *path, const char *args); /// @brief Locks the access to the given file. /// @param file The file to lock. @@ -199,7 +191,6 @@ 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. diff --git a/mentos/src/drivers/ata.c b/mentos/src/drivers/ata.c index bca28c74..741382a1 100644 --- a/mentos/src/drivers/ata.c +++ b/mentos/src/drivers/ata.c @@ -1172,6 +1172,25 @@ static int ata_stat(const char *path, stat_t *stat) } // == VFS ENTRY GENERATION ==================================================== + +/// @brief The mount call-back, which prepares everything and calls the actual +/// ATA 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 *ata_mount_callback(const char *path, const char *device) +{ + pr_err("mount_callback(%s, %s): ATA has no mount callback!\n", path, device); + return NULL; +} + +/// Filesystem information. +static file_system_type ata_file_system_type = { + .name = "ata", + .fs_flags = 0, + .mount = ata_mount_callback +}; + /// Filesystem general operations. static vfs_sys_operations_t ata_sys_operations = { .mkdir_f = NULL, @@ -1208,9 +1227,9 @@ 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->uid = 0; + file->gid = 0; + file->mask = 0x2000 | 0600; file->atime = sys_time(NULL); file->mtime = sys_time(NULL); file->ctime = sys_time(NULL); @@ -1259,7 +1278,7 @@ static ata_device_type_t ata_device_detect(ata_device_t *dev) // Update the filesystem entry with the length of the device. dev->fs_root->length = ata_max_offset(dev); // Try to mount the drive. - if (!vfs_mount(dev->path, dev->fs_root)) { + if (!vfs_register_superblock(dev->fs_root->name, dev->path, &ata_file_system_type, dev->fs_root)) { pr_alert("Failed to mount ata device!\n"); // Free the memory. kmem_cache_free(dev->fs_root); @@ -1273,12 +1292,6 @@ static ata_device_type_t ata_device_detect(ata_device_t *dev) } else if (type == ata_dev_type_no_device) { pr_debug("[%s] Found no device...\n", ata_get_device_settings_str(dev)); } - // if (type == ata_dev_type_unknown) { - // pr_debug("[%s] Found unsupported device...\n", ata_get_device_settings_str(dev)); - // } - // if ((type != ata_dev_type_no_device) && (type != ata_dev_type_unknown)) { - // pr_warning(" Found %s device connected to %s.\n", ata_get_device_type_str(type), ata_get_device_settings_str(dev)); - // } return type; } @@ -1320,11 +1333,15 @@ static void pci_find_ata(uint32_t device, uint16_t vendorid, uint16_t deviceid, } // == INITIALIZE/FINALIZE ATA ================================================= + int ata_initialize(void) { // Search for ATA devices. pci_scan(&pci_find_ata, -1, &ata_pci); + // Register the filesystem. + vfs_register_filesystem(&ata_file_system_type); + // Install the IRQ handlers. irq_install_handler(IRQ_FIRST_HD, ata_irq_handler_master, "IDE Master"); irq_install_handler(IRQ_SECOND_HD, ata_irq_handler_slave, "IDE Slave"); diff --git a/mentos/src/drivers/mem.c b/mentos/src/drivers/mem.c index d57063f2..b64e3d98 100644 --- a/mentos/src/drivers/mem.c +++ b/mentos/src/drivers/mem.c @@ -27,9 +27,10 @@ struct memdev { static struct memdev *devices; -static void add_device(struct memdev *device) { +static void add_device(struct memdev *device) +{ struct memdev *dit = devices; - for (;dit != NULL; dit = dit->next); + for (; dit != NULL; dit = dit->next); if (dit == NULL) { devices = device; } else { @@ -37,8 +38,9 @@ static void add_device(struct memdev *device) { } } -static vfs_file_t* find_device_file(const char *path) { - for(struct memdev *dev = devices; dev != NULL; dev = dev->next) { +static vfs_file_t *find_device_file(const char *path) +{ + for (struct memdev *dev = devices; dev != NULL; dev = dev->next) { if (strcmp(dev->file->name, path) == 0) { return dev->file; } @@ -46,7 +48,7 @@ static vfs_file_t* find_device_file(const char *path) { return NULL; } -static int mem_stat(const char* path, stat_t *stat); +static int mem_stat(const char *path, stat_t *stat); static vfs_sys_operations_t mem_sys_operations = { .mkdir_f = NULL, @@ -55,10 +57,28 @@ static vfs_sys_operations_t mem_sys_operations = { }; static vfs_file_t *null_open(const char *path, int flags, mode_t mode); -static int null_close(vfs_file_t * file); -static ssize_t null_write(vfs_file_t * file, const void *buffer, off_t offset, size_t size); -static ssize_t null_read(vfs_file_t * file, char *buffer, off_t offset, size_t size); -static int null_fstat(vfs_file_t * file, stat_t *stat); +static int null_close(vfs_file_t *file); +static ssize_t null_write(vfs_file_t *file, const void *buffer, off_t offset, size_t size); +static ssize_t null_read(vfs_file_t *file, char *buffer, off_t offset, size_t size); +static int null_fstat(vfs_file_t *file, stat_t *stat); + +/// @brief The mount call-back, which prepares everything and calls the actual +/// NULL 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 *null_mount_callback(const char *path, const char *device) +{ + pr_err("mount_callback(%s, %s): NULL has no mount callback!\n", path, device); + return NULL; +} + +/// Filesystem information. +static file_system_type null_file_system_type = { + .name = "null", + .fs_flags = 0, + .mount = null_mount_callback +}; static vfs_file_operations_t null_fs_operations = { .open_f = null_open, @@ -72,10 +92,11 @@ static vfs_file_operations_t null_fs_operations = { .getdents_f = NULL }; -static struct memdev *null_device_create(const char* name) { +static struct memdev *null_device_create(const char *name) +{ // Create the device. struct memdev *dev = kmalloc(sizeof(struct memdev)); - dev->next = NULL; + dev->next = NULL; // Create the file. vfs_file_t *file = kmem_cache_alloc(vfs_file_cache, GFP_KERNEL); @@ -87,13 +108,13 @@ static struct memdev *null_device_create(const char* name) { // Set the device name. strncpy(file->name, name, NAME_MAX); - file->count = 0; - file->uid = 0; - file->gid = 0; - file->mask = 0x2000 | 0666; - file->atime = sys_time(NULL); - file->mtime = sys_time(NULL); - file->ctime = sys_time(NULL); + file->count = 0; + file->uid = 0; + file->gid = 0; + file->mask = 0x2000 | 0666; + file->atime = sys_time(NULL); + file->mtime = sys_time(NULL); + file->ctime = sys_time(NULL); file->length = 0; // Set the operations. file->sys_operations = &mem_sys_operations; @@ -101,8 +122,9 @@ static struct memdev *null_device_create(const char* name) { return dev; } -static vfs_file_t* null_open(const char *path, int flags, mode_t mode) { - vfs_file_t* file = find_device_file(path); +static vfs_file_t *null_open(const char *path, int flags, mode_t mode) +{ + vfs_file_t *file = find_device_file(path); if (file) { file->count++; } @@ -110,21 +132,24 @@ static vfs_file_t* null_open(const char *path, int flags, mode_t mode) { return file; } -static int null_close(vfs_file_t * file) { +static int null_close(vfs_file_t *file) +{ assert(file && "Received null file."); file->count--; return 0; } -static ssize_t null_write(vfs_file_t * file, const void *buffer, off_t offset, size_t size) { +static ssize_t null_write(vfs_file_t *file, const void *buffer, off_t offset, size_t size) +{ return size; } -static ssize_t null_read(vfs_file_t * file, char *buffer, off_t offset, size_t size) { +static ssize_t null_read(vfs_file_t *file, char *buffer, off_t offset, size_t size) +{ return 0; } -static int null_fstat(vfs_file_t * file, stat_t *stat) +static int null_fstat(vfs_file_t *file, stat_t *stat) { pr_debug("null_fstat(%s, %p)\n", file->name, stat); stat->st_dev = 0; @@ -139,8 +164,9 @@ static int null_fstat(vfs_file_t * file, stat_t *stat) return 0; } -static int mem_stat(const char *path, stat_t *stat) { - vfs_file_t* file = find_device_file(path); +static int mem_stat(const char *path, stat_t *stat) +{ + vfs_file_t *file = find_device_file(path); if (file) { return file->fs_operations->stat_f(file, stat); @@ -155,13 +181,14 @@ int mem_devs_initialize(void) pr_err("Failed to create devnull"); return -ENODEV; } - - if (!vfs_mount("/dev/null", devnull->file)) { - pr_err("Failed to mount /dev/null"); + if (!vfs_register_filesystem(&null_file_system_type)) { + pr_err("Failed to register NULL filesystem."); + return 1; + } + if (!vfs_register_superblock("null", "/dev/null", &null_file_system_type, devnull->file)) { + pr_err("Failed to mount /dev/null."); return 1; } - add_device(devnull); - return 0; } diff --git a/mentos/src/fs/vfs.c b/mentos/src/fs/vfs.c index c49c26fd..188b9a52 100644 --- a/mentos/src/fs/vfs.c +++ b/mentos/src/fs/vfs.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__ "[VFS ]" ///< 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__ "[VFS ]" ///< Change header. +#define __DEBUG_LEVEL__ LOGLEVEL_DEBUG ///< Set log level. +#include "io/debug.h" // Include debugging functions. #include "fcntl.h" #include "sys/stat.h" @@ -62,11 +62,11 @@ void vfs_init(void) int vfs_register_filesystem(file_system_type *fs) { - if (hashmap_set(vfs_filesystems, (void *)fs->name, (void *)fs) != NULL) { + if (hashmap_set(vfs_filesystems, fs->name, fs) != NULL) { pr_err("Filesystem already registered.\n"); return 0; } - pr_debug("vfs_register_filesystem(`%s`) : %p\n", fs->name, fs); + pr_debug("vfs_register_filesystem(name: %s)\n", fs->name); return 1; } @@ -76,35 +76,65 @@ int vfs_unregister_filesystem(file_system_type *fs) pr_err("Filesystem not present to unregister.\n"); return 0; } + pr_debug("vfs_unregister_filesystem(name: %s)\n", fs->name); return 1; } -super_block_t *vfs_get_superblock(const char *absolute_path) +int vfs_register_superblock(const char *name, const char *path, file_system_type *type, vfs_file_t *root) { - size_t last_sb_len = 0; - super_block_t *last_sb = NULL, *superblock = NULL; + pr_debug("vfs_register_superblock(name: %s, path: %s, type: %s)\n", name, path, type->name); + // Lock the vfs spinlock. + spinlock_lock(&vfs_spinlock); + // Create the superblock. + super_block_t *sb = kmem_cache_alloc(vfs_superblock_cache, GFP_KERNEL); + // Check if the superblock was correctly allocated. + assert(sb && "Cannot allocate memory for the superblock.\n"); + // Copy the name. + strcpy(sb->name, name); + // Copy the path. + strcpy(sb->path, path); + // Set the pointer. + sb->root = root; + // Set the type. + sb->type = type; + // Add the superblock to the list. + list_head_insert_after(&sb->mounts, &vfs_super_blocks); + + pr_debug("Superblocks:\n"); + list_for_each_decl(it, &vfs_super_blocks) + { + super_block_t *_sb = list_entry(it, super_block_t, mounts); + pr_debug(" Name: %-12s, Path: %-12s, Type: %-12s\n", _sb->name, _sb->path, _sb->type->name); + } + pr_debug("\n"); + + // Unlock the vfs spinlock. + spinlock_unlock(&vfs_spinlock); + return 1; +} + +int vfs_unregister_superblock(super_block_t *sb) +{ + pr_debug("vfs_unregister_superblock(name: %s, path: %s, type: %s)\n", sb->name, sb->path, sb->type->name); + list_head_remove(&sb->mounts); + kmem_cache_free(sb); + return 1; +} + +super_block_t *vfs_get_superblock(const char *path) +{ + size_t last_sb_len = 0, len; + super_block_t *last_sb = NULL, *sb = NULL; list_head *it; list_for_each (it, &vfs_super_blocks) { - superblock = list_entry(it, super_block_t, mounts); -#if 0 - int len = strlen(superblock->name); - pr_debug("`%s` vs `%s`\n", absolute_path, superblock->name); - if (!strncmp(absolute_path, superblock->name, len)) { - size_t sbl = strlen(superblock->name); - if (sbl > last_sb_len) { - last_sb_len = sbl; - last_sb = superblock; - } - } -#else - size_t len = strlen(superblock->path); - if (!strncmp(absolute_path, superblock->path, len)) { + sb = list_entry(it, super_block_t, mounts); + len = strlen(sb->path); + if (!strncmp(path, sb->path, len)) { if (len > last_sb_len) { last_sb_len = len; - last_sb = superblock; + last_sb = sb; } } -#endif } return last_sb; } @@ -448,39 +478,7 @@ int vfs_fstat(vfs_file_t *file, stat_t *buf) return file->fs_operations->stat_f(file, buf); } -int vfs_mount(const char *path, vfs_file_t *new_fs_root) -{ - if (!path || path[0] != '/') { - pr_err("vfs_mount(%s): Path must be absolute for superblock.\n", path); - return 0; - } - if (new_fs_root == NULL) { - pr_err("vfs_mount(%s): You must provide a valid file!\n", path); - return 0; - } - // Lock the vfs spinlock. - spinlock_lock(&vfs_spinlock); - pr_debug("Mounting file with path `%s` as root '%s'...\n", new_fs_root->name, path); - // Create the superblock. - super_block_t *sb = kmem_cache_alloc(vfs_superblock_cache, GFP_KERNEL); - if (!sb) { - pr_debug("Cannot allocate memory for the superblock.\n"); - } else { - // Copy the name. - strcpy(sb->name, new_fs_root->name); - // Copy the path. - strcpy(sb->path, path); - // Set the pointer. - sb->root = new_fs_root; - // Add to the list. - list_head_insert_after(&sb->mounts, &vfs_super_blocks); - } - spinlock_unlock(&vfs_spinlock); - pr_debug("Correctly mounted '%s' on '%s'...\n", new_fs_root->name, path); - return 1; -} - -int do_mount(const char *type, const char *path, const char *args) +int vfs_mount(const char *type, const char *path, const char *args) { file_system_type *fst = (file_system_type *)hashmap_get(vfs_filesystems, type); if (fst == NULL) { @@ -491,23 +489,18 @@ int do_mount(const char *type, const char *path, const char *args) pr_err("No mount callback set: %s\n", type); return -ENODEV; } + pr_debug("vfs_mount(type: %s, path: %s, args: %s)\n", fst->name, path, args); vfs_file_t *file = fst->mount(path, args); if (file == NULL) { pr_err("Mount callback return a null pointer: %s\n", type); return -ENODEV; } - if (!vfs_mount(path, file)) { - pr_err("do_mount(`%s`, `%s`, `%s`) : failed to mount.\n", type, path, args); - return -ENODEV; - } - super_block_t *sb = vfs_get_superblock(path); - if (sb == NULL) { - pr_err("do_mount(`%s`, `%s`, `%s`) : Cannot find the superblock.\n", type, path, args); + // Register the proc superblock. + if (!vfs_register_superblock(file->name, path, fst, file)) { + pr_alert("Failed to register %s superblock!\n", file->name); return -ENODEV; } - // Set the filesystem type. - sb->type = fst; - pr_debug("Mounted %s[%s] to `%s`: file = %p\n", type, args, path, file); + pr_debug("vfs_mount(type: %s, path: %s, args: %s), file: %s\n", fst->name, path, args, file->name); return 0; } diff --git a/mentos/src/kernel.c b/mentos/src/kernel.c index 803e0cb4..8336c840 100644 --- a/mentos/src/kernel.c +++ b/mentos/src/kernel.c @@ -237,7 +237,7 @@ int kmain(boot_info_t *boot_informations) //========================================================================== pr_notice("Mount EXT2 filesystem...\n"); printf("Mount EXT2 filesystem..."); - if (do_mount("ext2", "/", "/dev/hda")) { + if (vfs_mount("ext2", "/", "/dev/hda")) { pr_emerg("Failed to mount EXT2 filesystem...\n"); return 1; } @@ -266,7 +266,7 @@ int kmain(boot_info_t *boot_informations) //========================================================================== pr_notice(" Mounting 'procfs'...\n"); printf(" Mounting 'procfs'..."); - if (do_mount("procfs", "/proc", NULL)) { + if (vfs_mount("procfs", "/proc", NULL)) { pr_emerg("Failed to mount procfs at `/proc`!\n"); return 1; } From 162ca8c88908944ba965b11a33f9e586a4fe2b40 Mon Sep 17 00:00:00 2001 From: "Enrico Fraccaroli (Galfurian)" Date: Tue, 27 Aug 2024 09:05:38 -0400 Subject: [PATCH 07/18] Fix tokenize function --- libc/inc/string.h | 2 +- libc/src/string.c | 21 +++++++++++---------- mentos/src/klib/string.c | 26 ++++++++++++++------------ 3 files changed, 26 insertions(+), 23 deletions(-) diff --git a/libc/inc/string.h b/libc/inc/string.h index 9c24a31c..575ff9e3 100644 --- a/libc/inc/string.h +++ b/libc/inc/string.h @@ -178,7 +178,7 @@ char *strtok_r(char *str, const char *delim, char **saveptr); /// @param buffer the buffer where we save the parsed token. /// @param buflen the length of the buffer. /// @return 1 if we still have things to parse, 0 if we finished parsing. -int tokenize(const char *string, char *separators, size_t *offset, char *buffer, ssize_t buflen); +int tokenize(const char *string, const char *separators, size_t *offset, char *buffer, ssize_t buflen); /// @brief Copies the values of num bytes from the location pointed by source /// to the memory block pointed by destination. diff --git a/libc/src/string.c b/libc/src/string.c index d3a396fd..c57c59e3 100644 --- a/libc/src/string.c +++ b/libc/src/string.c @@ -218,23 +218,24 @@ char *strpbrk(const char *string, const char *control) return NULL; } -int tokenize(const char *string, char *separators, size_t *offset, char *buffer, ssize_t buflen) +int tokenize(const char *string, const char *separators, size_t *offset, char *buffer, ssize_t buflen) { // If we reached the end of the parsed string, stop. if ((*offset >= buflen) || (string[*offset] == 0)) { return 0; } + // If the first character is a separator, skip it. + *offset += (*offset == 0) && strchr(separators, string[*offset]); // Keep copying character until we either reach 1) the end of the buffer, 2) a // separator, or 3) the end of the string we are parsing. do { - for (char *separator = separators; *separator != 0; ++separator) { - if (string[*offset] == *separator) { - // Skip the character. - ++(*offset); - // Close the buffer. - *buffer = '\0'; - return 1; - } + // Check if the character is a separator. + if (strchr(separators, string[*offset])) { + // Skip the character. + ++(*offset); + // Close the buffer. + *buffer = '\0'; + return 1; } // Save the character. *buffer = string[*offset]; @@ -496,7 +497,7 @@ size_t strlen(const char *s) size_t strnlen(const char *s, size_t count) { const char *p = memchr(s, 0, count); - return p ? (size_t)(p-s) : count; + return p ? (size_t)(p - s) : count; } int strcmp(const char *s1, const char *s2) diff --git a/mentos/src/klib/string.c b/mentos/src/klib/string.c index 37ec3eb2..eae471ff 100644 --- a/mentos/src/klib/string.c +++ b/mentos/src/klib/string.c @@ -218,27 +218,29 @@ char *strpbrk(const char *string, const char *control) return NULL; } -int tokenize(const char *string, char *separators, size_t *offset, char *buffer, ssize_t buflen) +int tokenize(const char *string, const char *separators, size_t *offset, char *buffer, ssize_t buflen) { // If we reached the end of the parsed string, stop. if ((*offset >= buflen) || (string[*offset] == 0)) { return 0; } + // If the first character is a separator, skip it. + *offset += (*offset == 0) && strchr(separators, string[*offset]); // Keep copying character until we either reach 1) the end of the buffer, 2) a // separator, or 3) the end of the string we are parsing. do { - for (char *separator = separators; *separator != 0; ++separator) { - if (string[*offset] == *separator) { - // Skip the character. - ++(*offset); - // Close the buffer. - *buffer = '\0'; - return 1; - } + // Check if the character is a separator. + if (strchr(separators, string[*offset])) { + // Skip the character. + ++(*offset); + // Close the buffer. + *buffer = '\0'; + return 1; } // Save the character. *buffer = string[*offset]; - // Advance the offset, decrese the available size in the buffer, and advance the buffer. + // Advance the offset, decrese the available size in the buffer, and advance + // the buffer. ++(*offset), --buflen, ++buffer; } while ((buflen > 0) && (string[*offset] != 0)); // Close the buffer. @@ -488,14 +490,14 @@ char *strcpy(char *dst, const char *src) size_t strlen(const char *s) { const char *it = s; - for(; *it; it++); + for (; *it; it++); return (size_t)(it - s); } size_t strnlen(const char *s, size_t count) { const char *p = memchr(s, 0, count); - return p ? (size_t)(p-s) : count; + return p ? (size_t)(p - s) : count; } int strcmp(const char *s1, const char *s2) From 3d88f1c4edab37b217a908691f50b5c9770b71c1 Mon Sep 17 00:00:00 2001 From: "Enrico Fraccaroli (Galfurian)" Date: Tue, 27 Aug 2024 09:05:51 -0400 Subject: [PATCH 08/18] Show inode when using stat program --- programs/stat.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/programs/stat.c b/programs/stat.c index 0de79dec..6653dba1 100644 --- a/programs/stat.c +++ b/programs/stat.c @@ -56,7 +56,8 @@ int main(int argc, char **argv) } } putchar('\n'); - printf("Size: %s\n", to_human_size(dstat.st_size)); + printf("Size: %12s ", to_human_size(dstat.st_size)); + printf("Inode: %d\n", dstat.st_ino); printf("File type: "); switch (dstat.st_mode & S_IFMT) { case S_IFBLK : printf("block device\n"); break; From f9c192f823c2948db753a8491ebbfece832e6db8 Mon Sep 17 00:00:00 2001 From: "Enrico Fraccaroli (Galfurian)" Date: Tue, 27 Aug 2024 09:06:10 -0400 Subject: [PATCH 09/18] Correctly follow links when using ls --- programs/ls.c | 51 +++++++++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/programs/ls.c b/programs/ls.c index cccf4fef..6bf53c2d 100644 --- a/programs/ls.c +++ b/programs/ls.c @@ -131,26 +131,45 @@ static inline void print_dir_entry(dirent_t *dirent, const char *path, unsigned } } -static void print_ls(int fd, const char *path, unsigned int flags) +static void print_ls(const char *path, unsigned int flags) { + // Read the link, if the path points to one. + char real_path[PATH_MAX], link_path[PATH_MAX]; + ssize_t link_len = readlink(path, link_path, sizeof(link_path)); + if (link_len > 0) { + link_path[link_len] = '\0'; + if (realpath(link_path, real_path, sizeof(real_path)) != real_path) { + printf("ls: cannot resolve path '%s': %s\n", real_path, strerror(errno)); + return; + } + } else { + strncpy(real_path, path, strlen(path)); + } + + // Open the directory. + int fd = open(real_path, O_RDONLY | O_DIRECTORY, 0); + if (fd == -1) { + printf("ls: cannot access '%s': %s\n", real_path, strerror(errno)); + return; + } + + // Clear the directory entry buffer. dirent_t dents[DENTS_NUM]; memset(&dents, 0, DENTS_NUM * sizeof(dirent_t)); - size_t total_size = 0; 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); + print_dir_entry(&dents[i], real_path, flags, &total_size); } } if (bytes_read < 0) { perror("getdents failed"); } - printf("\n"); - if (bitmask_check(flags, FLAG_L)) { printf("Total: %s\n", to_human_size(total_size)); } + close(fd); } int main(int argc, char *argv[]) @@ -184,31 +203,19 @@ int main(int argc, char *argv[]) bitmask_set_assign(flags, FLAG_I); } } - bool_t no_directory = true; for (int i = 1; i < argc; ++i) { - if (argv[i][0] == '-') - continue; - no_directory = false; - int fd = open(argv[i], O_RDONLY | O_DIRECTORY, 0); - if (fd == -1) { - printf("ls: cannot access '%s': %s\n", argv[i], strerror(errno)); - } else { + if (argv[i][0] != '-') { + no_directory = false; printf("%s:\n", argv[i]); - print_ls(fd, argv[i], flags); - close(fd); + print_ls(argv[i], flags); + printf("\n"); } } if (no_directory) { char cwd[PATH_MAX]; getcwd(cwd, PATH_MAX); - int fd = open(cwd, O_RDONLY | O_DIRECTORY, 0); - if (fd == -1) { - printf("ls: cannot access '%s': %s\n", cwd, strerror(errno)); - } else { - print_ls(fd, cwd, flags); - close(fd); - } + print_ls(cwd, flags); } return 0; } From 67755cb65a1dbef2d54692e414595b518b3c3f5c Mon Sep 17 00:00:00 2001 From: "Enrico Fraccaroli (Galfurian)" Date: Tue, 27 Aug 2024 09:10:17 -0400 Subject: [PATCH 10/18] Initialize buffer in ls command --- programs/ls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/ls.c b/programs/ls.c index 6bf53c2d..93fd66cd 100644 --- a/programs/ls.c +++ b/programs/ls.c @@ -134,7 +134,7 @@ static inline void print_dir_entry(dirent_t *dirent, const char *path, unsigned static void print_ls(const char *path, unsigned int flags) { // Read the link, if the path points to one. - char real_path[PATH_MAX], link_path[PATH_MAX]; + char real_path[PATH_MAX] = { 0 }, link_path[PATH_MAX] = { 0 }; ssize_t link_len = readlink(path, link_path, sizeof(link_path)); if (link_len > 0) { link_path[link_len] = '\0'; From 60b3f53514a5cbb4748128f74f4bf8b802441f1f Mon Sep 17 00:00:00 2001 From: "Enrico Fraccaroli (Galfurian)" Date: Tue, 27 Aug 2024 09:14:59 -0400 Subject: [PATCH 11/18] Brighter colors for ls command --- programs/ls.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/programs/ls.c b/programs/ls.c index 93fd66cd..2c126e9d 100644 --- a/programs/ls.c +++ b/programs/ls.c @@ -27,25 +27,25 @@ static inline void print_dir_entry_name(const char *name, mode_t st_mode) { if (S_ISSOCK(st_mode)) { - printf(FG_YELLOW "%s" FG_RESET, name); + printf(FG_YELLOW_BRIGHT "%s" FG_RESET, name); } if (S_ISLNK(st_mode)) { - printf(FG_CYAN "%s" FG_RESET, name); + printf(FG_CYAN_BRIGHT "%s" FG_RESET, name); } if (S_ISREG(st_mode)) { - printf(FG_WHITE "%s" FG_RESET, name); + printf(FG_WHITE_BRIGHT "%s" FG_RESET, name); } if (S_ISBLK(st_mode)) { - printf(FG_GREEN "%s" FG_RESET, name); + printf(FG_GREEN_BRIGHT "%s" FG_RESET, name); } if (S_ISDIR(st_mode)) { - printf(FG_BLUE "%s" FG_RESET, name); + printf(FG_BLUE_BRIGHT "%s" FG_RESET, name); } if (S_ISCHR(st_mode)) { - printf(FG_YELLOW "%s" FG_RESET, name); + printf(FG_YELLOW_BRIGHT "%s" FG_RESET, name); } if (S_ISFIFO(st_mode)) { - printf(FG_YELLOW "%s" FG_RESET, name); + printf(FG_YELLOW_BRIGHT "%s" FG_RESET, name); } } @@ -63,8 +63,9 @@ static inline void print_dir_entry(dirent_t *dirent, const char *path, unsigned // Prepare the relative path. strcpy(relative_path, path); - if (strcmp(path, "/") != 0) + if (strcmp(path, "/") != 0) { strcat(relative_path, "/"); + } strcat(relative_path, dirent->d_name); // Stat the file. From fdc4840396c6a47be8ef0cf41d1a3345a258d031 Mon Sep 17 00:00:00 2001 From: "Enrico Fraccaroli (Galfurian)" Date: Tue, 27 Aug 2024 15:22:53 -0400 Subject: [PATCH 12/18] - Rewrite the function. - Now does not reaquire an open file. - Move inside vfs some of the calls. - Improve programs that manipulates files and paths. --- files/home/user/.bashrc | 0 files/{dev/README => home/user/.shellrc} | 0 files/home/user/tmp.md | 1 + files/home/user/welcome.md | 8 + files/proc/README | 0 mentos/inc/fs/vfs.h | 4 +- mentos/inc/fs/vfs_types.h | 2 +- mentos/src/fs/ext2.c | 111 ++++++---- mentos/src/fs/namei.c | 246 ++++++++--------------- mentos/src/fs/vfs.c | 89 ++++---- mentos/src/process/process.c | 32 +-- programs/login.c | 16 +- programs/ls.c | 9 +- programs/stat.c | 4 +- programs/tests/t_dup.c | 2 +- programs/tests/t_write_read.c | 1 + programs/touch.c | 11 +- 17 files changed, 259 insertions(+), 277 deletions(-) delete mode 100644 files/home/user/.bashrc rename files/{dev/README => home/user/.shellrc} (100%) create mode 120000 files/home/user/tmp.md create mode 100644 files/home/user/welcome.md delete mode 100644 files/proc/README diff --git a/files/home/user/.bashrc b/files/home/user/.bashrc deleted file mode 100644 index e69de29b..00000000 diff --git a/files/dev/README b/files/home/user/.shellrc similarity index 100% rename from files/dev/README rename to files/home/user/.shellrc diff --git a/files/home/user/tmp.md b/files/home/user/tmp.md new file mode 120000 index 00000000..9b519420 --- /dev/null +++ b/files/home/user/tmp.md @@ -0,0 +1 @@ +../user/welcome.md \ No newline at end of file diff --git a/files/home/user/welcome.md b/files/home/user/welcome.md new file mode 100644 index 00000000..b3572567 --- /dev/null +++ b/files/home/user/welcome.md @@ -0,0 +1,8 @@ +MentOS 0.7.2 + +Welcome to the MentOS, the Mentoring Operating System. + +If you want some help enter the "man" command into the cli. + +Bye, +The Ment(OS) Team diff --git a/files/proc/README b/files/proc/README deleted file mode 100644 index e69de29b..00000000 diff --git a/mentos/inc/fs/vfs.h b/mentos/inc/fs/vfs.h index 19c1c718..4faef2b5 100644 --- a/mentos/inc/fs/vfs.h +++ b/mentos/inc/fs/vfs.h @@ -131,11 +131,11 @@ int vfs_rmdir(const char *path); vfs_file_t *vfs_creat(const char *path, mode_t mode); /// @brief Read the symbolic link, if present. -/// @param file the file for which we want to read the symbolic link information. +/// @param path the path to the symbolic link. /// @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. -ssize_t vfs_readlink(vfs_file_t *file, char *buffer, size_t bufsize); +ssize_t vfs_readlink(const char *path, char *buffer, size_t bufsize); /// @brief Creates a symbolic link. /// @param linkname the name of the link. diff --git a/mentos/inc/fs/vfs_types.h b/mentos/inc/fs/vfs_types.h index 2a46a03b..1d6a0d82 100644 --- a/mentos/inc/fs/vfs_types.h +++ b/mentos/inc/fs/vfs_types.h @@ -50,7 +50,7 @@ typedef int (*vfs_ioctl_callback)(vfs_file_t *, int, void *); /// Function for creating symbolic links. typedef int (*vfs_symlink_callback)(const char *, const char *); /// Function that reads the symbolic link data associated with a file. -typedef ssize_t (*vfs_readlink_callback)(vfs_file_t *, char *, size_t); +typedef ssize_t (*vfs_readlink_callback)(const char *, char *, size_t); /// Function used to modify the attributes of an fs entry. typedef int (*vfs_setattr_callback)(const char *, struct iattr *); /// Function used to modify the attributes of a file. diff --git a/mentos/src/fs/ext2.c b/mentos/src/fs/ext2.c index 9faf0690..e1929fa3 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" @@ -368,7 +368,7 @@ static off_t ext2_lseek(vfs_file_t *file, off_t offset, int whence); static int ext2_fstat(vfs_file_t *file, stat_t *stat); static int ext2_ioctl(vfs_file_t *file, int request, void *data); static ssize_t ext2_getdents(vfs_file_t *file, dirent_t *dirp, off_t doff, size_t count); -static ssize_t ext2_readlink(vfs_file_t *file, char *buffer, size_t bufsize); +static ssize_t ext2_readlink(const char *path, char *buffer, size_t bufsize); static int ext2_fsetattr(vfs_file_t *file, struct iattr *attr); static int ext2_mkdir(const char *path, mode_t mode); @@ -1483,14 +1483,13 @@ static uint32_t ext2_get_real_block_index(ext2_filesystem_t *fs, ext2_inode_t *i // The real index. uint32_t real_index = 0; - // Allocate the cache. - uint8_t *cache = ext2_alloc_cache(fs); - // Check if the index is among the DIRECT blocks. a = block_index - EXT2_DIRECT_BLOCKS; if (a < 0) { real_index = inode->data.blocks.dir_blocks[block_index]; } else { + // Allocate the cache. + uint8_t *cache = ext2_alloc_cache(fs); // Check if the index is among the INDIRECT blocks. b = a - p; if (b < 0) { @@ -1534,9 +1533,9 @@ static uint32_t ext2_get_real_block_index(ext2_filesystem_t *fs, ext2_inode_t *i } } } + // Free the cache. + ext2_dealloc_cache(cache); } - // Free the cache. - ext2_dealloc_cache(cache); return real_index; } @@ -1590,7 +1589,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); } @@ -1704,9 +1703,12 @@ static ssize_t ext2_write_inode_data(ext2_filesystem_t *fs, ext2_inode_t *inode, uint32_t curr_off = 0, left, right, ret = end_offset - offset; for (uint32_t block_index = start_block; block_index <= end_block; ++block_index) { + pr_debug("ext2_write_inode_data: index = %4u, start = %4u, end = %4u\n", + block_index, start_block, end_block); left = 0, right = fs->block_size; // Read the real block. Do not check for ext2_read_inode_block(fs, inode, block_index, cache); + pr_debug("ext2_write_inode_data: read block %4u done.\n", block_index); if (block_index == start_block) { left = start_off; } @@ -1718,6 +1720,8 @@ static ssize_t ext2_write_inode_data(ext2_filesystem_t *fs, ext2_inode_t *inode, // Move the offset. curr_off += (right - left + 1); // Write the block back. + pr_debug("ext2_write_inode_data: Write inode = %4u, block = %4u\n", + inode_index, block_index); if (!ext2_write_inode_block(fs, inode, inode_index, block_index, cache)) { pr_err("Failed to write the inode block %u of inode %u\n", block_index, inode_index); ret = -1; @@ -1841,6 +1845,7 @@ static inline int ext2_directory_is_empty(ext2_filesystem_t *fs, uint8_t *cache, /// @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) { + pr_debug("ext2_clean_inode_content(%p, %p, %u)\n", fs, inode, inode_index); // Check the type of operation. if ((inode->mode & S_IFREG) != S_IFREG) { pr_alert("Trying to clean the content of a non-regular file.\n"); @@ -1853,10 +1858,13 @@ static int ext2_clean_inode_content(ext2_filesystem_t *fs, ext2_inode_t *inode, // int ret = 0; for (ssize_t offset = 0, to_write; offset < inode->size;) { + pr_debug("ext2_clean_inode_content(%p, %p, %u): offset = %6u of size = %u\n", fs, inode, inode_index, offset, inode->size); // We do not want to extend the size of the inode. to_write = max(min(offset + cache_size, inode->size), 0); + pr_debug("ext2_clean_inode_content(%p, %p, %u): to_write = %6u\n", fs, inode, inode_index, to_write); // Override the content. ssize_t written = ext2_write_inode_data(fs, inode, inode_index, offset, to_write, (char *)cache); + pr_debug("ext2_clean_inode_content(%p, %p, %u): written = %6u\n", fs, inode, inode_index, written); if (written < 0) { pr_err("Failed to clean content of inode %d\n", inode_index); ret = -1; @@ -2298,13 +2306,13 @@ static int ext2_find_direntry(ext2_filesystem_t *fs, ino_t ino, const char *name } // Check that the parent is a directory. if (!bitmask_check(inode.mode, S_IFDIR)) { - pr_err("The parent inode is not a directory (ino: %d, mode: %d).\n", ino, inode.mode); + pr_err("The parent inode is not a directory (ino: %d, mode: %d, name: %s).\n", ino, inode.mode, name); return -1; } // Check that we are allowed to reach through the directory if (!__valid_x_permission(scheduler_get_current_process(), &inode)) { - pr_err("The parent inode has no x permission (ino: %d, mode: %d).\n", ino, inode.mode); + pr_err("The parent inode has no x permission (ino: %d, mode: %d, name: %s).\n", ino, inode.mode, name); return -EPERM; } @@ -2332,8 +2340,9 @@ static int ext2_find_direntry(ext2_filesystem_t *fs, ino_t ino, const char *name // Copy the inode of the parent, even if we did not find the entry. search->parent_inode = ino; // Check if we have found the entry. - if (it.direntry == NULL) + if (it.direntry == NULL) { goto free_cache_return_error; + } // Copy the direntry. search->direntry.inode = it.direntry->inode; search->direntry.rec_len = it.direntry->rec_len; @@ -2359,7 +2368,7 @@ static int ext2_find_direntry(ext2_filesystem_t *fs, ino_t ino, const char *name /// @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, -errno on failure. -static int ext2_resolve_path(vfs_file_t *directory, char *path, ext2_direntry_search_t *search) +static int ext2_resolve_path(vfs_file_t *directory, const char *path, ext2_direntry_search_t *search) { // Check the pointers. if (directory == NULL) { @@ -2384,17 +2393,16 @@ static int ext2_resolve_path(vfs_file_t *directory, char *path, ext2_direntry_se if (strcmp(path, "/") == 0) { return ext2_find_direntry(fs, directory->ino, path, search); } - ino_t ino = directory->ino; - char *saveptr, *token = strtok_r(path, "/", &saveptr); - while (token) { - if (!ext2_find_direntry(fs, ino, token, search)) { - ino = search->direntry.inode; - } else { + ino_t ino = directory->ino; + char token[NAME_MAX] = { 0 }; + size_t offset = 0; + while (tokenize(path, "/", &offset, token, NAME_MAX)) { + if (ext2_find_direntry(fs, ino, token, search)) { return -1; } - token = strtok_r(NULL, "/", &saveptr); + ino = search->direntry.inode; } - pr_debug("resolve_path(directory: %s, path: %s) -> (%s, %d)\n", + pr_debug("ext2_resolve_path(directory: %s, path: %s) -> (%s, %d)\n", directory->name, path, search->direntry.name, search->direntry.inode); return 0; } @@ -3143,26 +3151,49 @@ static ssize_t ext2_getdents(vfs_file_t *file, dirent_t *dirp, off_t doff, size_ /// @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) +static ssize_t ext2_readlink(const char *path, char *buffer, size_t bufsize) { + pr_debug("ext2_readlink(%s, %s, %d)\n", path, buffer, bufsize); + super_block_t *sb = vfs_get_superblock(path); + if (sb == NULL) { + pr_err("ext2_readlink(%s, %s, %d): Cannot find the superblock!.\n", path, buffer, bufsize); + return -ENODEV; + } + if (sb->root == NULL) { + pr_err("ext2_readlink(%s, %s, %d): Cannot find the superblock root.\n", path, buffer, bufsize); + return -ENOENT; + } // Get the filesystem. - ext2_filesystem_t *fs = (ext2_filesystem_t *)file->device; + ext2_filesystem_t *fs = (ext2_filesystem_t *)sb->root->device; if (fs == NULL) { - pr_err("The file does not belong to an EXT2 filesystem `%s`.\n", file->name); + pr_err("ext2_readlink(%s, %s, %d): The file does not belong to an EXT2 filesystem.\n", path, buffer, bufsize); + return -ENOENT; + } + // Prepare the structure for the search. + ext2_direntry_search_t search; + memset(&search, 0, sizeof(ext2_direntry_search_t)); + // Resolve the path to the directory entry. + if (ext2_resolve_path(sb->root, path, &search)) { + pr_err("ext2_readlink(%s, %s, %d): Failed to resolve path.\n", path, buffer, bufsize); return -ENOENT; } // 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 (%d).\n", file->ino); + if (ext2_read_inode(fs, &inode, search.direntry.inode) == -1) { + pr_err("ext2_readlink(%s, %s, %d): Failed to read the inode (%d).\n", path, buffer, bufsize, search.direntry.inode); return -ENOENT; } - // Get the length of the symlink. - ssize_t nbytes = min(strlen(inode.data.symlink), bufsize); - // Copy the symlink information. - strncpy(buffer, inode.data.symlink, nbytes); - // Return how much we read. - return nbytes; + if ((inode.mode & S_IFLNK) == S_IFLNK) { + // Get the length of the symlink. + ssize_t nbytes = min(strlen(inode.data.symlink), bufsize); + // Copy the symlink information. + strncpy(buffer, inode.data.symlink, nbytes); + // Return how much we read. + return nbytes; + } else { + return -ENOLINK; + } + return 0; } /// @brief Creates a new directory at the given path. @@ -3179,6 +3210,7 @@ static int ext2_mkdir(const char *path, mode_t permission) pr_err("mkdir(%s): Cannot get the absolute path.\n", path); return -ENOENT; } + pr_debug("mkdir(%s, %d): %s -> %s\n", path, permission, path, absolute_path); // Get the parent directory. char parent_path[PATH_MAX]; if (!dirname(absolute_path, parent_path, sizeof(parent_path))) { @@ -3595,16 +3627,9 @@ static vfs_file_t *ext2_mount(vfs_file_t *block_device, const char *path) /// @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. - 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("mount_callback(%s, %s): Cannot get the absolute path.", path, device); - return NULL; - } - super_block_t *sb = vfs_get_superblock(absolute_path); + super_block_t *sb = vfs_get_superblock(device); if (sb == NULL) { - pr_err("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!\n", path, device); return NULL; } vfs_file_t *block_device = sb->root; diff --git a/mentos/src/fs/namei.c b/mentos/src/fs/namei.c index 77142348..f5aedba9 100644 --- a/mentos/src/fs/namei.c +++ b/mentos/src/fs/namei.c @@ -15,21 +15,15 @@ #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; \ +#define APPEND_PATH_SEPARATOR(buffer, buflen) \ + { \ + if (buffer[strnlen(buffer, buflen) - 1] != '/') { strncat(buffer, "/", buflen); } \ } -/// 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; \ +/// Appends the path. +#define APPEND_PATH(buffer, token) \ + { \ + strncat(buffer, token, strlen(token)); \ } int sys_unlink(const char *path) @@ -86,16 +80,8 @@ int sys_readlink(const char *path, char *buffer, size_t bufsize) pr_err("sys_readlink(%s): Cannot resolve path!\n", path); return ret; } - // Try to open the file. - vfs_file_t *file = vfs_open_abspath(absolute_path, O_RDONLY, 0); - if (file == NULL) { - pr_err("sys_readlink(%s): Cannot open file!\n", path); - return -errno; - } // Read the link. - ssize_t nbytes = vfs_readlink(file, buffer, bufsize); - // Close the file. - vfs_close(file); + ssize_t nbytes = vfs_readlink(path, buffer, bufsize); // Return the number of bytes we read. return nbytes; } @@ -110,160 +96,102 @@ char *realpath(const char *path, char *buffer, size_t buflen) return buffer; } -int resolve_path(const char *path, char *buffer, size_t buflen, int flags) +static inline int __get_link_content(const char *path, char *link, size_t length) { - assert(path && "Provided null path."); - assert(buffer && "Provided null buffer."); - - // Buffer used to build up the absolute path - char abspath[buflen]; - // Null-terminate our work buffer - memset(abspath, 0, buflen); - int remaining = buflen - 1; + ssize_t link_length = vfs_readlink(path, link, length); + if (link_length < 0) { + return -errno; + } + // Null-terminate link. + link[link_length] = 0; + return link_length; +} - // Track the resolved symlinks to ensure we do not end up in a loop - int symlinks = 0; +int __resolve_path(const char *path, char *abspath, size_t buflen, int flags, int link_depth) +{ + char token[NAME_MAX] = { 0 }; + char buffer[PATH_MAX] = { 0 }; + char linkpath[PATH_MAX] = { 0 }; + size_t offset = 0, linklen = 0, tokenlen = 0; + int contains_links = 0; + stat_t statbuf; if (path[0] != '/') { // Get the working directory of the current task. - sys_getcwd(abspath, remaining); - // Check the absolute path. - assert((strlen(abspath) > 0) && "Current working directory is not set."); - // Check that the current working directory is an absolute path. - assert((abspath[0] == '/') && "Current working directory is not an absolute path."); - // Count the remaining space in the absolute path. - remaining -= strlen(abspath); - APPEND_PATH_SEP_OR_FAIL(abspath, remaining); + sys_getcwd(buffer, buflen); + pr_notice("|%-32s|%-32s| (INIT)\n", path, buffer); } - // Copy the path into the working buffer; - APPEND_PATH_OR_FAIL(abspath, path, remaining); - - int absidx, pathidx; -resolve_abspath: - absidx = pathidx = 0; - while (abspath[absidx]) { - // Skip multiple consecutive / characters - if (!strncmp("//", abspath + absidx, 2)) { - absidx++; - } - // Go to previous directory if /../ is found - else if (!strncmp("/../", abspath + absidx, 4)) { - // Go to a valid path character (pathidx points to the next one) - if (pathidx) { - pathidx--; - } - while (pathidx && buffer[pathidx] != '/') { - pathidx--; + while (tokenize(path, "/", &offset, token, NAME_MAX)) { + tokenlen = strlen(token); + if ((strcmp(token, "..") == 0) && (tokenlen == 2)) { + // Handle parent directory token "..". + if (strlen(buffer) > 0) { + // Find the last occurrence of '/'. + char *last_slash = strrchr(buffer, '/'); + if (!last_slash || (last_slash == buffer)) { + // This case handles if buffer is already empty (e.g., ".." + // from the root). + buffer[0] = '/'; + buffer[1] = 0; + } else { + // Truncate at the last slash. + *last_slash = '\0'; + } } - absidx += 3; - } else if (!strncmp("/./", abspath + absidx, 3)) { - absidx += 2; + } else if ((strcmp(token, ".") == 0) && (tokenlen == 1)) { + // Nothing to do. } else { - // Resolve a possible symlink + if (strlen(buffer) + strlen(token) + 1 < buflen) { + APPEND_PATH_SEPARATOR(buffer, buflen); + APPEND_PATH(buffer, token); + } else { + pr_err("Buffer overflow while resolving path.\n"); + return -ENAMETOOLONG; + } if (flags & FOLLOW_LINKS) { - // Write the next path separator - buffer[pathidx++] = abspath[absidx++]; - - // Find the next separator after the current path component - char *sep_after_cur = strchr(abspath + absidx, '/'); - if (sep_after_cur) { - // Null-terminate work buffer to properly open the current component - *sep_after_cur = 0; - } - - stat_t statbuf; - int ret = vfs_stat(abspath, &statbuf); - if (ret < 0) { - // This is the last path component and we want to create it anyway. - if (ret == -ENOENT && !sep_after_cur && (flags & CREAT_LAST_COMPONENT)) { - // Just copy the component into the buffer - goto copy_path_component; + ssize_t link_length = __get_link_content(buffer, linkpath, PATH_MAX); + if (link_length > 0) { + if (link_depth >= SYMLOOP_MAX) { + pr_err("Reached symbolic link maximum depth `%d`.\n", link_depth); + return -ELOOP; } - return ret; - } - - // The path component is no symbolic link - if (!S_ISLNK(statbuf.st_mode)) { - // Restore replaced path separator - *sep_after_cur = '/'; - // Just copy the component into the buffer - goto copy_path_component; - } - - symlinks++; - if (symlinks > SYMLOOP_MAX) { return -ELOOP; } - - char link[PATH_MAX]; - vfs_file_t *link_file = vfs_open_abspath(abspath, O_RDONLY, 0); - if (link_file == NULL) { return -errno; } - ssize_t nbytes = vfs_readlink(link_file, link, sizeof(link)); - vfs_close(link_file); - if (nbytes == -1) { return -errno; } - - // Null-terminate link - link[nbytes] = 0; - - // Link is an absolute path, replace everything and continue - if (link[0] == '/') { - // Save the rest of the current abspath into the buffer - if (sep_after_cur) { - strncpy(buffer, sep_after_cur + 1, buflen); + linklen = strlen(linkpath); + + if (linkpath[0] == '/') { + memcpy(buffer, linkpath, linklen); + } else { + // Find the last occurrence of '/'. + char *last_slash = strrchr(buffer, '/'); + if (last_slash) { + memcpy(++last_slash, linkpath, linklen); + pr_notice("|%-32s|%-32s|%-32s| (LINK)\n", path, buffer, linkpath); + } } - - // Reset abspath with link - remaining = buflen - 1; - strncpy(abspath, link, remaining); - - remaining -= strlen(link); - if (remaining < 0) { return -ENAMETOOLONG; } - - // This is not the last component, therefore it must be a directory - if (sep_after_cur) { - APPEND_PATH_SEP_OR_FAIL(abspath, remaining); - // Copy the saved content from buffer back to the abspath - APPEND_PATH_OR_FAIL(abspath, buffer, remaining); - } - goto resolve_abspath; - // Link is relative, add it and continue - } else { - // Recalculate the remaining space in the working buffer - remaining = buflen - absidx - 1; - strncpy(abspath + absidx, link, remaining); - - remaining -= strlen(link); - if (remaining < 0) { return -ENAMETOOLONG; } - - if (sep_after_cur) { - // Restore replaced path separator - *sep_after_cur = '/'; + contains_links = 1; + } else if (link_length < 0) { + // This is the last path component and we want to create it anyway. + if ((link_length == -ENOENT) && !strchr(path + offset, '/') && (flags & CREAT_LAST_COMPONENT)) { + } else { + pr_err("Cannot find entry `%s`.\n", buffer); + return link_length; } - - // Continue with to previous path separator - absidx--; - pathidx--; } - - } - // Copy the path component - else { - copy_path_component: - do { - buffer[pathidx++] = abspath[absidx++]; - } while (abspath[absidx] && abspath[absidx] != '/'); } } + pr_notice("|%-32s|%-32s|\n", path, buffer); } - - // Null-terminate buffer - buffer[pathidx] = 0; - - if (flags & REMOVE_TRAILING_SLASH) { - // Ensure the path is not just "/" - if (pathidx > 1 && buffer[pathidx] == '/') { - buffer[pathidx - 1] = '\0'; - } + if (contains_links) { + pr_notice("|%-32s|%-32s| (RECU)\n", path, buffer); + return __resolve_path(buffer, abspath, buflen, flags, ++link_depth); + } else { + strncpy(abspath, buffer, buflen); + pr_notice("|%-32s|%-32s| (END)\n", path, buffer); } - return 0; } + +int resolve_path(const char *path, char *abspath, size_t buflen, int flags) +{ + return __resolve_path(path, abspath, buflen, flags, 0); +} diff --git a/mentos/src/fs/vfs.c b/mentos/src/fs/vfs.c index 188b9a52..ffb4507c 100644 --- a/mentos/src/fs/vfs.c +++ b/mentos/src/fs/vfs.c @@ -143,13 +143,13 @@ vfs_file_t *vfs_open_abspath(const char *absolute_path, int flags, mode_t mode) { super_block_t *sb = vfs_get_superblock(absolute_path); if (sb == NULL) { - pr_err("vfs_open(%s): Cannot find the superblock!\n", absolute_path); + pr_err("vfs_open_abspath(%s): Cannot find the superblock!\n", absolute_path); errno = ENOENT; return NULL; } vfs_file_t *sb_root = sb->root; if (sb_root == NULL) { - pr_err("vfs_open(%s): Cannot find the superblock root!\n", absolute_path); + pr_err("vfs_open_abspath(%s): Cannot find the superblock root!\n", absolute_path); errno = ENOENT; return NULL; } @@ -157,14 +157,14 @@ vfs_file_t *vfs_open_abspath(const char *absolute_path, int flags, mode_t mode) //size_t name_offset = (strcmp(mp->name, "/") == 0) ? 0 : strlen(mp->name); // Check if the function is implemented. if (sb_root->fs_operations->open_f == NULL) { - pr_err("vfs_open(%s): Function not supported in current filesystem.", absolute_path); + pr_err("vfs_open_abspath(%s): Function not supported in current filesystem.\n", absolute_path); errno = ENOSYS; return NULL; } // Retrieve the file. vfs_file_t *file = sb_root->fs_operations->open_f(absolute_path, flags, mode); if (file == NULL) { - pr_debug("vfs_open(%s): Filesystem open returned NULL file (errno: %d, %s)!\n", + pr_debug("vfs_open_abspath(%s): Filesystem open returned NULL file (errno: %d, %s)!\n", absolute_path, errno, strerror(errno)); return NULL; } @@ -178,20 +178,22 @@ vfs_file_t *vfs_open(const char *path, int flags, mode_t mode) { pr_debug("vfs_open(path: %s, flags: %d, mode: %d)\n", path, flags, mode); assert(path && "Provided null path."); - // Allocate a variable for the path. - char absolute_path[PATH_MAX]; // Resolve all symbolic links in the path before opening the file. - int resolve_flags = FOLLOW_LINKS; + int resolve_flags = FOLLOW_LINKS | REMOVE_TRAILING_SLASH; // Allow the last component to be non existing when attempting to create it. if (bitmask_check(flags, O_CREAT)) { resolve_flags |= CREAT_LAST_COMPONENT; } + // Allocate a variable for the path. + char absolute_path[PATH_MAX]; + // If the first character is not the '/' then get the absolute path. int ret = resolve_path(path, absolute_path, sizeof(absolute_path), resolve_flags); if (ret < 0) { pr_err("vfs_open(%s): Cannot resolve path!\n", path); errno = -ret; return NULL; } + pr_debug("vfs_open(path: %s, flags: %d, mode: %d) -> %s\n", path, flags, mode, absolute_path); return vfs_open_abspath(absolute_path, flags, mode); } @@ -260,8 +262,8 @@ int vfs_unlink(const char *path) // Allocate a variable for the 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("vfs_unlink(%s): Cannot get the absolute path.", path); + if (resolve_path(path, absolute_path, sizeof(absolute_path), REMOVE_TRAILING_SLASH | FOLLOW_LINKS) < 0) { + pr_err("vfs_unlink(%s): Cannot get the absolute path.\n", path); return -ENODEV; } super_block_t *sb = vfs_get_superblock(absolute_path); @@ -271,12 +273,12 @@ int vfs_unlink(const char *path) } vfs_file_t *sb_root = sb->root; if (sb_root == NULL) { - pr_err("vfs_unlink(%s): Cannot find the superblock root.", path); + pr_err("vfs_unlink(%s): Cannot find the superblock root.\n", path); return -ENOENT; } // Check if the function is implemented. if (sb_root->fs_operations->unlink_f == NULL) { - pr_err("vfs_unlink(%s): Function not supported in current filesystem.", path); + pr_err("vfs_unlink(%s): Function not supported in current filesystem.\n", path); return -ENOSYS; } return sb_root->fs_operations->unlink_f(absolute_path); @@ -284,13 +286,16 @@ int vfs_unlink(const char *path) int vfs_mkdir(const char *path, mode_t mode) { + pr_debug("vfs_mkdir(path: %s, mode: %d)\n", path, mode); // Allocate a variable for the 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("vfs_mkdir(%s): Cannot get the absolute path.", path); + if (resolve_path(path, absolute_path, sizeof(absolute_path), + REMOVE_TRAILING_SLASH | FOLLOW_LINKS | CREAT_LAST_COMPONENT) < 0) { + pr_err("vfs_mkdir(%s): Cannot get the absolute path.\n", path); return -ENODEV; } + pr_debug("vfs_mkdir(path: %s, mode: %d) -> absolute_path: %s\n", path, mode, absolute_path); super_block_t *sb = vfs_get_superblock(absolute_path); if (sb == NULL) { pr_err("vfs_mkdir(%s): Cannot find the superblock!\n"); @@ -298,12 +303,12 @@ int vfs_mkdir(const char *path, mode_t mode) } vfs_file_t *sb_root = sb->root; if (sb_root == NULL) { - pr_err("vfs_mkdir(%s): Cannot find the superblock root.", path); + pr_err("vfs_mkdir(%s): Cannot find the superblock root.\n", path); return -ENOENT; } // Check if the function is implemented. if (sb_root->sys_operations->mkdir_f == NULL) { - pr_err("vfs_mkdir(%s): Function not supported in current filesystem.", path); + pr_err("vfs_mkdir(%s): Function not supported in current filesystem.\n", path); return -ENOSYS; } return sb_root->sys_operations->mkdir_f(absolute_path, mode); @@ -314,8 +319,8 @@ int vfs_rmdir(const char *path) // Allocate a variable for the 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("vfs_rmdir(%s): Cannot get the absolute path.", path); + if (resolve_path(path, absolute_path, sizeof(absolute_path), REMOVE_TRAILING_SLASH | FOLLOW_LINKS) < 0) { + pr_err("vfs_rmdir(%s): Cannot get the absolute path.\n", path); return -ENODEV; } super_block_t *sb = vfs_get_superblock(absolute_path); @@ -325,12 +330,12 @@ int vfs_rmdir(const char *path) } vfs_file_t *sb_root = sb->root; if (sb_root == NULL) { - pr_err("vfs_rmdir(%s): Cannot find the superblock root.", path); + pr_err("vfs_rmdir(%s): Cannot find the superblock root.\n", path); return -ENOENT; } // Check if the function is implemented. if (sb_root->sys_operations->rmdir_f == NULL) { - pr_err("vfs_rmdir(%s): Function not supported in current filesystem.", path); + pr_err("vfs_rmdir(%s): Function not supported in current filesystem.\n", path); return -ENOSYS; } // Remove the file. @@ -342,8 +347,8 @@ vfs_file_t *vfs_creat(const char *path, mode_t mode) // Allocate a variable for the 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("vfs_creat(%s): Cannot get the absolute path.", path); + if (resolve_path(path, absolute_path, sizeof(absolute_path), REMOVE_TRAILING_SLASH | FOLLOW_LINKS) < 0) { + pr_err("vfs_creat(%s): Cannot get the absolute path.\n", path); errno = ENODEV; return NULL; } @@ -355,13 +360,13 @@ vfs_file_t *vfs_creat(const char *path, mode_t mode) } vfs_file_t *sb_root = sb->root; if (sb_root == NULL) { - pr_err("vfs_creat(%s): Cannot find the superblock root.", path); + pr_err("vfs_creat(%s): Cannot find the superblock root.\n", path); errno = ENOENT; return NULL; } // Check if the function is implemented. if (sb_root->sys_operations->creat_f == NULL) { - pr_err("vfs_creat(%s): Function not supported in current filesystem.", path); + pr_err("vfs_creat(%s): Function not supported in current filesystem.\n", path); errno = ENOSYS; return NULL; } @@ -378,19 +383,23 @@ vfs_file_t *vfs_creat(const char *path, mode_t mode) return file; } -ssize_t vfs_readlink(vfs_file_t *file, char *buffer, size_t bufsize) +ssize_t vfs_readlink(const char *path, char *buffer, size_t bufsize) { - if (file == NULL) { - pr_err("vfs_readlink: received a null pointer for file.\n"); + pr_debug("vfs_readlink(%s, %s, %d)\n", path, buffer, bufsize); + super_block_t *sb = vfs_get_superblock(path); + if (sb == NULL) { + pr_err("vfs_readlink(%s, %s, %d): Cannot find the superblock!.\n", path, buffer, bufsize); + return -ENODEV; + } + if (sb->root == NULL) { + pr_err("vfs_readlink(%s, %s, %d): Cannot find the superblock root.\n", path, buffer, bufsize); return -ENOENT; } - if (file->fs_operations->readlink_f == NULL) { - pr_err("vfs_readlink(%s): Function not supported in current filesystem.", file->name); + if (sb->root->fs_operations->readlink_f == NULL) { return -ENOSYS; } - pr_debug("vfs_readlink(file: %s, ino:%d)\n", file->name, file->ino); // Perform the read. - return file->fs_operations->readlink_f(file, buffer, bufsize); + return sb->root->fs_operations->readlink_f(path, buffer, bufsize); } int vfs_symlink(const char *linkname, const char *path) @@ -398,7 +407,7 @@ int vfs_symlink(const char *linkname, const char *path) // Allocate a variable for the path. char absolute_path[PATH_MAX]; // If the first character is not the '/' then get the absolute path. - if (!realpath(linkname, absolute_path, sizeof(absolute_path))) { + if (resolve_path(path, absolute_path, sizeof(absolute_path), REMOVE_TRAILING_SLASH | FOLLOW_LINKS) < 0) { pr_err("vfs_symlink(%s, %s): Cannot get the absolute path.", linkname, path); return -ENODEV; } @@ -423,12 +432,14 @@ int vfs_symlink(const char *linkname, const char *path) int vfs_stat(const char *path, stat_t *buf) { + pr_debug("vfs_stat(path: %s, buf: %p)\n", path, buf); // Allocate a variable for the 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))) { + int ret = resolve_path(path, absolute_path, PATH_MAX, REMOVE_TRAILING_SLASH | FOLLOW_LINKS); + if (ret < 0) { pr_err("vfs_stat(%s): Cannot get the absolute path.", path); - return -ENODEV; + return -ret; } super_block_t *sb = vfs_get_superblock(absolute_path); if (sb == NULL) { @@ -489,8 +500,16 @@ int vfs_mount(const char *type, const char *path, const char *args) pr_err("No mount callback set: %s\n", type); return -ENODEV; } - pr_debug("vfs_mount(type: %s, path: %s, args: %s)\n", fst->name, path, args); - vfs_file_t *file = fst->mount(path, args); + // Allocate a variable for the path. + char absolute_path[PATH_MAX]; + // If the first character is not the '/' then get the absolute path. + if (resolve_path(args, absolute_path, sizeof(absolute_path), REMOVE_TRAILING_SLASH) < 0) { + pr_err("vfs_mount(type: %s, path: %s, args: %s): Cannot get the absolute path\n", + fst->name, path, args); + return -ENODEV; + } + pr_debug("vfs_mount(type: %s, path: %s, args: %s (%s))\n", fst->name, path, args, absolute_path); + vfs_file_t *file = fst->mount(path, absolute_path); if (file == NULL) { pr_err("Mount callback return a null pointer: %s\n", type); return -ENODEV; diff --git a/mentos/src/process/process.c b/mentos/src/process/process.c index 49015d7a..be9f408c 100644 --- a/mentos/src/process/process.c +++ b/mentos/src/process/process.c @@ -13,7 +13,6 @@ #include "elf/elf.h" #include "fcntl.h" #include "sys/stat.h" -#include "fs/vfs.h" #include "hardware/timer.h" #include "klib/stack_helper.h" #include "libgen.h" @@ -24,6 +23,8 @@ #include "string.h" #include "sys/errno.h" #include "system/panic.h" +#include "fs/vfs.h" +#include "fs/namei.h" /// Cache for creating the task structs. static kmem_cache_t *task_struct_cache; @@ -118,7 +119,8 @@ static int __reset_process(task_struct *task) /// @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) { +static int __has_shebang(vfs_file_t *file) +{ char buf[2]; vfs_read(file, buf, 0, sizeof(buf)); return buf[0] == '#' && buf[1] == '!'; @@ -132,7 +134,7 @@ static int __has_shebang(vfs_file_t *file) { static int __load_executable(const char *path, task_struct *task, uint32_t *entry) { // Return code variable. - int ret = 0; + int ret = 0; int interpreter_loop = 0; start: pr_debug("__load_executable(`%s`, %p `%s`, %p)\n", path, task, task->name, entry); @@ -180,14 +182,14 @@ static int __load_executable(const char *path, task_struct *task, uint32_t *entr if (interpreter_loop) { ret = -ELOOP; // Free interpreter buffer - kfree((void*)path); + kfree((void *)path); goto close_and_return; } // Read shebang line char buf[PATH_MAX]; ssize_t bytes_read = vfs_read(file, buf, 2, sizeof(buf)); - buf[bytes_read] = 0; + buf[bytes_read] = 0; vfs_close(file); // Find end of the line @@ -211,7 +213,7 @@ static int __load_executable(const char *path, task_struct *task, uint32_t *entr // Free potential interpreter path if (interpreter_loop) { // Free interpreter buffer - kfree((void*)path); + kfree((void *)path); ret = 2; } @@ -441,9 +443,9 @@ int sys_chdir(char const *path) return -EFAULT; } char absolute_path[PATH_MAX]; - if (!realpath(path, absolute_path, sizeof(absolute_path))) { + if (resolve_path(path, absolute_path, sizeof(absolute_path), REMOVE_TRAILING_SLASH | FOLLOW_LINKS) < 0) { pr_err("Cannot get the absolute path for path `%s`.\n", path); - return -ENOENT; + return -errno; } // Check that the directory exists. vfs_file_t *dir = vfs_open(absolute_path, O_RDONLY | O_DIRECTORY, S_IXUSR); @@ -475,7 +477,7 @@ int sys_fchdir(int fd) return -ENOTDIR; } char absolute_path[PATH_MAX]; - if (!realpath(vfd->file_struct->name, absolute_path, sizeof(absolute_path))) { + if (resolve_path(vfd->file_struct->name, absolute_path, sizeof(absolute_path), REMOVE_TRAILING_SLASH | FOLLOW_LINKS) < 0) { pr_err("Cannot get the absolute path for path `%s`.\n", vfd->file_struct->name); return -ENOENT; } @@ -508,9 +510,9 @@ pid_t sys_fork(pt_regs *f) proc->sid = current->sid; proc->pgid = current->pgid; proc->uid = current->uid; - proc->ruid = current->ruid; + proc->ruid = current->ruid; proc->gid = current->gid; - proc->rgid = current->rgid; + proc->rgid = current->rgid; // Active the new process. scheduler_enqueue_task(proc); @@ -600,7 +602,7 @@ int sys_execve(pt_regs *f) // 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*)); + char **int_argv = kmalloc((argc + 2) * sizeof(char *)); if (!int_argv) { pr_err("Failed to allocate memory for interpreter argv array.\n"); return -1; @@ -608,7 +610,7 @@ int sys_execve(pt_regs *f) 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]; + int_argv[i + 1] = saved_argv[i]; } argc++; @@ -622,8 +624,8 @@ int sys_execve(pt_regs *f) } // 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); + 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. diff --git a/programs/login.c b/programs/login.c index d5fce55f..246ccc3c 100644 --- a/programs/login.c +++ b/programs/login.c @@ -178,17 +178,17 @@ int main(int argc, char **argv) __print_message_file("/etc/issue"); passwd_t *pwd; - char username[CREDENTIALS_LENGTH], password[CREDENTIALS_LENGTH]; + char username[CREDENTIALS_LENGTH] = "user", password[CREDENTIALS_LENGTH] = "user"; do { // Get the username. - do { - printf("Username: "); - } while (!__get_input(username, sizeof(username), false)); + // do { + // printf("Username: "); + // } while (!__get_input(username, sizeof(username), false)); - // Get the password. - do { - printf("Password: "); - } while (!__get_input(password, sizeof(password), true)); + // // Get the password. + // do { + // printf("Password: "); + // } while (!__get_input(password, sizeof(password), true)); // Check if we can find the user. if ((pwd = getpwnam(username)) == NULL) { diff --git a/programs/ls.c b/programs/ls.c index 2c126e9d..d56390ba 100644 --- a/programs/ls.c +++ b/programs/ls.c @@ -63,13 +63,14 @@ static inline void print_dir_entry(dirent_t *dirent, const char *path, unsigned // Prepare the relative path. strcpy(relative_path, path); - if (strcmp(path, "/") != 0) { + if (path[strnlen(path, PATH_MAX) - 1] != '/') { strcat(relative_path, "/"); } strcat(relative_path, dirent->d_name); // Stat the file. - if (stat(relative_path, &dstat) == -1) { + if (stat(relative_path, &dstat) < 0) { + printf("ls: failed to stat `%s`\n", relative_path); return; } @@ -109,8 +110,8 @@ static inline void print_dir_entry(dirent_t *dirent, const char *path, unsigned if (S_ISLNK(dstat.st_mode)) { char link_buffer[PATH_MAX]; - ssize_t len; - if ((len = readlink(relative_path, link_buffer, sizeof(link_buffer))) != -1) { + ssize_t len = readlink(relative_path, link_buffer, sizeof(link_buffer)); + if (len > 0) { link_buffer[len] = '\0'; printf(" -> %s", link_buffer); } diff --git a/programs/stat.c b/programs/stat.c index 6653dba1..e804f12a 100644 --- a/programs/stat.c +++ b/programs/stat.c @@ -49,8 +49,8 @@ int main(int argc, char **argv) printf("File: %s", argv[1]); if (S_ISLNK(dstat.st_mode)) { char link_buffer[PATH_MAX]; - ssize_t len; - if ((len = readlink(argv[1], link_buffer, sizeof(link_buffer))) != -1) { + ssize_t len = readlink(argv[1], link_buffer, sizeof(link_buffer)); + if (len < 0) { link_buffer[len] = '\0'; printf(" -> %s", link_buffer); } diff --git a/programs/tests/t_dup.c b/programs/tests/t_dup.c index f53bc87a..5bc2171e 100644 --- a/programs/tests/t_dup.c +++ b/programs/tests/t_dup.c @@ -13,7 +13,7 @@ int main(int argc, char *argv[]) { - char *file = "t_dup_file"; + const char *file = "t_dup_file"; int fd1, fd2; int flags = O_WRONLY | O_CREAT | O_TRUNC; mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; diff --git a/programs/tests/t_write_read.c b/programs/tests/t_write_read.c index 1b41ff3e..c491d6e3 100644 --- a/programs/tests/t_write_read.c +++ b/programs/tests/t_write_read.c @@ -44,6 +44,7 @@ int check_content(const char *filename, const char *content, int length) close(fd); return EXIT_FAILURE; } + close(fd); return EXIT_SUCCESS; } diff --git a/programs/touch.c b/programs/touch.c index eae2ec27..942349db 100644 --- a/programs/touch.c +++ b/programs/touch.c @@ -11,7 +11,7 @@ #include #include -int main(int argc, char** argv) +int main(int argc, char **argv) { if (argc != 2) { printf("%s: missing operand.\n", argv[0]); @@ -24,13 +24,10 @@ int main(int argc, char** argv) printf(" touch \n"); return 0; } - int fd = open(argv[1], O_RDONLY, 0); + int fd = open(argv[1], O_CREAT, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH); if (fd < 0) { - fd = open(argv[1], O_CREAT, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH); - if (fd < 0) { - err(EXIT_FAILURE, "cannot touch %s", argv[1]); - } - close(fd); + err(EXIT_FAILURE, "cannot touch %s", argv[1]); } + close(fd); return 0; } From 9e1284adbe39f658ed1916c18137fa6c3d7ee3a0 Mon Sep 17 00:00:00 2001 From: "Enrico Fraccaroli (Galfurian)" Date: Tue, 27 Aug 2024 15:53:43 -0400 Subject: [PATCH 13/18] Move resolve_path calls out of ETX2 and into kernel core functions. --- mentos/src/fs/ext2.c | 149 +++++++++++++++++------------------------- mentos/src/fs/namei.c | 15 +++-- mentos/src/fs/vfs.c | 44 ++++++++----- 3 files changed, 97 insertions(+), 111 deletions(-) diff --git a/mentos/src/fs/ext2.c b/mentos/src/fs/ext2.c index e1929fa3..43bc52c1 100644 --- a/mentos/src/fs/ext2.c +++ b/mentos/src/fs/ext2.c @@ -1589,7 +1589,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); } @@ -2730,31 +2730,27 @@ 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("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. - if (!realpath(path, absolute_path, sizeof(absolute_path))) { - pr_err("Cannot get the absolute path for path `%s`.\n", path); - return NULL; - } + pr_debug("ext2_open(path: '%s', flags: %d, mode: %d)\n", path, flags, mode); // Get the EXT2 filesystem. - ext2_filesystem_t *fs = get_ext2_filesystem(absolute_path); + ext2_filesystem_t *fs = get_ext2_filesystem(path); if (fs == NULL) { - pr_err("Failed to get the EXT2 filesystem for absolute path `%s`.\n", absolute_path); + pr_err("ext2_open(path: '%s', flags: %d, mode: %d): Failed to get the EXT2 filesystem.\n", + path, flags, mode); return NULL; } // Prepare the structure for the search. ext2_direntry_search_t search; memset(&search, 0, sizeof(ext2_direntry_search_t)); // First check, if a file with the given name already exists. - if (!ext2_resolve_path(fs->root, absolute_path, &search)) { + if (!ext2_resolve_path(fs->root, path, &search)) { if (bitmask_check(flags, O_CREAT) && bitmask_check(flags, O_EXCL)) { - pr_err("A file or directory already exists at `%s` (O_CREAT | O_EXCL).\n", absolute_path); + pr_err("ext2_open(path: '%s', flags: %d, mode: %d): A file or directory already exists (O_CREAT | O_EXCL).\n", + path, flags, mode); return NULL; } if (bitmask_check(flags, O_DIRECTORY) && (search.direntry.file_type != ext2_file_type_directory)) { - pr_err("Directory entry `%s` is not a directory.\n", search.direntry.name); + pr_err("ext2_open(path: '%s', flags: %d, mode: %d): Directory entry `%s` is not a directory.\n", + path, flags, mode, search.direntry.name); errno = ENOTDIR; return NULL; } @@ -2763,7 +2759,8 @@ static vfs_file_t *ext2_open(const char *path, int flags, mode_t mode) if (bitmask_check(flags, O_CREAT)) { return ext2_creat(path, mode); } - pr_err("The file does not exist `%s`.\n", absolute_path); + pr_err("ext2_open(path: '%s', flags: %d, mode: %d): The file does not exist.\n", + path, flags, mode); errno = ENOENT; return NULL; } @@ -2772,21 +2769,25 @@ static vfs_file_t *ext2_open(const char *path, int flags, mode_t mode) memset(&inode, 0, sizeof(ext2_inode_t)); // Get the inode associated with the directory entry. 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("ext2_open(path: '%s', flags: %d, mode: %d): Failed to read the inode.\n", + path, flags, mode); return NULL; } if (!vfs_valid_open_permissions(flags, inode.mode, inode.uid, inode.gid)) { - pr_err("Task does not have access permission.\n"); + pr_err("ext2_open(path: '%s', flags: %d, mode: %d): Task does not have access permission.\n", + path, flags, mode); errno = EACCES; return NULL; } // Check if the file is a regular file, and the user wants to write and truncate. - if (bitmask_exact(inode.mode, S_IFREG) && (bitmask_exact(flags, O_RDWR | O_TRUNC) || bitmask_exact(flags, O_RDONLY | O_TRUNC))) { + if (bitmask_exact(inode.mode, S_IFREG) && + (bitmask_exact(flags, O_RDWR | O_TRUNC) || bitmask_exact(flags, O_RDONLY | O_TRUNC))) { // Clean the content of the newly created file. if (ext2_clean_inode_content(fs, &inode, search.direntry.inode) < 0) { - pr_err("Failed to clean the content of the newly created inode.\n"); + pr_err("ext2_open(path: '%s', flags: %d, mode: %d): Failed to clean the content of the newly created inode.\n", + path, flags, mode); return NULL; } } @@ -2796,11 +2797,13 @@ static vfs_file_t *ext2_open(const char *path, int flags, mode_t mode) // Allocate the memory for the file. file = kmem_cache_alloc(vfs_file_cache, GFP_KERNEL); if (file == NULL) { - pr_err("Failed to allocate memory for the EXT2 file.\n"); + pr_err("ext2_open(path: '%s', flags: %d, mode: %d): Failed to allocate memory for the EXT2 file.\n", + path, flags, mode); return NULL; } if (ext2_init_vfs_file(fs, file, &inode, search.direntry.inode, search.direntry.name, search.direntry.name_len) == -1) { - pr_err("Failed to properly set the VFS file.\n"); + pr_err("ext2_open(path: '%s', flags: %d, mode: %d): Failed to properly set the VFS file.\n", + path, flags, mode); return NULL; } // Add the vfs_file to the list of associated files. @@ -2815,37 +2818,30 @@ static vfs_file_t *ext2_open(const char *path, int flags, mode_t mode) static int ext2_unlink(const char *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. - if (!realpath(path, absolute_path, sizeof(absolute_path))) { - pr_err("Cannot get the absolute path for path `%s`.\n", path); - return -ENOENT; - } // Get the name of the entry we want to unlink. - const char *name = basename(absolute_path); + const char *name = basename(path); if (name == NULL) { - pr_err("Cannot get the basename from the absolute path `%s`.\n", absolute_path); + pr_err("unlink(%s): Cannot get the basename.\n", path); return -ENOENT; } // Get the EXT2 filesystem. - ext2_filesystem_t *fs = get_ext2_filesystem(absolute_path); + ext2_filesystem_t *fs = get_ext2_filesystem(path); if (fs == NULL) { - pr_err("Failed to get the EXT2 filesystem for absolute path `%s`.\n", absolute_path); + pr_err("unlink(%s): Failed to get the EXT2 filesystem.\n", path); return -ENOENT; } // Prepare the structure for the search. ext2_direntry_search_t search; 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); + if (ext2_resolve_path(fs->root, path, &search)) { + pr_err("unlink(%s): Failed to resolve path.\n", 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) { - pr_err("stat(%s): Failed to read the inode of parent of `%s`.\n", path, search.direntry.name); + pr_err("unlink(%s): Failed to read the inode of parent (%d).\n", path, search.parent_inode); return -ENOENT; } // Allocate the cache. @@ -2853,13 +2849,13 @@ static int ext2_unlink(const char *path) // 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); + pr_err("unlink(%s): Failed to read the parent inode block (%d).\n", path, 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"); + pr_err("unlink(%s): We found a NULL ext2_dirent_t.\n", path); goto free_cache_return_error; } // Clear the directory entry. @@ -2869,13 +2865,14 @@ static int ext2_unlink(const char *path) actual_dirent->file_type = ext2_file_type_unknown; // 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); + pr_err("unlink(%s): Failed to write the inode block (%d).\n", path, search.block_index); goto free_cache_return_error; } // 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("unlink(%s): Failed to read the inode (%d: %s).\n", + path, search.direntry.inode, search.direntry.name); goto free_cache_return_error; } if (--inode.links_count == 0) { @@ -2884,7 +2881,8 @@ static int ext2_unlink(const char *path) } else { // 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); + pr_err("unlink(%s): Failed to update the inode (%d: %s).\n", + path, search.direntry.inode, search.direntry.name); goto free_cache_return_error; } } @@ -3203,35 +3201,27 @@ static ssize_t ext2_readlink(const char *path, char *buffer, size_t bufsize) static int ext2_mkdir(const char *path, mode_t 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("mkdir(%s): Cannot get the absolute path.\n", path); - return -ENOENT; - } - pr_debug("mkdir(%s, %d): %s -> %s\n", path, permission, path, absolute_path); // Get the parent directory. char parent_path[PATH_MAX]; - if (!dirname(absolute_path, parent_path, sizeof(parent_path))) { + if (!dirname(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); + if (strcmp(parent_path, path) == 0) { + pr_err("mkdir(%s): Failed to properly get the parent directory (%s).\n", path, parent_path); return -ENOENT; } // Get the EXT2 filesystem. - ext2_filesystem_t *fs = get_ext2_filesystem(absolute_path); + ext2_filesystem_t *fs = get_ext2_filesystem(path); if (fs == NULL) { - pr_err("mkdir(%s): Failed to get the EXT2 filesystem for absolute path `%s`.\n", path, absolute_path); + pr_err("mkdir(%s): Failed to get the EXT2 filesystem.\n", path); return -ENOENT; } // Prepare the structure for the search. ext2_direntry_search_t search; // Search if the entry already exists. - if (!ext2_resolve_path(fs->root, absolute_path, &search)) { - pr_err("mkdir(%s): Directory already exists.\n", absolute_path); + if (!ext2_resolve_path(fs->root, path, &search)) { + pr_err("mkdir(%s): Directory already exists.\n", path); return -EEXIST; } // Set the inode mode. @@ -3285,31 +3275,24 @@ static int ext2_mkdir(const char *path, mode_t permission) static int ext2_rmdir(const char *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("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); + const char *name = basename(path); if (name == NULL) { - pr_err("rmdir(%s): Cannot get the basename from the absolute path `%s`.\n", path, absolute_path); + pr_err("rmdir(%s): Cannot get the basename`.\n", path); return -ENOENT; } // Get the EXT2 filesystem. - ext2_filesystem_t *fs = get_ext2_filesystem(absolute_path); + ext2_filesystem_t *fs = get_ext2_filesystem(path); if (fs == NULL) { - pr_err("rmdir(%s): Failed to get the EXT2 filesystem for absolute path `%s`.\n", path, absolute_path); + pr_err("rmdir(%s): Failed to get the EXT2 filesystem.\n", path); return -ENOENT; } // Prepare the structure for the search. ext2_direntry_search_t search; 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("rmdir(%s): Failed to resolve path `%s`.\n", path, absolute_path); + if (ext2_resolve_path(fs->root, path, &search)) { + pr_err("rmdir(%s): Failed to resolve path.\n", path); return -ENOENT; } @@ -3335,25 +3318,18 @@ static int ext2_rmdir(const char *path) static int ext2_stat(const char *path, stat_t *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("stat(%s): Cannot get the absolute path.\n", path); - return -ENOENT; - } // Get the EXT2 filesystem. - ext2_filesystem_t *fs = get_ext2_filesystem(absolute_path); + ext2_filesystem_t *fs = get_ext2_filesystem(path); if (fs == NULL) { - pr_err("stat(%s): Failed to get the EXT2 filesystem for absolute path `%s`.\n", path, absolute_path); + pr_err("stat(%s): Failed to get the EXT2 filesystem.\n", path); return -ENOENT; } // Prepare the structure for the search. ext2_direntry_search_t search; memset(&search, 0, sizeof(ext2_direntry_search_t)); // Resolve the path. - if (ext2_resolve_path(fs->root, absolute_path, &search)) { - pr_err("stat(%s): Failed to resolve path `%s`.\n", path, absolute_path); + if (ext2_resolve_path(fs->root, path, &search)) { + pr_err("stat(%s): Failed to resolve path.\n", path); return -ENOENT; } // Get the inode associated with the directory entry. @@ -3438,25 +3414,18 @@ static int ext2_fsetattr(vfs_file_t *file, struct iattr *attr) static int ext2_setattr(const char *path, struct iattr *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("setattr(%s): Cannot get the absolute path.\n", path); - return -ENOENT; - } // Get the EXT2 filesystem. - ext2_filesystem_t *fs = get_ext2_filesystem(absolute_path); + ext2_filesystem_t *fs = get_ext2_filesystem(path); if (fs == NULL) { - pr_err("setattr(%s): Failed to get the EXT2 filesystem for absolute path `%s`.\n", path, absolute_path); + pr_err("setattr(%s): Failed to get the EXT2 filesystem for absolute path `%s`.\n", path); return -ENOENT; } // Prepare the structure for the search. ext2_direntry_search_t search; memset(&search, 0, sizeof(ext2_direntry_search_t)); // Resolve the path. - if (ext2_resolve_path(fs->root, absolute_path, &search)) { - pr_err("setattr(%s): Failed to resolve path `%s`.\n", path, absolute_path); + if (ext2_resolve_path(fs->root, path, &search)) { + pr_err("setattr(%s): Failed to resolve path.\n", path); return -ENOENT; } // Get the inode associated with the directory entry. diff --git a/mentos/src/fs/namei.c b/mentos/src/fs/namei.c index f5aedba9..24c29e5a 100644 --- a/mentos/src/fs/namei.c +++ b/mentos/src/fs/namei.c @@ -119,7 +119,7 @@ int __resolve_path(const char *path, char *abspath, size_t buflen, int flags, in if (path[0] != '/') { // Get the working directory of the current task. sys_getcwd(buffer, buflen); - pr_notice("|%-32s|%-32s| (INIT)\n", path, buffer); + pr_debug("|%-32s|%-32s| (INIT)\n", path, buffer); } while (tokenize(path, "/", &offset, token, NAME_MAX)) { @@ -165,7 +165,7 @@ int __resolve_path(const char *path, char *abspath, size_t buflen, int flags, in char *last_slash = strrchr(buffer, '/'); if (last_slash) { memcpy(++last_slash, linkpath, linklen); - pr_notice("|%-32s|%-32s|%-32s| (LINK)\n", path, buffer, linkpath); + pr_debug("|%-32s|%-32s|%-32s| (LINK)\n", path, buffer, linkpath); } } contains_links = 1; @@ -179,14 +179,19 @@ int __resolve_path(const char *path, char *abspath, size_t buflen, int flags, in } } } - pr_notice("|%-32s|%-32s|\n", path, buffer); + pr_debug("|%-32s|%-32s|\n", path, buffer); } if (contains_links) { - pr_notice("|%-32s|%-32s| (RECU)\n", path, buffer); + pr_debug("|%-32s|%-32s| (RECU)\n", path, buffer); return __resolve_path(buffer, abspath, buflen, flags, ++link_depth); } else { + // Remove trailing slash if requested. + if (flags & REMOVE_TRAILING_SLASH) { + size_t buffer_end = strnlen(buffer, buflen) - 1; + if (buffer[buffer_end] == '/') { buffer[buffer_end] = 0; } + } strncpy(abspath, buffer, buflen); - pr_notice("|%-32s|%-32s| (END)\n", path, buffer); + pr_debug("|%-32s|%-32s| (END)\n", path, buffer); } return 0; } diff --git a/mentos/src/fs/vfs.c b/mentos/src/fs/vfs.c index ffb4507c..0c241eeb 100644 --- a/mentos/src/fs/vfs.c +++ b/mentos/src/fs/vfs.c @@ -187,7 +187,7 @@ vfs_file_t *vfs_open(const char *path, int flags, mode_t mode) // Allocate a variable for the path. char absolute_path[PATH_MAX]; // If the first character is not the '/' then get the absolute path. - int ret = resolve_path(path, absolute_path, sizeof(absolute_path), resolve_flags); + int ret = resolve_path(path, absolute_path, PATH_MAX, resolve_flags); if (ret < 0) { pr_err("vfs_open(%s): Cannot resolve path!\n", path); errno = -ret; @@ -262,9 +262,11 @@ int vfs_unlink(const char *path) // Allocate a variable for the path. char absolute_path[PATH_MAX]; // If the first character is not the '/' then get the absolute path. - if (resolve_path(path, absolute_path, sizeof(absolute_path), REMOVE_TRAILING_SLASH | FOLLOW_LINKS) < 0) { + int resolve_flags = REMOVE_TRAILING_SLASH | FOLLOW_LINKS; + int ret = resolve_path(path, absolute_path, PATH_MAX, resolve_flags); + if (ret < 0) { pr_err("vfs_unlink(%s): Cannot get the absolute path.\n", path); - return -ENODEV; + return ret; } super_block_t *sb = vfs_get_superblock(absolute_path); if (sb == NULL) { @@ -290,10 +292,11 @@ int vfs_mkdir(const char *path, mode_t mode) // Allocate a variable for the path. char absolute_path[PATH_MAX]; // If the first character is not the '/' then get the absolute path. - if (resolve_path(path, absolute_path, sizeof(absolute_path), - REMOVE_TRAILING_SLASH | FOLLOW_LINKS | CREAT_LAST_COMPONENT) < 0) { + int resolve_flags = REMOVE_TRAILING_SLASH | FOLLOW_LINKS | CREAT_LAST_COMPONENT; + int ret = resolve_path(path, absolute_path, PATH_MAX, resolve_flags); + if (ret < 0) { pr_err("vfs_mkdir(%s): Cannot get the absolute path.\n", path); - return -ENODEV; + return ret; } pr_debug("vfs_mkdir(path: %s, mode: %d) -> absolute_path: %s\n", path, mode, absolute_path); super_block_t *sb = vfs_get_superblock(absolute_path); @@ -319,9 +322,11 @@ int vfs_rmdir(const char *path) // Allocate a variable for the path. char absolute_path[PATH_MAX]; // If the first character is not the '/' then get the absolute path. - if (resolve_path(path, absolute_path, sizeof(absolute_path), REMOVE_TRAILING_SLASH | FOLLOW_LINKS) < 0) { + int resolve_flags = REMOVE_TRAILING_SLASH | FOLLOW_LINKS; + int ret = resolve_path(path, absolute_path, PATH_MAX, resolve_flags); + if (ret < 0) { pr_err("vfs_rmdir(%s): Cannot get the absolute path.\n", path); - return -ENODEV; + return ret; } super_block_t *sb = vfs_get_superblock(absolute_path); if (sb == NULL) { @@ -347,9 +352,11 @@ vfs_file_t *vfs_creat(const char *path, mode_t mode) // Allocate a variable for the path. char absolute_path[PATH_MAX]; // If the first character is not the '/' then get the absolute path. - if (resolve_path(path, absolute_path, sizeof(absolute_path), REMOVE_TRAILING_SLASH | FOLLOW_LINKS) < 0) { + int resolve_flags = REMOVE_TRAILING_SLASH | FOLLOW_LINKS; + int ret = resolve_path(path, absolute_path, PATH_MAX, resolve_flags); + if (ret < 0) { pr_err("vfs_creat(%s): Cannot get the absolute path.\n", path); - errno = ENODEV; + errno = ret; return NULL; } super_block_t *sb = vfs_get_superblock(absolute_path); @@ -407,9 +414,11 @@ int vfs_symlink(const char *linkname, const char *path) // Allocate a variable for the path. char absolute_path[PATH_MAX]; // If the first character is not the '/' then get the absolute path. - if (resolve_path(path, absolute_path, sizeof(absolute_path), REMOVE_TRAILING_SLASH | FOLLOW_LINKS) < 0) { + int resolve_flags = REMOVE_TRAILING_SLASH | FOLLOW_LINKS; + int ret = resolve_path(path, absolute_path, PATH_MAX, resolve_flags); + if (ret < 0) { pr_err("vfs_symlink(%s, %s): Cannot get the absolute path.", linkname, path); - return -ENODEV; + return ret; } super_block_t *sb = vfs_get_superblock(absolute_path); if (sb == NULL) { @@ -436,10 +445,11 @@ int vfs_stat(const char *path, stat_t *buf) // Allocate a variable for the path. char absolute_path[PATH_MAX]; // If the first character is not the '/' then get the absolute path. - int ret = resolve_path(path, absolute_path, PATH_MAX, REMOVE_TRAILING_SLASH | FOLLOW_LINKS); + int resolve_flags = REMOVE_TRAILING_SLASH | FOLLOW_LINKS; + int ret = resolve_path(path, absolute_path, PATH_MAX, resolve_flags); if (ret < 0) { pr_err("vfs_stat(%s): Cannot get the absolute path.", path); - return -ret; + return ret; } super_block_t *sb = vfs_get_superblock(absolute_path); if (sb == NULL) { @@ -503,10 +513,12 @@ int vfs_mount(const char *type, const char *path, const char *args) // Allocate a variable for the path. char absolute_path[PATH_MAX]; // If the first character is not the '/' then get the absolute path. - if (resolve_path(args, absolute_path, sizeof(absolute_path), REMOVE_TRAILING_SLASH) < 0) { + int resolve_flags = 0; + int ret = resolve_path(args, absolute_path, PATH_MAX, resolve_flags); + if (ret < 0) { pr_err("vfs_mount(type: %s, path: %s, args: %s): Cannot get the absolute path\n", fst->name, path, args); - return -ENODEV; + return ret; } pr_debug("vfs_mount(type: %s, path: %s, args: %s (%s))\n", fst->name, path, args, absolute_path); vfs_file_t *file = fst->mount(path, absolute_path); From 87992057c73059fa507f5d7dcfe759df55cd95bc Mon Sep 17 00:00:00 2001 From: "Enrico Fraccaroli (Galfurian)" Date: Wed, 28 Aug 2024 10:20:25 -0400 Subject: [PATCH 14/18] Fix ps command. --- programs/ps.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/programs/ps.c b/programs/ps.c index 445476ca..33da7a06 100644 --- a/programs/ps.c +++ b/programs/ps.c @@ -9,10 +9,30 @@ #include #include #include +#include #define FORMAT_S "%5s %5s %6s %s\n" #define FORMAT "%5d %5d %6c %s\n" +static inline int __is_number(const char *str) +{ + // Check for NULL pointer. + if (str == NULL) { return 0; } + // Skip leading whitespace. + while (isspace((unsigned char)*str)) { str++; } + // Check if there is a sign at the beginning. + if (*str == '-' || *str == '+') { str++; } + // Check if the string is empty or only contains a sign. + if (*str == '\0') { return 0; } + // Check each character to ensure it's a digit + while (*str) { + if (!isdigit((unsigned char)*str)) { return 0; } + str++; + } + // If we reach here, all characters were digits. + return 1; +} + static inline void __iterate_proc_dirs(int proc_fd) { char absolute_path[PATH_MAX] = "/proc/"; @@ -49,6 +69,10 @@ static inline void __iterate_proc_dirs(int proc_fd) if (dent.d_type != DT_DIR) { continue; } + // Skip directories that are not PIDs. + if (!__is_number(dent.d_name)) { + continue; + } // Build the path to the stat file (i.e., `/proc//stat`). strcpy(absolute_path + 6, dent.d_name); strcat(absolute_path, "/stat"); From 547a11260258ef7a13300ae4dce35dd968d8e289 Mon Sep 17 00:00:00 2001 From: "Enrico Fraccaroli (Galfurian)" Date: Wed, 28 Aug 2024 10:29:12 -0400 Subject: [PATCH 15/18] Standardize debugging in EXT2. --- mentos/src/fs/ext2.c | 255 ++++++++++++++++++++++--------------------- 1 file changed, 130 insertions(+), 125 deletions(-) diff --git a/mentos/src/fs/ext2.c b/mentos/src/fs/ext2.c index 43bc52c1..cd517b57 100644 --- a/mentos/src/fs/ext2.c +++ b/mentos/src/fs/ext2.c @@ -585,7 +585,7 @@ static void ext2_dump_inode(ext2_filesystem_t *fs, ext2_inode_t *inode) /// @param dirent the object to dump. static void ext2_dump_dirent(ext2_dirent_t *dirent) { - pr_debug("Inode: %4u Rec. Len.: %4u Name Len.: %4u Type:%4s Name: %s\n", dirent->inode, dirent->rec_len, dirent->name_len, ext2_file_type_to_string(dirent->file_type), dirent->name); + pr_debug("Inode: %4u Rec. Len.: %4u Name Len.: %4u Type: %4s Name: %s\n", dirent->inode, dirent->rec_len, dirent->name_len, ext2_file_type_to_string(dirent->file_type), dirent->name); } /// @brief Dumps on debugging output the BGDT. @@ -982,15 +982,15 @@ static int ext2_write_block(ext2_filesystem_t *fs, uint32_t block_index, uint8_t /// @return 0 on success, -1 on failure. static int ext2_read_bgdt(ext2_filesystem_t *fs) { - pr_debug("Read BGDT for EXT2 filesystem (0x%x)\n", fs); - if (fs->block_groups) { - for (uint32_t i = 0; i < fs->bgdt_length; ++i) { - ext2_read_block(fs, fs->bgdt_start_block + i, (uint8_t *)((uintptr_t)fs->block_groups + (fs->block_size * i))); - } - return 0; + pr_debug("ext2_read_bgdt(%p)\n", fs); + if (!fs->block_groups) { + pr_err("The `block_groups` list is not initialized.\n"); + return -1; } - pr_err("The `block_groups` list is not initialized.\n"); - return -1; + for (uint32_t i = 0; i < fs->bgdt_length; ++i) { + ext2_read_block(fs, fs->bgdt_start_block + i, (uint8_t *)((uintptr_t)fs->block_groups + (fs->block_size * i))); + } + return 0; } /// @brief Writes the Block Group Descriptor Table (BGDT) to the block device associated with this filesystem. @@ -998,15 +998,15 @@ static int ext2_read_bgdt(ext2_filesystem_t *fs) /// @return 0 on success, -1 on failure. static int ext2_write_bgdt(ext2_filesystem_t *fs) { - pr_debug("Write BGDT for EXT2 filesystem (0x%x)\n", fs); - if (fs->block_groups) { - for (uint32_t i = 0; i < fs->bgdt_length; ++i) { - ext2_write_block(fs, fs->bgdt_start_block + i, (uint8_t *)((uintptr_t)fs->block_groups + (fs->block_size * i))); - } - return 0; + pr_debug("ext2_write_bgdt(%p)\n", fs); + if (!fs->block_groups) { + pr_err("The `block_groups` list is not initialized.\n"); + return -1; } - pr_err("The `block_groups` list is not initialized.\n"); - return -1; + for (uint32_t i = 0; i < fs->bgdt_length; ++i) { + ext2_write_block(fs, fs->bgdt_start_block + i, (uint8_t *)((uintptr_t)fs->block_groups + (fs->block_size * i))); + } + return 0; } /// @brief Reads an inode. @@ -1029,7 +1029,7 @@ 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", + // 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. @@ -1070,7 +1070,7 @@ 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", + // 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. @@ -1122,7 +1122,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("ext2_allocate_inode(inode: %4u, 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. @@ -1171,7 +1171,7 @@ static uint32_t ext2_allocate_block(ext2_filesystem_t *fs) // Compute the block index. block_index = (group_index * fs->superblock.blocks_per_group) + group_offset; // Log the allocation of the inode. - pr_debug("Allocate block (block_index:%u, group_index:%4u, group_offset:%4u)\n", block_index, group_index, group_offset); + pr_debug("ext2_allocate_block(block: %4u, group_index: %4u, group_offset: %4u)\n", block_index, group_index, group_offset); // Set the block as occupied. ext2_bitmap_set(cache, group_offset); // Update the bitmap. @@ -1213,7 +1213,7 @@ static void ext2_free_block(ext2_filesystem_t *fs, uint32_t block_index) uint32_t block_bitmap = fs->block_groups[group_index].block_bitmap; // Log the allocation of the inode. - pr_debug("Free block (block_index:%u, group_index:%4u, group_offset:%4u)\n", block_index, group_index, group_offset); + pr_debug("ext2_free_block(block: %4u, group_index: %4u, group_offset: %4u)\n", block_index, group_index, group_offset); // Allocate the cache. uint8_t *cache = ext2_alloc_cache(fs); @@ -1259,7 +1259,7 @@ static int ext2_free_inode(ext2_filesystem_t *fs, ext2_inode_t *inode, uint32_t uint32_t block_number = (inode->size / fs->block_size) + ((inode->size % fs->block_size) != 0); // Log the allocation of the inode. - pr_debug("Free inode (group_index:%u, inode_index:%4u, group_offset:%4u)\n", group_index, inode_index, group_offset); + pr_debug("ext2_free_inode(group: %4u, inode_index: %4u, group_offset: %4u)\n", group_index, inode_index, group_offset); // Free its blocks. for (uint32_t block_index = 0; block_index < block_number; ++block_index) { @@ -1375,14 +1375,13 @@ static int ext2_set_real_block_index( // Result of the operation. int ret = 0; - // Allocate the cache. - uint8_t *cache = ext2_alloc_cache(fs); - // Are we setting a DIRECT block pointer. a = ((int)block_index) - EXT2_DIRECT_BLOCKS; if (a <= 0) { inode->data.blocks.dir_blocks[block_index] = real_index; } else { + // Allocate the cache. + uint8_t *cache = ext2_alloc_cache(fs); // Are we setting an INDIRECT block pointer. b = a - p; if (b <= 0) { @@ -1462,10 +1461,10 @@ static int ext2_set_real_block_index( } } } + early_exit: + // Free the cache. + ext2_dealloc_cache(cache); } -early_exit: - // Free the cache. - ext2_dealloc_cache(cache); return ret; } @@ -1547,7 +1546,6 @@ 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 `%d` for inode `%d`.\n", block_index, inode_index); // Allocate the block. int real_index = ext2_allocate_block(fs); if (real_index == -1) { @@ -1557,6 +1555,7 @@ static int ext2_allocate_inode_block(ext2_filesystem_t *fs, ext2_inode_t *inode, if (ext2_set_real_block_index(fs, inode, inode_index, block_index, real_index) == -1) { return -1; } + pr_debug("ext2_allocate_inode_block(inode: %4u, block: %4u, real: %4u)\n", inode_index, block_index, real_index); // Compute the new blocks count. uint32_t blocks_count = (block_index + 1) * fs->blocks_per_block_count; if (inode->blocks_count < blocks_count) { @@ -1568,7 +1567,6 @@ 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; } @@ -1588,8 +1586,9 @@ static ssize_t ext2_read_inode_block(ext2_filesystem_t *fs, ext2_inode_t *inode, if (real_index == 0) { return -1; } + pr_debug("ext2_read_inode_block(block: %4u, real: %4u)\n", block_index, real_index); // 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); } @@ -1604,9 +1603,6 @@ 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("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) { pr_crit("Failed to write allocate inode block\n"); } @@ -1617,7 +1613,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("ext2_write_inode_block(block: %4u, inode: %4u, real: %4u)\n", block_index, inode_index, real_index); // Write the block. return ext2_write_block(fs, real_index, buffer); } @@ -1642,6 +1638,8 @@ static ssize_t ext2_read_inode_data(ext2_filesystem_t *fs, ext2_inode_t *inode, // How much bytes to read for the end block. uint32_t end_size = end_offset - end_block * fs->block_size; + pr_debug("ext2_read_inode_data(inode: %4u, offset: %4u, nbyte: %4u)\n", inode_index, offset, nbyte); + // Allocate the cache. uint8_t *cache = ext2_alloc_cache(fs); @@ -1651,7 +1649,7 @@ static ssize_t ext2_read_inode_data(ext2_filesystem_t *fs, ext2_inode_t *inode, // Read the real block. if (ext2_read_inode_block(fs, inode, block_index, cache) == -1) { // TODO: Understand why sometimes it fails. - pr_warning("Failed to read the inode block %u of inode %u\n", block_index, inode_index); + pr_warning("Failed to read the inode block %4u of inode %4u\n", block_index, inode_index); // ret = -1; // break; } @@ -1698,17 +1696,18 @@ static ssize_t ext2_write_inode_data(ext2_filesystem_t *fs, ext2_inode_t *inode, // How much bytes to read for the end block. uint32_t end_size = end_offset - end_block * fs->block_size; + pr_debug("ext2_write_inode_data(inode: %4u, offset: %4u, nbyte: %4u)\n", inode_index, offset, nbyte); + // Allocate the cache. 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) { - pr_debug("ext2_write_inode_data: index = %4u, start = %4u, end = %4u\n", - block_index, start_block, end_block); left = 0, right = fs->block_size; // Read the real block. Do not check for - ext2_read_inode_block(fs, inode, block_index, cache); - pr_debug("ext2_write_inode_data: read block %4u done.\n", block_index); + if (ext2_read_inode_block(fs, inode, block_index, cache) < 0) { + pr_warning("Failed to read the inode block %4u of inode %4u\n", block_index, inode_index); + } if (block_index == start_block) { left = start_off; } @@ -1720,8 +1719,6 @@ static ssize_t ext2_write_inode_data(ext2_filesystem_t *fs, ext2_inode_t *inode, // Move the offset. curr_off += (right - left + 1); // Write the block back. - pr_debug("ext2_write_inode_data: Write inode = %4u, block = %4u\n", - inode_index, block_index); if (!ext2_write_inode_block(fs, inode, inode_index, block_index, cache)) { pr_err("Failed to write the inode block %u of inode %u\n", block_index, inode_index); ret = -1; @@ -2629,7 +2626,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("creat(path: \"%s\", mode: %d)\n", path, mode); + pr_debug("ext2_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))) { @@ -2817,17 +2814,18 @@ 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("unlink(%s)\n", path); + pr_debug("ext2_unlink(%s)\n", path); + int ret = 0; // Get the name of the entry we want to unlink. const char *name = basename(path); if (name == NULL) { - pr_err("unlink(%s): Cannot get the basename.\n", path); + pr_err("ext2_unlink(%s): Cannot get the basename.\n", path); return -ENOENT; } // Get the EXT2 filesystem. ext2_filesystem_t *fs = get_ext2_filesystem(path); if (fs == NULL) { - pr_err("unlink(%s): Failed to get the EXT2 filesystem.\n", path); + pr_err("ext2_unlink(%s): Failed to get the EXT2 filesystem.\n", path); return -ENOENT; } // Prepare the structure for the search. @@ -2835,13 +2833,13 @@ static int ext2_unlink(const char *path) memset(&search, 0, sizeof(ext2_direntry_search_t)); // Resolve the path to the directory entry. if (ext2_resolve_path(fs->root, path, &search)) { - pr_err("unlink(%s): Failed to resolve path.\n", path); + pr_err("ext2_unlink(%s): Failed to resolve path.\n", 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) { - pr_err("unlink(%s): Failed to read the inode of parent (%d).\n", path, search.parent_inode); + pr_err("ext2_unlink(%s): Failed to read the inode of parent (%d).\n", path, search.parent_inode); return -ENOENT; } // Allocate the cache. @@ -2849,14 +2847,17 @@ static int ext2_unlink(const char *path) // Read the block where the direntry resides. if (ext2_read_inode_block(fs, &parent_inode, search.block_index, cache) == -1) { - pr_err("unlink(%s): Failed to read the parent inode block (%d).\n", path, search.block_index); - goto free_cache_return_error; + pr_err("ext2_unlink(%s): Failed to read the parent inode block (%d).\n", path, search.block_index); + ret = -1; + goto early_exit; } // 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("unlink(%s): We found a NULL ext2_dirent_t.\n", path); - goto free_cache_return_error; + pr_err("ext2_unlink(%s): We found a NULL ext2_dirent_t.\n", path); + + ret = -1; + goto early_exit; } // Clear the directory entry. actual_dirent->inode = 0; @@ -2865,15 +2866,17 @@ static int ext2_unlink(const char *path) actual_dirent->file_type = ext2_file_type_unknown; // Write back the parent directory block. if (!ext2_write_inode_block(fs, &parent_inode, search.parent_inode, search.block_index, cache)) { - pr_err("unlink(%s): Failed to write the inode block (%d).\n", path, search.block_index); - goto free_cache_return_error; + pr_err("ext2_unlink(%s): Failed to write the inode block (%d).\n", path, search.block_index); + ret = -1; + goto early_exit; } // 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("unlink(%s): Failed to read the inode (%d: %s).\n", + pr_err("ext2_unlink(%s): Failed to read the inode (%d: %s).\n", path, search.direntry.inode, search.direntry.name); - goto free_cache_return_error; + ret = -1; + goto early_exit; } if (--inode.links_count == 0) { // Free the inode. @@ -2881,19 +2884,16 @@ static int ext2_unlink(const char *path) } else { // Update the inode. if (ext2_write_inode(fs, &inode, search.direntry.inode) == -1) { - pr_err("unlink(%s): Failed to update the inode (%d: %s).\n", + pr_err("ext2_unlink(%s): Failed to update the inode (%d: %s).\n", path, search.direntry.inode, search.direntry.name); - goto free_cache_return_error; + ret = -1; + goto early_exit; } } - - // Free the cache. - ext2_dealloc_cache(cache); - return 0; -free_cache_return_error: +early_exit: // Free the cache. ext2_dealloc_cache(cache); - return -1; + return ret; } /// @brief Closes the given file. @@ -2911,7 +2911,7 @@ static int ext2_close(vfs_file_t *file) if (file == fs->root) { return -1; } - pr_debug("close(ino: %d, file: \"%s\")\n", file->ino, file->name); + pr_debug("ext2_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. @@ -2927,7 +2927,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("read(%s, %p, %d, %d)\n", file->name, buffer, offset, nbyte); + pr_debug("ext2_read(file: %s, offset: %4u, nbyte: %4u)\n", file->name, offset, nbyte); // Get the filesystem. ext2_filesystem_t *fs = (ext2_filesystem_t *)file->device; if (fs == NULL) { @@ -2956,6 +2956,7 @@ static ssize_t ext2_read(vfs_file_t *file, char *buffer, off_t offset, size_t nb /// @return The number of written bytes. static ssize_t ext2_write(vfs_file_t *file, const void *buffer, off_t offset, size_t nbyte) { + pr_debug("ext2_write(file: %s, offset: %4u, nbyte: %4u)\n", file->name, offset, nbyte); // Get the filesystem. ext2_filesystem_t *fs = (ext2_filesystem_t *)file->device; if (fs == NULL) { @@ -2988,6 +2989,7 @@ static ssize_t ext2_write(vfs_file_t *file, const void *buffer, off_t offset, si /// indicate the error. static off_t ext2_lseek(vfs_file_t *file, off_t offset, int whence) { + pr_debug("ext2_lseek(file: %s, offset: %4u, whence: %4u)\n", file->name, offset, whence); // Get the filesystem. ext2_filesystem_t *fs = (ext2_filesystem_t *)file->device; if (fs == NULL) { @@ -3055,6 +3057,7 @@ static int ext2_fstat(vfs_file_t *file, stat_t *stat) pr_err("We received a NULL stat pointer.\n"); return -EFAULT; } + pr_debug("ext2_fstat(file: %s)\n", file->name); // Get the filesystem. ext2_filesystem_t *fs = (ext2_filesystem_t *)file->device; if (fs == NULL) { @@ -3075,6 +3078,41 @@ static int ext2_fstat(vfs_file_t *file, stat_t *stat) return __ext2_stat(&inode, stat); } +/// @brief Retrieves information concerning the file at the given position. +/// @param path The path where the file resides. +/// @param stat The structure where the information are stored. +/// @return 0 if success. +static int ext2_stat(const char *path, stat_t *stat) +{ + pr_debug("ext2_fstat(path: %s)\n", path); + // Get the EXT2 filesystem. + ext2_filesystem_t *fs = get_ext2_filesystem(path); + if (fs == NULL) { + pr_err("stat(%s): Failed to get the EXT2 filesystem.\n", path); + return -ENOENT; + } + // Prepare the structure for the search. + ext2_direntry_search_t search; + memset(&search, 0, sizeof(ext2_direntry_search_t)); + // Resolve the path. + if (ext2_resolve_path(fs->root, path, &search)) { + pr_err("stat(%s): Failed to resolve path.\n", 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("stat(%s): Failed to read the inode of `%s`.\n", path, search.direntry.name); + return -ENOENT; + } + /// ID of device containing file. + stat->st_dev = fs->block_device->ino; + // Set the inode. + stat->st_ino = search.direntry.inode; + // Set the rest of the structure. + 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. @@ -3096,7 +3134,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("getdents(%s, %p, %d, %d)\n", file->name, dirp, doff, count); + pr_debug("ext2_getdents(file: %s, doff: %4u, count: %4u)\n", file->name, doff, count); // Get the filesystem. ext2_filesystem_t *fs = (ext2_filesystem_t *)file->device; if (fs == NULL) { @@ -3151,20 +3189,20 @@ static ssize_t ext2_getdents(vfs_file_t *file, dirent_t *dirp, off_t doff, size_ /// set to indicate the error. static ssize_t ext2_readlink(const char *path, char *buffer, size_t bufsize) { - pr_debug("ext2_readlink(%s, %s, %d)\n", path, buffer, bufsize); + pr_debug("ext2_readlink(path: %s)\n", path); super_block_t *sb = vfs_get_superblock(path); if (sb == NULL) { - pr_err("ext2_readlink(%s, %s, %d): Cannot find the superblock!.\n", path, buffer, bufsize); + pr_err("ext2_readlink(path: %s): Cannot find the superblock!.\n", path); return -ENODEV; } if (sb->root == NULL) { - pr_err("ext2_readlink(%s, %s, %d): Cannot find the superblock root.\n", path, buffer, bufsize); + pr_err("ext2_readlink(path: %s): Cannot find the superblock root.\n", path); return -ENOENT; } // Get the filesystem. ext2_filesystem_t *fs = (ext2_filesystem_t *)sb->root->device; if (fs == NULL) { - pr_err("ext2_readlink(%s, %s, %d): The file does not belong to an EXT2 filesystem.\n", path, buffer, bufsize); + pr_err("ext2_readlink(path: %s): The file does not belong to an EXT2 filesystem.\n", path); return -ENOENT; } // Prepare the structure for the search. @@ -3172,13 +3210,13 @@ static ssize_t ext2_readlink(const char *path, char *buffer, size_t bufsize) memset(&search, 0, sizeof(ext2_direntry_search_t)); // Resolve the path to the directory entry. if (ext2_resolve_path(sb->root, path, &search)) { - pr_err("ext2_readlink(%s, %s, %d): Failed to resolve path.\n", path, buffer, bufsize); + pr_err("ext2_readlink(path: %s): Failed to resolve path.\n", path); return -ENOENT; } // Get the inode associated with the file. ext2_inode_t inode; if (ext2_read_inode(fs, &inode, search.direntry.inode) == -1) { - pr_err("ext2_readlink(%s, %s, %d): Failed to read the inode (%d).\n", path, buffer, bufsize, search.direntry.inode); + pr_err("ext2_readlink(path: %s): Failed to read the inode (%d).\n", path, search.direntry.inode); return -ENOENT; } if ((inode.mode & S_IFLNK) == S_IFLNK) { @@ -3200,7 +3238,7 @@ static ssize_t ext2_readlink(const char *path, char *buffer, size_t bufsize) /// @return Returns a negative value on failure. static int ext2_mkdir(const char *path, mode_t permission) { - pr_debug("mkdir(%s, %d)\n", path, permission); + pr_debug("ext2_mkdir(path: %s, permission: %u)\n", path, permission); // Get the parent directory. char parent_path[PATH_MAX]; if (!dirname(path, parent_path, sizeof(parent_path))) { @@ -3208,20 +3246,20 @@ static int ext2_mkdir(const char *path, mode_t permission) } // Check the parent path. if (strcmp(parent_path, path) == 0) { - pr_err("mkdir(%s): Failed to properly get the parent directory (%s).\n", path, parent_path); + pr_err("ext2_mkdir(path: %s): Failed to properly get the parent directory (%s).\n", path, parent_path); return -ENOENT; } // Get the EXT2 filesystem. ext2_filesystem_t *fs = get_ext2_filesystem(path); if (fs == NULL) { - pr_err("mkdir(%s): Failed to get the EXT2 filesystem.\n", path); + pr_err("ext2_mkdir(path: %s): Failed to get the EXT2 filesystem.\n", path); return -ENOENT; } // Prepare the structure for the search. ext2_direntry_search_t search; // Search if the entry already exists. if (!ext2_resolve_path(fs->root, path, &search)) { - pr_err("mkdir(%s): Directory already exists.\n", path); + pr_err("ext2_mkdir(path: %s): Directory already exists.\n", path); return -EEXIST; } // Set the inode mode. @@ -3234,7 +3272,7 @@ static int ext2_mkdir(const char *path, mode_t permission) // Create and initialize the new inode. int inode_index = ext2_create_inode(fs, &inode, mode, group_index); if (inode_index == -1) { - pr_err("mkdir(%s): Failed to create a new inode (group index: %d).\n", path, group_index); + pr_err("ext2_mkdir(path: %s): Failed to create a new inode (group index: %d).\n", path, group_index); return -ENOENT; } // Increase the number of directories inside the group. @@ -3248,22 +3286,22 @@ static int ext2_mkdir(const char *path, mode_t permission) const char *directory_name = basename(path); // Create a directory entry for the directory. 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); + pr_err("ext2_mkdir(path: %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("mkdir(%s): Failed to allocate a new block for an inode.\n", path); + pr_err("ext2_mkdir(path: %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("mkdir(%s): Failed to allocate a new direntry for the inode.\n", path); + pr_err("ext2_mkdir(path: %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, search.parent_inode, "..", ext2_file_type_directory) == -1) { - pr_err("mkdir(%s): Failed to allocate a new direntry for the inode.\n", path); + pr_err("ext2_mkdir(path: %s): Failed to allocate a new direntry for the inode.\n", path); return -ENOENT; } return 0; @@ -3274,17 +3312,17 @@ 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("rmdir(%s)\n", path); + pr_debug("ext2_rmdir(path: %s)\n", path); // Get the name of the entry we want to unlink. const char *name = basename(path); if (name == NULL) { - pr_err("rmdir(%s): Cannot get the basename`.\n", path); + pr_err("ext2_rmdir(path: %s): Cannot get the basename`.\n", path); return -ENOENT; } // Get the EXT2 filesystem. ext2_filesystem_t *fs = get_ext2_filesystem(path); if (fs == NULL) { - pr_err("rmdir(%s): Failed to get the EXT2 filesystem.\n", path); + pr_err("ext2_rmdir(path: %s): Failed to get the EXT2 filesystem.\n", path); return -ENOENT; } // Prepare the structure for the search. @@ -3292,60 +3330,25 @@ 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, path, &search)) { - pr_err("rmdir(%s): Failed to resolve path.\n", path); + pr_err("ext2_rmdir(path: %s): Failed to resolve path.\n", 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("rmdir(%s): Failed to read the inode of parent of `%s`.\n", path, search.direntry.name); + pr_err("ext2_rmdir(path: %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("rmdir(%s): Failed to read the inode of `%s`.\n", path, search.direntry.name); + pr_err("ext2_rmdir(path: %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); } -/// @brief Retrieves information concerning the file at the given position. -/// @param path The path where the file resides. -/// @param stat The structure where the information are stored. -/// @return 0 if success. -static int ext2_stat(const char *path, stat_t *stat) -{ - pr_debug("stat(%s, %p)\n", path, stat); - // Get the EXT2 filesystem. - ext2_filesystem_t *fs = get_ext2_filesystem(path); - if (fs == NULL) { - pr_err("stat(%s): Failed to get the EXT2 filesystem.\n", path); - return -ENOENT; - } - // Prepare the structure for the search. - ext2_direntry_search_t search; - memset(&search, 0, sizeof(ext2_direntry_search_t)); - // Resolve the path. - if (ext2_resolve_path(fs->root, path, &search)) { - pr_err("stat(%s): Failed to resolve path.\n", 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("stat(%s): Failed to read the inode of `%s`.\n", path, search.direntry.name); - return -ENOENT; - } - /// ID of device containing file. - stat->st_dev = fs->block_device->ino; - // Set the inode. - stat->st_ino = search.direntry.inode; - // Set the rest of the structure. - return __ext2_stat(&inode, stat); -} - /// @brief Sets the attributes of an inode and saves it /// @param inode The inode to set the attributes /// @param attr The structure where the attributes are stored. @@ -3388,6 +3391,7 @@ static int __ext2_check_setattr_permission(uid_t file_owner) /// @return 0 if success. static int ext2_fsetattr(vfs_file_t *file, struct iattr *attr) { + pr_debug("ext2_fsetattr(file: %s)\n", file->name); if (!__ext2_check_setattr_permission(file->uid)) { return -EPERM; } @@ -3413,7 +3417,7 @@ 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("setattr(%s, %p)\n", path, attr); + pr_debug("ext2_setattr(file: %s)\n", path); // Get the EXT2 filesystem. ext2_filesystem_t *fs = get_ext2_filesystem(path); if (fs == NULL) { @@ -3447,6 +3451,7 @@ static int ext2_setattr(const char *path, struct iattr *attr) /// @return the VFS root node of the EXT2 filesystem. static vfs_file_t *ext2_mount(vfs_file_t *block_device, const char *path) { + pr_debug("ext2_mount(device: %s, path: %s)\n", block_device->name, path); // Create the ext2 filesystem. ext2_filesystem_t *fs = kmalloc(sizeof(ext2_filesystem_t)); // Clean the memory. From 61f913783c7d9642dbe7cbbe47173544ffaa7d31 Mon Sep 17 00:00:00 2001 From: "Enrico Fraccaroli (Galfurian)" Date: Thu, 29 Aug 2024 13:23:22 -0400 Subject: [PATCH 16/18] - Fix tokenizer function; - Fix __resolve_path function; - Improve on ls and touch output; - Standardize how VFS handles errors; --- libc/src/string.c | 10 +++++-- mentos/src/fs/ext2.c | 56 +++++++++++++++++++++------------------- mentos/src/fs/namei.c | 46 +++++++++++++++++++-------------- mentos/src/fs/vfs.c | 13 +++++----- mentos/src/klib/string.c | 10 +++++-- programs/login.c | 17 ++++++------ programs/ls.c | 20 +++----------- programs/touch.c | 2 ++ 8 files changed, 93 insertions(+), 81 deletions(-) diff --git a/libc/src/string.c b/libc/src/string.c index c57c59e3..525e7a77 100644 --- a/libc/src/string.c +++ b/libc/src/string.c @@ -224,8 +224,14 @@ int tokenize(const char *string, const char *separators, size_t *offset, char *b if ((*offset >= buflen) || (string[*offset] == 0)) { return 0; } - // If the first character is a separator, skip it. - *offset += (*offset == 0) && strchr(separators, string[*offset]); + // Skip any leading (multiple) separators. + while (string[*offset] != 0 && strchr(separators, string[*offset])) { + ++(*offset); + } + // If we reach the end after skipping, return 0. + if (string[*offset] == 0) { + return 0; + } // Keep copying character until we either reach 1) the end of the buffer, 2) a // separator, or 3) the end of the string we are parsing. do { diff --git a/mentos/src/fs/ext2.c b/mentos/src/fs/ext2.c index cd517b57..79465ccb 100644 --- a/mentos/src/fs/ext2.c +++ b/mentos/src/fs/ext2.c @@ -4,10 +4,12 @@ /// 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. +// If defined, ETX2 will debug everything. +// #define EXT2_FULL_DEBUG #include "assert.h" #include "fcntl.h" @@ -1586,9 +1588,10 @@ static ssize_t ext2_read_inode_block(ext2_filesystem_t *fs, ext2_inode_t *inode, if (real_index == 0) { return -1; } - pr_debug("ext2_read_inode_block(block: %4u, real: %4u)\n", block_index, real_index); // Log the address to the inode block. - // pr_debug("Read inode block (block_index: %4u, real_index: %4u)\n", block_index, real_index); +#ifdef EXT2_FULL_DEBUG + pr_debug("ext2_read_inode_block(block: %4u, real: %4u)\n", block_index, real_index); +#endif // Read the block. return ext2_read_block(fs, real_index, buffer); } @@ -1613,7 +1616,9 @@ static ssize_t ext2_write_inode_block(ext2_filesystem_t *fs, ext2_inode_t *inode return -1; } // Log the address to the inode block. +#ifdef EXT2_FULL_DEBUG pr_debug("ext2_write_inode_block(block: %4u, inode: %4u, real: %4u)\n", block_index, inode_index, real_index); +#endif // Write the block. return ext2_write_block(fs, real_index, buffer); } @@ -1638,7 +1643,9 @@ static ssize_t ext2_read_inode_data(ext2_filesystem_t *fs, ext2_inode_t *inode, // How much bytes to read for the end block. uint32_t end_size = end_offset - end_block * fs->block_size; +#ifdef EXT2_FULL_DEBUG pr_debug("ext2_read_inode_data(inode: %4u, offset: %4u, nbyte: %4u)\n", inode_index, offset, nbyte); +#endif // Allocate the cache. uint8_t *cache = ext2_alloc_cache(fs); @@ -1696,7 +1703,9 @@ static ssize_t ext2_write_inode_data(ext2_filesystem_t *fs, ext2_inode_t *inode, // How much bytes to read for the end block. uint32_t end_size = end_offset - end_block * fs->block_size; +#ifdef EXT2_FULL_DEBUG pr_debug("ext2_write_inode_data(inode: %4u, offset: %4u, nbyte: %4u)\n", inode_index, offset, nbyte); +#endif // Allocate the cache. uint8_t *cache = ext2_alloc_cache(fs); @@ -2927,7 +2936,9 @@ 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) { +#ifdef EXT2_FULL_DEBUG pr_debug("ext2_read(file: %s, offset: %4u, nbyte: %4u)\n", file->name, offset, nbyte); +#endif // Get the filesystem. ext2_filesystem_t *fs = (ext2_filesystem_t *)file->device; if (fs == NULL) { @@ -2956,7 +2967,9 @@ static ssize_t ext2_read(vfs_file_t *file, char *buffer, off_t offset, size_t nb /// @return The number of written bytes. static ssize_t ext2_write(vfs_file_t *file, const void *buffer, off_t offset, size_t nbyte) { +#ifdef EXT2_FULL_DEBUG pr_debug("ext2_write(file: %s, offset: %4u, nbyte: %4u)\n", file->name, offset, nbyte); +#endif // Get the filesystem. ext2_filesystem_t *fs = (ext2_filesystem_t *)file->device; if (fs == NULL) { @@ -3190,26 +3203,17 @@ static ssize_t ext2_getdents(vfs_file_t *file, dirent_t *dirp, off_t doff, size_ static ssize_t ext2_readlink(const char *path, char *buffer, size_t bufsize) { pr_debug("ext2_readlink(path: %s)\n", path); - super_block_t *sb = vfs_get_superblock(path); - if (sb == NULL) { - pr_err("ext2_readlink(path: %s): Cannot find the superblock!.\n", path); - return -ENODEV; - } - if (sb->root == NULL) { - pr_err("ext2_readlink(path: %s): Cannot find the superblock root.\n", path); - return -ENOENT; - } - // Get the filesystem. - ext2_filesystem_t *fs = (ext2_filesystem_t *)sb->root->device; + // Get the EXT2 filesystem. + ext2_filesystem_t *fs = get_ext2_filesystem(path); if (fs == NULL) { - pr_err("ext2_readlink(path: %s): The file does not belong to an EXT2 filesystem.\n", path); + pr_err("ext2_readlink(path: %s): Failed to get the EXT2 filesystem.\n", path); return -ENOENT; } // Prepare the structure for the search. ext2_direntry_search_t search; memset(&search, 0, sizeof(ext2_direntry_search_t)); - // Resolve the path to the directory entry. - if (ext2_resolve_path(sb->root, path, &search)) { + // Resolve the path. + if (ext2_resolve_path(fs->root, path, &search)) { pr_err("ext2_readlink(path: %s): Failed to resolve path.\n", path); return -ENOENT; } @@ -3219,17 +3223,15 @@ static ssize_t ext2_readlink(const char *path, char *buffer, size_t bufsize) pr_err("ext2_readlink(path: %s): Failed to read the inode (%d).\n", path, search.direntry.inode); return -ENOENT; } + ssize_t ret = -ENOENT; if ((inode.mode & S_IFLNK) == S_IFLNK) { // Get the length of the symlink. - ssize_t nbytes = min(strlen(inode.data.symlink), bufsize); + ret = min(strlen(inode.data.symlink), bufsize); // Copy the symlink information. - strncpy(buffer, inode.data.symlink, nbytes); - // Return how much we read. - return nbytes; - } else { - return -ENOLINK; + strncpy(buffer, inode.data.symlink, ret); } - return 0; + // Return how much we read. + return ret; } /// @brief Creates a new directory at the given path. diff --git a/mentos/src/fs/namei.c b/mentos/src/fs/namei.c index 24c29e5a..a80691a9 100644 --- a/mentos/src/fs/namei.c +++ b/mentos/src/fs/namei.c @@ -3,15 +3,21 @@ /// @copyright (c) 2014-2024 This file is distributed under the MIT License. /// 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__ "[NAMEI ]" ///< Change header. +#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE ///< Set log level. +#include "io/debug.h" // Include debugging functions. + #include "fs/namei.h" #include "assert.h" #include "limits.h" #include "fcntl.h" #include "sys/stat.h" #include "fs/vfs.h" -#include "io/debug.h" #include "process/scheduler.h" #include "sys/errno.h" +#include "strerror.h" #include "string.h" /// Appends the path with a "/" as separator. @@ -100,7 +106,7 @@ static inline int __get_link_content(const char *path, char *link, size_t length { ssize_t link_length = vfs_readlink(path, link, length); if (link_length < 0) { - return -errno; + return link_length; } // Null-terminate link. link[link_length] = 0; @@ -120,6 +126,8 @@ int __resolve_path(const char *path, char *abspath, size_t buflen, int flags, in // Get the working directory of the current task. sys_getcwd(buffer, buflen); pr_debug("|%-32s|%-32s| (INIT)\n", path, buffer); + } else { + pr_debug("|%-32s|%-32s| (INIT)\n", path, buffer); } while (tokenize(path, "/", &offset, token, NAME_MAX)) { @@ -134,17 +142,20 @@ int __resolve_path(const char *path, char *abspath, size_t buflen, int flags, in // from the root). buffer[0] = '/'; buffer[1] = 0; + pr_debug("|%-32s|%-32s| (RESET)\n", path, buffer); } else { // Truncate at the last slash. *last_slash = '\0'; + pr_debug("|%-32s|%-32s| (TRUNCATE)\n", path, buffer); } } } else if ((strcmp(token, ".") == 0) && (tokenlen == 1)) { // Nothing to do. } else { - if (strlen(buffer) + strlen(token) + 1 < buflen) { + if (strlen(buffer) + tokenlen + 1 < buflen) { APPEND_PATH_SEPARATOR(buffer, buflen); APPEND_PATH(buffer, token); + pr_debug("|%-32s|%-32s|%d| (APPEND)\n", path, buffer, tokenlen); } else { pr_err("Buffer overflow while resolving path.\n"); return -ENAMETOOLONG; @@ -160,6 +171,7 @@ int __resolve_path(const char *path, char *abspath, size_t buflen, int flags, in if (linkpath[0] == '/') { memcpy(buffer, linkpath, linklen); + pr_debug("|%-32s|%-32s| (REPLACE)\n", path, buffer); } else { // Find the last occurrence of '/'. char *last_slash = strrchr(buffer, '/'); @@ -169,30 +181,26 @@ int __resolve_path(const char *path, char *abspath, size_t buflen, int flags, in } } contains_links = 1; - } else if (link_length < 0) { - // This is the last path component and we want to create it anyway. - if ((link_length == -ENOENT) && !strchr(path + offset, '/') && (flags & CREAT_LAST_COMPONENT)) { - } else { - pr_err("Cannot find entry `%s`.\n", buffer); - return link_length; - } } } } - pr_debug("|%-32s|%-32s|\n", path, buffer); } if (contains_links) { pr_debug("|%-32s|%-32s| (RECU)\n", path, buffer); return __resolve_path(buffer, abspath, buflen, flags, ++link_depth); - } else { - // Remove trailing slash if requested. - if (flags & REMOVE_TRAILING_SLASH) { - size_t buffer_end = strnlen(buffer, buflen) - 1; - if (buffer[buffer_end] == '/') { buffer[buffer_end] = 0; } - } - strncpy(abspath, buffer, buflen); - pr_debug("|%-32s|%-32s| (END)\n", path, buffer); } + // Get the end of the buffer. + size_t buffer_end = strnlen(buffer, buflen); + // If the buffer is empty, set it to '/', or remove trailing slash if requested. + if (buffer_end == 0) { + buffer[0] = '/'; + buffer[1] = 0; + } else if ((flags & REMOVE_TRAILING_SLASH) && (buffer_end > 1) && (buffer[buffer_end - 1] == '/')) { + pr_debug("|%-32s|%-32s|(%u) (REMTRAIL)\n", path, buffer, buffer_end); + buffer[buffer_end] = 0; + } + strncpy(abspath, buffer, buflen); + pr_debug("|%-32s|%-32s|(%u) (END)\n", path, buffer, buffer_end); return 0; } diff --git a/mentos/src/fs/vfs.c b/mentos/src/fs/vfs.c index 0c241eeb..e498ae91 100644 --- a/mentos/src/fs/vfs.c +++ b/mentos/src/fs/vfs.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__ "[VFS ]" ///< 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__ "[VFS ]" ///< Change header. +#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE ///< Set log level. +#include "io/debug.h" // Include debugging functions. #include "fcntl.h" #include "sys/stat.h" @@ -123,6 +123,7 @@ int vfs_unregister_superblock(super_block_t *sb) super_block_t *vfs_get_superblock(const char *path) { + pr_debug("vfs_get_superblock(path: %s)\n", path); size_t last_sb_len = 0, len; super_block_t *last_sb = NULL, *sb = NULL; list_head *it; @@ -396,14 +397,14 @@ ssize_t vfs_readlink(const char *path, char *buffer, size_t bufsize) super_block_t *sb = vfs_get_superblock(path); if (sb == NULL) { pr_err("vfs_readlink(%s, %s, %d): Cannot find the superblock!.\n", path, buffer, bufsize); - return -ENODEV; + return -ENOENT; } if (sb->root == NULL) { pr_err("vfs_readlink(%s, %s, %d): Cannot find the superblock root.\n", path, buffer, bufsize); return -ENOENT; } if (sb->root->fs_operations->readlink_f == NULL) { - return -ENOSYS; + return -ENOENT; } // Perform the read. return sb->root->fs_operations->readlink_f(path, buffer, bufsize); diff --git a/mentos/src/klib/string.c b/mentos/src/klib/string.c index eae471ff..f33c35ce 100644 --- a/mentos/src/klib/string.c +++ b/mentos/src/klib/string.c @@ -224,8 +224,14 @@ int tokenize(const char *string, const char *separators, size_t *offset, char *b if ((*offset >= buflen) || (string[*offset] == 0)) { return 0; } - // If the first character is a separator, skip it. - *offset += (*offset == 0) && strchr(separators, string[*offset]); + // Skip any leading (multiple) separators. + while (string[*offset] != 0 && strchr(separators, string[*offset])) { + ++(*offset); + } + // If we reach the end after skipping, return 0. + if (string[*offset] == 0) { + return 0; + } // Keep copying character until we either reach 1) the end of the buffer, 2) a // separator, or 3) the end of the string we are parsing. do { diff --git a/programs/login.c b/programs/login.c index 246ccc3c..a72c9134 100644 --- a/programs/login.c +++ b/programs/login.c @@ -178,17 +178,16 @@ int main(int argc, char **argv) __print_message_file("/etc/issue"); passwd_t *pwd; - char username[CREDENTIALS_LENGTH] = "user", password[CREDENTIALS_LENGTH] = "user"; + char username[CREDENTIALS_LENGTH], password[CREDENTIALS_LENGTH]; do { // Get the username. - // do { - // printf("Username: "); - // } while (!__get_input(username, sizeof(username), false)); - - // // Get the password. - // do { - // printf("Password: "); - // } while (!__get_input(password, sizeof(password), true)); + do { + printf("Username: "); + } while (!__get_input(username, sizeof(username), false)); + // Get the password. + do { + printf("Password: "); + } while (!__get_input(password, sizeof(password), true)); // Check if we can find the user. if ((pwd = getpwnam(username)) == NULL) { diff --git a/programs/ls.c b/programs/ls.c index d56390ba..9b316667 100644 --- a/programs/ls.c +++ b/programs/ls.c @@ -135,23 +135,10 @@ static inline void print_dir_entry(dirent_t *dirent, const char *path, unsigned static void print_ls(const char *path, unsigned int flags) { - // Read the link, if the path points to one. - char real_path[PATH_MAX] = { 0 }, link_path[PATH_MAX] = { 0 }; - ssize_t link_len = readlink(path, link_path, sizeof(link_path)); - if (link_len > 0) { - link_path[link_len] = '\0'; - if (realpath(link_path, real_path, sizeof(real_path)) != real_path) { - printf("ls: cannot resolve path '%s': %s\n", real_path, strerror(errno)); - return; - } - } else { - strncpy(real_path, path, strlen(path)); - } - // Open the directory. - int fd = open(real_path, O_RDONLY | O_DIRECTORY, 0); + int fd = open(path, O_RDONLY | O_DIRECTORY, 0); if (fd == -1) { - printf("ls: cannot access '%s': %s\n", real_path, strerror(errno)); + printf("ls: cannot access '%s': %s\n", path, strerror(errno)); return; } @@ -162,7 +149,7 @@ static void print_ls(const char *path, unsigned int flags) 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], real_path, flags, &total_size); + print_dir_entry(&dents[i], path, flags, &total_size); } } if (bytes_read < 0) { @@ -218,6 +205,7 @@ int main(int argc, char *argv[]) char cwd[PATH_MAX]; getcwd(cwd, PATH_MAX); print_ls(cwd, flags); + printf("\n"); } return 0; } diff --git a/programs/touch.c b/programs/touch.c index 942349db..22a8d89f 100644 --- a/programs/touch.c +++ b/programs/touch.c @@ -27,7 +27,9 @@ int main(int argc, char **argv) int fd = open(argv[1], O_CREAT, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH); if (fd < 0) { err(EXIT_FAILURE, "cannot touch %s", argv[1]); + printf("\n"); } close(fd); + printf("\n"); return 0; } From f384cb91f74200ad496e150c60d501a45329d1dd Mon Sep 17 00:00:00 2001 From: "Enrico Fraccaroli (Galfurian)" Date: Fri, 30 Aug 2024 11:00:40 -0400 Subject: [PATCH 17/18] - Fix how file modes are read; - In , first check if a path is a link before trying to read the link; --- libc/inc/sys/stat.h | 15 ++++++++------- mentos/src/fs/ext2.c | 10 +++++----- mentos/src/fs/namei.c | 32 ++++++++++++++++++++++++++++---- mentos/src/fs/vfs.c | 27 +++++++++++++-------------- programs/stat.c | 2 +- 5 files changed, 55 insertions(+), 31 deletions(-) diff --git a/libc/inc/sys/stat.h b/libc/inc/sys/stat.h index 1b99b1ec..691d49f6 100644 --- a/libc/inc/sys/stat.h +++ b/libc/inc/sys/stat.h @@ -26,13 +26,14 @@ /// @defgroup FileTypeTest File Type Test Macros /// @brief These macros allows to easily identify file types. /// @{ -#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) ///< Check if the input values identifies a socket. -#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) ///< Check if the input values identifies a symbolic link. -#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) ///< Check if the input values identifies a regular file. -#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) ///< Check if the input values identifies a block special. -#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) ///< Check if the input values identifies a directory. -#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) ///< Check if the input values identifies a char special. -#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) ///< Check if the input values identifies a fifo. +#define S_ISTYPE(mode, mask) (((mode) & S_IFMT) == (mask)) +#define S_ISSOCK(mode) (S_ISTYPE(mode, S_IFSOCK)) ///< Check if a socket. +#define S_ISLNK(mode) (S_ISTYPE(mode, S_IFLNK)) ///< Check if a symbolic link. +#define S_ISREG(mode) (S_ISTYPE(mode, S_IFREG)) ///< Check if a regular file. +#define S_ISBLK(mode) (S_ISTYPE(mode, S_IFBLK)) ///< Check if a block special. +#define S_ISDIR(mode) (S_ISTYPE(mode, S_IFDIR)) ///< Check if a directory. +#define S_ISCHR(mode) (S_ISTYPE(mode, S_IFCHR)) ///< Check if a char special. +#define S_ISFIFO(mode) (S_ISTYPE(mode, S_IFIFO)) ///< Check if a fifo. /// @} /// @defgroup ModeBitsAccessPermission Mode Bits for Access Permission diff --git a/mentos/src/fs/ext2.c b/mentos/src/fs/ext2.c index 79465ccb..2ec0f699 100644 --- a/mentos/src/fs/ext2.c +++ b/mentos/src/fs/ext2.c @@ -3097,11 +3097,11 @@ static int ext2_fstat(vfs_file_t *file, stat_t *stat) /// @return 0 if success. static int ext2_stat(const char *path, stat_t *stat) { - pr_debug("ext2_fstat(path: %s)\n", path); + pr_debug("ext2_stat(path: %s)\n", path); // Get the EXT2 filesystem. ext2_filesystem_t *fs = get_ext2_filesystem(path); if (fs == NULL) { - pr_err("stat(%s): Failed to get the EXT2 filesystem.\n", path); + pr_err("ext2_stat(path: %s): Failed to get the EXT2 filesystem.\n", path); return -ENOENT; } // Prepare the structure for the search. @@ -3109,13 +3109,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, path, &search)) { - pr_err("stat(%s): Failed to resolve path.\n", path); + pr_err("ext2_stat(path: %s): Failed to resolve path.\n", 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("stat(%s): Failed to read the inode of `%s`.\n", path, search.direntry.name); + pr_err("ext2_stat(path: %s): Failed to read the inode of `%s`.\n", path, search.direntry.name); return -ENOENT; } /// ID of device containing file. @@ -3224,7 +3224,7 @@ static ssize_t ext2_readlink(const char *path, char *buffer, size_t bufsize) return -ENOENT; } ssize_t ret = -ENOENT; - if ((inode.mode & S_IFLNK) == S_IFLNK) { + if (S_ISLNK(inode.mode)) { // Get the length of the symlink. ret = min(strlen(inode.data.symlink), bufsize); // Copy the symlink information. diff --git a/mentos/src/fs/namei.c b/mentos/src/fs/namei.c index a80691a9..0d4be61d 100644 --- a/mentos/src/fs/namei.c +++ b/mentos/src/fs/namei.c @@ -102,17 +102,41 @@ char *realpath(const char *path, char *buffer, size_t buflen) return buffer; } -static inline int __get_link_content(const char *path, char *link, size_t length) +/// @brief Determines if the path points to a link. +/// @param path the path to the file. +/// @return 1 if it is a link, 0 otherwise. +static inline int __is_a_link(const char *path) { - ssize_t link_length = vfs_readlink(path, link, length); + stat_t statbuf; + if (vfs_stat(path, &statbuf) > 0) { + return S_ISLNK(statbuf.st_mode); + } + return 0; +} + +/// @brief Returns the content of the link. +/// @param path the path to the file. +/// @param buffer the buffer where we store the link content. +/// @param buflen length of the buffer. +/// @return the length of the link, or a negative value on error. +static inline int __get_link_content(const char *path, char *buffer, size_t buflen) +{ + ssize_t link_length = vfs_readlink(path, buffer, buflen); if (link_length < 0) { return link_length; } // Null-terminate link. - link[link_length] = 0; + buffer[link_length] = 0; return link_length; } +/// @brief Resolve the path by following all symbolic links. +/// @param path the path to resolve. +/// @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. +/// @param link_depth the current link depth. +/// @return -errno on fail, 1 on success. int __resolve_path(const char *path, char *abspath, size_t buflen, int flags, int link_depth) { char token[NAME_MAX] = { 0 }; @@ -160,7 +184,7 @@ int __resolve_path(const char *path, char *abspath, size_t buflen, int flags, in pr_err("Buffer overflow while resolving path.\n"); return -ENAMETOOLONG; } - if (flags & FOLLOW_LINKS) { + if ((flags & FOLLOW_LINKS) && __is_a_link(buffer)) { ssize_t link_length = __get_link_content(buffer, linkpath, PATH_MAX); if (link_length > 0) { if (link_depth >= SYMLOOP_MAX) { diff --git a/mentos/src/fs/vfs.c b/mentos/src/fs/vfs.c index e498ae91..2bfaf033 100644 --- a/mentos/src/fs/vfs.c +++ b/mentos/src/fs/vfs.c @@ -394,7 +394,15 @@ vfs_file_t *vfs_creat(const char *path, mode_t mode) ssize_t vfs_readlink(const char *path, char *buffer, size_t bufsize) { pr_debug("vfs_readlink(%s, %s, %d)\n", path, buffer, bufsize); - super_block_t *sb = vfs_get_superblock(path); + // Allocate a variable for the path. + char absolute_path[PATH_MAX] = { 0 }; + // If the first character is not the '/' then get the absolute path. + int ret = resolve_path(path, absolute_path, PATH_MAX, REMOVE_TRAILING_SLASH); + if (ret < 0) { + pr_err("vfs_readlink(%s, %s, %d): Cannot get the absolute path.", path, buffer, bufsize); + return ret; + } + super_block_t *sb = vfs_get_superblock(absolute_path); if (sb == NULL) { pr_err("vfs_readlink(%s, %s, %d): Cannot find the superblock!.\n", path, buffer, bufsize); return -ENOENT; @@ -407,7 +415,7 @@ ssize_t vfs_readlink(const char *path, char *buffer, size_t bufsize) return -ENOENT; } // Perform the read. - return sb->root->fs_operations->readlink_f(path, buffer, bufsize); + return sb->root->fs_operations->readlink_f(absolute_path, buffer, bufsize); } int vfs_symlink(const char *linkname, const char *path) @@ -444,10 +452,9 @@ int vfs_stat(const char *path, stat_t *buf) { pr_debug("vfs_stat(path: %s, buf: %p)\n", path, buf); // Allocate a variable for the path. - char absolute_path[PATH_MAX]; + char absolute_path[PATH_MAX] = { 0 }; // If the first character is not the '/' then get the absolute path. - int resolve_flags = REMOVE_TRAILING_SLASH | FOLLOW_LINKS; - int ret = resolve_path(path, absolute_path, PATH_MAX, resolve_flags); + int ret = resolve_path(path, absolute_path, PATH_MAX, REMOVE_TRAILING_SLASH); if (ret < 0) { pr_err("vfs_stat(%s): Cannot get the absolute path.", path); return ret; @@ -468,15 +475,7 @@ int vfs_stat(const char *path, stat_t *buf) return -ENOSYS; } // Reset the structure. - buf->st_dev = 0; - buf->st_ino = 0; - buf->st_mode = 0; - buf->st_uid = 0; - buf->st_gid = 0; - buf->st_size = 0; - buf->st_atime = 0; - buf->st_mtime = 0; - buf->st_ctime = 0; + memset(buf, 0, sizeof(stat_t)); // Retrieve the file. return sb_root->sys_operations->stat_f(absolute_path, buf); } diff --git a/programs/stat.c b/programs/stat.c index e804f12a..456659db 100644 --- a/programs/stat.c +++ b/programs/stat.c @@ -50,7 +50,7 @@ int main(int argc, char **argv) if (S_ISLNK(dstat.st_mode)) { char link_buffer[PATH_MAX]; ssize_t len = readlink(argv[1], link_buffer, sizeof(link_buffer)); - if (len < 0) { + if (len > 0) { link_buffer[len] = '\0'; printf(" -> %s", link_buffer); } From a3cb62377416668f208fced38dba34b526d77cb8 Mon Sep 17 00:00:00 2001 From: "Enrico Fraccaroli (Galfurian)" Date: Fri, 30 Aug 2024 11:44:34 -0400 Subject: [PATCH 18/18] Update version numbers. --- mentos/inc/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mentos/inc/version.h b/mentos/inc/version.h index 042f8a6b..5b8be03d 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 2 +#define OS_MICRO_VERSION 3 /// Helper to transform the given argument into a string. #define OS_STR_HELPER(x) #x