From 8b5ede80fef01791766bcb639ed755100d57be5c Mon Sep 17 00:00:00 2001 From: Yann MAGNIN Date: Fri, 4 Apr 2025 11:25:18 +0200 Subject: [PATCH] fygue: support directory lseek,write(error),close --- CMakeLists.txt | 6 +- src/fs/fygue/fat/fat.h | 10 +- src/fs/fygue/fat/fat_dir_close.c | 11 ++ .../fygue/fat/{readdir.c => fat_dir_read.c} | 4 +- src/fs/fygue/fat/resolve.c | 2 +- src/fs/fygue/fygue.c | 4 +- src/fs/fygue/fygue.h | 18 ++- src/fs/fygue/fygue_dir_close.c | 30 +++++ src/fs/fygue/fygue_dir_lseek.c | 45 ++++++++ src/fs/fygue/fygue_dir_read.c | 104 ++++++++++++------ src/fs/fygue/fygue_dir_write.c | 22 ++++ 11 files changed, 215 insertions(+), 41 deletions(-) create mode 100644 src/fs/fygue/fat/fat_dir_close.c rename src/fs/fygue/fat/{readdir.c => fat_dir_read.c} (99%) create mode 100644 src/fs/fygue/fygue_dir_close.c create mode 100644 src/fs/fygue/fygue_dir_lseek.c create mode 100644 src/fs/fygue/fygue_dir_write.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 0e95cbf..d021385 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -264,9 +264,13 @@ set(SOURCES src/fs/fygue/fygue_open.c src/fs/fygue/fygue_syncfs.c src/fs/fygue/fygue_dir_read.c + src/fs/fygue/fygue_dir_lseek.c + src/fs/fygue/fygue_dir_write.c + src/fs/fygue/fygue_dir_close.c src/fs/fygue/fat/cluster.c src/fs/fygue/fat/initialize.c - src/fs/fygue/fat/readdir.c + src/fs/fygue/fat/fat_dir_read.c + src/fs/fygue/fat/fat_dir_close.c src/fs/fygue/fat/resolve.c src/fs/fygue/fat/sector.c src/fs/fygue/flash/cluster.c diff --git a/src/fs/fygue/fat/fat.h b/src/fs/fygue/fat/fat.h index a6e3fea..dc0af07 100644 --- a/src/fs/fygue/fat/fat.h +++ b/src/fs/fygue/fat/fat.h @@ -99,13 +99,19 @@ extern int fygue_fat_resolve( struct fygue_fat_resolve *resolve ); -/* fygue_fat_readdir(): readdir primitive */ -extern int fygue_fat_readdir( +/* fygue_fat_dir_read(): readdir primitive */ +extern int fygue_fat_dir_read( struct fygue_fat *fat, struct fygue_fat_dir *dir, struct fygue_fat_dirent *dirent ); +/* fygue_fat_dir_close(): closedir primitive */ +extern int fygue_fat_dir_close( + struct fygue_fat *fat, + struct fygue_fat_dir *dir +); + //--- // Cluster interface //--- diff --git a/src/fs/fygue/fat/fat_dir_close.c b/src/fs/fygue/fat/fat_dir_close.c new file mode 100644 index 0000000..19319a1 --- /dev/null +++ b/src/fs/fygue/fat/fat_dir_close.c @@ -0,0 +1,11 @@ +#include "fat.h" + +/* fygue_fat_dir_close(): closedir primitive */ +int fygue_fat_dir_close(struct fygue_fat *fat, struct fygue_fat_dir *dir) +{ + if (fat == NULL || dir == NULL) + return -1; + // nothing to do here... + return 0; +} + diff --git a/src/fs/fygue/fat/readdir.c b/src/fs/fygue/fat/fat_dir_read.c similarity index 99% rename from src/fs/fygue/fat/readdir.c rename to src/fs/fygue/fat/fat_dir_read.c index 6cb4ec1..24333fd 100644 --- a/src/fs/fygue/fat/readdir.c +++ b/src/fs/fygue/fat/fat_dir_read.c @@ -371,14 +371,14 @@ static int _fygue_readdir_fat_check(struct _fat_info *finfo) // Public //--- -/* fygue_fat_readdir() - readdir-like primitive +/* fygue_fat_dir_read() - readdir-like primitive * * return * -3 no dirent remaning * -2 internal error * -1 argument error * 0 success */ -int fygue_fat_readdir( +int fygue_fat_dir_read( struct fygue_fat *fat, struct fygue_fat_dir *dir, struct fygue_fat_dirent *current diff --git a/src/fs/fygue/fat/resolve.c b/src/fs/fygue/fat/resolve.c index 7db2d87..8c0bb2a 100644 --- a/src/fs/fygue/fat/resolve.c +++ b/src/fs/fygue/fat/resolve.c @@ -76,7 +76,7 @@ static int _fygue_dirent_find( ) { while (true) { - if (fygue_fat_readdir(fat, dir, dirent) != 0) + if (fygue_fat_dir_read(fat, dir, dirent) != 0) return -1; if (strncmp(dirent->name, start, len) != 0) continue; diff --git a/src/fs/fygue/fygue.c b/src/fs/fygue/fygue.c index 51445b8..377fdc8 100644 --- a/src/fs/fygue/fygue.c +++ b/src/fs/fygue/fygue.c @@ -92,7 +92,7 @@ const fs_descriptor_type_t fygue_descriptor_type = { const fs_descriptor_type_t fygue_dir_descriptor_type = { .read = (void*)&fygue_dir_read, - .write = NULL, - .lseek = NULL, + .write = (void*)&fygue_dir_write, + .lseek = (void*)&fygue_dir_lseek, .close = NULL, }; diff --git a/src/fs/fygue/fygue.h b/src/fs/fygue/fygue.h index 16e9ae9..8ea0003 100644 --- a/src/fs/fygue/fygue.h +++ b/src/fs/fygue/fygue.h @@ -68,7 +68,9 @@ struct fygue_resolve { } file; struct { struct fygue_fat_dir fat; - struct dirent *dirent; + struct dirent **dirent; + int count; + int pos; } dir; }; }; @@ -99,6 +101,20 @@ extern int fygue_dir_read( size_t size ); +/* fygue_dir_lseek(): seek directory */ +extern off_t fygue_dir_lseek( + struct fygue_descriptor *desc, + off_t offset, + int whence +); + +/* fygue_dir_write(): write directory (EISDIR) */ +ssize_t fygue_dir_write( + struct fygue_descriptor *desc, + void *buffer, + size_t size +); + #ifdef __cplusplus } #endif diff --git a/src/fs/fygue/fygue_dir_close.c b/src/fs/fygue/fygue_dir_close.c new file mode 100644 index 0000000..a09dba9 --- /dev/null +++ b/src/fs/fygue/fygue_dir_close.c @@ -0,0 +1,30 @@ +#include +#include +#include "fygue.h" +#include "fat/fat.h" + +int fygue_dir_close(struct fygue_descriptor *desc) +{ + struct fygue_fsinfo *fsinfo; + + ENOTSUP_IF_NOT_FYGUE(-1); + if (desc == NULL || desc->resolve.type != FYGUE_FILE_TYPE_DIR) { + errno = EBADF; + return -1; + } + if (fygue_mount(&fsinfo, true) != 0) { + errno = EIO; + return -1; + } + fygue_fat_dir_close(&(fsinfo->fat), &desc->resolve.dir.fat); + if (desc->resolve.dir.dirent != NULL) + { + for (int i = 0 ; i < desc->resolve.dir.count ; i++) { + if (desc->resolve.dir.dirent[i] != NULL) + free(desc->resolve.dir.dirent[i]); + } + free(desc->resolve.dir.dirent); + } + memset(desc, 0x00, sizeof(struct fygue_descriptor)); + return 0; +} diff --git a/src/fs/fygue/fygue_dir_lseek.c b/src/fs/fygue/fygue_dir_lseek.c new file mode 100644 index 0000000..76e1a71 --- /dev/null +++ b/src/fs/fygue/fygue_dir_lseek.c @@ -0,0 +1,45 @@ +#include "fygue.h" + +//--- +// Internals +//--- + +/* _fygue_dir_discover(): force discover all directory */ +static void _fygue_dir_discover(struct fygue_descriptor *desc) +{ + struct dirent *ent = NULL; + + while (true) + { + if (fygue_dir_read(desc, &ent, sizeof(ent)) != sizeof(ent)) + break; + } +} + +//--- +// Public +//--- + +/* fygue_dir_lseek(): seek directory */ +off_t fygue_dir_lseek( + struct fygue_descriptor *desc, + off_t offset, + int whence +) { + if (desc == NULL || desc->resolve.type != FYGUE_FILE_TYPE_DIR) { + errno = EBADF; + return -1; + } + if(whence == SEEK_CUR) + offset += desc->resolve.dir.pos; + if(whence == SEEK_END) { + _fygue_dir_discover(desc); + offset += desc->resolve.dir.count; + } + if(offset < 0 || offset >= desc->resolve.dir.count + 1) { + errno = EINVAL; + return -1; + } + desc->resolve.dir.pos = offset; + return desc->resolve.dir.pos; +} diff --git a/src/fs/fygue/fygue_dir_read.c b/src/fs/fygue/fygue_dir_read.c index e73e9b7..626da97 100644 --- a/src/fs/fygue/fygue_dir_read.c +++ b/src/fs/fygue/fygue_dir_read.c @@ -2,6 +2,68 @@ #include #include "fygue.h" +//--- +// Internals +//--- + +/* _fygue_dir_fat_read(): read and update internal cache + * + * return + * -2 no directory found + * -1 internal error + * 0 success */ +static int _fygue_dir_fat_read( + struct fygue_fsinfo *fsinfo, + struct fygue_descriptor *desc +) { + struct fygue_fat_dirent fat_dirent; + struct dirent **dirent; + void *tmp; + size_t len; + int rc; + + rc = fygue_fat_dir_read( + &(fsinfo->fat), + &desc->resolve.dir.fat, + &fat_dirent + ); + if (rc <= -3) + return -2; + if (rc < 0) { + errno = EIO; + return -1; + } + tmp = reallocarray( + desc->resolve.dir.dirent, + desc->resolve.dir.count + 1, + sizeof(struct dirent *) + ); + if (tmp == NULL) { + errno = ENOMEM; + return -1; + } + desc->resolve.dir.dirent = tmp; + desc->resolve.dir.count += 1; + //FIXME: ensure UTF-8/SHIFT-JS + len = strlen(fat_dirent.name); + dirent = &(desc->resolve.dir.dirent[desc->resolve.dir.pos]); + *dirent = calloc(1, sizeof(struct dirent) + len + 2); + if (*dirent == NULL) { + desc->resolve.dir.count -= 1; + errno = ENOMEM; + return -1; + } + //FIXME: ensure UTF-8/SHIFT-JS + (*dirent)->d_ino = fat_dirent.cluster_id; + (*dirent)->d_type = DT_REG; + memcpy((*dirent)->d_name, fat_dirent.name, len + 1); + return 0; +} + +//--- +// Public +//--- + /* fygue_dir_read(): directory read implementation * * notes @@ -11,9 +73,7 @@ int fygue_dir_read( struct dirent **dirent, size_t size ) { - struct fygue_fat_dirent fat_dirent; struct fygue_fsinfo *fsinfo; - size_t len; int rc; ENOTSUP_IF_NOT_FYGUE(-1); @@ -34,35 +94,15 @@ int fygue_dir_read( errno = EIO; return -1; } - - /* get the next FAT dirent */ - rc = fygue_fat_readdir( - &(fsinfo->fat), - &desc->resolve.dir.fat, - &fat_dirent - ); - if (rc <= -3) - return 0; - if (rc < 0) { - errno = EIO; - return -1; + if (desc->resolve.dir.pos >= desc->resolve.dir.count) + { + rc = _fygue_dir_fat_read(fsinfo, desc); + if (rc == -2) + return 0; + if (rc < 0) + return rc; } - - /* since `struct dirent` use flexible array to store the filename - * we need to reallocate the buffer each time */ - //FIXME: ensure UTF-8/SHIFT-JS - len = strlen(fat_dirent.name); - *dirent = desc->resolve.dir.dirent; - *dirent = realloc(*dirent, sizeof(struct dirent) + len + 2); - if (*dirent == NULL) { - errno = ENOMEM; - return -1; - } - - /* convert FAT dirent into generic dirent information */ - //FIXME: ensure UTF-8/SHIFT-JS - (*dirent)->d_ino = fat_dirent.cluster_id; - (*dirent)->d_type = DT_REG; - memcpy((*dirent)->d_name, fat_dirent.name, len + 1); - return 0; + *dirent = desc->resolve.dir.dirent[desc->resolve.dir.pos]; + desc->resolve.dir.pos += 1; + return sizeof *dirent; } diff --git a/src/fs/fygue/fygue_dir_write.c b/src/fs/fygue/fygue_dir_write.c new file mode 100644 index 0000000..5fba95d --- /dev/null +++ b/src/fs/fygue/fygue_dir_write.c @@ -0,0 +1,22 @@ +#include "fygue.h" + +/* fygue_dir_write(): write directory (EISDIR) */ +ssize_t fygue_dir_write( + struct fygue_descriptor *desc, + void *buffer, + size_t size +) { + ENOTSUP_IF_NOT_FYGUE(-1); + if (desc == NULL || desc->resolve.type != FYGUE_FILE_TYPE_DIR) { + errno = EBADF; + return -1; + } + if (buffer == NULL) { + errno = EFAULT; + return -1; + } + if (size == 0) + return 0; + errno = EISDIR; + return -1; +}