From: quzar <qu...@us...> - 2024-05-12 04:24:02
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "A pseudo Operating System for the Dreamcast.". The branch, master has been updated via 39ade8b98f51fb6536e3e4aa3e04f78b4bdb5d74 (commit) from 1bd6f475dc9c9d3f6fac03357e1d1401513d3f51 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 39ade8b98f51fb6536e3e4aa3e04f78b4bdb5d74 Author: Falco Girgis <gyr...@gm...> Date: Sat May 11 23:23:32 2024 -0500 Fixed directory reading using FAM to conserve RAM (#546) * Fixed directory reading using FAM to conserve RAM - The zero-sized array approach that was tried previously was apparently causing undefined behavior since it was not the last member of the DIR structure, when calling readdir() - Modified it back to using a FAM, except this time got it working with C++ (and GNU extensions), by using a unionization of the inner dirent structure along with an additional extension to hold the name. * Fixed handling NULL terminator for NAME_MAX. The POSIX NAME_MAX is not supposed to be the array capacity for the name, it's supposed to be the MAX STRING LENGTH, meaning we also must have one extra byte for a NULL terminator! --------- ----------------------------------------------------------------------- Summary of changes: include/sys/dirent.h | 50 ++++++++++++++++++++++++++++++-------------- kernel/libc/koslib/readdir.c | 8 ++++++- kernel/libc/koslib/scandir.c | 2 +- 3 files changed, 42 insertions(+), 18 deletions(-) diff --git a/include/sys/dirent.h b/include/sys/dirent.h index 7951c390..37bff92f 100644 --- a/include/sys/dirent.h +++ b/include/sys/dirent.h @@ -54,35 +54,53 @@ __BEGIN_DECLS #define DT_WHT 14 /**< \brief Whiteout (ignored) */ /** @} */ -/** \brief POSIX directory entry structure. +/** \brief POSIX directory entry structure. This structure contains information about a single entry in a directory in the VFS. - - \headerfile sys/dirent.h */ struct dirent { - int d_ino; /**< \brief File unique identifier. */ - off_t d_off; /**< \brief File offset */ - uint16_t d_reclen; /**< \brief Record length */ - uint8_t d_type; /**< \brief File type */ - char d_name[0]; /**< \brief Filename */ + int d_ino; /**< \brief File unique identifier */ + off_t d_off; /**< \brief File offset */ + uint16_t d_reclen; /**< \brief Record length */ + uint8_t d_type; /**< \brief File type */ + /** \brief File name + + \warning + This field is a flexible array member, which means the structure + requires manual over-allocation to reserve storage for this string. + \note + This allows us to optimize our memory usage by only allocating + exactly as many bytes as the string is long for this field. + */ + char d_name[]; }; -/** \brief Type representing a directory stream. +/** \brief Type representing a directory stream. This type represents a directory stream and is used by the directory reading functions to trace their position in the directory. - The values in this function are all private and subject to change. Do not - attempt to use any of them directly. - - \headerfile sys/dirent.h + \note + The end of this structure is providing extra fixed storage for its inner + d_ent.d_name[] FAM, hence the unionization of the d_ent structure along + with a d_name[NAME_MAX] extension. */ typedef struct { - file_t fd; /**< \brief File descriptor for the directory */ - struct dirent d_ent; /**< \brief Current directory entry */ - char d_name[NAME_MAX]; /**< \brief Filename */ + /** \brief File descriptor for the directory */ + file_t fd; + /** \brief Union of dirent + extended dirent required for C++ */ + union { + /** \brief Current directory entry */ + struct dirent d_ent; + /** \brief Extended dirent structure with name storage */ + struct { + /** \brief Current directory entry (alias) */ + struct dirent d_ent2; + /** \brief Storage for d_ent::d_name[] FAM */ + char d_name[NAME_MAX + 1]; + }; + }; } DIR; // Standard UNIX dir functions. Not all of these are fully functional diff --git a/kernel/libc/koslib/readdir.c b/kernel/libc/koslib/readdir.c index d2bbd601..3fd51ea2 100644 --- a/kernel/libc/koslib/readdir.c +++ b/kernel/libc/koslib/readdir.c @@ -12,6 +12,7 @@ struct dirent *readdir(DIR *dir) { dirent_t *d; + size_t len; if(!dir) { errno = EBADF; @@ -32,7 +33,12 @@ struct dirent *readdir(DIR *dir) { else dir->d_ent.d_type = DT_REG; - strncpy(dir->d_name, d->name, sizeof(dir->d_name)); + len = strlen(d->name); + if(len > sizeof(dir->d_name) - 1) + len = sizeof(dir->d_name) - 1; + + strncpy(dir->d_ent.d_name, d->name, len); + dir->d_ent.d_name[len] = '\0'; return &dir->d_ent; } diff --git a/kernel/libc/koslib/scandir.c b/kernel/libc/koslib/scandir.c index 1c26c445..c81106e5 100644 --- a/kernel/libc/koslib/scandir.c +++ b/kernel/libc/koslib/scandir.c @@ -62,7 +62,7 @@ static int push_back(struct dirent ***list, int *size, int *capacity, entry_size = sizeof(struct dirent) + strlen(dir->d_name) + 1; new_dir = malloc(entry_size); - /* Check for malloc() failure of the singel entry */ + /* Check for malloc() failure of the single entry */ if(!new_dir) goto out_of_memory; hooks/post-receive -- A pseudo Operating System for the Dreamcast. |