fs: basic filesystem support over BFile

This commit is contained in:
Lephe 2021-12-10 07:25:00 +01:00
parent 71de4dcb95
commit 8635880bbb
No known key found for this signature in database
GPG key ID: 1BBA026E13FC0495
12 changed files with 390 additions and 0 deletions

View file

@ -22,18 +22,34 @@ endif()
configure_file(include/gint/config.h.in include/gint/config.h) configure_file(include/gint/config.h.in include/gint/config.h)
set(SOURCES_COMMON set(SOURCES_COMMON
# Clock Pulse Generator driver
src/cpg/cpg.c src/cpg/cpg.c
# CPU driver
src/cpu/atomic.c src/cpu/atomic.c
src/cpu/cpu.c src/cpu/cpu.c
src/cpu/ics.s src/cpu/ics.s
src/cpu/registers.s src/cpu/registers.s
src/cpu/sleep.c src/cpu/sleep.c
# Direct Memory Access driver
src/dma/dma.c src/dma/dma.c
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)
src/fs/close.c
src/fs/creat.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
# Interrupt Controller driver
src/intc/intc.c src/intc/intc.c
src/intc/inth.s src/intc/inth.s
# Kernel
src/kernel/exch.c src/kernel/exch.c
src/kernel/exch.s src/kernel/exch.s
src/kernel/hardware.c src/kernel/hardware.c
@ -44,15 +60,19 @@ set(SOURCES_COMMON
src/kernel/syscalls.S src/kernel/syscalls.S
src/kernel/tlbh.S src/kernel/tlbh.S
src/kernel/world.c src/kernel/world.c
# Key Scan Interface driver
src/keysc/getkey.c src/keysc/getkey.c
src/keysc/iokbd.c src/keysc/iokbd.c
src/keysc/keycodes.c src/keysc/keycodes.c
src/keysc/keydev.c src/keysc/keydev.c
src/keysc/keysc.c src/keysc/keysc.c
# Memory allocator
src/kmalloc/arena_gint.c src/kmalloc/arena_gint.c
src/kmalloc/arena_osheap.c src/kmalloc/arena_osheap.c
src/kmalloc/kmalloc.c src/kmalloc/kmalloc.c
# MMU driver
src/mmu/mmu.c src/mmu/mmu.c
# Rendering
src/render/dhline.c src/render/dhline.c
src/render/dimage.c src/render/dimage.c
src/render/dline.c src/render/dline.c
@ -62,13 +82,17 @@ set(SOURCES_COMMON
src/render/dupdate_hook.c src/render/dupdate_hook.c
src/render/dvline.c src/render/dvline.c
src/render/topti.c src/render/topti.c
# RTC driver
src/rtc/rtc.c src/rtc/rtc.c
src/rtc/rtc_ticks.c src/rtc/rtc_ticks.c
# Sound Processing Unit driver
src/spu/spu.c src/spu/spu.c
# Timer Unit driver
src/tmu/inth-etmu.s src/tmu/inth-etmu.s
src/tmu/inth-tmu.s src/tmu/inth-tmu.s
src/tmu/sleep.c src/tmu/sleep.c
src/tmu/tmu.c src/tmu/tmu.c
# USB driver
src/usb/classes/ff-bulk.c src/usb/classes/ff-bulk.c
src/usb/configure.c src/usb/configure.c
src/usb/pipes.c src/usb/pipes.c
@ -77,6 +101,7 @@ set(SOURCES_COMMON
src/usb/usb.c src/usb/usb.c
) )
set(SOURCES_FX set(SOURCES_FX
# Gray engine
src/gray/engine.c src/gray/engine.c
src/gray/gclear.c src/gray/gclear.c
src/gray/gint_gline.c src/gray/gint_gline.c
@ -84,6 +109,7 @@ set(SOURCES_FX
src/gray/grect.c src/gray/grect.c
src/gray/gsubimage.c src/gray/gsubimage.c
src/gray/gtext.c src/gray/gtext.c
# Rendering
src/render-fx/bopti-asm-gray-scsp.s src/render-fx/bopti-asm-gray-scsp.s
src/render-fx/bopti-asm-gray.s src/render-fx/bopti-asm-gray.s
src/render-fx/bopti-asm-mono-scsp.s src/render-fx/bopti-asm-mono-scsp.s
@ -98,11 +124,15 @@ set(SOURCES_FX
src/render-fx/masks.c src/render-fx/masks.c
src/render-fx/topti-asm.s src/render-fx/topti-asm.s
src/render-fx/topti.c src/render-fx/topti.c
# T6K11 driver
src/t6k11/t6k11.c src/t6k11/t6k11.c
src/usb/classes/ff-bulk-gray.c src/usb/classes/ff-bulk-gray.c
) )
set(SOURCES_CG set(SOURCES_CG
# R61524 driver
src/r61524/r61524.c src/r61524/r61524.c
# Rendering
src/render-cg/bopti-asm.s src/render-cg/bopti-asm.s
src/render-cg/bopti.c src/render-cg/bopti.c
src/render-cg/dclear.c src/render-cg/dclear.c

14
src/fs/close.c Normal file
View file

@ -0,0 +1,14 @@
#include <unistd.h>
#include "util.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;
}
return 0;
}

6
src/fs/creat.c Normal file
View file

@ -0,0 +1,6 @@
#include <fcntl.h>
int creat(char const *path, mode_t mode)
{
return open(path, O_CREAT | O_WRONLY | O_TRUNC, mode);
}

37
src/fs/lseek.c Normal file
View file

@ -0,0 +1,37 @@
#include <unistd.h>
#include "util.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;
}
/* 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(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;
}

74
src/fs/open.c Normal file
View file

@ -0,0 +1,74 @@
#include <fcntl.h>
#include "util.h"
int open(char const *path, int flags, ...)
{
ENOTSUP_IF_NOT_FUGUE(-1);
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;
}

17
src/fs/pread.c Normal file
View file

@ -0,0 +1,17 @@
#include <unistd.h>
#include "util.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;
}
BFile_Seek(fd, -size);
return rc;
}

28
src/fs/pwrite.c Normal file
View file

@ -0,0 +1,28 @@
#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);
if(current == (off_t)-1)
return (ssize_t)-1;
ssize_t rc = -1;
if(lseek(fd, 0, offset) == (off_t)-1)
goto end;
rc = BFile_Write(fd, buf, size);
if(rc < 0) {
errno = bfile_error_to_errno(rc);
goto end;
}
end:
/* At the end, always try to restore the current position */
lseek(fd, current, SEEK_CUR);
return rc;
}

14
src/fs/read.c Normal file
View file

@ -0,0 +1,14 @@
#include <unistd.h>
#include "util.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;
}
return size;
}

