fs: folder support, part 1 (mkdir/rmdir and the opendir(3) family)

This commit is contained in:
Lephe 2021-12-21 19:01:00 +01:00
parent 34c73ba0ba
commit 9cae0040b5
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
23 changed files with 560 additions and 142 deletions

View File

@ -37,17 +37,31 @@ set(SOURCES_COMMON
src/dma/memset.c
# Filesystem interface
src/fs/close.c
src/fs/closedir.c
src/fs/creat.c
src/fs/fdopendir.c
src/fs/fs.c
src/fs/lseek.c
src/fs/mkdir.c
src/fs/open.c
src/fs/opendir.c
src/fs/pread.c
src/fs/pwrite.c
src/fs/read.c
src/fs/readdir.c
src/fs/rewinddir.c
src/fs/rmdir.c
src/fs/seekdir.c
src/fs/telldir.c
src/fs/unlink.c
src/fs/write.c
# Filesystem interface to Fugue
src/fs/fugue/BFile_Ext_Stat.c
src/fs/fugue/fugue.c
src/fs/fugue/fugue_dir.c
src/fs/fugue/fugue_open.c
src/fs/fugue/fugue_mkdir.c
src/fs/fugue/fugue_unlink.c
src/fs/fugue/util.c
# Interrupt Controller driver
src/intc/intc.c

10
TODO
View File

@ -1,22 +1,22 @@
Extensions on existing code:
* usb: add PC->calc reading, and interrupt pipes
* fs: support RAM files
* fs: support USB streams as generic file descriptors
* fugue: support glob() and stat() to abstract away BFile entirely
* bfile: implement the optimization-restart as realized by Kbd2
* kernel: better restore to userspace before panic (ensure BL=0 IMASK=0)
* project: add license file
* kernel: group linker script symbols in a single header file
* bopti: try to display fullscreen images with TLB access + DMA on fxcg50
* core: try to leave add-in without reset in case of panic
* core: use cmp/str for memchr()
* r61524: brightness control and clean the file
* core: review forgotten globals and MPU addresses not in <gint/mpu/*.h>
* core: run destructors when a task-switch results in leaving the app
* core rtc: use qdiv10 to massively improve division performance
Future directions.
* A complete file system abstraction
Future directions:
* Integrate overclock management
* Audio playback using TSWilliamson's libsnd method
* Serial communication
* USB communication, using Yatis' reverse-engineering of the module
* Make fx9860g projects work out of the box on fxcg50
* Use the DSP to enhance parallel computation
* Base for Yatis' threads library

View File

@ -294,6 +294,17 @@ int BFile_FindNext(int shandle, uint16_t *foundfile,
/* Close a search handle (with or without exhausting the matches). */
int BFile_FindClose(int shandle);
//---
// Additional functions
//
// The following functions are implemented in gint using lower-level BFile
// functions. They add abstraction/convenience to the API, but can be pretty
// slow as they result in more BFile calls being made.
//---
/* BFile_Ext_Stat(): Stat an entry for type and size */
int BFile_Ext_Stat(uint16_t const *path, int *type, int *size);
#ifdef __cplusplus
}
#endif

View File

@ -71,7 +71,7 @@ fs_descriptor_t const *fs_get_descriptor(int fd);
errno = ENFILE. */
int fs_create_descriptor(fs_descriptor_t const *data);
/* fs_free_descriptor(): Clsoe a file descriptor's slot
/* fs_free_descriptor(): Close 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

10
src/fs/closedir.c Normal file
View File

@ -0,0 +1,10 @@
#include <dirent.h>
#include <unistd.h>
#include <stdlib.h>
int closedir(DIR *dp)
{
int rc = close(dp->fd);
free(dp);
return rc;
}

27
src/fs/fdopendir.c Normal file
View File

@ -0,0 +1,27 @@
#include <gint/fs.h>
#include <dirent.h>
#include <stdlib.h>
#include <errno.h>
#include "fugue/fugue.h"
DIR *fdopendir(int fd)
{
fs_descriptor_t const *desc = fs_get_descriptor(fd);
if(desc == NULL) {
errno = EBADF;
return NULL;
}
if(desc->type != &fugue_dir_descriptor_type) {
errno = ENOTDIR;
return NULL;
}
DIR *dp = malloc(sizeof *dp);
if(!dp) {
errno = ENOMEM;
return NULL;
}
dp->fd = fd;
return dp;
}

View File

@ -0,0 +1,24 @@
#include <gint/bfile.h>
#include "util.h"
int BFile_Ext_Stat(uint16_t const *path, int *type, int *size)
{
int search_handle, rc;
uint16_t found_file[256];
struct BFile_FileInfo fileinfo;
rc = BFile_FindFirst(path, &search_handle, found_file, &fileinfo);
if(rc < 0) {
if(type) *type = -1;
if(size) *size = -1;
rc = -1;
}
else {
if(type) *type = fileinfo.type;
if(size) *size = fileinfo.file_size;
rc = 0;
}
BFile_FindClose(search_handle);
return rc;
}

View File

@ -48,26 +48,18 @@ 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;
if(whence == SEEK_CUR)
offset += BFile_GetPos(fugue_fd);
else if(whence == SEEK_END)
destination = BFile_Size(fugue_fd) + offset;
offset += BFile_Size(fugue_fd);
int rc = BFile_Seek(fugue_fd, destination);
int rc = BFile_Seek(fugue_fd, offset);
if(rc < 0) {
errno = bfile_error_to_errno(rc);
@ -75,8 +67,8 @@ off_t fugue_lseek(void *data, off_t offset, int whence)
}
/* rc is the amount of space left in the file (including pre-allocated
space), so instead just return destination directly */
return (off_t)destination;
space), so instead just return offset directly */
return offset;
}
int fugue_close(void *data)
@ -91,119 +83,10 @@ int fugue_close(void *data)
return 0;
}
static const fs_descriptor_type_t fugue_descriptor_type = {
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;
}

