From a614195a2e6a95f830d4e26cb043ba2d3e6f6f90 Mon Sep 17 00:00:00 2001 From: Maieul BOYER Date: Fri, 24 May 2024 16:52:23 +0200 Subject: [PATCH] Fs interal WIP --- stdme/include/me/fs/fs.h | 195 ++++++++++++++++++++- stdme/src.list | 6 +- stdme/src/fs/fd_array_buffer.c | 75 -------- stdme/src/fs/fs_internal.c | 302 +++++++++++++++++++++++++++++++++ stdme/src/os/exit.c | 2 +- 5 files changed, 496 insertions(+), 84 deletions(-) delete mode 100644 stdme/src/fs/fd_array_buffer.c create mode 100644 stdme/src/fs/fs_internal.c diff --git a/stdme/include/me/fs/fs.h b/stdme/include/me/fs/fs.h index ed402abf..411a37a0 100644 --- a/stdme/include/me/fs/fs.h +++ b/stdme/include/me/fs/fs.h @@ -13,6 +13,7 @@ #ifndef FS_H #define FS_H +#include "me/fs/read_to_vec.h" #include "me/types.h" #include #include @@ -26,6 +27,13 @@ # define FILE_SLOT_LEN 512 #endif +/// The tag of slot, used to know what is in the slot +/// A slot can only have one type at a time +/// @note you should never set this value yourself +/// `Unused` means the slot is not used +/// `FD` means the slot is used by a file descriptor +/// `DIR` means the slot is used by a directory stream +/// `FILE` means the slot is used by a file stream enum e_file_slot_kind { SLOT_UNUSED = 0 << 0, @@ -34,6 +42,8 @@ enum e_file_slot_kind SLOT_FILE = 1 << 2, }; +/// The type of an open file descriptor +/// You should never set this value yourself typedef enum e_fd_type { FD_FILE = 1 << 0, @@ -42,12 +52,18 @@ typedef enum e_fd_type FD_UNKNOWN = 1 << 7, } t_fd_type; +/// @brief File descriptor permission +/// @note you can combine them with the `|` operator typedef enum e_fd_perm { FD_READ = 1 << 0, FD_WRITE = 1 << 1, } t_fd_perm; +/// @brief File open options +/// @note you can combine them with the `|` operator +/// They are named rather explicitely +/// They are just an alias to the "Raw" options using the `O` prefix typedef enum e_file_open_option { FD_CREATE = O_CREAT, @@ -57,6 +73,14 @@ typedef enum e_file_open_option FD_NON_BLOCKING = O_NONBLOCK, } t_file_open_option; +/// @brief File permission +/// `O` means owner +/// `G` means group +/// `U` means user +/// `ALL` means all +/// There are the raw permission, you can combine them to get the permission you want +/// And there are "aliases" that are common permission set +/// @note you can combine them with the `|` operator typedef enum e_file_perm { FP_OEXEC = 1 << 0, @@ -76,6 +100,11 @@ typedef enum e_file_perm FP_DEFAULT_EXEC = FP_UWRITE | FP_ALL_EXEC | FP_ALL_READ, } t_file_perm; +/// @brief File descriptor structure +/// name: the name of the file, NULL if unknown +/// fd: the file descriptor itself +/// perms: the permission of the file descriptor +/// type: the type of the file descriptor typedef struct s_fd { t_str name; @@ -84,55 +113,211 @@ typedef struct s_fd t_fd_type type; } t_fd; +/// @brief Directory structure +/// name: the name of the directory, NULL if unknown +/// ptr: the directory stream itself typedef struct s_dir { DIR *ptr; t_str name; } t_dir; +/// @brief File structure +/// name: the name of the file, NULL if unknown +/// ptr: the file stream itself typedef struct s_file { FILE *ptr; t_str name; } t_file; +/// @brief Union of the file slot +/// @note if you use this, you should know what you are doing union u_file_slot { t_fd fd; t_dir dir; t_file file; }; + +/// @brief File slot structure +/// ty: the type of the slot +/// slot: the slot itself +/// @note you should know what you are doing if you use this struct s_file_slot { enum e_file_slot_kind ty; union u_file_slot slot; }; +/// An array of file slots +/// @note you should know what you are doing if you use this typedef struct s_fd_array { struct s_file_slot storage[FILE_SLOT_LEN]; } t_fd_array; +/// @brief A mode used to open a file +typedef t_const_str t_mode; + +/// @brief Stat structure +/// @note this is a simple typedef because I hate the struct keyword typedef struct stat t_stat; + +/// @brief Directory entry structure +/// @note this is a simple typedef because I hate the struct keyword and it is always behind a pointer typedef struct dirent *t_dir_entry; +/*_____ _ _ _______ ______ _____ _ _ _ + |_ _| \ | |__ __| ____| __ \| \ | | /\ | | + | | | \| | | | | |__ | |__) | \| | / \ | | + | | | . ` | | | | __| | _ /| . ` | / /\ \ | | + _| |_| |\ | | | | |____| | \ \| |\ |/ ____ \| |____ + |_____|_| \_| |_| |______|_| \_\_| \_/_/ \_\______| +*/ + /// @brief Get the fd arrays object -/// @return fd_arrays -/// @note internal function used to get the fd arrays +/// @return pointer to the files's array +/// @note internal function used to get the files array t_fd_array *get_fd_arrays(void); + +/// @brief Get the unused fd slot object +/// @return pointer to the unused file slot +/// @note Will abort if no slot is available struct s_file_slot *get_unused_fd_slot(void); + + +/// @brief Close all slots +/// @note This is probably NOT what you want void close_all_slots(void); + +/// @note Close the given slot +/// @param[in] slot the slot to close +/// @note this is probably NOT what you want void close_slot(struct s_file_slot *slot); + + +/* ______ _____ + | ____| __ \ + | |__ | | | | + | __| | | | | + | | | |__| | + |_| |_____/ +*/ + +/// @brief Open a file descriptor +/// @param pathname the path to the file +/// @param permission the permission given to open the file (read, write, ...) +/// @param open_options the options to open the file +/// @param fileperm the file permission +/// @return the file descriptor* on success, NULL otherwise t_fd *open_fd(t_str name, t_fd_perm perms, t_file_open_option open_options, t_file_perm file_perm); + +/// @brief Read from a file descriptor +/// @param[in] fd the file descriptor +/// @param[out] buffer the buffer to read into +/// @param[in] size the size of the buffer +/// @param[out] read_count the number of bytes read +/// @return true on error, false otherwise t_error read_fd(t_fd *fd, t_u8 *buffer, t_usize size, t_isize *read_count); -t_error write_fd(t_fd *fd, t_u8 *buffer, t_usize size, t_isize *read_count); + +/// @brief Write to a file descriptor +/// @param[in] fd the file descriptor +/// @param[in] buffer the buffer to write from +/// @param[in] size the size of the buffer +/// @param[out] write_count the number of bytes written +/// @return true on error, false otherwise +/// @note write_count can be NULL +t_error write_fd(t_fd *fd, t_u8 *buffer, t_usize size, t_isize *write_count); + +/// @brief Get the file descriptor's information through stat +/// @param[in] fd the file descriptor +/// @param[out] stat the stat structure to fill +/// @return true on error, false otherwise t_error stat_fd(t_fd *fd, t_stat *stat); + +/// @brief Close a file descriptor +/// @param[in] fd the file descriptor +/// @note Will close the file descriptor and free the slot void close_fd(t_fd *fd); -t_error open_dir(t_str name, t_dir *dir); +/// @brief write a number to a file descriptor +/// @note will fail silently if the fd is not open in write mode +void put_number_fd(t_fd *fd, t_u64 number); + +/// @brief write a string to a file descriptor +/// @note will fail silently if the fd is not open in write mode +void put_string_fd(t_fd *fd, t_const_str string); + +/// @brief write a char to a file descriptor +/// @note will fail silently if the fd is not open in write mode +void put_char_fd(t_fd *fd, t_u8 c); + +/* _____ _____ _____ ______ _____ _______ ____ _______ __ + | __ \_ _| __ \| ____/ ____|__ __/ __ \| __ \ \ / / + | | | || | | |__) | |__ | | | | | | | | |__) \ \_/ / + | | | || | | _ /| __|| | | | | | | | _ / \ / + | |__| || |_| | \ \| |___| |____ | | | |__| | | \ \ | | + |_____/_____|_| \_\______\_____| |_| \____/|_| \_\ |_| +*/ + + +/// @brief Open a file +/// @param[in] name the name of the file +/// @param[out] dir the file structure to fill +/// @return true on error, false otherwise +t_error open_dir(t_str name, t_dir **dir); + +/// @brief Read a directory, advancing in the directory stream +/// @param[in] dir the directory to read from +/// @param[out] out the directory entry to fill +/// @return true on error, false otherwise +/// @note you need to open the dir again to read from the begining +/// @note you will get an NULL at the end of the directory stream t_error read_dir(t_dir *dir, t_dir_entry *out); -t_error close_dir(t_dir *dir); + +/// @brief Close a directory +/// @param[in] dir the directory to close +/// @note Will close the directory and free the slot +void close_dir(t_dir *dir); + +/*______ _____ _ ______ + | ____|_ _| | | ____| + | |__ | | | | | |__ + | __| | | | | | __| + | | _| |_| |____| |____ + |_| |_____|______|______| +*/ + +/// @brief Open a file using a file stream +/// @param[in] name the name of the file +/// @param[in] mode the mode to open the file +/// @param[out] file the file structure to fill +/// @return true on error, false otherwise +t_error open_file(t_str name, t_mode mode, t_file **file); + +/// @brief Read a file +/// @param[in] file the file to read from +/// @param[out] buffer the buffer to read into +/// @param[in] size the size of the buffer +/// @param[out] read_count the number of bytes read +/// @return true on error, false otherwise +t_error read_file(t_file *file, t_u8 *buffer, t_usize size, t_isize *read_count); + +/// @brief Write to a file +/// @param[in] file the file to write to +/// @param[in] buffer the buffer to write from +/// @param[in] size the size of the buffer +/// @param[out] write_count the number of bytes written +/// @return true on error, false otherwise +/// @note write_count can be NULL +t_error write_file(t_file *file, t_u8 *buffer, t_usize size, t_isize *write_count); + +/// @brief Close the underlying file stream +/// @param[in] file the file to close +/// @note Will close the file and free the slot +void close_file(t_file *file); #endif /* FS_H */ diff --git a/stdme/src.list b/stdme/src.list index bdef8e56..bb0e2b82 100644 --- a/stdme/src.list +++ b/stdme/src.list @@ -28,7 +28,7 @@ char/toupper convert/atoi convert/itoa fs/close -fs/fd_array_buffer +fs/fs_internal fs/open fs/putchar_fd fs/putendl_fd @@ -38,10 +38,10 @@ fs/read fs/read_to_vec fs/write gnl/get_next_line -hash/hasher hash/hash_signed hash/hash_str hash/hash_unsigned +hash/hasher hash/sip/sip13 hash/sip/sip_utils hash/sip/sip_utils2 @@ -86,7 +86,6 @@ printf/formatter/utils_numbers printf/matchers printf/printf printf/vprintf -string/mod str/str_clone str/str_compare str/str_find_chr @@ -103,3 +102,4 @@ str/str_n_find_str str/str_split str/str_substring str/str_trim +string/mod diff --git a/stdme/src/fs/fd_array_buffer.c b/stdme/src/fs/fd_array_buffer.c deleted file mode 100644 index 1ab68951..00000000 --- a/stdme/src/fs/fd_array_buffer.c +++ /dev/null @@ -1,75 +0,0 @@ -/* ************************************************************************** */ -/* */ -/* ::: :::::::: */ -/* fd_array_buffer.c :+: :+: :+: */ -/* +:+ +:+ +:+ */ -/* By: maiboyer +#+ +:+ +#+ */ -/* +#+#+#+#+#+ +#+ */ -/* Created: 2024/05/19 15:53:50 by maiboyer #+# #+# */ -/* Updated: 2024/05/24 14:44:45 by maiboyer ### ########.fr */ -/* */ -/* ************************************************************************** */ - -#include "me/fs/fs.h" -#include "me/mem/mem.h" -#include "me/types.h" -#include - -t_fd_array *get_fd_arrays(void) -{ - static t_fd_array val = {}; - - return (&val); -} - -struct s_file_slot *get_unused_fd_slot(void) -{ - t_usize i; - t_fd_array *arr; - - arr = get_fd_arrays(); - i = 0; - while (i < FILE_SLOT_LEN) - { - if (arr->storage[i].ty == SLOT_UNUSED) - return (&arr->storage[i]); - i++; - } - me_abort( - "Unable to find slot for a file descriptor, increate FILE_SLOT_LEN"); - return (NULL); -} - -void close_all_slots(void) -{ - t_usize i; - t_fd_array *arr; - - arr = get_fd_arrays(); - i = 0; - while (i < FILE_SLOT_LEN) - close_slot(&arr->storage[i++]); -} - -void close_slot(struct s_file_slot *slot) -{ - if (slot == NULL) - return; - if (slot->ty == SLOT_UNUSED) - ; - else if (slot->ty == SLOT_FD) - close(slot->slot.fd.fd); - else if (slot->ty == SLOT_DIR) - closedir(slot->slot.dir.ptr); - else if (slot->ty == SLOT_FILE) - fclose(slot->slot.file.ptr); - else - write(2, "Unknown SLOT type", 17); - mem_set_zero(slot, sizeof(*slot)); -} - -t_fd *me_open(char *pathname, t_fd_perm permission, - t_file_open_option open_options, t_file_perm fileperm) -{ - return (NULL); -} diff --git a/stdme/src/fs/fs_internal.c b/stdme/src/fs/fs_internal.c new file mode 100644 index 00000000..bd1734a0 --- /dev/null +++ b/stdme/src/fs/fs_internal.c @@ -0,0 +1,302 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* fs_internal.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: maiboyer +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/19 15:53:50 by maiboyer #+# #+# */ +/* Updated: 2024/05/24 14:44:45 by maiboyer ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "me/types.h" +#include "me/fs/fs.h" +#include "me/mem/mem.h" +#include "me/str/str.h" + +#include +#include +#include +#include + +t_fd_array *get_fd_arrays(void) +{ + static t_fd_array val = {}; + + return (&val); +} + +struct s_file_slot *get_unused_fd_slot(void) +{ + t_usize i; + t_fd_array *arr; + + arr = get_fd_arrays(); + i = 0; + while (i < FILE_SLOT_LEN) + { + if (arr->storage[i].ty == SLOT_UNUSED) + return (&arr->storage[i]); + i++; + } + me_abort( + "Unable to find slot for a file descriptor, increate FILE_SLOT_LEN"); + return (NULL); +} + +void close_all_slots(void) +{ + t_usize i; + t_fd_array *arr; + + arr = get_fd_arrays(); + i = 0; + while (i < FILE_SLOT_LEN) + close_slot(&arr->storage[i++]); +} + +void close_slot(struct s_file_slot *slot) +{ + if (slot == NULL) + return; + if (slot->ty == SLOT_UNUSED) + ; + else if (slot->ty == SLOT_FD) + close_fd(&slot->slot.fd); + else if (slot->ty == SLOT_DIR) + close_dir(&slot->slot.dir); + else if (slot->ty == SLOT_FILE) + close_file(&slot->slot.file); + else + write(2, "Unknown SLOT type", 17); + mem_set_zero(slot, sizeof(*slot)); +} + +/* ______ _____ + | ____| __ \ + | |__ | | | | + | __| | | | | + | | | |__| | + |_| |_____/ +*/ + +t_fd *open_fd(t_str name, t_fd_perm perms, t_file_open_option open_options, + t_file_perm file_perm) +{ + t_fd *fd; + struct s_file_slot *slot; + int actual_perms; + + if (perms & FD_READ && perms & FD_WRITE) + actual_perms = O_RDWR; + else if (perms & FD_READ) + actual_perms = O_RDONLY; + else if (perms & FD_WRITE) + actual_perms = O_WRONLY; + else + return (NULL); + actual_perms |= open_options; + slot = get_unused_fd_slot(); + fd = &slot->slot.fd; + fd->fd = open(name, actual_perms, file_perm); + if (fd->fd == -1) + return (fd->fd = 0, NULL); + slot->ty = SLOT_FD; + fd->name = str_clone(name); + fd->perms = perms; + fd->type = FD_FILE; + return (fd); +} + +t_error read_fd(t_fd *fd, t_u8 *buffer, t_usize size, t_isize *read_count) +{ + t_isize ret; + + if (fd == NULL || buffer == NULL || read_count == NULL || fd->fd == -1 || !(fd->perms & FD_READ)) + return (ERROR); + ret = read(fd->fd, buffer, size); + if (ret == -1) + return (ERROR); + *read_count = ret; + return (NO_ERROR); +} + +t_error write_fd(t_fd *fd, t_u8 *buffer, t_usize size, t_isize *write_count) +{ + t_isize ret; + t_isize fake_ret; + + if (write_count == NULL) + write_count = &fake_ret; + if (fd == NULL || buffer == NULL || fd->fd == -1 || !(fd->perms & FD_WRITE)) + return (ERROR); + ret = write(fd->fd, buffer, size); + if (ret == -1) + return (ERROR); + *write_count = ret; + return (NO_ERROR); +} + +t_error stat_fd(t_fd *fd, t_stat *stat) +{ + if (fd == NULL || stat == NULL || fd->fd == -1) + return (ERROR); + if (fstat(fd->fd, stat) == -1) + return (ERROR); + return (NO_ERROR); +} + +void close_fd(t_fd *fd) +{ + struct s_file_slot *slot; + + if (fd == NULL) + return ; + if (close(fd->fd) == -1) + return ; + slot = (void*)(fd) - offsetof(struct s_file_slot, slot.fd); + mem_set_zero(slot, sizeof(*slot)); +} + +#define INLINE_BUFFER_SIZE 128 + +void put_number_fd(t_fd *fd, t_u64 number) +{ + t_u8 buffer[INLINE_BUFFER_SIZE]; + t_usize i; + + i = 0; + while (number > 0) + { + buffer[i++] = number % 10 + '0'; + number /= 10; + } + while (i > 0) + write_fd(fd, &buffer[--i], 1, NULL); +} + +void put_string_fd(t_fd *fd, t_const_str string) +{ + write_fd(fd, (t_u8*)string, str_len(string), NULL); +} + +void put_char_fd(t_fd *fd, t_u8 c) +{ + write_fd(fd, &c, 1, NULL); +} + +/* _____ _____ _____ ______ _____ _______ ____ _______ __ + | __ \_ _| __ \| ____/ ____|__ __/ __ \| __ \ \ / / + | | | || | | |__) | |__ | | | | | | | | |__) \ \_/ / + | | | || | | _ /| __|| | | | | | | | _ / \ / + | |__| || |_| | \ \| |___| |____ | | | |__| | | \ \ | | + |_____/_____|_| \_\______\_____| |_| \____/|_| \_\ |_| +*/ + +t_error open_dir(t_str name, t_dir **dir) +{ + t_dir *out; + struct s_file_slot *slot; + + slot = get_unused_fd_slot(); + out = &slot->slot.dir; + out->ptr = opendir(name); + if (out->ptr == NULL) + return (ERROR); + slot->ty = SLOT_DIR; + out->name = str_clone(name); + *dir = out; + return (NO_ERROR); +} + +t_error read_dir(t_dir *dir, t_dir_entry *out) +{ + struct dirent *entry; + + if (dir == NULL || out == NULL || dir->ptr == NULL) + return (ERROR); + errno = 0; + entry = readdir(dir->ptr); + if (entry == NULL && errno != 0) + return (ERROR); + *out = entry; + return (NO_ERROR); +} + +void close_dir(t_dir *dir) +{ + struct s_file_slot *slot; + + if (dir == NULL) + return ; + if (closedir(dir->ptr) == -1) + return ; + slot = (void*)(dir) - offsetof(struct s_file_slot, slot.dir); + mem_set_zero(slot, sizeof(*slot)); +} + +/*______ _____ _ ______ + | ____|_ _| | | ____| + | |__ | | | | | |__ + | __| | | | | | __| + | | _| |_| |____| |____ + |_| |_____|______|______| +*/ + +t_error open_file(t_str name, t_mode mode, t_file **file) +{ + t_file *out; + struct s_file_slot *slot; + + slot = get_unused_fd_slot(); + out = &slot->slot.file; + out->ptr = fopen(name, mode); + if (out->ptr == NULL) + return (ERROR); + slot->ty = SLOT_FILE; + out->name = str_clone(name); + *file = out; + return (NO_ERROR); +} + +t_error write_file(t_file *file, t_u8 *buffer, t_usize size, t_isize *write_count) +{ + t_isize ret; + t_isize fake_ret; + + if (write_count == NULL) + write_count = &fake_ret; + if (file == NULL || buffer == NULL || file->ptr == NULL) + return (ERROR); + ret = fwrite(buffer, size, 1, file->ptr); + if (ret == -1) + return (ERROR); + *write_count = ret; + return (NO_ERROR); +} + +t_error read_file(t_file *file, t_u8 *buffer, t_usize size, t_isize *read_count) +{ + t_isize ret; + + if (file == NULL || buffer == NULL || read_count == NULL || file->ptr == NULL) + return (ERROR); + ret = fread(buffer, size, 1, file->ptr); + if (ret == -1) + return (ERROR); + *read_count = ret; + return (NO_ERROR); +} + +void close_file(t_file *file) +{ + struct s_file_slot *slot; + + if (file == NULL) + return ; + if (fclose(file->ptr) == -1) + return ; + slot = (void*)(file) - offsetof(struct s_file_slot, slot.file); + mem_set_zero(slot, sizeof(*slot)); +} \ No newline at end of file diff --git a/stdme/src/os/exit.c b/stdme/src/os/exit.c index afde4d30..04e0faff 100644 --- a/stdme/src/os/exit.c +++ b/stdme/src/os/exit.c @@ -17,7 +17,7 @@ void me_exit(t_i32 exit_code) { - close_all_fds(); + close_all_slots(); uninit_global_allocator(); exit(exit_code); }