From 9cae0040b5b22faaed6006871dc270a67597c700 Mon Sep 17 00:00:00 2001 From: Lephe Date: Tue, 21 Dec 2021 19:01:00 +0100 Subject: [PATCH] fs: folder support, part 1 (mkdir/rmdir and the opendir(3) family) --- CMakeLists.txt | 14 +++ TODO | 10 +- include/gint/bfile.h | 11 +++ include/gint/fs.h | 2 +- src/fs/closedir.c | 10 ++ src/fs/fdopendir.c | 27 ++++++ src/fs/fugue/BFile_Ext_Stat.c | 24 +++++ src/fs/fugue/fugue.c | 131 ++------------------------ src/fs/fugue/fugue.h | 19 +++- src/fs/fugue/fugue_dir.c | 168 ++++++++++++++++++++++++++++++++++ src/fs/fugue/fugue_mkdir.c | 23 +++++ src/fs/fugue/fugue_open.c | 119 ++++++++++++++++++++++++ src/fs/fugue/fugue_unlink.c | 28 ++++++ src/fs/fugue/util.c | 28 ++++-- src/fs/fugue/util.h | 14 ++- src/fs/lseek.c | 5 + src/fs/mkdir.c | 8 ++ src/fs/opendir.c | 23 +++++ src/fs/readdir.c | 9 ++ src/fs/rewinddir.c | 7 ++ src/fs/rmdir.c | 8 ++ src/fs/seekdir.c | 7 ++ src/fs/telldir.c | 7 ++ 23 files changed, 560 insertions(+), 142 deletions(-) create mode 100644 src/fs/closedir.c create mode 100644 src/fs/fdopendir.c create mode 100644 src/fs/fugue/BFile_Ext_Stat.c create mode 100644 src/fs/fugue/fugue_dir.c create mode 100644 src/fs/fugue/fugue_mkdir.c create mode 100644 src/fs/fugue/fugue_open.c create mode 100644 src/fs/fugue/fugue_unlink.c create mode 100644 src/fs/mkdir.c create mode 100644 src/fs/opendir.c create mode 100644 src/fs/readdir.c create mode 100644 src/fs/rewinddir.c create mode 100644 src/fs/rmdir.c create mode 100644 src/fs/seekdir.c create mode 100644 src/fs/telldir.c diff --git a/CMakeLists.txt b/CMakeLists.txt index c7b88d8..77fc193 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,17 +37,31 @@ set(SOURCES_COMMON src/dma/memset.c # Filesystem interface src/fs/close.c + src/fs/closedir.c src/fs/creat.c + src/fs/fdopendir.c src/fs/fs.c src/fs/lseek.c + src/fs/mkdir.c src/fs/open.c + src/fs/opendir.c src/fs/pread.c src/fs/pwrite.c src/fs/read.c + src/fs/readdir.c + src/fs/rewinddir.c + src/fs/rmdir.c + src/fs/seekdir.c + src/fs/telldir.c src/fs/unlink.c src/fs/write.c # Filesystem interface to Fugue + src/fs/fugue/BFile_Ext_Stat.c src/fs/fugue/fugue.c + src/fs/fugue/fugue_dir.c + src/fs/fugue/fugue_open.c + src/fs/fugue/fugue_mkdir.c + src/fs/fugue/fugue_unlink.c src/fs/fugue/util.c # Interrupt Controller driver src/intc/intc.c diff --git a/TODO b/TODO index 4c032c5..8c68414 100644 --- a/TODO +++ b/TODO @@ -1,22 +1,22 @@ Extensions on existing code: +* usb: add PC->calc reading, and interrupt pipes +* fs: support RAM files +* fs: support USB streams as generic file descriptors +* fugue: support glob() and stat() to abstract away BFile entirely * bfile: implement the optimization-restart as realized by Kbd2 * kernel: better restore to userspace before panic (ensure BL=0 IMASK=0) * project: add license file * kernel: group linker script symbols in a single header file -* bopti: try to display fullscreen images with TLB access + DMA on fxcg50 * core: try to leave add-in without reset in case of panic * core: use cmp/str for memchr() * r61524: brightness control and clean the file * core: review forgotten globals and MPU addresses not in * core: run destructors when a task-switch results in leaving the app -* core rtc: use qdiv10 to massively improve division performance -Future directions. -* A complete file system abstraction +Future directions: * Integrate overclock management * Audio playback using TSWilliamson's libsnd method * Serial communication -* USB communication, using Yatis' reverse-engineering of the module * Make fx9860g projects work out of the box on fxcg50 * Use the DSP to enhance parallel computation * Base for Yatis' threads library diff --git a/include/gint/bfile.h b/include/gint/bfile.h index a6acd53..9008c6c 100644 --- a/include/gint/bfile.h +++ b/include/gint/bfile.h @@ -294,6 +294,17 @@ int BFile_FindNext(int shandle, uint16_t *foundfile, /* Close a search handle (with or without exhausting the matches). */ int BFile_FindClose(int shandle); +//--- +// Additional functions +// +// The following functions are implemented in gint using lower-level BFile +// functions. They add abstraction/convenience to the API, but can be pretty +// slow as they result in more BFile calls being made. +//--- + +/* BFile_Ext_Stat(): Stat an entry for type and size */ +int BFile_Ext_Stat(uint16_t const *path, int *type, int *size); + #ifdef __cplusplus } #endif diff --git a/include/gint/fs.h b/include/gint/fs.h index f427b5c..e7b3d4c 100644 --- a/include/gint/fs.h +++ b/include/gint/fs.h @@ -71,7 +71,7 @@ fs_descriptor_t const *fs_get_descriptor(int fd); errno = ENFILE. */ int fs_create_descriptor(fs_descriptor_t const *data); -/* fs_free_descriptor(): Clsoe a file descriptor's slot +/* fs_free_descriptor(): Close a file descriptor's slot This function frees the specified file descriptor. It is automatically called by close() after the descriptor type's close() function, so there is diff --git a/src/fs/closedir.c b/src/fs/closedir.c new file mode 100644 index 0000000..f2ba4b4 --- /dev/null +++ b/src/fs/closedir.c @@ -0,0 +1,10 @@ +#include +#include +#include + +int closedir(DIR *dp) +{ + int rc = close(dp->fd); + free(dp); + return rc; +} diff --git a/src/fs/fdopendir.c b/src/fs/fdopendir.c new file mode 100644 index 0000000..62e3547 --- /dev/null +++ b/src/fs/fdopendir.c @@ -0,0 +1,27 @@ +#include +#include +#include +#include +#include "fugue/fugue.h" + +DIR *fdopendir(int fd) +{ + fs_descriptor_t const *desc = fs_get_descriptor(fd); + if(desc == NULL) { + errno = EBADF; + return NULL; + } + if(desc->type != &fugue_dir_descriptor_type) { + errno = ENOTDIR; + return NULL; + } + + DIR *dp = malloc(sizeof *dp); + if(!dp) { + errno = ENOMEM; + return NULL; + } + + dp->fd = fd; + return dp; +} diff --git a/src/fs/fugue/BFile_Ext_Stat.c b/src/fs/fugue/BFile_Ext_Stat.c new file mode 100644 index 0000000..bde0c2a --- /dev/null +++ b/src/fs/fugue/BFile_Ext_Stat.c @@ -0,0 +1,24 @@ +#include +#include "util.h" + +int BFile_Ext_Stat(uint16_t const *path, int *type, int *size) +{ + int search_handle, rc; + uint16_t found_file[256]; + struct BFile_FileInfo fileinfo; + + rc = BFile_FindFirst(path, &search_handle, found_file, &fileinfo); + if(rc < 0) { + if(type) *type = -1; + if(size) *size = -1; + rc = -1; + } + else { + if(type) *type = fileinfo.type; + if(size) *size = fileinfo.file_size; + rc = 0; + } + + BFile_FindClose(search_handle); + return rc; +} diff --git a/src/fs/fugue/fugue.c b/src/fs/fugue/fugue.c index 84fb13f..3795968 100644 --- a/src/fs/fugue/fugue.c +++ b/src/fs/fugue/fugue.c @@ -48,26 +48,18 @@ off_t fugue_lseek(void *data, off_t offset, int whence) { int fugue_fd = (int)data; - if(whence != SEEK_SET && whence != SEEK_CUR && whence != SEEK_END) { - errno = EINVAL; - return (off_t)-1; - } - /* On Graph 35+E II, there is no documented way to know the offset. */ if(gint[HWCALC] == HWCALC_G35PE2 && whence == SEEK_CUR) { errno = ENOTSUP; return (off_t)-1; } - off_t destination; - if(whence == SEEK_SET) - destination = offset; - else if(whence == SEEK_CUR) - destination = BFile_GetPos(fugue_fd) + offset; + if(whence == SEEK_CUR) + offset += BFile_GetPos(fugue_fd); else if(whence == SEEK_END) - destination = BFile_Size(fugue_fd) + offset; + offset += BFile_Size(fugue_fd); - int rc = BFile_Seek(fugue_fd, destination); + int rc = BFile_Seek(fugue_fd, offset); if(rc < 0) { errno = bfile_error_to_errno(rc); @@ -75,8 +67,8 @@ off_t fugue_lseek(void *data, off_t offset, int whence) } /* rc is the amount of space left in the file (including pre-allocated - space), so instead just return destination directly */ - return (off_t)destination; + space), so instead just return offset directly */ + return offset; } int fugue_close(void *data) @@ -91,119 +83,10 @@ int fugue_close(void *data) return 0; } -static const fs_descriptor_type_t fugue_descriptor_type = { +const fs_descriptor_type_t fugue_descriptor_type = { .read = fugue_read, .pread = fugue_pread, .write = fugue_write, .lseek = fugue_lseek, .close = fugue_close, }; - -int fugue_open(char const *path, int flags, GUNUSED mode_t mode) -{ - if(gint[HWFS] != HWFS_FUGUE) { - errno = ENOTSUP; - return -1; - } - - uint16_t *fcpath = utf8_to_fc_alloc(path, u"\\\\fls0\\"); - int fugue_fd, err, rc = -1; - - if(!fcpath) { - errno = ENOMEM; - return -1; - } - - /* Open mode */ - int bfile_mode = BFile_ReadOnly; - if(flags & O_WRONLY) - bfile_mode = BFile_WriteOnly; - else if(flags & O_RDWR) - bfile_mode = BFile_ReadWrite; - - /* Exclusive creation requires the file to be created by the call */ - bool excl = (flags & O_EXCL) && (flags & O_CREAT); - /* Truncation requires the file to be removed/recreated */ - bool trunc = (flags & O_TRUNC) && (flags & O_CREAT); - - /* Try and open the file normally, unless O_TRUNC is specified without - O_EXCL, in which case we simply delete and recreate the file. */ - fugue_fd = BFile_EntryNotFound; - if(excl || !trunc) - fugue_fd = BFile_Open(fcpath, bfile_mode); - - /* If the file exists and O_EXCL was requested, fail. */ - if(fugue_fd >= 0 && excl) { - BFile_Close(fugue_fd); - errno = EEXIST; - return -1; - } - - /* If O_TRUNC is requested and either the file exists or O_CREAT is - set, temporarily remove it. */ - if((flags & O_TRUNC) && (fugue_fd >= 0 || (flags & O_CREAT))) { - if(fugue_fd >= 0) BFile_Close(fugue_fd); - BFile_Remove(fcpath); - fugue_fd = BFile_EntryNotFound; - } - - /* If the file does not exist and O_CREAT is set, create it */ - if((flags & O_CREAT) && ((flags & O_TRUNC) || fugue_fd < 0)) { - int size = 0; - err = BFile_Create(fcpath, BFile_File, &size); - if(err < 0) { - errno = bfile_error_to_errno(err); - goto end; - } - fugue_fd = BFile_Open(fcpath, bfile_mode); - } - - if(fugue_fd < 0) { - errno = bfile_error_to_errno(fugue_fd); - goto end; - } - - /* If O_APPEND is set, move to the end of the file */ - if((flags & O_APPEND)) - BFile_Seek(fugue_fd, BFile_Size(fugue_fd)); - - /* Return the now-open file descriptor */ - fs_descriptor_t data = { - .type = &fugue_descriptor_type, - .data = (void *)fugue_fd, - }; - int fd = fs_create_descriptor(&data); - - if(fd == -1) { - BFile_Close(fugue_fd); - errno = ENFILE; - goto end; - } - - rc = fd; -end: - free(fcpath); - return rc; -} - -int fugue_unlink(char const *path) -{ - if(gint[HWFS] != HWFS_FUGUE) { - errno = ENOTSUP; - return -1; - } - - uint16_t *fcpath = utf8_to_fc_alloc(path, u"\\\\fls0\\"); - if(!fcpath) { - errno = ENOMEM; - return -1; - } - - int err = BFile_Remove(fcpath); - if(err < 0) { - errno = bfile_error_to_errno(err); - return -1; - } - - return 0; -} diff --git a/src/fs/fugue/fugue.h b/src/fs/fugue/fugue.h index 1b139b4..bfa8886 100644 --- a/src/fs/fugue/fugue.h +++ b/src/fs/fugue/fugue.h @@ -1,13 +1,28 @@ #ifndef FS_FUGUE_FUGUE_H #define FS_FUGUE_FUGUE_H +#include #include #include +#include + +/* File descriptor type */ +extern const fs_descriptor_type_t fugue_descriptor_type; +/* Directory descriptor type */ +extern const fs_descriptor_type_t fugue_dir_descriptor_type; + +/* Specific implementations of some standard functions */ -/* Specific implementation of open() */ int fugue_open(char const *path, int flags, mode_t mode); -/* Specific implementation of unlink() */ int fugue_unlink(char const *path); +int fugue_mkdir(char const *path, mode_t mode); + +int fugue_rmdir(char const *path); + +/* Other functions */ + +void *fugue_dir_explore(char const *path); + #endif /* FS_FUGUE_FUGUE_H */ diff --git a/src/fs/fugue/fugue_dir.c b/src/fs/fugue/fugue_dir.c new file mode 100644 index 0000000..c568f06 --- /dev/null +++ b/src/fs/fugue/fugue_dir.c @@ -0,0 +1,168 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "util.h" +#include "fugue.h" + +typedef struct +{ + /* Number of entries */ + int count; + /* All entries */ + struct dirent **entries; + /* Current position in directory */ + off_t pos; + +} dir_t; + +/* There is no well-standardized API for reading from directory descriptors. + getdents(2) is a thing, but it's mostly Linux-specific and has no glibc + wrapper, so no userspace application is using it directly. We define our + directory descriptor interface to mimic opendir(3) for efficiency. */ + +ssize_t fugue_dir_read(void *data, void *buf, GUNUSED size_t size) +{ + struct dirent **dirent_ptr = buf; + if(size < sizeof *dirent_ptr) + return 0; + + dir_t *dp = data; + if(dp->pos >= dp->count) + *dirent_ptr = NULL; + else + *dirent_ptr = dp->entries[dp->pos++]; + + return sizeof *dirent_ptr; +} + +ssize_t fugue_dir_pread(GUNUSED void *data, GUNUSED void *buf, + GUNUSED size_t size, GUNUSED off_t offset) +{ + errno = EISDIR; + return -1; +} + +ssize_t fugue_dir_write(GUNUSED void *data, GUNUSED const void *buf, + GUNUSED size_t size) +{ + errno = EISDIR; + return -1; +} + +off_t fugue_dir_lseek(void *data, off_t offset, int whence) +{ + dir_t *dp = data; + + if(whence == SEEK_CUR) + offset += dp->pos; + if(whence == SEEK_END) + offset += dp->count; + + if(offset < 0 || offset >= dp->count) { + errno = EINVAL; + return -1; + } + + dp->pos = offset; + return dp->pos; +} + +int fugue_dir_close(void *data) +{ + dir_t *dp = data; + + if(dp && dp->entries) { + for(int i = 0; i < dp->count; i++) + free(dp->entries[i]); + free(dp->entries); + } + free(dp); + + return 0; +} + +const fs_descriptor_type_t fugue_dir_descriptor_type = { + .read = fugue_dir_read, + .pread = fugue_dir_pread, + .write = fugue_dir_write, + .lseek = fugue_dir_lseek, + .close = fugue_dir_close, +}; + +void *fugue_dir_explore(char const *path) +{ + struct BFile_FileInfo info; + uint16_t *fc_path=NULL, *search=NULL; + + dir_t *dp = malloc(sizeof *dp); + if(!dp) goto alloc_failure; + + dp->count = 0; + dp->entries = NULL; + dp->pos = 0; + /* We allocate by batches of 8 */ + int sd=-1, rc, allocated=0; + + fc_path = malloc(512 * sizeof *fc_path); + if(!fc_path) goto alloc_failure; + + search = utf8_to_fc_alloc(u"\\\\fls0\\", path, u"\\*"); + if(!search) goto alloc_failure; + + rc = BFile_FindFirst(search, &sd, fc_path, &info); + if(rc < 0) { + if(rc != BFile_EntryNotFound) + errno = bfile_error_to_errno(rc); + goto end; + } + + do { + if(dp->count+1 > allocated) { + struct dirent **new_entries = realloc(dp->entries, + (allocated + 8) * sizeof *dp->entries); + if(!new_entries) + goto alloc_failure; + dp->entries = new_entries; + allocated += 8; + } + + size_t name_length = fc_len(fc_path); + size_t s = sizeof(struct dirent) + name_length + 1; + struct dirent *ent = malloc(s); + if(!ent) goto alloc_failure; + + ent->d_ino = 0; + ent->d_type = DT_UNKNOWN; + fc_to_utf8(ent->d_name, fc_path, name_length + 1); + + if(info.type == BFile_Type_File) + ent->d_type = DT_REG; + if(info.type == BFile_Type_Directory) + ent->d_type = DT_DIR; + if(info.type == BFile_Type_Dot) + ent->d_type = DT_DIR; + if(info.type == BFile_Type_DotDot) + ent->d_type = DT_DIR; + + dp->entries[dp->count++] = ent; + + rc = BFile_FindNext(sd, fc_path, &info); + } + while(rc >= 0); + goto end; + +alloc_failure: + errno = ENOMEM; + fugue_dir_close(dp); +end: + free(search); + free(fc_path); + if(sd >= 0) + BFile_FindClose(sd); + return dp; +} diff --git a/src/fs/fugue/fugue_mkdir.c b/src/fs/fugue/fugue_mkdir.c new file mode 100644 index 0000000..4118eef --- /dev/null +++ b/src/fs/fugue/fugue_mkdir.c @@ -0,0 +1,23 @@ +#include +#include +#include +#include "util.h" + +int fugue_mkdir(char const *path, GUNUSED mode_t mode) +{ + ENOTSUP_IF_NOT_FUGUE(-1); + + uint16_t *fcpath = utf8_to_fc_alloc(u"\\\\fls0\\", path, NULL); + if(!fcpath) { + errno = ENOMEM; + return -1; + } + + int rc = BFile_Create(fcpath, BFile_Folder, NULL); + if(rc < 0) { + errno = bfile_error_to_errno(rc); + return -1; + } + + return 0; +} diff --git a/src/fs/fugue/fugue_open.c b/src/fs/fugue/fugue_open.c new file mode 100644 index 0000000..493c275 --- /dev/null +++ b/src/fs/fugue/fugue_open.c @@ -0,0 +1,119 @@ +#include +#include +#include +#include +#include "util.h" +#include "fugue.h" + +/* TODO: fugue_open(): Handle trailing '/' and filesystem root */ + +int fugue_open(char const *path, int flags, GUNUSED mode_t mode) +{ + ENOTSUP_IF_NOT_FUGUE(-1); + + uint16_t *fcpath = utf8_to_fc_alloc(u"\\\\fls0\\", path, NULL); + int fugue_fd, err, rc=-1, type, fd=-1; + + if(!fcpath) { + errno = ENOMEM; + return -1; + } + + /* Open mode */ + int bfile_mode = BFile_ReadOnly; + if(flags & O_WRONLY) + bfile_mode = BFile_WriteOnly; + else if(flags & O_RDWR) + bfile_mode = BFile_ReadWrite; + + /* Exclusive open means no sense unless creation is also requested */ + bool excl = (flags & O_EXCL) && (flags & O_CREAT); + /* Truncation requires the file to be removed/recreated */ + bool trunc = (flags & O_TRUNC) && (flags & O_CREAT); + + /* Stat the entry */ + bool exists = (BFile_Ext_Stat(fcpath, &type, NULL) == 0); + if(!exists) type = -1; + + /* If the entry exists and O_EXCL was requested, fail. */ + if(exists && excl) { + errno = EEXIST; + return -1; + } + + /* If the entry is not a directory but O_DIRECTORY is set, fail. If the + directory doesn't exist, we fail regardless of O_CREAT. */ + if((flags & O_DIRECTORY) && type != BFile_Type_Directory) { + errno = (exists ? ENOTDIR : ENOENT); + return -1; + } + + /* If the entry is a directory, open it as such */ + if(type == BFile_Type_Directory) { + void *dp = fugue_dir_explore(path); + fs_descriptor_t data = { + .type = &fugue_dir_descriptor_type, + .data = dp, + }; + fd = fs_create_descriptor(&data); + rc = fd; + goto end; + } + + /* Try and open the file normally, unless O_TRUNC is specified without + O_EXCL, in which case we simply delete and recreate the file. */ + if(trunc) + fugue_fd = BFile_EntryNotFound; + else + fugue_fd = BFile_Open(fcpath, bfile_mode); + + /* If O_TRUNC is requested and either the file exists or we can create + it, remove it. (If fugue_fd < 0 an opening error might still have + occurred so we delete it just in case.) */ + if((flags & O_TRUNC) && (fugue_fd >= 0 || (flags & O_CREAT))) { + if(fugue_fd >= 0) + BFile_Close(fugue_fd); + BFile_Remove(fcpath); + fugue_fd = BFile_EntryNotFound; + } + + /* If the file does not exist and O_CREAT is set, create it */ + if((flags & O_CREAT) && ((flags & O_TRUNC) || fugue_fd < 0)) { + int size = 0; + err = BFile_Create(fcpath, BFile_File, &size); + if(err < 0) { + errno = bfile_error_to_errno(err); + goto end; + } + fugue_fd = BFile_Open(fcpath, bfile_mode); + } + + if(fugue_fd < 0) { + errno = bfile_error_to_errno(fugue_fd); + rc = fugue_fd; + goto end; + } + + /* If O_APPEND is set, move to the end of the file */ + // TODO: O_APPEND should move the cursor before *each* write + if((flags & O_APPEND)) + BFile_Seek(fugue_fd, BFile_Size(fugue_fd)); + + /* Return the now-open file descriptor */ + fs_descriptor_t data = { + .type = &fugue_descriptor_type, + .data = (void *)fugue_fd, + }; + fd = fs_create_descriptor(&data); + + if(fd == -1) { + BFile_Close(fugue_fd); + errno = ENFILE; + goto end; + } + + rc = fd; +end: + free(fcpath); + return rc; +} diff --git a/src/fs/fugue/fugue_unlink.c b/src/fs/fugue/fugue_unlink.c new file mode 100644 index 0000000..29216df --- /dev/null +++ b/src/fs/fugue/fugue_unlink.c @@ -0,0 +1,28 @@ +#include +#include +#include +#include "util.h" + +int fugue_unlink(char const *path) +{ + ENOTSUP_IF_NOT_FUGUE(-1); + + uint16_t *fcpath = utf8_to_fc_alloc(u"\\\\fls0\\", path, NULL); + if(!fcpath) { + errno = ENOMEM; + return -1; + } + + int err = BFile_Remove(fcpath); + if(err < 0) { + errno = bfile_error_to_errno(err); + return -1; + } + + return 0; +} + +int fugue_rmdir(char const *path) +{ + return fugue_unlink(path); +} diff --git a/src/fs/fugue/util.c b/src/fs/fugue/util.c index 5ff6d55..e4bf711 100644 --- a/src/fs/fugue/util.c +++ b/src/fs/fugue/util.c @@ -26,14 +26,14 @@ int bfile_error_to_errno(int e) } /* Length of FONTCHARACTER and UTF-8 strings, counting only ASCII characters */ -static size_t utf8_len(char const *utf8) +size_t utf8_len(char const *utf8) { size_t len = 0; for(size_t i = 0; utf8[i] != 0; i++) len += (utf8[i] >= 0 && (uint8_t)utf8[i] <= 0x7f); return len; } -static size_t fc_len(uint16_t const *fc) +size_t fc_len(uint16_t const *fc) { size_t len = 0; for(size_t i = 0; fc[i] != 0 && fc[i] != 0xffff; i++) @@ -46,7 +46,9 @@ void utf8_to_fc(uint16_t *fc, char const *utf8, size_t fc_len) size_t j = 0; for(size_t i = 0; j < fc_len && utf8[i] != 0; i++) { - if(utf8[i] >= 0 && (uint8_t)utf8[i] <= 0x7f) + if(utf8[i] == '/') + fc[j++] = '\\'; + else if(utf8[i] >= 0 && (uint8_t)utf8[i] <= 0x7f) fc[j++] = utf8[i]; } @@ -59,7 +61,9 @@ void fc_to_utf8(char *utf8, uint16_t const *fc, size_t utf8_len) size_t j = 0; for(size_t i = 0; j < utf8_len && fc[i] != 0 && fc[i] != 0xffff; i++) { - if(fc[i] <= 0x7f) + if(fc[i] == '\\') + utf8[j++] = '/'; + else if(fc[i] <= 0x7f) utf8[j++] = fc[i]; } @@ -67,21 +71,29 @@ void fc_to_utf8(char *utf8, uint16_t const *fc, size_t utf8_len) utf8[j++] = 0; } -uint16_t *utf8_to_fc_alloc(char const *utf8, uint16_t *prefix) +uint16_t *utf8_to_fc_alloc(uint16_t *prefix, char const *utf8, + uint16_t *suffix) { - size_t lenp = 0; + size_t lenp=0, lens=0; if(prefix) { while(prefix[lenp] != 0 && prefix[lenp] != 0xffff) lenp++; } + if(suffix) { + while(suffix[lens] != 0 && suffix[lens] != 0xffff) + lens++; + } size_t len = utf8_len(utf8); - uint16_t *fc = malloc((lenp+len+1) * sizeof *fc); + uint16_t *fc = malloc((lenp+len+lens+1) * sizeof *fc); if(fc != NULL) { if(prefix) memcpy(fc, prefix, lenp * sizeof *prefix); - utf8_to_fc(fc + lenp, utf8, len+1); + utf8_to_fc(fc + lenp, utf8, len); + if(suffix) + memcpy(fc + lenp + len, suffix, lens * sizeof *suffix); + fc[lenp+len+lens] = 0; } return fc; } diff --git a/src/fs/fugue/util.h b/src/fs/fugue/util.h index 22b4175..8d39d70 100644 --- a/src/fs/fugue/util.h +++ b/src/fs/fugue/util.h @@ -6,8 +6,12 @@ extern "C" { #endif #include -#include #include +#include +#include + +#define ENOTSUP_IF_NOT_FUGUE(rc) \ + if(gint[HWFS] != HWFS_FUGUE) { errno = ENOTSUP; return (rc); } /* Translate common BFile error codes to errno values. */ extern int bfile_error_to_errno(int bfile_error_code); @@ -15,6 +19,11 @@ extern int bfile_error_to_errno(int bfile_error_code); /* TODO: These functions do not actually translate special characters between encodings, they simply strip them. */ +/* Length of UTF-8 string _as copied by utf8_to_fc functions_ */ +size_t utf8_len(char const *utf8); +/* Length of FONTCHARACTER string _as copied by fc_to_utf8 functions_ */ +size_t fc_len(uint16_t const *fc); + /* Convert UTF-8 to FONTCHARACTER; outputs fc_len characters with padding. If fc[fc_len-1] is not 0 after the call, then fc is too short. */ extern void utf8_to_fc(uint16_t *fc, char const *utf8, size_t fc_len); @@ -23,7 +32,8 @@ extern void utf8_to_fc(uint16_t *fc, char const *utf8, size_t fc_len); extern void fc_to_utf8(char *utf8, uint16_t const *fc, size_t utf8_len); /* Same as utf8_to_fc() but allocates a string with malloc(). */ -extern uint16_t *utf8_to_fc_alloc(char const *utf8, uint16_t *prefix); +extern uint16_t *utf8_to_fc_alloc(uint16_t *prefix, char const *utf8, + uint16_t *suffix); /* Same as fc_to_utf8() but allocates a string with malloc(). */ extern char *fc_to_utf8_alloc(uint16_t const *fc); diff --git a/src/fs/lseek.c b/src/fs/lseek.c index c08fb35..c277c8b 100644 --- a/src/fs/lseek.c +++ b/src/fs/lseek.c @@ -4,6 +4,11 @@ off_t lseek(int fd, off_t offset, int whence) { + if(whence != SEEK_SET && whence != SEEK_CUR && whence != SEEK_END) { + errno = EINVAL; + return (off_t)-1; + } + fs_descriptor_t const *d = fs_get_descriptor(fd); if(!d) { errno = EBADF; diff --git a/src/fs/mkdir.c b/src/fs/mkdir.c new file mode 100644 index 0000000..08940eb --- /dev/null +++ b/src/fs/mkdir.c @@ -0,0 +1,8 @@ +#include +#include "fugue/fugue.h" + +int mkdir(char const *path, mode_t mode) +{ + /* Standard mkdir() is the Fugue filesystem only */ + return fugue_mkdir(path, mode); +} diff --git a/src/fs/opendir.c b/src/fs/opendir.c new file mode 100644 index 0000000..e795e23 --- /dev/null +++ b/src/fs/opendir.c @@ -0,0 +1,23 @@ +#include +#include +#include +#include +#include + +DIR *opendir(const char *name) +{ + DIR *dp = malloc(sizeof *dp); + if(!dp) { + errno = ENOMEM; + return NULL; + } + + int fd = open(name, O_DIRECTORY | O_RDONLY); + if(fd < 0) { + free(dp); + return NULL; + } + + dp->fd = fd; + return dp; +} diff --git a/src/fs/readdir.c b/src/fs/readdir.c new file mode 100644 index 0000000..10d0115 --- /dev/null +++ b/src/fs/readdir.c @@ -0,0 +1,9 @@ +#include +#include + +struct dirent *readdir(DIR *dp) +{ + struct dirent *ent = NULL; + read(dp->fd, &ent, sizeof ent); + return ent; +} diff --git a/src/fs/rewinddir.c b/src/fs/rewinddir.c new file mode 100644 index 0000000..8e33178 --- /dev/null +++ b/src/fs/rewinddir.c @@ -0,0 +1,7 @@ +#include +#include + +void rewinddir(DIR *dp) +{ + lseek(dp->fd, 0, SEEK_SET); +} diff --git a/src/fs/rmdir.c b/src/fs/rmdir.c new file mode 100644 index 0000000..ef2c9b7 --- /dev/null +++ b/src/fs/rmdir.c @@ -0,0 +1,8 @@ +#include +#include "fugue/fugue.h" + +int rmdir(char const *path) +{ + /* Standard rmdir() is the Fugue filesystem only */ + return fugue_rmdir(path); +} diff --git a/src/fs/seekdir.c b/src/fs/seekdir.c new file mode 100644 index 0000000..06f42b1 --- /dev/null +++ b/src/fs/seekdir.c @@ -0,0 +1,7 @@ +#include +#include + +void seekdir(DIR *dp, long loc) +{ + lseek(dp->fd, loc, SEEK_SET); +} diff --git a/src/fs/telldir.c b/src/fs/telldir.c new file mode 100644 index 0000000..29d7ced --- /dev/null +++ b/src/fs/telldir.c @@ -0,0 +1,7 @@ +#include +#include + +long telldir(DIR *dp) +{ + return lseek(dp->fd, 0, SEEK_CUR); +}