View File

@ -1,13 +1,28 @@
#ifndef FS_FUGUE_FUGUE_H
#define FS_FUGUE_FUGUE_H
#include <gint/fs.h>
#include <fcntl.h>
#include <unistd.h>
#include <dirent.h>
/* File descriptor type */
extern const fs_descriptor_type_t fugue_descriptor_type;
/* Directory descriptor type */
extern const fs_descriptor_type_t fugue_dir_descriptor_type;
/* Specific implementations of some standard functions */
/* 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);
int fugue_mkdir(char const *path, mode_t mode);
int fugue_rmdir(char const *path);
/* Other functions */
void *fugue_dir_explore(char const *path);
#endif /* FS_FUGUE_FUGUE_H */

168
src/fs/fugue/fugue_dir.c Normal file
View File

@ -0,0 +1,168 @@
#include <gint/fs.h>
#include <gint/hardware.h>
#include <gint/bfile.h>
#include <dirent.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include "util.h"
#include "fugue.h"
typedef struct
{
/* Number of entries */
int count;
/* All entries */
struct dirent **entries;
/* Current position in directory */
off_t pos;
} dir_t;
/* There is no well-standardized API for reading from directory descriptors.
getdents(2) is a thing, but it's mostly Linux-specific and has no glibc
wrapper, so no userspace application is using it directly. We define our
directory descriptor interface to mimic opendir(3) for efficiency. */
ssize_t fugue_dir_read(void *data, void *buf, GUNUSED size_t size)
{
struct dirent **dirent_ptr = buf;
if(size < sizeof *dirent_ptr)
return 0;
dir_t *dp = data;
if(dp->pos >= dp->count)
*dirent_ptr = NULL;
else
*dirent_ptr = dp->entries[dp->pos++];
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)
{
errno = EISDIR;
return -1;
}
off_t fugue_dir_lseek(void *data, off_t offset, int whence)
{
dir_t *dp = data;
if(whence == SEEK_CUR)
offset += dp->pos;
if(whence == SEEK_END)
offset += dp->count;
if(offset < 0 || offset >= dp->count) {
errno = EINVAL;
return -1;
}
dp->pos = offset;
return dp->pos;
}
int fugue_dir_close(void *data)
{
dir_t *dp = data;
if(dp && dp->entries) {
for(int i = 0; i < dp->count; i++)
free(dp->entries[i]);
free(dp->entries);
}
free(dp);
return 0;
}
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,
};
void *fugue_dir_explore(char const *path)
{
struct BFile_FileInfo info;
uint16_t *fc_path=NULL, *search=NULL;
dir_t *dp = malloc(sizeof *dp);
if(!dp) goto alloc_failure;
dp->count = 0;
dp->entries = NULL;
dp->pos = 0;
/* We allocate by batches of 8 */
int sd=-1, rc, allocated=0;
fc_path = malloc(512 * sizeof *fc_path);
if(!fc_path) goto alloc_failure;
search = utf8_to_fc_alloc(u"\\\\fls0\\", path, u"\\*");
if(!search) goto alloc_failure;
rc = BFile_FindFirst(search, &sd, fc_path, &info);
if(rc < 0) {
if(rc != BFile_EntryNotFound)
errno = bfile_error_to_errno(rc);
goto end;
}
do {
if(dp->count+1 > allocated) {
struct dirent **new_entries = realloc(dp->entries,
(allocated + 8) * sizeof *dp->entries);
if(!new_entries)
goto alloc_failure;
dp->entries = new_entries;
allocated += 8;
}
size_t name_length = fc_len(fc_path);
size_t s = sizeof(struct dirent) + name_length + 1;
struct dirent *ent = malloc(s);
if(!ent) goto alloc_failure;
ent->d_ino = 0;
ent->d_type = DT_UNKNOWN;
fc_to_utf8(ent->d_name, fc_path, name_length + 1);
if(info.type == BFile_Type_File)
ent->d_type = DT_REG;
if(info.type == BFile_Type_Directory)
ent->d_type = DT_DIR;
if(info.type == BFile_Type_Dot)
ent->d_type = DT_DIR;
if(info.type == BFile_Type_DotDot)
ent->d_type = DT_DIR;
dp->entries[dp->count++] = ent;
rc = BFile_FindNext(sd, fc_path, &info);
}
while(rc >= 0);
goto end;
alloc_failure:
errno = ENOMEM;
fugue_dir_close(dp);
end:
free(search);
free(fc_path);
if(sd >= 0)
BFile_FindClose(sd);
return dp;
}

