diff --git a/include/gint/fs.h b/include/gint/fs.h index 77cec45..6f553ba 100644 --- a/include/gint/fs.h +++ b/include/gint/fs.h @@ -20,17 +20,10 @@ extern "C" { This structure provides the base functions for every type of file descriptor. The prototypes are standard, except that the first argument (int fd) is replaced by (void *data) which points to the custom data - allocator for the descriptor. - - pread() is normally implemented in terms of lseek() and read(), however on - Fugue file descriptors on the G-III series there is no way to determine the - current position so this method won't work, and pread() is instead provided - by a non-standard parameter of BFile_Read(). The overloaded entry supports - this alternative. */ + allocator for the descriptor. */ typedef struct { /* See for a description of these functions */ ssize_t (*read)(void *data, void *buf, size_t size); - ssize_t (*pread)(void *data, void *buf, size_t size, off_t offset); ssize_t (*write)(void *data, void const *buf, size_t size); off_t (*lseek)(void *data, off_t offset, int whence); int (*close)(void *data); diff --git a/include/gint/rtc.h b/include/gint/rtc.h index 7ea8162..f1bd374 100644 --- a/include/gint/rtc.h +++ b/include/gint/rtc.h @@ -17,7 +17,11 @@ extern "C" { // Time management //--- -/* rtc_time_t: A point in time, representable in the RTC registers */ +/* rtc_time_t: A point in time, representable in the RTC registers + + WARNING: A copy of this definition is used in fxlibc, make sure to keep it + in sync. (We don't install kernel headers before compiling the fxlibc, it's + kind of a nightmare for the modest build system.) */ typedef struct { uint16_t year; /* Years (exact value, e.g. 2018) */ diff --git a/src/fs/fs.c b/src/fs/fs.c index 939ff03..57ca51b 100644 --- a/src/fs/fs.c +++ b/src/fs/fs.c @@ -76,7 +76,6 @@ int open_generic(fs_descriptor_type_t *type, void *data, int fd) static fs_descriptor_type_t devnull = { .read = NULL, - .pread = NULL, .write = NULL, .lseek = NULL, .close = NULL, @@ -92,5 +91,4 @@ GCONSTRUCTOR static void init_standard_streams(void) fdtable[STDERR_FILENO].type = &devnull; fdtable[STDERR_FILENO].data = NULL; - } diff --git a/src/fs/fugue/fugue.c b/src/fs/fugue/fugue.c index 3795968..c7d1cd8 100644 --- a/src/fs/fugue/fugue.c +++ b/src/fs/fugue/fugue.c @@ -1,91 +1,89 @@ #include #include #include +#include #include #include +#include "fugue.h" #include "util.h" -ssize_t fugue_read(void *data, void *buf, size_t size) +ssize_t fugue_read(void *data0, void *buf, size_t size) { - int fugue_fd = (int)data; + fugue_fd_t *data = data0; + int fugue_fd = data->fd; + + /* Fugue allows to read past EOF up to the end of the sector */ + int filesize = BFile_Size(fugue_fd); + if(data->pos + (int)size > filesize) + size = filesize - data->pos; int rc = BFile_Read(fugue_fd, buf, size, -1); if(rc < 0) { errno = bfile_error_to_errno(rc); return -1; } + data->pos += rc; return size; } -ssize_t fugue_pread(void *data, void *buf, size_t size, off_t offset) +ssize_t fugue_write(void *data0, const void *buf, size_t size) { - int fugue_fd = (int)data; - - /* Thanks to the extra argument to BFile_Read(), we can perform this - call without knowing the current offset, even on G-III models */ - int rc = BFile_Read(fugue_fd, buf, size, offset); - if(rc < 0) { - errno = bfile_error_to_errno(rc); - return -1; - } - BFile_Seek(fugue_fd, -size); - return rc; -} - -ssize_t fugue_write(void *data, const void *buf, size_t size) -{ - int fugue_fd = (int)data; + fugue_fd_t *data = data0; + int fugue_fd = data->fd; int rc = BFile_Write(fugue_fd, buf, size); if(rc < 0) { errno = bfile_error_to_errno(rc); return -1; } + data->pos += rc; return rc; } -off_t fugue_lseek(void *data, off_t offset, int whence) +off_t fugue_lseek(void *data0, off_t offset, int whence) { - int fugue_fd = (int)data; + fugue_fd_t *data = data0; + int fugue_fd = data->fd; - /* 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; - } + int filesize = BFile_Size(fugue_fd); if(whence == SEEK_CUR) - offset += BFile_GetPos(fugue_fd); + offset += data->pos; else if(whence == SEEK_END) - offset += BFile_Size(fugue_fd); + offset += filesize; + + /* BFile_Seek() clamps to the file size, but still returns the argument + when it does... */ + offset = min(offset, filesize); int rc = BFile_Seek(fugue_fd, offset); - if(rc < 0) { errno = bfile_error_to_errno(rc); return -1; } + data->pos = offset; /* rc is the amount of space left in the file (including pre-allocated space), so instead just return offset directly */ return offset; } -int fugue_close(void *data) +int fugue_close(void *data0) { - int fugue_fd = (int)data; + fugue_fd_t *data = data0; + int fugue_fd = data->fd; int rc = BFile_Close(fugue_fd); if(rc < 0) { errno = bfile_error_to_errno(rc); return -1; } + free(data); return 0; } const fs_descriptor_type_t fugue_descriptor_type = { .read = fugue_read, - .pread = fugue_pread, .write = fugue_write, .lseek = fugue_lseek, .close = fugue_close, diff --git a/src/fs/fugue/fugue.h b/src/fs/fugue/fugue.h index 3848779..1a4d4d8 100644 --- a/src/fs/fugue/fugue.h +++ b/src/fs/fugue/fugue.h @@ -12,6 +12,13 @@ extern const fs_descriptor_type_t fugue_descriptor_type; /* Directory descriptor type */ extern const fs_descriptor_type_t fugue_dir_descriptor_type; +/* Since on Graph 35+E II / fx-9860G III there is no (known) syscall to update + the file position, we need to track it ourselves, hopefully faithfully. */ +typedef struct { + int fd; + int pos; +} fugue_fd_t; + /* Specific implementations of some standard functions */ int fugue_open(char const *path, int flags, mode_t mode); diff --git a/src/fs/fugue/fugue_dir.c b/src/fs/fugue/fugue_dir.c index 4d89296..69c9467 100644 --- a/src/fs/fugue/fugue_dir.c +++ b/src/fs/fugue/fugue_dir.c @@ -41,13 +41,6 @@ ssize_t fugue_dir_read(void *data, void *buf, GUNUSED size_t size) 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) { @@ -90,7 +83,6 @@ int fugue_dir_close(void *data) 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, diff --git a/src/fs/fugue/fugue_open.c b/src/fs/fugue/fugue_open.c index aa1cdc7..e1c4684 100644 --- a/src/fs/fugue/fugue_open.c +++ b/src/fs/fugue/fugue_open.c @@ -113,14 +113,23 @@ int fugue_open(char const *path, int flags, GUNUSED mode_t mode) BFile_Seek(fugue_fd, BFile_Size(fugue_fd)); /* Return the now-open file descriptor */ - fs_descriptor_t data = { + fugue_fd_t *data = malloc(sizeof *data); + if(!data) { + BFile_Close(fugue_fd); + goto end; + } + data->fd = fugue_fd; + data->pos = 0; + + fs_descriptor_t fd_data = { .type = &fugue_descriptor_type, - .data = (void *)fugue_fd, + .data = data, }; - rc = fd = fs_create_descriptor(&data); + rc = fd = fs_create_descriptor(&fd_data); if(fd == -1) { BFile_Close(fugue_fd); + free(data); errno = ENFILE; goto end; } diff --git a/src/fs/pread.c b/src/fs/pread.c index 42aa7d6..d06f777 100644 --- a/src/fs/pread.c +++ b/src/fs/pread.c @@ -4,15 +4,21 @@ ssize_t pread(int fd, void *buf, size_t size, off_t offset) { - fs_descriptor_t const *d = fs_get_descriptor(fd); - if(!d) { - errno = EBADF; + off_t current = lseek(fd, 0, SEEK_CUR); + if(current == (off_t)-1) return (ssize_t)-1; - } - if(d->type->pread) - return d->type->pread(d->data, buf, size, offset); + ssize_t rc = -1; - /* No seek function: cannot seek */ - return 0; + if(lseek(fd, offset, SEEK_SET) == (off_t)-1) + goto end; + + rc = read(fd, buf, size); + if(rc < 0) + goto end; + +end: + /* At the end, always try to restore the current position */ + lseek(fd, current, SEEK_CUR); + return rc; } diff --git a/src/fs/pwrite.c b/src/fs/pwrite.c index bcbcb5f..10b8ff7 100644 --- a/src/fs/pwrite.c +++ b/src/fs/pwrite.c @@ -3,8 +3,6 @@ ssize_t pwrite(int fd, const void *buf, size_t size, off_t offset) { off_t current = lseek(fd, 0, SEEK_CUR); - - /* This fails on G-III BFile and non-seekable file descriptors */ if(current == (off_t)-1) return (ssize_t)-1;