diff --git a/include/gint/bfile.h b/include/gint/bfile.h index fecab0e..6be4ba5 100644 --- a/include/gint/bfile.h +++ b/include/gint/bfile.h @@ -64,8 +64,13 @@ extern "C" { #endif +#include #include +// BFile has a different interface on CP-400, which is not exposed by gint +// because the standard API is always available. +#if !GINT_OS_CP + //--- // Common file access functions //--- @@ -308,6 +313,8 @@ int BFile_FindClose(int shandle); /* BFile_Ext_Stat(): Stat an entry for type and size */ int BFile_Ext_Stat(uint16_t const *path, int *type, int *size); +#endif /* !GINT_OS_CP */ + #ifdef __cplusplus } #endif diff --git a/src/fs/fugue/BFile_Ext_Stat.c b/src/fs/fugue/BFile_Ext_Stat.c index bde0c2a..45b24a0 100644 --- a/src/fs/fugue/BFile_Ext_Stat.c +++ b/src/fs/fugue/BFile_Ext_Stat.c @@ -1,6 +1,10 @@ #include #include "util.h" +#include "bfilecp.h" +// TODO: BFile_Ext_Stat: Use native stat function on CP-400? +// Unlike find functions, it doesn't provide type, as per documented API at +// least, and stat really needs it. So for now I'm sticking to the find check. int BFile_Ext_Stat(uint16_t const *path, int *type, int *size) { int search_handle, rc; diff --git a/src/fs/fugue/bfilecp.h b/src/fs/fugue/bfilecp.h new file mode 100644 index 0000000..5822cf5 --- /dev/null +++ b/src/fs/fugue/bfilecp.h @@ -0,0 +1,121 @@ +// CP version of the BFile interface, which is much closer to POSIX. +// Functions not available elsewhere that could be useful for optimization: +// fstat, getAddr + +#ifndef GINT_FS_BFILECP_H +#define GINT_FS_BFILECP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +// Only for CP, obviously. +#if GINT_OS_CP + +#define BFileCP_ENOMEM -1 +#define BFileCP_EINVAL -2 +#define BFileCP_EDEVFAIL -3 +#define BFileCP_EMOUNTED -4 +#define BFileCP_EACCES -5 +#define BFileCP_EBADFSID -6 +#define BFileCP_ENOVOLUME -7 +#define BFileCP_ENOPATH -8 +#define BFileCP_EEXIST -9 +#define BFileCP_ENAMETOOLONG -10 +#define BFileCP_EOUTOFBOUND -11 +#define BFileCP_EUNFORMAT -12 +#define BFileCP_ENOSPC -13 +#define BFileCP_ENOENT -14 +#define BFileCP_EISDIRECTORY -15 +#define BFileCP_ESHARE -16 +#define BFileCP_EMFILE -17 +#define BFileCP_EBADF -18 +#define BFileCP_EEOF -19 +#define BFileCP_ENOTEMPTY -20 +#define BFileCP_ECLUSTERSIZEMISMATCH -40 +#define BFileCP_ESYSTEM -99 + +#define BFile_ReadOnly 0x01 +#define BFile_WriteOnly 0x02 +#define BFile_ReadWrite (BFile_ReadOnly | BFile_WriteOnly) +#define BFile_CreateFlag 0x04 +#define BFile_AppendFlag 0x10 + +int BFile_Open(const char *path, int flags); + +int BFile_Read(int fd, void *buf, int size); +int BFile_Write(int fd, void const *buf, int size); + +#define BFileCP_SEEK_SET 0 +#define BFileCP_SEEK_CUR 1 +#define BFileCP_SEEK_END 2 +int BFile_Seek(int fd, int offset, int whence); + +int BFile_Close(int fd); + +int BFile_Remove(char const *path); +int BFile_Rename(char const *oldpath, char const *newpath); +int BFile_Mkdir(char const *path); + +//--- +// Metadata API +//--- + +// Dates are bitfields { year-1980: 8; month-1-12: 4; day-1-31: 4; } +// Times are bitfields { hour: 5; minute: 6; seconds_div2: 5; } +struct BFile_Statbuf { + u32 _1; + u32 size; // file size in bytes + u16 creationDate; + u16 creationTime; + u16 lastModifiedDate; + u16 lastModifiedTime; + u16 _2; + u16 lastAccessDate; +}; + +int BFile_FStat(int fd, struct BFile_Statbuf *statbuf); + +// For API compatibility with older models. +static inline int BFile_Size(int fd) { + struct BFile_Statbuf statbuf; + int rc = BFile_FStat(fd, &statbuf); + return (rc >= 0) ? (int)statbuf.size : rc; +} + +int BFile_Stat(const char *path, struct BFile_Statbuf *statbuf); + +// Same as legacy, uses find API. +int BFile_Ext_Stat(uint16_t const *path, int *type, int *size); + +//--- +// Search API +//--- + +#define BFile_Type_File 1 +#define BFile_Type_Directory 5 + +struct BFile_FileInfo { + u32 _1; + u16 type; /* 1=File, 5=Directory */ + u16 _2; + u32 file_size; /* in bytes; 0 for folders */ + u32 _3, _4; +}; + +// Same as legacy. +int BFile_FindFirst(u16 const *pattern, int *shandle, u16 *foundfile, + struct BFile_FileInfo *fileinfo); +int BFile_FindNext( + int shandle, u16 *foundfile, struct BFile_FileInfo *fileinfo); +int BFile_FindClose(int shandle); + +#endif /* GINT_OS_CP */ + +#ifdef __cplusplus +} +#endif + +#endif /* GINT_FS_BFILECP_H */ diff --git a/src/fs/fugue/fugue.c b/src/fs/fugue/fugue.c index 00185da..fd55df7 100644 --- a/src/fs/fugue/fugue.c +++ b/src/fs/fugue/fugue.c @@ -8,6 +8,7 @@ #include #include "fugue.h" #include "util.h" +#include "bfilecp.h" ssize_t fugue_read(void *data0, void *buf, size_t size) { @@ -19,7 +20,11 @@ ssize_t fugue_read(void *data0, void *buf, size_t size) if(data->pos + (int)size > filesize) size = filesize - data->pos; +#if GINT_OS_CP + int rc = BFile_Read(fugue_fd, buf, size); +#else int rc = BFile_Read(fugue_fd, buf, size, -1); +#endif if(rc < 0) { errno = bfile_error_to_errno(rc); return -1; @@ -100,6 +105,19 @@ off_t fugue_lseek(void *data0, off_t offset, int whence) fugue_fd_t *data = data0; int fugue_fd = data->fd; + // TODO: fugue_lseek: CP400 optimization with native whence? +#if GINT_OS_CP + whence = (whence == SEEK_SET) ? BFileCP_SEEK_SET : + (whence == SEEK_CUR) ? BFileCP_SEEK_CUR : + BFileCP_SEEK_END; + int rc = BFile_Seek(fugue_fd, offset, whence); + if(rc < 0) { + errno = bfile_error_to_errno(rc); + return -1; + } + data->pos = rc; + return rc; +#else int filesize = BFile_Size(fugue_fd); if(whence == SEEK_CUR) @@ -121,6 +139,7 @@ off_t fugue_lseek(void *data0, off_t offset, int whence) /* rc is the amount of space left in the file (including pre-allocated space), so instead just return offset directly */ return offset; +#endif } int fugue_close(void *data0) diff --git a/src/fs/fugue/fugue_dir.c b/src/fs/fugue/fugue_dir.c index d8a8fc0..54292c7 100644 --- a/src/fs/fugue/fugue_dir.c +++ b/src/fs/fugue/fugue_dir.c @@ -9,6 +9,7 @@ #include #include "util.h" #include "fugue.h" +#include "bfilecp.h" typedef struct { @@ -116,7 +117,11 @@ void *fugue_dir_explore(char const *path) rc = BFile_FindFirst(search, &sd, fc_path, &info); if(rc < 0) { +#if GINT_OS_CP + if(rc != BFileCP_ENOENT) // BFileCP_EOUTOFBOUND? +#else if(rc != BFile_EntryNotFound) +#endif errno = bfile_error_to_errno(rc); goto error; } diff --git a/src/fs/fugue/fugue_mkdir.c b/src/fs/fugue/fugue_mkdir.c index 29f10b9..5dba72e 100644 --- a/src/fs/fugue/fugue_mkdir.c +++ b/src/fs/fugue/fugue_mkdir.c @@ -3,11 +3,20 @@ #include #include #include "util.h" +#include "bfilecp.h" int fugue_mkdir(char const *path, GUNUSED mode_t mode) { ENOTSUP_IF_NOT_FUGUE(-1); +#if GINT_OS_CP + int rc = BFile_Mkdir(path); + if(rc < 0) { + errno = bfile_error_to_errno(rc); + return -1; + } + return 0; +#else uint16_t *fcpath = fs_path_normalize_fc(path); if(!fcpath) { errno = ENOMEM; @@ -23,4 +32,5 @@ int fugue_mkdir(char const *path, GUNUSED mode_t mode) free(fcpath); return 0; +#endif } diff --git a/src/fs/fugue/fugue_open.c b/src/fs/fugue/fugue_open.c index c9ecce4..2599c7f 100644 --- a/src/fs/fugue/fugue_open.c +++ b/src/fs/fugue/fugue_open.c @@ -5,32 +5,44 @@ #include #include "util.h" #include "fugue.h" +#include "bfilecp.h" -static int new_file_size; +GUNUSED static int new_file_size; int fugue_open(char const *path, int flags, GUNUSED mode_t mode) { ENOTSUP_IF_NOT_FUGUE(-1); uint16_t *fcpath = fs_path_normalize_fc(path); - int fugue_fd, err, rc=-1, type, fd=-1; + int fugue_fd, rc=-1, type, fd=-1; if(!fcpath) { errno = ENOMEM; return -1; } +#if GINT_OS_CP + char *normpath = fs_path_normalize(path); + if(!normpath) { + errno = ENOMEM; + free(fcpath); + return -1; + } +#define NORMALIZED_PATH normpath +#else +#define NORMALIZED_PATH fcpath +#endif + /* 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); +#if GINT_OS_CP + if(flags & O_APPEND) + bfile_mode |= BFile_AppendFlag; +#endif /* Stat the entry. A special case is needed for the root, which doesn't respond well. fs_path_normalize_fc() normalizes the path so we just @@ -45,8 +57,9 @@ int fugue_open(char const *path, int flags, GUNUSED mode_t mode) if(!exists) type = -1; } - /* If the entry exists and O_EXCL was requested, fail. */ - if(exists && excl) { + /* O_EXCL: Succeed *only* if we're creating the file. Only has an + effect when combined with O_CREAT, unsurprisingly. */ + if(exists && (flags & O_EXCL) && (flags & O_CREAT)) { errno = EEXIST; rc = -1; goto end; @@ -76,35 +89,42 @@ int fugue_open(char const *path, int flags, GUNUSED mode_t mode) 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); + /* We now have a regular file. Before opening it, we may need to: + 1. Delete it to truncate it (BFile never truncates AFAIK) + - If O_TRUNC and the file exists (obviously). + - Deleting and recreating for truncation purposes is allowed when + not setting O_CREAT. In case of error midway, good luck. + 2. Create it (except fx-CP 400 which can create in BFile_Open()) + - If it didn't exist and O_CREAT was allowed; or + - if it did exist but was removed for truncation in step 1. + 3. Finally, open the file. */ - /* 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; + /* Delete for truncation. */ + if((flags & O_TRUNC) && exists) { + BFile_Remove(NORMALIZED_PATH); + /* Whatever happens now, allow recreating the file. */ + exists = false; + flags |= O_CREAT; } - /* If the file does not exist and O_CREAT is set, create it */ - if((flags & O_CREAT) && ((flags & O_TRUNC) || fugue_fd < 0)) { - new_file_size = 0; - err = BFile_Create(fcpath, BFile_File, &new_file_size); + /* Create the file now, either directly with BFile_Create(), or with + the appropriate flag on fx-CP 400. */ + if((flags & O_CREAT) && !exists) { +#if GINT_OS_CP + bfile_mode |= BFile_CreateFlag; +#else + int err = BFile_Create(fcpath, BFile_File, &new_file_size); if(err < 0) { errno = bfile_error_to_errno(err); rc = -1; goto end; } - fugue_fd = BFile_Open(fcpath, bfile_mode); +#endif } + /* Proceed with the final BFile_Open() call. */ + fugue_fd = BFile_Open(NORMALIZED_PATH, bfile_mode); + if(fugue_fd < 0) { errno = bfile_error_to_errno(fugue_fd); rc = fugue_fd; @@ -114,10 +134,12 @@ int fugue_open(char const *path, int flags, GUNUSED mode_t mode) /* If O_APPEND is set, move to the end of the file */ // TODO: O_APPEND should move the cursor before *each* write int pos = 0; +#if !GINT_OS_CP if((flags & O_APPEND)) { pos = BFile_Size(fugue_fd); BFile_Seek(fugue_fd, pos); } +#endif /* Return the now-open file descriptor */ fugue_fd_t *data = malloc(sizeof *data); @@ -142,6 +164,9 @@ int fugue_open(char const *path, int flags, GUNUSED mode_t mode) } end: +#if GINT_OS_CP + free(normpath); +#endif free(fcpath); return rc; } diff --git a/src/fs/fugue/fugue_rename.c b/src/fs/fugue/fugue_rename.c index 6eaded6..d3ff266 100644 --- a/src/fs/fugue/fugue_rename.c +++ b/src/fs/fugue/fugue_rename.c @@ -4,35 +4,35 @@ #include #include #include "util.h" +#include "bfilecp.h" int fugue_rename(char const *oldpath, char const *newpath) { ENOTSUP_IF_NOT_FUGUE(-1); - int rc = -1; - uint16_t *fcpath_1 = NULL; - uint16_t *fcpath_2 = NULL; - - fcpath_1 = fs_path_normalize_fc(oldpath); +#if GINT_OS_CP + int rc = BFile_Rename(oldpath, newpath); +#else + u16 *fcpath_1 = fs_path_normalize_fc(oldpath); if(!fcpath_1) { errno = ENOMEM; - goto end; + return -1; } - fcpath_2 = fs_path_normalize_fc(newpath); + u16 *fcpath_2 = fs_path_normalize_fc(newpath); if(!fcpath_2) { errno = ENOMEM; - goto end; + free(fcpath_1); + return -1; } - rc = BFile_Rename(fcpath_1, fcpath_2); - if(rc < 0) { - errno = bfile_error_to_errno(rc); - rc = -1; - } - else rc = 0; - -end: + int rc = BFile_Rename(fcpath_1, fcpath_2); free(fcpath_1); free(fcpath_2); - return rc; +#endif + + if(rc < 0) { + errno = bfile_error_to_errno(rc); + return -1; + } + return 0; } diff --git a/src/fs/fugue/fugue_rmdir.c b/src/fs/fugue/fugue_rmdir.c index ceff28e..c0cf60e 100644 --- a/src/fs/fugue/fugue_rmdir.c +++ b/src/fs/fugue/fugue_rmdir.c @@ -6,6 +6,7 @@ #include #include "util.h" #include "fugue.h" +#include "bfilecp.h" int fugue_rmdir(char const *path) { @@ -33,6 +34,9 @@ int fugue_rmdir(char const *path) return -1; } +#if GINT_OS_CP + int rc = BFile_Remove(path); +#else uint16_t *fcpath = fs_path_normalize_fc(path); if(!fcpath) { errno = ENOMEM; @@ -40,12 +44,12 @@ int fugue_rmdir(char const *path) } int rc = BFile_Remove(fcpath); + free(fcpath); +#endif + if(rc < 0) { errno = bfile_error_to_errno(rc); - rc = -1; + return -1; } - else rc = 0; - - free(fcpath); - return rc; + return 0; } diff --git a/src/fs/fugue/fugue_stat.c b/src/fs/fugue/fugue_stat.c index 6cf43a9..14bc845 100644 --- a/src/fs/fugue/fugue_stat.c +++ b/src/fs/fugue/fugue_stat.c @@ -5,6 +5,7 @@ #include #include #include "util.h" +#include "bfilecp.h" int fugue_stat(char const * restrict path, struct stat * restrict statbuf) { diff --git a/src/fs/fugue/fugue_unlink.c b/src/fs/fugue/fugue_unlink.c index cff9cb8..be51a98 100644 --- a/src/fs/fugue/fugue_unlink.c +++ b/src/fs/fugue/fugue_unlink.c @@ -4,6 +4,7 @@ #include #include #include "util.h" +#include "bfilecp.h" int fugue_unlink(char const *path) { @@ -19,23 +20,25 @@ int fugue_unlink(char const *path) rc = BFile_Ext_Stat(fcpath, &type, &size); if(rc < 0) { errno = bfile_error_to_errno(rc); - rc = -1; - goto end; + free(fcpath); + return -1; } if(bfile_type_to_mode_t(type) != S_IFREG) { errno = ENOTDIR; - rc = -1; - goto end; + free(fcpath); + return -1; } +#if GINT_OS_CP + rc = BFile_Remove(path); +#else rc = BFile_Remove(fcpath); +#endif + free(fcpath); + if(rc < 0) { errno = bfile_error_to_errno(rc); - rc = -1; + return -1; } - else rc = 0; - -end: - free(fcpath); - return rc; + return 0; } diff --git a/src/fs/fugue/util.c b/src/fs/fugue/util.c index 2759bb3..b7131d2 100644 --- a/src/fs/fugue/util.c +++ b/src/fs/fugue/util.c @@ -1,4 +1,5 @@ #include "util.h" +#include "bfilecp.h" #include #include #include @@ -9,6 +10,33 @@ int bfile_error_to_errno(int e) { +#if GINT_OS_CP + switch(e) { + case BFileCP_ENOMEM: return ENOMEM; + case BFileCP_EINVAL: return EINVAL; + case BFileCP_EDEVFAIL: return EIO; + case BFileCP_EMOUNTED: return ENODEV; + case BFileCP_EACCES: return EACCES; + case BFileCP_EBADFSID: return ENODEV; + case BFileCP_ENOVOLUME: return ENODEV; + case BFileCP_ENOPATH: return ENOENT; + case BFileCP_EEXIST: return EEXIST; + case BFileCP_ENAMETOOLONG: return EINVAL; + case BFileCP_EOUTOFBOUND: return EINVAL; + case BFileCP_EUNFORMAT: return EINVAL; + case BFileCP_ENOSPC: return ENOSPC; + case BFileCP_ENOENT: return ENOENT; + case BFileCP_EISDIRECTORY: return EISDIR; + case BFileCP_ESHARE: return EINVAL; + case BFileCP_EMFILE: return EMFILE; + case BFileCP_EBADF: return EBADF; + case BFileCP_EEOF: return EINVAL; + case BFileCP_ENOTEMPTY: return EINVAL; + case BFileCP_ECLUSTERSIZEMISMATCH: return EINVAL; + case BFileCP_ESYSTEM: return EINVAL; + default: return errno; + } +#else /* TODO: Find BFile code for too many fds and map it to ENFILE. */ switch(e) { case BFile_EntryNotFound: return ENOENT; @@ -26,20 +54,28 @@ int bfile_error_to_errno(int e) case BFile_DeviceNotFound: return ENOENT; default: return errno; } +#endif } int bfile_type_to_mode_t(int bfile_type) { +#if GINT_OS_CP + return bfile_type == BFile_Type_Directory ? S_IFDIR : S_IFREG; +#else switch(bfile_type) { case BFile_Type_Directory: return S_IFDIR; case BFile_Type_Dot: return S_IFDIR; case BFile_Type_DotDot: return S_IFDIR; default: return S_IFREG; } +#endif } int bfile_type_to_dirent(int bfile_type) { +#if GINT_OS_CP + return bfile_type == BFile_Type_Directory ? DT_DIR : DT_REG; +#else switch(bfile_type) { case BFile_Type_Directory: return DT_DIR; case BFile_Type_Dot: return DT_DIR; @@ -54,6 +90,7 @@ int bfile_type_to_dirent(int bfile_type) case BFile_Type_Archived: return DT_REG; default: return DT_UNKNOWN; } +#endif } /* Length of FONTCHARACTER and UTF-8 strings, counting only ASCII characters */