View File

@ -0,0 +1,23 @@
#include <gint/hardware.h>
#include <gint/bfile.h>
#include <errno.h>
#include "util.h"
int fugue_mkdir(char const *path, GUNUSED mode_t mode)
{
ENOTSUP_IF_NOT_FUGUE(-1);
uint16_t *fcpath = utf8_to_fc_alloc(u"\\\\fls0\\", path, NULL);
if(!fcpath) {
errno = ENOMEM;
return -1;
}
int rc = BFile_Create(fcpath, BFile_Folder, NULL);
if(rc < 0) {
errno = bfile_error_to_errno(rc);
return -1;
}
return 0;
}

119
src/fs/fugue/fugue_open.c Normal file
View File

@ -0,0 +1,119 @@
#include <gint/fs.h>
#include <gint/bfile.h>
#include <fcntl.h>
#include <errno.h>
#include "util.h"
#include "fugue.h"
/* TODO: fugue_open(): Handle trailing '/' and filesystem root */
int fugue_open(char const *path, int flags, GUNUSED mode_t mode)
{
ENOTSUP_IF_NOT_FUGUE(-1);
uint16_t *fcpath = utf8_to_fc_alloc(u"\\\\fls0\\", path, NULL);
int fugue_fd, err, rc=-1, type, fd=-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 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);
/* Stat the entry */
bool exists = (BFile_Ext_Stat(fcpath, &type, NULL) == 0);
if(!exists) type = -1;
/* If the entry exists and O_EXCL was requested, fail. */
if(exists && excl) {
errno = EEXIST;
return -1;
}
/* If the entry is not a directory but O_DIRECTORY is set, fail. If the
directory doesn't exist, we fail regardless of O_CREAT. */
if((flags & O_DIRECTORY) && type != BFile_Type_Directory) {
errno = (exists ? ENOTDIR : ENOENT);
return -1;
}
/* If the entry is a directory, open it as such */
if(type == BFile_Type_Directory) {
void *dp = fugue_dir_explore(path);
fs_descriptor_t data = {
.type = &fugue_dir_descriptor_type,
.data = dp,
};
fd = fs_create_descriptor(&data);
rc = fd;
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);
/* 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;
}
/* 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);
rc = fugue_fd;
goto end;
}
/* If O_APPEND is set, move to the end of the file */
// TODO: O_APPEND should move the cursor before *each* write
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,
};
fd = fs_create_descriptor(&data);
if(fd == -1) {
BFile_Close(fugue_fd);
errno = ENFILE;
goto end;
}
rc = fd;
end:
free(fcpath);
return rc;
}

View File

@ -0,0 +1,28 @@
#include <gint/hardware.h>
#include <gint/bfile.h>
#include <errno.h>
#include "util.h"
int fugue_unlink(char const *path)
{
ENOTSUP_IF_NOT_FUGUE(-1);
uint16_t *fcpath = utf8_to_fc_alloc(u"\\\\fls0\\", path, NULL);
if(!fcpath) {
errno = ENOMEM;
return -1;
}
int err = BFile_Remove(fcpath);
if(err < 0) {
errno = bfile_error_to_errno(err);
return -1;
}
return 0;
}
int fugue_rmdir(char const *path)
{
return fugue_unlink(path);
}

View File

