mirror of
https://git.planet-casio.com/Lephenixnoir/gint.git
synced 2024-12-28 04:23: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/memcpy.c
|
||||
src/dma/memset.c
|
||||
# Filesystem interface (Fugue only)
|
||||
# Filesystem interface
|
||||
src/fs/close.c
|
||||
src/fs/creat.c
|
||||
src/fs/fs.c
|
||||
src/fs/lseek.c
|
||||
src/fs/open.c
|
||||
src/fs/pread.c
|
||||
src/fs/pwrite.c
|
||||
src/fs/read.c
|
||||
src/fs/unlink.c
|
||||
src/fs/util.c
|
||||
src/fs/write.c
|
||||
# Filesystem interface to Fugue
|
||||
src/fs/fugue/fugue.c
|
||||
src/fs/fugue/util.c
|
||||
# Interrupt Controller driver
|
||||
src/intc/intc.c
|
||||
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 == -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
|
||||
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). */
|
||||
|
|
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 "util.h"
|
||||
#include <gint/fs.h>
|
||||
#include <errno.h>
|
||||
|
||||
int close(int fd)
|
||||
{
|
||||
ENOTSUP_IF_NOT_FUGUE(-1);
|
||||
|
||||
int err = BFile_Close(fd);
|
||||
if(err < 0) {
|
||||
errno = bfile_error_to_errno(err);
|
||||
return -1;
|
||||
fs_descriptor_t const *d = fs_get_descriptor(fd);
|
||||
if(!d) {
|
||||
errno = EBADF;
|
||||
return (ssize_t)-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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <bfile.h>
|
||||
|
||||
int bfile_error_to_errno(int e)
|
||||
{
|
|
@ -7,13 +7,7 @@ extern "C" {
|
|||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
#include <bfile.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. */
|
||||
extern int bfile_error_to_errno(int bfile_error_code);
|
|
@ -1,37 +1,18 @@
|
|||
#include <unistd.h>
|
||||
#include "util.h"
|
||||
#include <gint/fs.h>
|
||||
#include <errno.h>
|
||||
|
||||
off_t lseek(int fd, off_t offset, int whence)
|
||||
{
|
||||
ENOTSUP_IF_NOT_FUGUE((off_t)-1);
|
||||
|
||||
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;
|
||||
return (ssize_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;
|
||||
}
|
||||
if(d->type->lseek)
|
||||
return d->type->lseek(d->data, offset, whence);
|
||||
|
||||
off_t destination;
|
||||
if(whence == SEEK_SET)
|
||||
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;
|
||||
/* No seek function: cannot seek */
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,74 +1,14 @@
|
|||
#include <fcntl.h>
|
||||
#include "util.h"
|
||||
#include <stdarg.h>
|
||||
#include "fugue/fugue.h"
|
||||
|
||||
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\\");
|
||||
int 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. */
|
||||
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;
|
||||
/* Standard open() is the Fugue filesystem only */
|
||||
return fugue_open(path, flags, mode);
|
||||
}
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
#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)
|
||||
{
|
||||
ENOTSUP_IF_NOT_FUGUE(-1);
|
||||
|
||||
/* 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(fd, buf, size, offset);
|
||||
if(rc < 0) {
|
||||
errno = bfile_error_to_errno(rc);
|
||||
return -1;
|
||||
fs_descriptor_t const *d = fs_get_descriptor(fd);
|
||||
if(!d) {
|
||||
errno = EBADF;
|
||||
return (ssize_t)-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 "util.h"
|
||||
|
||||
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);
|
||||
|
||||
/* This fails on G-III BFile and non-seekable file descriptors */
|
||||
if(current == (off_t)-1)
|
||||
return (ssize_t)-1;
|
||||
|
||||
ssize_t rc = -1;
|
||||
|
||||
if(lseek(fd, 0, offset) == (off_t)-1)
|
||||
if(lseek(fd, offset, SEEK_SET) == (off_t)-1)
|
||||
goto end;
|
||||
|
||||
rc = BFile_Write(fd, buf, size);
|
||||
if(rc < 0) {
|
||||
errno = bfile_error_to_errno(rc);
|
||||
rc = write(fd, buf, size);
|
||||
if(rc < 0)
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
/* At the end, always try to restore the current position */
|
||||
|
|
|
@ -1,14 +1,18 @@
|
|||
#include <unistd.h>
|
||||
#include "util.h"
|
||||
#include <gint/fs.h>
|
||||
#include <errno.h>
|
||||
|
||||
ssize_t read(int fd, void *buf, size_t size)
|
||||
{
|
||||
ENOTSUP_IF_NOT_FUGUE(-1);
|
||||
|
||||
int err = BFile_Read(fd, buf, size, -1);
|
||||
if(err < 0) {
|
||||
errno = bfile_error_to_errno(err);
|
||||
return -1;
|
||||
fs_descriptor_t const *d = fs_get_descriptor(fd);
|
||||
if(!d) {
|
||||
errno = EBADF;
|
||||
return (ssize_t)-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 "util.h"
|
||||
#include "fugue/fugue.h"
|
||||
|
||||
int unlink(char const *path)
|
||||
{
|
||||
ENOTSUP_IF_NOT_FUGUE(-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;
|
||||
/* Standard unlink() is the Fugue filesystem only */
|
||||
return fugue_unlink(path);
|
||||
}
|
||||
|
|
|
@ -1,14 +1,18 @@
|
|||
#include <unistd.h>
|
||||
#include "util.h"
|
||||
#include <gint/fs.h>
|
||||
#include <errno.h>
|
||||
|
||||
ssize_t write(int fd, const void *buf, size_t size)
|
||||
{
|
||||
ENOTSUP_IF_NOT_FUGUE(-1);
|
||||
|
||||
int rc = BFile_Write(fd, buf, size);
|
||||
if(rc < 0) {
|
||||
errno = bfile_error_to_errno(rc);
|
||||
return -1;
|
||||
fs_descriptor_t const *d = fs_get_descriptor(fd);
|
||||
if(!d) {
|
||||
errno = EBADF;
|
||||
return (ssize_t)-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