diff --git a/CMakeLists.txt b/CMakeLists.txt index 77fc193..84a40ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,6 +52,7 @@ set(SOURCES_COMMON src/fs/rewinddir.c src/fs/rmdir.c src/fs/seekdir.c + src/fs/stat.c src/fs/telldir.c src/fs/unlink.c src/fs/write.c @@ -61,6 +62,8 @@ set(SOURCES_COMMON src/fs/fugue/fugue_dir.c src/fs/fugue/fugue_open.c src/fs/fugue/fugue_mkdir.c + src/fs/fugue/fugue_stat.c + src/fs/fugue/fugue_rmdir.c src/fs/fugue/fugue_unlink.c src/fs/fugue/util.c # Interrupt Controller driver diff --git a/TODO b/TODO index 8c68414..ef203f1 100644 --- a/TODO +++ b/TODO @@ -2,7 +2,8 @@ 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 +* fugue: support glob() to abstract away BFile entirely +* fugue/fs: offer a primitive to remove recursively, which is native in Fugue * 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 diff --git a/src/fs/fugue/fugue.h b/src/fs/fugue/fugue.h index bfa8886..3848779 100644 --- a/src/fs/fugue/fugue.h +++ b/src/fs/fugue/fugue.h @@ -5,6 +5,7 @@ #include #include #include +#include /* File descriptor type */ extern const fs_descriptor_type_t fugue_descriptor_type; @@ -21,6 +22,8 @@ int fugue_mkdir(char const *path, mode_t mode); int fugue_rmdir(char const *path); +int fugue_stat(char const * restrict path, struct stat * restrict statbuf); + /* Other functions */ void *fugue_dir_explore(char const *path); diff --git a/src/fs/fugue/fugue_dir.c b/src/fs/fugue/fugue_dir.c index 85c8918..4d89296 100644 --- a/src/fs/fugue/fugue_dir.c +++ b/src/fs/fugue/fugue_dir.c @@ -145,20 +145,8 @@ void *fugue_dir_explore(char const *path) if(!ent) goto alloc_failure; ent->d_ino = 0; - ent->d_type = DT_UNKNOWN; + ent->d_type = bfile_type_to_dirent(info.type); 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_Archived) - 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); diff --git a/src/fs/fugue/fugue_rmdir.c b/src/fs/fugue/fugue_rmdir.c new file mode 100644 index 0000000..ceff28e --- /dev/null +++ b/src/fs/fugue/fugue_rmdir.c @@ -0,0 +1,51 @@ +#include +#include +#include +#include +#include +#include +#include "util.h" +#include "fugue.h" + +int fugue_rmdir(char const *path) +{ + ENOTSUP_IF_NOT_FUGUE(-1); + + /* Check if the folder is empty */ + DIR *dp = opendir(path); + if(!dp) return -1; + + bool empty = true; + struct dirent *ent; + + while((ent = readdir(dp))) { + if(strcmp(ent->d_name, ".") != 0 && + strcmp(ent->d_name, "..") != 0) { + empty = false; + break; + } + } + + closedir(dp); + + if(!empty) { + errno = ENOTEMPTY; + return -1; + } + + uint16_t *fcpath = fs_path_normalize_fc(path); + if(!fcpath) { + errno = ENOMEM; + return -1; + } + + int rc = BFile_Remove(fcpath); + if(rc < 0) { + errno = bfile_error_to_errno(rc); + rc = -1; + } + else rc = 0; + + free(fcpath); + return rc; +} diff --git a/src/fs/fugue/fugue_stat.c b/src/fs/fugue/fugue_stat.c new file mode 100644 index 0000000..6cf43a9 --- /dev/null +++ b/src/fs/fugue/fugue_stat.c @@ -0,0 +1,36 @@ +#include +#include +#include +#include "fugue.h" +#include +#include +#include "util.h" + +int fugue_stat(char const * restrict path, struct stat * restrict statbuf) +{ + ENOTSUP_IF_NOT_FUGUE(-1); + + uint16_t *fcpath = fs_path_normalize_fc(path); + if(!fcpath) { + errno = ENOMEM; + return -1; + } + + int type, size, rc; + rc = BFile_Ext_Stat(fcpath, &type, &size); + free(fcpath); + + if(rc < 0) { + errno = bfile_error_to_errno(rc); + return -1; + } + + statbuf->st_mode = bfile_type_to_mode_t(type) | 0777; + statbuf->st_size = -1; + + if(S_ISREG(statbuf->st_mode)) { + statbuf->st_size = size; + } + + return 0; +} diff --git a/src/fs/fugue/fugue_unlink.c b/src/fs/fugue/fugue_unlink.c index 2d33647..cff9cb8 100644 --- a/src/fs/fugue/fugue_unlink.c +++ b/src/fs/fugue/fugue_unlink.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "util.h" int fugue_unlink(char const *path) @@ -14,18 +15,27 @@ int fugue_unlink(char const *path) return -1; } - int err = BFile_Remove(fcpath); - if(err < 0) { - errno = bfile_error_to_errno(err); - free(fcpath); - return -1; + int type, size, rc; + rc = BFile_Ext_Stat(fcpath, &type, &size); + if(rc < 0) { + errno = bfile_error_to_errno(rc); + rc = -1; + goto end; + } + if(bfile_type_to_mode_t(type) != S_IFREG) { + errno = ENOTDIR; + rc = -1; + goto end; } - free(fcpath); - return 0; -} + rc = BFile_Remove(fcpath); + if(rc < 0) { + errno = bfile_error_to_errno(rc); + rc = -1; + } + else rc = 0; -int fugue_rmdir(char const *path) -{ - return fugue_unlink(path); +end: + free(fcpath); + return rc; } diff --git a/src/fs/fugue/util.c b/src/fs/fugue/util.c index dd04203..967a217 100644 --- a/src/fs/fugue/util.c +++ b/src/fs/fugue/util.c @@ -4,6 +4,8 @@ #include #include #include +#include +#include int bfile_error_to_errno(int e) { @@ -26,6 +28,32 @@ int bfile_error_to_errno(int e) } } +int bfile_type_to_mode_t(int bfile_type) +{ + switch(bfile_type) { + case BFile_Type_Directory: return S_IFDIR; + case BFile_Type_Dot: return S_IFDIR; + case BFile_Type_DotDot: return S_IFDIR; + case BFile_Type_MainMem: return S_IFBLK; + case BFile_Type_File: return S_IFREG; + case BFile_Type_Archived: return S_IFREG; + default: return S_IFREG; + } +} + +int bfile_type_to_dirent(int bfile_type) +{ + switch(bfile_type) { + case BFile_Type_Directory: return DT_DIR; + case BFile_Type_Dot: return DT_DIR; + case BFile_Type_DotDot: return DT_DIR; + case BFile_Type_MainMem: return DT_BLK; + case BFile_Type_File: return DT_REG; + case BFile_Type_Archived: return DT_REG; + default: return DT_UNKNOWN; + } +} + /* Length of FONTCHARACTER and UTF-8 strings, counting only ASCII characters */ size_t utf8_len(char const *utf8) { diff --git a/src/fs/fugue/util.h b/src/fs/fugue/util.h index c0a8184..0f66441 100644 --- a/src/fs/fugue/util.h +++ b/src/fs/fugue/util.h @@ -16,6 +16,12 @@ extern "C" { /* Translate common BFile error codes to errno values. */ int bfile_error_to_errno(int bfile_error_code); +/* Translate BFile file types to st_mode values. */ +int bfile_type_to_mode_t(int bfile_type); + +/* Translate BFile file types to struct dirent values. */ +int bfile_type_to_dirent(int bfile_type); + /* TODO: These functions do not actually translate special characters between encodings, they simply strip them. */ diff --git a/src/fs/stat.c b/src/fs/stat.c new file mode 100644 index 0000000..872e6c1 --- /dev/null +++ b/src/fs/stat.c @@ -0,0 +1,8 @@ +#include +#include "fugue/fugue.h" + +int stat(char const * restrict path, struct stat * restrict statbuf) +{ + /* Standard stat() is the Fugue filesystem only */ + return fugue_stat(path, statbuf); +}