@ -26,14 +26,14 @@ int bfile_error_to_errno(int e)
}
/* Length of FONTCHARACTER and UTF-8 strings, counting only ASCII characters */
static size_t utf8_len(char const *utf8)
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 fc_len(uint16_t const *fc)
{
size_t len = 0;
for(size_t i = 0; fc[i] != 0 && fc[i] != 0xffff; i++)
@ -46,7 +46,9 @@ 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)
if(utf8[i] == '/')
fc[j++] = '\\';
else if(utf8[i] >= 0 && (uint8_t)utf8[i] <= 0x7f)
fc[j++] = utf8[i];
}
@ -59,7 +61,9 @@ 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)
if(fc[i] == '\\')
utf8[j++] = '/';
else if(fc[i] <= 0x7f)
utf8[j++] = fc[i];
}
@ -67,21 +71,29 @@ void fc_to_utf8(char *utf8, uint16_t const *fc, size_t utf8_len)
utf8[j++] = 0;
}
uint16_t *utf8_to_fc_alloc(char const *utf8, uint16_t *prefix)
uint16_t *utf8_to_fc_alloc(uint16_t *prefix, char const *utf8,
uint16_t *suffix)
{
size_t lenp = 0;
size_t lenp=0, lens=0;
if(prefix) {
while(prefix[lenp] != 0 && prefix[lenp] != 0xffff)
lenp++;
}
if(suffix) {
while(suffix[lens] != 0 && suffix[lens] != 0xffff)
lens++;
}
size_t len = utf8_len(utf8);
uint16_t *fc = malloc((lenp+len+1) * sizeof *fc);
uint16_t *fc = malloc((lenp+len+lens+1) * sizeof *fc);
if(fc != NULL) {
if(prefix)
memcpy(fc, prefix, lenp * sizeof *prefix);
utf8_to_fc(fc + lenp, utf8, len+1);
utf8_to_fc(fc + lenp, utf8, len);
if(suffix)
memcpy(fc + lenp + len, suffix, lens * sizeof *suffix);
fc[lenp+len+lens] = 0;
}
return fc;
}

View File

@ -6,8 +6,12 @@ extern "C" {
#endif
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include <gint/hardware.h>
#include <errno.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);
@ -15,6 +19,11 @@ 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. */
/* Length of UTF-8 string _as copied by utf8_to_fc functions_ */
size_t utf8_len(char const *utf8);
/* Length of FONTCHARACTER string _as copied by fc_to_utf8 functions_ */
size_t fc_len(uint16_t const *fc);
/* 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);
@ -23,7 +32,8 @@ extern void utf8_to_fc(uint16_t *fc, char const *utf8, size_t fc_len);
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);
extern uint16_t *utf8_to_fc_alloc(uint16_t *prefix, char const *utf8,
uint16_t *suffix);
/* Same as fc_to_utf8() but allocates a string with malloc(). */
extern char *fc_to_utf8_alloc(uint16_t const *fc);

View File

@ -4,6 +4,11 @@
off_t lseek(int fd, off_t offset, int whence)
{
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;

8
src/fs/mkdir.c Normal file
View File

@ -0,0 +1,8 @@
#include <unistd.h>
#include "fugue/fugue.h"
int mkdir(char const *path, mode_t mode)
{
/* Standard mkdir() is the Fugue filesystem only */
return fugue_mkdir(path, mode);
}

23
src/fs/opendir.c Normal file
View File

@ -0,0 +1,23 @@
#include <dirent.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <errno.h>
DIR *opendir(const char *name)
{
DIR *dp = malloc(sizeof *dp);
if(!dp) {
errno = ENOMEM;
return NULL;
}
int fd = open(name, O_DIRECTORY | O_RDONLY);
if(fd < 0) {
free(dp);
return NULL;
}
dp->fd = fd;
return dp;
}

9
src/fs/readdir.c Normal file
View File

@ -0,0 +1,9 @@
#include <dirent.h>
#include <unistd.h>
struct dirent *readdir(DIR *dp)
{
struct dirent *ent = NULL;
read(dp->fd, &ent, sizeof ent);
return ent;
}

7
src/fs/rewinddir.c Normal file
View File

@ -0,0 +1,7 @@
#include <dirent.h>
#include <unistd.h>
void rewinddir(DIR *dp)
{
lseek(dp->fd, 0, SEEK_SET);
}

8
src/fs/rmdir.c Normal file
View File

@ -0,0 +1,8 @@
#include <unistd.h>
#include "fugue/fugue.h"
int rmdir(char const *path)
{
/* Standard rmdir() is the Fugue filesystem only */
return fugue_rmdir(path);
}

7
src/fs/seekdir.c Normal file
View File

@ -0,0 +1,7 @@
#include <dirent.h>
#include <unistd.h>
void seekdir(DIR *dp, long loc)
{
lseek(dp->fd, loc, SEEK_SET);
}

7
src/fs/telldir.c Normal file
View File

@ -0,0 +1,7 @@
#include <dirent.h>
#include <unistd.h>
long telldir(DIR *dp)
{
return lseek(dp->fd, 0, SEEK_CUR);
}