21
src/fs/unlink.c Normal file
View file

@ -0,0 +1,21 @@
#include <unistd.h>
#include "util.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;
}

94
src/fs/util.c Normal file
View file

@ -0,0 +1,94 @@
#include "util.h"
#include <stdlib.h>
#include <string.h>
int bfile_error_to_errno(int e)
{
/* TODO: Find BFile code for too many fds and map it to ENFILE. */
switch(e) {
case BFile_EntryNotFound: return ENOENT;
case BFile_IllegalPath: return EINVAL;
case BFile_DeviceFull: return EDQUOT;
case BFile_IllegalDevice: return EINVAL;
case BFile_AccessDenied: return EACCES;
case BFile_PermissionError: return EACCES;
case BFile_EntryFull: return EDQUOT;
case BFile_AlreadyExists: return EEXIST;
case BFile_ReadOnlyFile: return EACCES;
case BFile_EnumerateEnd: return ENOENT;
case BFile_IllegalSeekPos: return EINVAL;
case BFile_NotMountDevice: return ENOENT;
case BFile_DeviceNotFound: return ENOENT;
default: return errno;
}
}
/* Length of FONTCHARACTER and UTF-8 strings, counting only ASCII characters */
static 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 len = 0;
for(size_t i = 0; fc[i] != 0 && fc[i] != 0xffff; i++)
len += (fc[i] <= 0x7f);
return len;
}
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)
fc[j++] = utf8[i];
}
while(j < fc_len)
fc[j++] = 0;
}
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)
utf8[j++] = fc[i];
}
while(j < utf8_len)
utf8[j++] = 0;
}
uint16_t *utf8_to_fc_alloc(char const *utf8, uint16_t *prefix)
{
size_t lenp = 0;
if(prefix) {
while(prefix[lenp] != 0 && prefix[lenp] != 0xffff)
lenp++;
}
size_t len = utf8_len(utf8);
uint16_t *fc = malloc((lenp+len+1) * sizeof *fc);
if(fc != NULL) {
if(prefix)
memcpy(fc, prefix, lenp * sizeof *prefix);
utf8_to_fc(fc + lenp, utf8, len+1);
}
return fc;
}
char *fc_to_utf8_alloc(uint16_t const *fc)
{
size_t len = fc_len(fc);
char *utf8 = malloc(len+1);
if(utf8 != NULL)
fc_to_utf8(utf8, fc, len+1);
return utf8;
}

41
src/fs/util.h Normal file
View file

@ -0,0 +1,41 @@
#ifndef FS_UTIL_H
#define FS_UTIL_H
#ifdef __cplusplus
extern "C" {
#endif
#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);
/* TODO: These functions do not actually translate special characters between
encodings, they simply strip them. */
/* 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);
/* Same in the other direction. */
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);
/* Same as fc_to_utf8() but allocates a string with malloc(). */
extern char *fc_to_utf8_alloc(uint16_t const *fc);
#ifdef __cplusplus
}
#endif
#endif /* FS_UTIL_H */

14
src/fs/write.c Normal file
View file

@ -0,0 +1,14 @@
#include <unistd.h>
#include "util.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;
}
return rc;
}