mirror of
https://git.planet-casio.com/Lephenixnoir/gint.git
synced 2024-12-28 20:43:36 +01:00
fs: cast BFile support into generic file descriptors
This paves the way for standard streams, USB streams, and some more.
This commit is contained in:
parent
321d6937e0
commit
6903bd58d5
16 changed files with 498 additions and 164 deletions
|
@ -35,17 +35,20 @@ set(SOURCES_COMMON
|
||||||
src/dma/inth.s
|
src/dma/inth.s
|
||||||
src/dma/memcpy.c
|
src/dma/memcpy.c
|
||||||
src/dma/memset.c
|
src/dma/memset.c
|
||||||
# Filesystem interface (Fugue only)
|
# Filesystem interface
|
||||||
src/fs/close.c
|
src/fs/close.c
|
||||||
src/fs/creat.c
|
src/fs/creat.c
|
||||||
|
src/fs/fs.c
|
||||||
src/fs/lseek.c
|
src/fs/lseek.c
|
||||||
src/fs/open.c
|
src/fs/open.c
|
||||||
src/fs/pread.c
|
src/fs/pread.c
|
||||||
src/fs/pwrite.c
|
src/fs/pwrite.c
|
||||||
src/fs/read.c
|
src/fs/read.c
|
||||||
src/fs/unlink.c
|
src/fs/unlink.c
|
||||||
src/fs/util.c
|
|
||||||
src/fs/write.c
|
src/fs/write.c
|
||||||
|
# Filesystem interface to Fugue
|
||||||
|
src/fs/fugue/fugue.c
|
||||||
|
src/fs/fugue/util.c
|
||||||
# Interrupt Controller driver
|
# Interrupt Controller driver
|
||||||
src/intc/intc.c
|
src/intc/intc.c
|
||||||
src/intc/inth.s
|
src/intc/inth.s
|
||||||
|
|
|
@ -129,6 +129,11 @@ int BFile_Write(int fd, void const *data, int even_size);
|
||||||
* If [whence >= 0], it is taken as an absolute location within the file;
|
* If [whence >= 0], it is taken as an absolute location within the file;
|
||||||
* If [whence == -1], BFile_Read() reads from the current position.
|
* If [whence == -1], BFile_Read() reads from the current position.
|
||||||
|
|
||||||
|
With Fugue this function can read past end of file and return the requested
|
||||||
|
amount of bytes even when the file does not have enough data to read that
|
||||||
|
much. It seems that extra bytes read as zeros. Reading past the end does
|
||||||
|
*not* extend the file size.
|
||||||
|
|
||||||
With CASIOWIN, returns how much data can be read from the updated file
|
With CASIOWIN, returns how much data can be read from the updated file
|
||||||
offset (ie. how many bytes until end of file), or an error code.
|
offset (ie. how many bytes until end of file), or an error code.
|
||||||
With Fugue, returns the amount of data read (or an error code). */
|
With Fugue, returns the amount of data read (or an error code). */
|
||||||
|
|
94
include/gint/fs.h
Normal file
94
include/gint/fs.h
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
//---
|
||||||
|
// gint:fs - Filesystem abstraction
|
||||||
|
//---
|
||||||
|
|
||||||
|
#ifndef GINT_FS
|
||||||
|
#define GINT_FS
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
/* Maximum number of file descriptors */
|
||||||
|
#define FS_FD_MAX 32
|
||||||
|
|
||||||
|
/* fs_descriptor_type_t: Overloaded file descriptor functions
|
||||||
|
|
||||||
|
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. */
|
||||||
|
typedef struct {
|
||||||
|
/* See <unistd.h> 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);
|
||||||
|
|
||||||
|
} fs_descriptor_type_t;
|
||||||
|
|
||||||
|
/* fs_descriptor_t: File descriptor information
|
||||||
|
This internal type describes the entries of the descriptor table. */
|
||||||
|
typedef struct {
|
||||||
|
/* Interface functions */
|
||||||
|
fs_descriptor_type_t const *type;
|
||||||
|
/* Custom data (can also be an integer cast to (void *)) */
|
||||||
|
void *data;
|
||||||
|
|
||||||
|
} fs_descriptor_t;
|
||||||
|
|
||||||
|
/* fs_get_descriptor(): Get a file descriptor's data
|
||||||
|
|
||||||
|
This function is used internally in order to implement read(), write(), and
|
||||||
|
other standard functions functions. It could be useful for other APIs that
|
||||||
|
want to present their resources as file descriptors but still implement
|
||||||
|
extra non-standard functions; this allows them to use the file descriptor as
|
||||||
|
input and still access the custom data.
|
||||||
|
|
||||||
|
Returns NULL if there is no file descriptor with this number, in which case
|
||||||
|
the caller probably needs to set errno = EBADF. */
|
||||||
|
fs_descriptor_t const *fs_get_descriptor(int fd);
|
||||||
|
|
||||||
|
/* fs_create_descriptor(): Create a new file descriptor
|
||||||
|
|
||||||
|
This function is used in open() and its variants to allocate new file
|
||||||
|
descriptors. The descriptor's data is created with a copy of the provided
|
||||||
|
structure, which must include a non-NULL type attribute.
|
||||||
|
|
||||||
|
This function always returns the smallest file descriptor that is unused by
|
||||||
|
the application and is not 0, 1 or 2; unless it runs out of file
|
||||||
|
descriptors, in which case it returns -1 and the caller might want to set
|
||||||
|
errno = ENFILE. */
|
||||||
|
int fs_create_descriptor(fs_descriptor_t const *data);
|
||||||
|
|
||||||
|
/* fs_free_descriptor(): Clsoe 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
|
||||||
|
normally no need to call this function directly. */
|
||||||
|
void fs_free_descriptor(int fd);
|
||||||
|
|
||||||
|
/* open_generic(): Open a file descriptor using custom file functions
|
||||||
|
|
||||||
|
Opens a new file descriptor of the specified type with the provided user
|
||||||
|
data. If reuse_fd < 0, a new file descriptor is allocated, otherwise the
|
||||||
|
exact file descriptor reuse_fd is used. (This is useful to reopen standard
|
||||||
|
streams.) In this case, the only possible return values are -1 and reuse_fd
|
||||||
|
itself. */
|
||||||
|
int open_generic(fs_descriptor_type_t *type, void *data, int reuse_fd);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* GINT_FS */
|
|
@ -1,14 +1,19 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include "util.h"
|
#include <gint/fs.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
int close(int fd)
|
int close(int fd)
|
||||||
{
|
{
|
||||||
ENOTSUP_IF_NOT_FUGUE(-1);
|
fs_descriptor_t const *d = fs_get_descriptor(fd);
|
||||||
|
if(!d) {
|
||||||
int err = BFile_Close(fd);
|
errno = EBADF;
|
||||||
if(err < 0) {
|
return (ssize_t)-1;
|
||||||
errno = bfile_error_to_errno(err);
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
|
int rc = 0;
|
||||||
|
if(d->type->close)
|
||||||
|
rc = d->type->close(d->data);
|
||||||
|
|
||||||
|
fs_free_descriptor(fd);
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
96
src/fs/fs.c
Normal file
96
src/fs/fs.c
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
#include <gint/fs.h>
|
||||||
|
#include <gint/defs/attributes.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
/* File descriptor table */
|
||||||
|
static fs_descriptor_t fdtable[FS_FD_MAX] = { 0 };
|
||||||
|
|
||||||
|
fs_descriptor_t const *fs_get_descriptor(int fd)
|
||||||
|
{
|
||||||
|
if((unsigned)fd >= FS_FD_MAX)
|
||||||
|
return NULL;
|
||||||
|
if(fdtable[fd].type == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return &fdtable[fd];
|
||||||
|
}
|
||||||
|
|
||||||
|
int fs_create_descriptor(fs_descriptor_t const *data)
|
||||||
|
{
|
||||||
|
if(data->type == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Leave 0/1/2 for stdin, stdout and stderr */
|
||||||
|
for(int i = 3; i < FS_FD_MAX; i++) {
|
||||||
|
if(fdtable[i].type == NULL) {
|
||||||
|
fdtable[i] = *data;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fs_free_descriptor(int fd)
|
||||||
|
{
|
||||||
|
if((unsigned)fd >= FS_FD_MAX)
|
||||||
|
return;
|
||||||
|
|
||||||
|
fdtable[fd].type = NULL;
|
||||||
|
fdtable[fd].data = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int open_generic(fs_descriptor_type_t *type, void *data, int fd)
|
||||||
|
{
|
||||||
|
if(!type) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
fs_descriptor_t d = {
|
||||||
|
.type = type,
|
||||||
|
.data = data
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Re-use file descriptor mode */
|
||||||
|
if(fd >= 0) {
|
||||||
|
if(fd >= FS_FD_MAX) {
|
||||||
|
errno = EBADF;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(fdtable[fd].type) {
|
||||||
|
errno = ENFILE;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fdtable[fd] = d;
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
/* Normal allocation mode */
|
||||||
|
else {
|
||||||
|
return fs_create_descriptor(&d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Standard streams */
|
||||||
|
|
||||||
|
static fs_descriptor_type_t devnull = {
|
||||||
|
.read = NULL,
|
||||||
|
.pread = NULL,
|
||||||
|
.write = NULL,
|
||||||
|
.lseek = NULL,
|
||||||
|
.close = NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
GCONSTRUCTOR static void init_standard_streams(void)
|
||||||
|
{
|
||||||
|
fdtable[STDIN_FILENO].type = &devnull;
|
||||||
|
fdtable[STDIN_FILENO].data = NULL;
|
||||||
|
|
||||||
|
fdtable[STDOUT_FILENO].type = &devnull;
|
||||||
|
fdtable[STDOUT_FILENO].data = NULL;
|
||||||
|
|
||||||
|
fdtable[STDERR_FILENO].type = &devnull;
|
||||||
|
fdtable[STDERR_FILENO].data = NULL;
|
||||||
|
|
||||||
|
}
|
209
src/fs/fugue/fugue.c
Normal file
209
src/fs/fugue/fugue.c
Normal file
|
@ -0,0 +1,209 @@
|
||||||
|
#include <gint/fs.h>
|
||||||
|
#include <gint/hardware.h>
|
||||||
|
#include <gint/bfile.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
ssize_t fugue_read(void *data, void *buf, size_t size)
|
||||||
|
{
|
||||||
|
int fugue_fd = (int)data;
|
||||||
|
|
||||||
|
int rc = BFile_Read(fugue_fd, buf, size, -1);
|
||||||
|
if(rc < 0) {
|
||||||
|
errno = bfile_error_to_errno(rc);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t fugue_pread(void *data, void *buf, size_t size, off_t offset)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
|
int rc = BFile_Write(fugue_fd, buf, size);
|
||||||
|
if(rc < 0) {
|
||||||
|
errno = bfile_error_to_errno(rc);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
else if(whence == SEEK_END)
|
||||||
|
destination = BFile_Size(fugue_fd) + offset;
|
||||||
|
|
||||||
|
int rc = BFile_Seek(fugue_fd, destination);
|
||||||
|
|
||||||
|
if(rc < 0) {
|
||||||
|
errno = bfile_error_to_errno(rc);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* rc is the amount of space left in the file (including pre-allocated
|
||||||
|
space), so instead just return destination directly */
|
||||||
|
return (off_t)destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fugue_close(void *data)
|
||||||
|
{
|
||||||
|
int fugue_fd = (int)data;
|
||||||
|
|
||||||
|
int rc = BFile_Close(fugue_fd);
|
||||||
|
if(rc < 0) {
|
||||||
|
errno = bfile_error_to_errno(rc);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static 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;
|
||||||
|
}
|
13
src/fs/fugue/fugue.h
Normal file
13
src/fs/fugue/fugue.h
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#ifndef FS_FUGUE_FUGUE_H
|
||||||
|
#define FS_FUGUE_FUGUE_H
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
||||||
|
#endif /* FS_FUGUE_FUGUE_H */
|
|
@ -1,6 +1,8 @@
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <bfile.h>
|
||||||
|
|
||||||
int bfile_error_to_errno(int e)
|
int bfile_error_to_errno(int e)
|
||||||
{
|
{
|
|
@ -7,13 +7,7 @@ extern "C" {
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <errno.h>
|
|
||||||
#include <bfile.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <gint/hardware.h>
|
|
||||||
|
|
||||||
#define ENOTSUP_IF_NOT_FUGUE(rc) \
|
|
||||||
if(gint[HWFS] != HWFS_FUGUE) { errno = ENOTSUP; return rc; }
|
|
||||||
|
|
||||||
/* Translate common BFile error codes to errno values. */
|
/* Translate common BFile error codes to errno values. */
|
||||||
extern int bfile_error_to_errno(int bfile_error_code);
|
extern int bfile_error_to_errno(int bfile_error_code);
|
|
@ -1,37 +1,18 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include "util.h"
|
#include <gint/fs.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
off_t lseek(int fd, off_t offset, int whence)
|
off_t lseek(int fd, off_t offset, int whence)
|
||||||
{
|
{
|
||||||
ENOTSUP_IF_NOT_FUGUE((off_t)-1);
|
fs_descriptor_t const *d = fs_get_descriptor(fd);
|
||||||
|
if(!d) {
|
||||||
if(whence != SEEK_SET && whence != SEEK_CUR && whence != SEEK_END) {
|
errno = EBADF;
|
||||||
errno = EINVAL;
|
return (ssize_t)-1;
|
||||||
return (off_t)-1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* On Graph 35+E II, there is no documented way to know the offset. */
|
if(d->type->lseek)
|
||||||
if(gint[HWCALC] == HWCALC_G35PE2 && whence == SEEK_CUR) {
|
return d->type->lseek(d->data, offset, whence);
|
||||||
errno = ENOTSUP;
|
|
||||||
return (off_t)-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
off_t destination;
|
/* No seek function: cannot seek */
|
||||||
if(whence == SEEK_SET)
|
return 0;
|
||||||
destination = offset;
|
|
||||||
else if(whence == SEEK_CUR)
|
|
||||||
destination = BFile_GetPos(fd) + offset;
|
|
||||||
else if(whence == SEEK_END)
|
|
||||||
destination = BFile_Size(fd) - offset;
|
|
||||||
|
|
||||||
int rc = BFile_Seek(fd, destination);
|
|
||||||
|
|
||||||
if(rc < 0) {
|
|
||||||
errno = bfile_error_to_errno(rc);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* rc is the amount of space left in the file (including pre-allocated
|
|
||||||
space), so instead just return destination directly */
|
|
||||||
return (off_t)destination;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,74 +1,14 @@
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include "util.h"
|
#include <stdarg.h>
|
||||||
|
#include "fugue/fugue.h"
|
||||||
|
|
||||||
int open(char const *path, int flags, ...)
|
int open(char const *path, int flags, ...)
|
||||||
{
|
{
|
||||||
ENOTSUP_IF_NOT_FUGUE(-1);
|
va_list args;
|
||||||
|
va_start(args, flags);
|
||||||
|
mode_t mode = va_arg(args, int);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
uint16_t *fcpath = utf8_to_fc_alloc(path, u"\\\\fls0\\");
|
/* Standard open() is the Fugue filesystem only */
|
||||||
int fd, err, rc = -1;
|
return fugue_open(path, flags, mode);
|
||||||
|
|
||||||
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. */
|
|
||||||
fd = BFile_EntryNotFound;
|
|
||||||
if(excl || !trunc)
|
|
||||||
fd = BFile_Open(fcpath, bfile_mode);
|
|
||||||
|
|
||||||
/* If the file exists and O_EXCL was requested, fail. */
|
|
||||||
if(fd >= 0 && excl) {
|
|
||||||
BFile_Close(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) && (fd >= 0 || (flags & O_CREAT))) {
|
|
||||||
if(fd >= 0) BFile_Close(fd);
|
|
||||||
BFile_Remove(fcpath);
|
|
||||||
fd = BFile_EntryNotFound;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If the file does not exist and O_CREAT is set, create it */
|
|
||||||
if((flags & O_CREAT) && ((flags & O_TRUNC) || fd < 0)) {
|
|
||||||
int size = 0;
|
|
||||||
err = BFile_Create(fcpath, BFile_File, &size);
|
|
||||||
if(err < 0) {
|
|
||||||
errno = bfile_error_to_errno(err);
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
fd = BFile_Open(fcpath, bfile_mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(fd < 0) {
|
|
||||||
errno = bfile_error_to_errno(fd);
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If O_APPEND is set, move to the end of the file */
|
|
||||||
if((flags & O_APPEND))
|
|
||||||
BFile_Seek(fd, BFile_Size(fd));
|
|
||||||
|
|
||||||
/* Return the now-open file descriptor */
|
|
||||||
rc = fd;
|
|
||||||
end:
|
|
||||||
free(fcpath);
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include "util.h"
|
#include <gint/fs.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
ssize_t pread(int fd, void *buf, size_t size, off_t offset)
|
ssize_t pread(int fd, void *buf, size_t size, off_t offset)
|
||||||
{
|
{
|
||||||
ENOTSUP_IF_NOT_FUGUE(-1);
|
fs_descriptor_t const *d = fs_get_descriptor(fd);
|
||||||
|
if(!d) {
|
||||||
/* Thanks to the extra argument to BFile_Read(), we can perform this
|
errno = EBADF;
|
||||||
call without knowing the current offset, even on G-III models */
|
return (ssize_t)-1;
|
||||||
int rc = BFile_Read(fd, buf, size, offset);
|
|
||||||
if(rc < 0) {
|
|
||||||
errno = bfile_error_to_errno(rc);
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
BFile_Seek(fd, -size);
|
|
||||||
return rc;
|
if(d->type->pread)
|
||||||
|
return d->type->pread(d->data, buf, size, offset);
|
||||||
|
|
||||||
|
/* No seek function: cannot seek */
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,21 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
ssize_t pwrite(int fd, const void *buf, size_t size, off_t offset)
|
ssize_t pwrite(int fd, const void *buf, size_t size, off_t offset)
|
||||||
{
|
{
|
||||||
ENOTSUP_IF_NOT_FUGUE((off_t)-1);
|
|
||||||
|
|
||||||
off_t current = lseek(fd, 0, SEEK_CUR);
|
off_t current = lseek(fd, 0, SEEK_CUR);
|
||||||
|
|
||||||
|
/* This fails on G-III BFile and non-seekable file descriptors */
|
||||||
if(current == (off_t)-1)
|
if(current == (off_t)-1)
|
||||||
return (ssize_t)-1;
|
return (ssize_t)-1;
|
||||||
|
|
||||||
ssize_t rc = -1;
|
ssize_t rc = -1;
|
||||||
|
|
||||||
if(lseek(fd, 0, offset) == (off_t)-1)
|
if(lseek(fd, offset, SEEK_SET) == (off_t)-1)
|
||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
rc = BFile_Write(fd, buf, size);
|
rc = write(fd, buf, size);
|
||||||
if(rc < 0) {
|
if(rc < 0)
|
||||||
errno = bfile_error_to_errno(rc);
|
|
||||||
goto end;
|
goto end;
|
||||||
}
|
|
||||||
|
|
||||||
end:
|
end:
|
||||||
/* At the end, always try to restore the current position */
|
/* At the end, always try to restore the current position */
|
||||||
|
|
|
@ -1,14 +1,18 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include "util.h"
|
#include <gint/fs.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
ssize_t read(int fd, void *buf, size_t size)
|
ssize_t read(int fd, void *buf, size_t size)
|
||||||
{
|
{
|
||||||
ENOTSUP_IF_NOT_FUGUE(-1);
|
fs_descriptor_t const *d = fs_get_descriptor(fd);
|
||||||
|
if(!d) {
|
||||||
int err = BFile_Read(fd, buf, size, -1);
|
errno = EBADF;
|
||||||
if(err < 0) {
|
return (ssize_t)-1;
|
||||||
errno = bfile_error_to_errno(err);
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
return size;
|
|
||||||
|
if(d->type->read)
|
||||||
|
return d->type->read(d->data, buf, size);
|
||||||
|
|
||||||
|
/* No read function: we can't read anything */
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,8 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include "util.h"
|
#include "fugue/fugue.h"
|
||||||
|
|
||||||
int unlink(char const *path)
|
int unlink(char const *path)
|
||||||
{
|
{
|
||||||
ENOTSUP_IF_NOT_FUGUE(-1);
|
/* Standard unlink() is the Fugue filesystem only */
|
||||||
|
return fugue_unlink(path);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,18 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include "util.h"
|
#include <gint/fs.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
ssize_t write(int fd, const void *buf, size_t size)
|
ssize_t write(int fd, const void *buf, size_t size)
|
||||||
{
|
{
|
||||||
ENOTSUP_IF_NOT_FUGUE(-1);
|
fs_descriptor_t const *d = fs_get_descriptor(fd);
|
||||||
|
if(!d) {
|
||||||
int rc = BFile_Write(fd, buf, size);
|
errno = EBADF;
|
||||||
if(rc < 0) {
|
return (ssize_t)-1;
|
||||||
errno = bfile_error_to_errno(rc);
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
return rc;
|
|
||||||
|
if(d->type->write)
|
||||||
|
return d->type->write(d->data, buf, size);
|
||||||
|
|
||||||
|
/* No write function: discard the contents but show no error */
|
||||||
|
return size;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue