From 6d99494d30b6ae1476867ac4e40ddf4dac8c9150 Mon Sep 17 00:00:00 2001 From: Yann MAGNIN Date: Wed, 2 Apr 2025 15:34:15 +0200 Subject: [PATCH] fygue: (WIP) add syncfs support + add FAT/Flash backend + prepare open() primitive --- CMakeLists.txt | 11 + src/fs/fygue/fat/cluster.c | 46 ++++ src/fs/fygue/fat/fat.h | 114 +++++++++ src/fs/fygue/fat/initialize.c | 195 ++++++++++++++++ src/fs/fygue/fat/readdir.c | 419 ++++++++++++++++++++++++++++++++++ src/fs/fygue/fat/resolve.c | 128 +++++++++++ src/fs/fygue/fat/sector.c | 23 ++ src/fs/fygue/flash/cluster.c | 191 ++++++++++++++++ src/fs/fygue/flash/cmap.c | 152 ++++++++++++ src/fs/fygue/flash/flash.h | 67 ++++++ src/fs/fygue/fygue.c | 84 +++++++ src/fs/fygue/fygue.h | 67 +++++- src/fs/fygue/fygue_open.c | 83 +++++++ src/fs/fygue/fygue_syncfs.c | 16 ++ src/fs/open.c | 8 +- 15 files changed, 1599 insertions(+), 5 deletions(-) create mode 100644 src/fs/fygue/fat/cluster.c create mode 100644 src/fs/fygue/fat/fat.h create mode 100644 src/fs/fygue/fat/initialize.c create mode 100644 src/fs/fygue/fat/readdir.c create mode 100644 src/fs/fygue/fat/resolve.c create mode 100644 src/fs/fygue/fat/sector.c create mode 100644 src/fs/fygue/flash/cluster.c create mode 100644 src/fs/fygue/flash/cmap.c create mode 100644 src/fs/fygue/flash/flash.h create mode 100644 src/fs/fygue/fygue.c create mode 100644 src/fs/fygue/fygue_open.c create mode 100644 src/fs/fygue/fygue_syncfs.c diff --git a/CMakeLists.txt b/CMakeLists.txt index b72d3d6..a3237a0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -259,6 +259,17 @@ set(SOURCES src/touch/adconv.c src/touch/touch.c src/touch/driver.c + # Fygue filesystem + src/fs/fygue/fygue.c + src/fs/fygue/fygue_open.c + src/fs/fygue/fygue_syncfs.c + src/fs/fygue/fat/cluster.c + src/fs/fygue/fat/initialize.c + src/fs/fygue/fat/readdir.c + src/fs/fygue/fat/resolve.c + src/fs/fygue/fat/sector.c + src/fs/fygue/flash/cluster.c + src/fs/fygue/flash/cmap.c ) set(ASSETS_FX src/font5x7.png src/gdb/icons-i1msb.png) diff --git a/src/fs/fygue/fat/cluster.c b/src/fs/fygue/fat/cluster.c new file mode 100644 index 0000000..6774a48 --- /dev/null +++ b/src/fs/fygue/fat/cluster.c @@ -0,0 +1,46 @@ +/* +** fygue/fat/cluster - FAT cluster handling +*/ +#include "fat.h" + +//--- +// Public +//--- + +/* fygue_fat_cluster_next() - find the next cluster ID of a file */ +int fygue_fat_cluster_next(struct fygue_fat *fat, int *cluster_current) +{ + uint16_t *fat0; + int cluster; + + if (fat == NULL || cluster_current == NULL) + return -1; + cluster = *cluster_current; + if (cluster <= 1) + return -2; + if (cluster >= fat->ClusterCount) + return -2; + fat0 = (void*)fat->FAT0Addr; + if (fat0[cluster] == 0xffff) + return -3; + *cluster_current = fat0[cluster]; + return 0; +} + +/* fygue_fat_cluster_get_sector() - get sector ID from cluster ID */ +int fygue_fat_cluster_get_sector( + struct fygue_fat *fat, + int cluster_id, + int *sector_id +) { + if (fat == NULL || sector_id == NULL) + return -1; + if (cluster_id >= fat->ClusterCount) + return -1; + if (cluster_id <= 1) { + *sector_id = fat->RootSectorID; + } else { + *sector_id = fat->DataSectorID + ((cluster_id - 2) * 8); + } + return 0; +} diff --git a/src/fs/fygue/fat/fat.h b/src/fs/fygue/fat/fat.h new file mode 100644 index 0000000..b695e4d --- /dev/null +++ b/src/fs/fygue/fat/fat.h @@ -0,0 +1,114 @@ +#ifndef FS_FYGUE_FAT_H +#define FS_FYGUE_FAT_H 1 + +#include + +#include "../flash/flash.h" + +/* _FAT_WORD() : helper for 16bit value */ +#define FAT_WORD(x) \ + (((x & 0xff00) >> 8) | ((x & 0x00ff) << 8)) + +/* _FAT_DWORD() : helper for 32bit value */ +#define FAT_DWORD(x) ( \ + (((x) & 0xff000000) >> 24) \ + | (((x) & 0x00ff0000) >> 8) \ + | (((x) & 0x0000ff00) << 8) \ + | (((x) & 0x000000ff) << 24) \ +) + +/* fygue_fat - fat information */ +struct fygue_fat +{ + enum { + FYGUE_FAT_TYPE_FAT12 = 0, + FYGUE_FAT_TYPE_FAT16 = 1, + } Type; + int SectorHiddenCount; + int SectorCount; + int ClusterCount; + int TotalCapacity; + int RootEntCount; + int FAT0SectorID; + int FAT1SectorID; + int RootSectorID; + int DataSectorID; + uintptr_t FAT0Addr; + uintptr_t FAT1Addr; + uintptr_t RootAddr; + uintptr_t BPB; + struct { + struct fygue_flash_cmap cmap; + } _flash; +}; + +/* fygue_fat_dirent - FAT dirent information */ +struct fygue_fat_dirent +{ + char name[256]; + int type; + size_t size; + uintptr_t meta_addr; + unsigned int cluster_id; +}; + + +/* fygue_fat_dir - fygue directory information */ +struct fygue_fat_dir +{ + int cluster_entry; + int cluster_current; + int root_dirent_count; + int sector_id; + int sector_count; + int dirent_cursor; + uintptr_t dirent_current_addr; + bool end_of_dirent; + bool dirty; +}; + +/* fygue_fat_init_cold() - fully initialize the FAT information */ +extern int fygue_fat_init_cold(struct fygue_fat *fat); + +/* fygue_fat_init_hot() - re-initialize the FAT information */ +extern int fygue_fat_init_hot(struct fygue_fat *fat); + +/* fygue_fat_resolve() - resolve the path and set the dirent information */ +extern int fygue_fat_resolve( + struct fygue_fat *fat, + char const * const path, + struct fygue_fat_dirent *dirent +); + +/* fygue_fat_readdir(): readdir primitive */ +extern int fygue_fat_readdir( + struct fygue_fat *fat, + struct fygue_fat_dir *dir, + struct fygue_fat_dirent *dirent +); + +//--- +// Cluster interface +//--- + +/* fygue_fat_cluster_get_next() - find the next cluster ID of a file */ +extern int fygue_fat_cluster_get_next( + struct fygue_fat *fat, + int *cluster_current +); + +/* fygue_fat_cluster_get_sector() - get sector ID from cluster ID */ +extern int fygue_fat_cluster_get_sector( + struct fygue_fat *fat, + int cluster_id, + int *sector_id +); + +/* fygue_fat_get_sector_addr() - get logical sector addr */ +extern int fygue_fat_sector_get_addr( + struct fygue_fat *fat, + uintptr_t *addr, + int sector +); + +#endif /* FS_FYGUE_FAT_H */ diff --git a/src/fs/fygue/fat/initialize.c b/src/fs/fygue/fat/initialize.c new file mode 100644 index 0000000..32b3fd4 --- /dev/null +++ b/src/fs/fygue/fat/initialize.c @@ -0,0 +1,195 @@ +/* +** fygue/fat/initialize - FAT initialization +*/ +#include + +#include + +#include "fat.h" + +//--- +// Internals +//--- + +/* struct _fat_bpb : Bios Parameter Block */ +struct _fat_bpb +{ + // common boot structure + uint8_t BS_jmpBoot[3]; + uint8_t BS_OEMName[8]; + + // BIOS parameter Block + uint16_t BPB_BytsPerSec; + uint8_t BPB_SecPerClus; + uint16_t BPB_RsvdSecCnt; + uint8_t BPB_NumFATs; + uint16_t BPB_RootEntCnt; + uint16_t BPB_TotSec16; + uint8_t BPB_Media; + uint16_t BPB_FATSz16; + uint16_t BPB_SecPerTrk; + uint16_t BPB_NumHeads; + uint32_t BPB_HiddSec; + uint32_t BPB_TotSec32; + + // Extended BIOS Parameter Block + uint8_t BS_DrvNum; + uint8_t BS_Reserved1; + uint8_t BS_BootSig; + uint8_t BS_VolID[4]; + uint8_t BS_VolLab[11]; + uint8_t BS_FilSysType[8]; + uint8_t _unused[448]; + + // Signature + uint8_t Signature_word[2]; +} GPACKED(1); + + +/* _fygue_fat_sector0() - load the special sector0 information + * + * notes + * Fugue use the special sector0 to fetch critical flash information + * (total logical sector count and number of hidden sector). Then, based + * on fecthed information, Fugue select an hardcoded FAT configuration + * + * return + * -1 unable to load the sector0 + * -2 unsupported Fugue configuration */ +static int _fygue_fat_sector0(struct fygue_fat *fat) +{ + uint8_t *sector; + int rc; + + rc = fygue_flash_cmap_lsector_get_addr( + &fat->_flash.cmap, + (void*)§or, + 0 + ); + if (rc != 0) + return -1; + fat->SectorHiddenCount = ( + (sector[0x1c9] << 24) | + (sector[0x1c8] << 16) | + (sector[0x1c7] << 8) | + (sector[0x1c6] << 0) + ); + fat->SectorCount = ( + (sector[0x1cd] << 24) | + (sector[0x1cc] << 16) | + (sector[0x1cb] << 8) | + (sector[0x1ca] << 0) + ); + rc = fygue_flash_cmap_lsector_get_addr( + &fat->_flash.cmap, + &fat->BPB, + fat->SectorHiddenCount + ); + if (rc != 0) + return -2; + return 0; +} + +/* _fygue_fat_configure() - configure the FAT information + * + * notes + * the objectif is to find the first FAT address and the reserved root + * cluster (at the end of FATs since we only have to handle FAT12/16) + * + * note that for FAT12/16 two special cluster entry are added, this is + * why we have a manual offset to calculate the number of sector per + * FAT */ +static int _fygue_fat_configure(struct fygue_fat *fat) +{ + struct _fat_bpb *bpb; + int RootDirSectors; + int DataSec; + int CountofClusters; + + bpb = (void *)fat->BPB; + + RootDirSectors = FAT_WORD(bpb->BPB_RootEntCnt) * 32; + RootDirSectors += FAT_WORD(bpb->BPB_BytsPerSec) - 1; + RootDirSectors /= FAT_WORD(bpb->BPB_BytsPerSec); + DataSec = FAT_WORD(bpb->BPB_RsvdSecCnt); + DataSec += FAT_WORD(bpb->BPB_FATSz16) * bpb->BPB_NumFATs; + DataSec += RootDirSectors; + DataSec = FAT_WORD(bpb->BPB_TotSec16) - DataSec; + CountofClusters = DataSec / bpb->BPB_SecPerClus; + if (CountofClusters < 4085) { + fat->Type = FYGUE_FAT_TYPE_FAT12; + } else if (CountofClusters < 65525) { + fat->Type = FYGUE_FAT_TYPE_FAT16; + } else { + // TODO: maybe gint panic ? + return -2; + } + + fat->TotalCapacity = DataSec * FAT_WORD(bpb->BPB_BytsPerSec); + fat->RootEntCount = FAT_WORD(bpb->BPB_RootEntCnt); + + // todo : FAT12-specific operation + fat->ClusterCount = FAT_WORD(bpb->BPB_FATSz16); + fat->ClusterCount *= FAT_WORD(bpb->BPB_BytsPerSec); + fat->ClusterCount /= 2; + + fat->FAT0SectorID = fat->SectorHiddenCount; + fat->FAT0SectorID += FAT_WORD(bpb->BPB_RsvdSecCnt); + fat->FAT1SectorID = fat->FAT0SectorID; + fat->FAT1SectorID += FAT_WORD(bpb->BPB_FATSz16); + fat->RootSectorID = fat->FAT1SectorID; + fat->RootSectorID += FAT_WORD(bpb->BPB_FATSz16); + fat->DataSectorID = fat->RootSectorID; + fat->DataSectorID += RootDirSectors; + return 0; +} + +/* _fygue_fat_prepare() - prepare logic information */ +static int _fygue_fat_prepare(struct fygue_fat *fat) { + int rc; + + rc = fygue_flash_cmap_lsector_get_addr( + &fat->_flash.cmap, + &fat->FAT0Addr, + fat->FAT0SectorID + ); + if (rc != 0) + return -1; + rc = fygue_flash_cmap_lsector_get_addr( + &fat->_flash.cmap, + (void*)&fat->FAT1Addr, + fat->FAT1SectorID + ); + if (rc != 0) + return -1; + rc = fygue_flash_cmap_lsector_get_addr( + &fat->_flash.cmap, + &fat->RootAddr, + fat->RootSectorID + ); + if (rc != 0) + return -1; + return 0; +} + +//--- +// Public +//--- + +/* fygue_fat_init_cold() - fully initialize the FAT information */ +int fygue_fat_init_cold(struct fygue_fat *fat) +{ + if (fat == NULL) + return -1; + memset(fat, 0x00, sizeof(struct fygue_fat)); + if (fygue_flash_cmap_init(&fat->_flash.cmap) != 0) + return -2; + if ( + _fygue_fat_sector0(fat) != 0 || + _fygue_fat_configure(fat) != 0 || + _fygue_fat_prepare(fat) != 0 + ) { + return -3; + } + return 0; +} diff --git a/src/fs/fygue/fat/readdir.c b/src/fs/fygue/fat/readdir.c new file mode 100644 index 0000000..6cb4ec1 --- /dev/null +++ b/src/fs/fygue/fat/readdir.c @@ -0,0 +1,419 @@ +/* +** fygue/fat/readdir - readdir primitive +*/ +#include + +#include + +#include "fat.h" + +//--- +// Internals +//--- + +// types + +/* _fat_dirent - FAT directory entry structure */ +struct _fat_dirent +{ + uint8_t DIR_Name[11]; + uint8_t DIR_Attr; + uint8_t DIR_NTRes; + uint8_t DIR_CrtTimeTenth; + uint16_t DIR_CrtTime; + uint16_t DIR_CrtDate; + uint16_t DIR_LstAccDate; + uint16_t DIR_FstClusHI; + uint16_t DIR_WrtTime; + uint16_t DIR_WrtDate; + uint16_t DIR_FstClusLO; + uint32_t DIR_FileSize; +} GPACKED(1); + +/* _fat_dir_name : Fugue directory name strcuture */ +struct _fat_dirname +{ + struct { + uint8_t :1; // must be 0 + uint8_t last :1; + uint8_t :1; // must be 0 + uint8_t id :5; + } DIR_Sequence; + uint16_t DIR_Char0; + uint16_t DIR_Char1; + uint16_t DIR_Char2; + uint16_t DIR_Char3; + uint16_t DIR_Char4; + uint8_t DIR_Attr; // must be 0x0f + uint8_t DIR_Type; // must be 0x00 + uint8_t checksum; + uint16_t DIR_Char5; + uint16_t DIR_Char6; + uint16_t DIR_Char7; + uint16_t DIR_Char8; + uint16_t DIR_Char9; + uint16_t DIR_Char10; + uint16_t DIR_FstClus; // must be 0x0000 + uint16_t DIR_Char11; + uint16_t DIR_Char12; +} GPACKED(1); + +/* _fat_info - internal struct info */ +struct _fat_info +{ + struct fygue_fat *fat; + struct fygue_fat_dir *dir; + struct fygue_fat_dirent *current; + uint8_t *filename; + int idx; +}; + + +/* _fygue_fat_readdir_cursor_update() - update internal directory cursor + * + * notes + * - assume that dir is always non-null + * - special root handling (root= dir->cluster_id == 0) + * + * return + * -1 end of dirent + * 0 success */ +static int _fygue_fat_readdir_cursor_update(struct _fat_info *finfo) +{ + struct fygue_fat_dir *dir; + int rc; + + dir = finfo->dir; + if (dir->end_of_dirent == true) + return -1; + dir->end_of_dirent = true; + if (dir->cluster_entry == 0) + { + dir->dirent_cursor += 1; + if (dir->dirent_cursor >= dir->root_dirent_count) + return -1; + if ((dir->dirent_cursor % 16) != 0) + { + dir->dirent_current_addr += sizeof(struct _fat_dirent); + dir->end_of_dirent = false; + return 0; + } + dir->sector_id += 1; + } else { + dir->dirent_cursor += 1; + if ((dir->dirent_cursor % 16) != 0) + { + dir->dirent_current_addr += sizeof(struct _fat_dirent); + dir->end_of_dirent = false; + return 0; + } + dir->dirent_cursor = 0; + dir->sector_count += 1; + if (dir->sector_count >= 8) + { + rc = fygue_fat_cluster_get_next( + finfo->fat, + &dir->cluster_current + ); + if (rc != 0) + return -1; + rc = fygue_fat_cluster_get_sector( + finfo->fat, + dir->cluster_current, + &dir->sector_id + ); + if (rc != 0) + return -1; + dir->sector_count = 0; + } + } + rc = fygue_fat_sector_get_addr( + finfo->fat, + &dir->dirent_current_addr, + dir->sector_id + ); + if (rc != 0) + return -1; + dir->end_of_dirent = false; + return 0; +} + +//--- +// FAT/VFAT dirent handling +//--- + +/* _fygue_fat_readdir_dirent_gen() - generate dirent */ +static void _fygue_fat_readdir_dirent_gen( + struct _fat_info *finfo, + struct _fat_dirent *dirent +) { + struct fygue_fat_dirent *current; + int idx; + + idx = 0; + current = finfo->current; + while (finfo->idx > 0) + current->name[idx++] = finfo->filename[--finfo->idx]; + current->name[idx] = 0x00; + current->type = dirent->DIR_Attr; + current->size = FAT_DWORD(dirent->DIR_FileSize); + current->meta_addr = (uintptr_t)dirent; + current->cluster_id = ( + (FAT_WORD(dirent->DIR_FstClusHI) << 16) | + (FAT_WORD(dirent->DIR_FstClusLO) << 0) + ); +} + +/* _fygue_fat_readdir_name_shard_update() - update internal name info */ +static int _fygue_fat_readdir_name_shard_update( + struct _fat_info *finfo, + uint16_t buffer[13] +) { + uint8_t b0; + uint8_t b1; + + for (int i = 0 ; i < 13 ; i++) + { + if (buffer[i] == 0x0000 || buffer[i] == 0xffff) + continue; + if (buffer[i] >= 0x20 && buffer[i] <= 0x7a) { + finfo->filename[finfo->idx++] = buffer[i] & 0x00ff; + continue; + } + b0 = (buffer[i] & 0x00ff) >> 0; + b1 = (buffer[i] & 0xff00) >> 8; + if ( + (b0 >= 0x81 && b0 <= 0x9f) || + (b0 >= 0xa1 && b0 <= 0xfc) + ) { + if (b1 >= 0x40 && b1 <= 0xfc && b1 != 0x7f) + { + finfo->filename[finfo->idx++] = b1; + finfo->filename[finfo->idx++] = b0; + continue; + } + } + return -2; + } + return 0; +} + +/* _fygue_fat_readdir_name_prepare() - classic FAT handling */ +static int _fygue_fat_readdir_name_fat_prepare( + struct _fat_info *finfo, + struct _fat_dirent *dirent +) { + uint16_t buffer[13]; + bool need_dot; + int j; + + j = 13; + need_dot = false; + for (int i = 0 ; i < 11 ; i++) + { + if (i == 8) + need_dot = true; + if (dirent->DIR_Name[i] == 0x20) + continue; + if (need_dot) { + buffer[--j] = '.'; + need_dot = false; + } + if (dirent->DIR_Name[i] >= 'A' && dirent->DIR_Name[i] <= 'Z') { + buffer[--j] = dirent->DIR_Name[i] + 0x20; + } else { + buffer[--j] = dirent->DIR_Name[i]; + } + } + while (--j >= 0) + buffer[j] = 0x0000; + finfo->idx = 0; + return _fygue_fat_readdir_name_shard_update(finfo, buffer); +} + +/* _fygue_fat_readdir_name_update() - pre-generate filename info */ +static int _fygue_fat_readdir_name_vfat_prepare( + struct _fat_info *finfo, + struct _fat_dirname *dirname +) { + uint16_t buffer[13]; + + buffer[0] = FAT_WORD(dirname->DIR_Char12); + buffer[1] = FAT_WORD(dirname->DIR_Char11); + buffer[2] = FAT_WORD(dirname->DIR_Char10); + buffer[3] = FAT_WORD(dirname->DIR_Char9); + buffer[4] = FAT_WORD(dirname->DIR_Char8); + buffer[5] = FAT_WORD(dirname->DIR_Char7); + buffer[6] = FAT_WORD(dirname->DIR_Char6); + buffer[7] = FAT_WORD(dirname->DIR_Char5); + buffer[8] = FAT_WORD(dirname->DIR_Char4); + buffer[9] = FAT_WORD(dirname->DIR_Char3); + buffer[10] = FAT_WORD(dirname->DIR_Char2); + buffer[11] = FAT_WORD(dirname->DIR_Char1); + buffer[12] = FAT_WORD(dirname->DIR_Char0); + return _fygue_fat_readdir_name_shard_update(finfo, buffer); +} + +//--- +// dirent handling +//--- + +/* _fygue_readdir_vfat() - handle VFAT dirent generation + * + * todo + * - properly handle broken chain (0x00, 0xe5, ...) + * - properly handle `cursor_update()` error + * returns + * -3 internal error + * -2 invalid VFAT + * -1 invlaid VFAT (start) + * 0 success */ +static int _fygue_readdir_vfat(struct _fat_info *finfo) +{ + struct _fat_dirname *dirname; + int count; + + dirname = (void*)finfo->dir->dirent_current_addr; + if (dirname->DIR_Sequence.last == 0) { + finfo->dir->dirty = true; + return -1; + } + finfo->idx = 0; + count = dirname->DIR_Sequence.id; + do { + dirname = (void*)finfo->dir->dirent_current_addr; + if (dirname->DIR_Attr != 0x0f) + return -2; + if (dirname->DIR_Sequence.id != count) + return -2; + if (_fygue_fat_readdir_name_vfat_prepare(finfo, dirname) != 0) + return -2; + if (_fygue_fat_readdir_cursor_update(finfo) != 0) + return -3; + count -= 1; + } while (count >= 1); + _fygue_fat_readdir_dirent_gen( + finfo, + (void*)finfo->dir->dirent_current_addr + ); + finfo->dir->dirty = true; + return 0; +} + +/* _fygue_readdir_fat() - handle FAT dirent generation */ +static int _fygue_readdir_fat(struct _fat_info *finfo) +{ + struct _fat_dirent *dirent; + + dirent = (void*)finfo->dir->dirent_current_addr; + _fygue_fat_readdir_name_fat_prepare(finfo, dirent); + _fygue_fat_readdir_dirent_gen(finfo, dirent); + finfo->dir->dirty = true; + return 0; +} + +/* _fygue_readdir_fat_check() - check FAT type + * + * notes + * check special first character of the FAT entry and try to determine + * if it is: + * 0x00 unused entry and all remaning entry will be unused + * 0xe5 unused entry + * 0x2e special "." or ".." entry + * then check the dirent attribute to distinguish an VFAT entry from an + * classic FAT entry + * + * return + * -4 unsupported enty (volume ID) + * -3 this is a end-of-dirent entry (0x00) + * -2 this is an unused entry (0xe5) + * -1 this is a special "." or ".." entry + * 0 this is a classic FAT entry + * 1 this is a VFAT entry */ +static int _fygue_readdir_fat_check(struct _fat_info *finfo) +{ + struct _fat_dirent *dirent; + + dirent = (void*)finfo->dir->dirent_current_addr; + switch (dirent->DIR_Name[0]) + { + case 0x00: + finfo->dir->end_of_dirent = true; + return -3; + case 0xe5: + finfo->dir->dirty = true; + return -2; + case 0x2e: + if (dirent->DIR_Name[1] == '.') { + finfo->filename[0] = '.'; + finfo->filename[1] = '.'; + finfo->filename[2] = '\0'; + finfo->idx = 2; + } else { + finfo->filename[0] = '.'; + finfo->filename[1] = '\0'; + finfo->idx = 1; + } + _fygue_fat_readdir_dirent_gen(finfo, dirent); + finfo->dir->dirty = true; + return -1; + } + if (dirent->DIR_Attr == 0x0f) + return 1; + if ((dirent->DIR_Attr & 0x08) != 0) { + finfo->dir->dirty = true; + return -4; + } + return 0; +} + +//--- +// Public +//--- + +/* fygue_fat_readdir() - readdir-like primitive + * + * return + * -3 no dirent remaning + * -2 internal error + * -1 argument error + * 0 success */ +int fygue_fat_readdir( + struct fygue_fat *fat, + struct fygue_fat_dir *dir, + struct fygue_fat_dirent *current +) { + struct _fat_info finfo; + int rc; + + if (fat == NULL || current == NULL || dir == NULL) + return -1; + finfo.fat = fat; + finfo.current = current; + finfo.dir = dir; + finfo.filename = alloca(256 * sizeof(uint8_t)); + if (finfo.filename == NULL) + return -2; + while (dir->end_of_dirent == false) + { + if (finfo.dir->dirty) + { + if (_fygue_fat_readdir_cursor_update(&finfo) != 0) + break; + finfo.dir->dirty = false; + } + rc = _fygue_readdir_fat_check(&finfo); + if (rc == -3) + break; + if (rc == -1) + return 0; + if (rc < 0) + continue; + if (rc == 0 && _fygue_readdir_fat(&finfo) == 0) + return 0; + if (rc == 1 && _fygue_readdir_vfat(&finfo) == 0) + return 0; + } + dir->end_of_dirent = true; + return -3; +} diff --git a/src/fs/fygue/fat/resolve.c b/src/fs/fygue/fat/resolve.c new file mode 100644 index 0000000..1a91174 --- /dev/null +++ b/src/fs/fygue/fat/resolve.c @@ -0,0 +1,128 @@ +#include +#include "fat.h" + +//--- +// Internals +//--- + +/* _fygue_path_get_name(): get the current file name + * + * notes: + * - assume that prefix is not NULL and clean + * - assume that size is not NULL + * - assume that prefix can start with '/' */ +static int _fygue_path_get_name(char const **prefix, size_t *len) +{ + while ((*prefix)[0] == '/') { + *prefix = &((*prefix)[1]); + } + if ((*prefix)[0] == '\0') + return -1; + *len = 0; + while ((*prefix)[0] != '\0' && (*prefix)[0] != '/') { + *len += 1; + *prefix = &((*prefix)[1]); + } + return 0; +} + +/* _fugue_dirent_resolve(): convert found dirent to dir */ +static int _fygue_dirent_resolve( + struct fygue_fat *fat, + struct fygue_fat_dir *dir, + struct fygue_fat_dirent *dirent +) { + memset(dir, 0x00, sizeof(struct fygue_fat_dir)); + if (dirent == NULL) + { + dir->cluster_entry = 0; + dir->root_dirent_count = fat->RootEntCount; + } else { + dir->cluster_entry = dirent->cluster_id; + dir->root_dirent_count = 0; + } + dir->dirty = false; + dir->sector_count = 0; + dir->dirent_cursor = 0; + dir->end_of_dirent = false; + dir->cluster_current = dir->cluster_entry; + int rc = fygue_fat_cluster_get_sector( + fat, + dir->cluster_current, + &dir->sector_id + ); + if (rc != 0) + return -1; + return fygue_fat_sector_get_addr( + fat, + &dir->dirent_current_addr, + dir->sector_id + ); +} + +/* _fygue_opendir_find() - try to find the directory entry */ +static int _fygue_dirent_find( + struct fygue_fat *fat, + struct fygue_fat_dir *dir, + struct fygue_fat_dirent *dirent, + char const *start, + size_t len +) { + while (true) + { + if (fygue_fat_readdir(fat, dir, dirent) != 0) + return -1; + if (strncmp(dirent->name, start, len) != 0) + continue; + return 0; + } +} + +//--- +// Public +//--- + +/* fygue_fat_resolve(): resolve any path provided + * + * notes + * - assume that the path is clean */ +int fygue_fat_resolve( + struct fygue_fat *fat, + char const * const path, + struct fygue_fat_dirent *dirent +) { + struct fygue_fat_dir dir; + char const *prefix; + size_t len; + bool is_root; + + if (fat == NULL || path == NULL || dirent == NULL) + return -1; + if (path[0] != '/') + return -1; + if (_fygue_dirent_resolve(fat, &dir, NULL) != 0) + return -3; + prefix = path; + is_root = true; + while (true) + { + if (_fygue_path_get_name(&prefix, &len) != 0) + break; + is_root = false; + if (_fygue_dirent_find(fat, &dir, dirent, prefix, len) != 0) + return -4; + if (_fygue_dirent_resolve(fat, &dir, dirent) != 0) + return -4; + } + if (is_root) + { + memset(dirent, 0x00, sizeof(struct fygue_fat_dirent)); + dirent->name[0] = '/'; + dirent->name[1] = '\0'; + dirent->type = 0x10; + dirent->size = sizeof(struct fygue_fat_dirent); + dirent->meta_addr = dir.dirent_current_addr; + dirent->cluster_id = dir.cluster_entry; + } + return 0; +} diff --git a/src/fs/fygue/fat/sector.c b/src/fs/fygue/fat/sector.c new file mode 100644 index 0000000..cf7ea42 --- /dev/null +++ b/src/fs/fygue/fat/sector.c @@ -0,0 +1,23 @@ +/* +** fygue/_fat/sector - FAT sector handling +*/ +#include "fat.h" + +//--- +// Public +//--- + +/* fygue_fat_sector_get_addr() - get logical sector addr */ +int fygue_fat_sector_get_addr( + struct fygue_fat *fat, + uintptr_t *addr, + int sector +) { + if (fat == NULL) + return -1; + return fygue_flash_cmap_lsector_get_addr( + &fat->_flash.cmap, + addr, + sector + ); +} diff --git a/src/fs/fygue/flash/cluster.c b/src/fs/fygue/flash/cluster.c new file mode 100644 index 0000000..d681cf7 --- /dev/null +++ b/src/fs/fygue/flash/cluster.c @@ -0,0 +1,191 @@ +/* +** fygue/_flash/cluster - flash cluster handling +*/ +#include + +#include + +#include "flash.h" + +//--- +// Internals +//--- + +/* _bfile_cluster_metadata - special cluster metadata information */ +struct _bfile_cluster_metadata +{ + uint8_t bitmask[2]; + uint32_t fcluster_version; + uint16_t lcluster_id; + uint16_t fcluster_crc; + uint8_t constant[24]; + uint8_t signature[3]; + uint8_t ecc_bitmask_position[3]; +} GPACKED(1); + +/* _fygue_flash_cluster_convert - ensure that the provided meta is valid + * + * notes + * - assume that fcluster is not NULL + * - try using P1 information first then, P2 if this greedy-read fail + * - to ensure that the provided bfile metadata is valid we will perform + * some test (also performed by Casio). First, ensure that the + * fcluster "kind" is valid (only 0x88, 0x22 or 0x11 are known and + * used) and then ensure that the "constant" part is also valid + * + * todo : ensure checksum + * todo : ensure ecc handling (?) + * todo : try P1 then P2 + * + * return + * -1 if the provided `fcluster` is not NULL + * -1 if the bfile metadata cannot be validated + * 0 otherwise */ +static int _fygue_flash_cluster_convert( + struct fygue_flash_cluster *fcluster, + uintptr_t bfile_meta +) { + static const uint8_t _constant1[] = { + 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, + }; + static const uint8_t _constant2[] = { + 0x11, 0x11, 0x11, 0x22, + 0x22, 0x22, 0x44, 0x44, + 0x44, 0x88, 0x88, 0x88, + 0x77, 0x77, 0x77, 0xbb, + 0xbb, 0xbb, 0xdd, 0xdd, + 0xdd, 0xee, 0xee, 0xee, + }; + struct _bfile_cluster_metadata *meta[2] = { + (void*)(bfile_meta | 0x80000000), + (void*)(bfile_meta | 0xa0000000), + }; + if (fcluster == NULL) + return -1; + for (int i = 0 ; i < 2 ; i++) + { + if ( + meta[i]->signature[0] != 0x5a || + meta[i]->signature[1] != 0x5a || + meta[i]->signature[2] != 0x5a + ) { + continue; + } + if ( + meta[i]->bitmask[0] != 0x88 && + meta[i]->bitmask[0] != 0x22 && + meta[i]->bitmask[0] != 0x11 + ) { + continue; + } + if (meta[i]->bitmask[1] != 0x0f) + continue; + if (meta[i]->bitmask[0] != 0x11 && meta[i]->lcluster_id != 0xffff) + continue; + if ( + memcmp(&(meta[i]->constant), _constant1, 0x18) != 0 && + memcmp(&(meta[i]->constant), _constant2, 0x18) != 0 + ) { + continue; + } + fcluster->lcluster_id = meta[i]->lcluster_id; + fcluster->kind = meta[i]->bitmask[0]; + fcluster->version = meta[i]->fcluster_version; + return 0; + } + return -2; +} + +//--- +// Public +//--- + +/* fygue_flash_cluster_geometry() - get geometry information + * + * notes + * generate flash cluster geometry information. Note that we handle + * sector as a full 32 entry table, which differ from logical cluster ID + * that ignore the last entry which contain meta information + * + * returns + * -1 if the provided address is not valid + * 0 success */ +int fygue_flash_cluster_geometry( + uintptr_t addr, + uint16_t *fcluster_id, + uint16_t *fsector_id, + uint16_t *fcluster_off +) { + if ((addr & 0x0fffffff) < 0x00c80000) + return -1; + addr = (addr & 0x0fffffff) - 0x00c80000; + if (fcluster_id != NULL) { + *fcluster_id = ((addr & 0xfffe0000) >> 17) * 32; + *fcluster_id += ((addr & 0x0001ffff) >> 12); + } + if (fsector_id != NULL) + *fsector_id = ((addr & 0xfffe0000) >> 17) * 32; + if (fcluster_off != NULL) + *fcluster_off = ((addr & 0x0001ffff) >> 12); + return 0; +} + +/* fygue_flash_cluster_get() - get flash cluster information + * + * return + * -1 if the provided `fline` is not valid + * -2 if the provided `fline` have invalid Bfile metadata + * 0 if the meta information has been generated */ +int fygue_flash_cluster_get( + uint16_t fcluster_id, + struct fygue_flash_cluster *fcluster +) { + uintptr_t bfile_meta; + uintptr_t bfile_data; + int fsector_id; + int fcluster_off; + + if (fcluster == NULL) + return -1; + if (fcluster_id >= __FYGUE_FCLUSTER_COUNT) + return -1; + fsector_id = fcluster_id / 32; + fcluster_off = fcluster_id % 32; + if (fcluster_off == 31) + { + fcluster->kind = 0x667; + fcluster->lcluster_id = 0xffff; + fcluster->version = 0xffffffff; + } else { + bfile_meta = 0x00c80000; + bfile_meta += (fsector_id * 0x20000) + 0x1f000; + bfile_meta += (fcluster_off * 0x40); + if (_fygue_flash_cluster_convert(fcluster, bfile_meta) != 0) + return -2; + } + bfile_data = 0x00c80000; + bfile_data += (fsector_id * 0x20000); + bfile_data += (fcluster_off * 0x1000); + fcluster->data_p1 = bfile_data | 0xa0000000; + fcluster->data_p2 = bfile_data | 0xa0000000; + fcluster->fcluster_id_bfile = (fsector_id * 31) + fcluster_off; + fcluster->fcluster_id = fcluster_id; + if (fcluster->kind == 0x22) + { + uint32_t *data = (void*)fcluster->data_p1; + if ( + ((data[0] ^ data[1]) != 0xffffffff) || + ((data[2] ^ data[3]) != 0xffffffff) || + ((data[4] ^ data[5]) != 0xffffffff) + ) { + return -2; + } + fcluster->version = data[0]; + } + return 0; +} diff --git a/src/fs/fygue/flash/cmap.c b/src/fs/fygue/flash/cmap.c new file mode 100644 index 0000000..1def9dd --- /dev/null +++ b/src/fs/fygue/flash/cmap.c @@ -0,0 +1,152 @@ +/* +** fygue/flash/cmap - flash cluster map +*/ +#include +#include + +#include + +#include "flash.h" + +//--- +// Internals +//--- + +/* fygue_flash_cmap_update() - update the cluster redirection map + * + * notes + * Since Casio use its own methods to handle flash sector and cluster we + * need to rebuild the translation page between "logical cluster" + * (lcluster) and "flash cluster" (fcluster). + * + * Casio do not erase systematicaly each sector when they become + * outdated, instead, they use a `age` mechanism which indicate "when" + * the cluster has been created a keep the more recent one + * + * return + * -1 if the provided information is not valid + * 0 if the provided lcluster exists and has not been updated + * 1 if the provided lcluster has been created + * 2 if the provided lcluster exists and has been updated */ +static int fygue_flash_cmap_update( + struct fygue_flash_cmap *cmap, + struct fygue_flash_cluster *fcluster +) { + struct fygue_flash_cmap_entry *entry; + + if (cmap == NULL || fcluster == NULL) + return -1; + if (fcluster->kind != 0x11) + return -1; + if (cmap->lcluster_id_max > fcluster->lcluster_id) + { + if ( + cmap->lcluster[fcluster->lcluster_id].version != 0xffffffff && + cmap->lcluster[fcluster->lcluster_id].version + < fcluster->version + ) { + return 1; + } + } else { + cmap->lcluster = realloc( + cmap->lcluster, + (fcluster->lcluster_id + 1) * sizeof( + struct fygue_flash_cmap_entry + ) + ); + for ( + int i = cmap->lcluster_id_max ; + i < fcluster->lcluster_id ; + i++ + ) { + cmap->lcluster[i].fcluster_id = 0xffff; + cmap->lcluster[i].fcluster_id_bfile = 0xffff; + cmap->lcluster[i].fcluster_data_p1 = 0xffffffff; + cmap->lcluster[i].fcluster_data_p2 = 0xffffffff; + cmap->lcluster[i].version = 0xffffffff; + } + cmap->lcluster_id_max = fcluster->lcluster_id + 1; + } + entry = &(cmap->lcluster[fcluster->lcluster_id]); + entry->fcluster_id = fcluster->fcluster_id; + entry->fcluster_id_bfile = fcluster->fcluster_id_bfile; + entry->fcluster_data_p1 = fcluster->data_p1; + entry->fcluster_data_p2 = fcluster->data_p2; + entry->version = fcluster->version; + return 0; +} + +//--- +// Public +//--- + +/* fygue_flash_cmap_init() - initialize fcluster translation + * + * notes: + * Casio have its own flash handling layer that hook Fugue primitives to + * control how/when the hardware will perform IO operation + * (read,write,erase). This because the Flash used in recent devices use + * sector of 128ko which imply, when you want to update one byte of + * memory, you need to: + * - copy the whole page in RAM + * - perform the modification + * - write the new page information + * + * So, todo + * + * returns: + * -1 if the sector 0 is not found + * 0 success */ +int fygue_flash_cmap_init(struct fygue_flash_cmap *cmap) +{ + struct fygue_flash_cluster fcluster; + int rc; + + if (cmap == NULL) + return -1; + for (int fsector = 0 ; fsector < __FYGUE_FSECTOR_COUNT ; fsector++) + { + if (fygue_flash_cluster_get(fsector * 32, &fcluster) != 0) + continue; + if (fcluster.kind != 0x22) + continue; + for (int j = 0 ; j < 31 ; j++) + { + rc = fygue_flash_cluster_get((fsector * 32) + j, &fcluster); + if (rc != 0) + continue; + if (fcluster.kind != 0x11) + continue; + fygue_flash_cmap_update(cmap, &fcluster); + } + } + if (cmap->lcluster == NULL) + return -1; + if (cmap->lcluster[0].fcluster_id == 0xffff) + return -1; + return 0; +} + +/* fygue_flash_cmap_lsector_get_addr() - get logical sector address */ +int fygue_flash_cmap_lsector_get_addr( + struct fygue_flash_cmap *cmap, + uintptr_t *sector, + uint16_t lsector_id +) { + uintptr_t fsector_addr; + uint16_t lcluster_id; + + if (sector == NULL || cmap == NULL || cmap->lcluster == NULL) + return -1; + lcluster_id = lsector_id / 8; + if ( + cmap->lcluster_id_max < lcluster_id || + cmap->lcluster[lcluster_id].fcluster_id == 0xffff + ) { + return -2; + } + fsector_addr = cmap->lcluster[lcluster_id].fcluster_data_p1; + fsector_addr += (lsector_id % 8) * 512; + *sector = fsector_addr; + return 0; +} diff --git a/src/fs/fygue/flash/flash.h b/src/fs/fygue/flash/flash.h new file mode 100644 index 0000000..e58f43e --- /dev/null +++ b/src/fs/fygue/flash/flash.h @@ -0,0 +1,67 @@ +#ifndef FS_FYGUE_FLASH_H +#define FS_FYGUE_FLASH_H 1 + +#include + +/* __FYGUE_* - hardcoded fygue information */ +#define __FYGUE_FSECTOR_COUNT (0x9c) +#define __FYGUE_FCLUSTER_COUNT (__FYGUE_FSECTOR_COUNT * 32) + +/* fygue_fcluster - generic flash cluster information */ +struct fygue_flash_cluster +{ + uint32_t kind; + uint16_t fcluster_id; + uint16_t fcluster_id_bfile; + uint16_t lcluster_id; + uint32_t version; + uintptr_t data_p1; + uintptr_t data_p2; +}; + +/* fygue_fcluster_map_entry - cmap list entry */ +struct fygue_flash_cmap_entry +{ + uint16_t fcluster_id; + uint16_t fcluster_id_bfile; + uintptr_t fcluster_data_p1; + uintptr_t fcluster_data_p2; + uint32_t version; +}; + +/* fygue_cmap_info - Cluster redirection information */ +struct fygue_flash_cmap +{ + struct fygue_flash_cmap_entry *lcluster; + int lcluster_id_max; +}; + +// cluster map interface + +/* fygue_flash_cmap_init() - initialize the fcluster redirection map */ +extern int fygue_flash_cmap_init(struct fygue_flash_cmap *cmap); + +/* fygue_flash_cmap_lsector_get_addr() - get logical sector address */ +extern int fygue_flash_cmap_lsector_get_addr( + struct fygue_flash_cmap *cmap, + uintptr_t *sector, + uint16_t lsector_id +); + +// cluster interface + +/* fygue_flash_cluster_geometry() - get geometry information */ +extern int fygue_flash_cluster_geometry( + uintptr_t addr, + uint16_t *fcluster_id, + uint16_t *fsector_id, + uint16_t *fcluster_off +); + +/* fygue_flash_cluster_get() - get cluster information */ +extern int fygue_flash_cluster_get( + uint16_t fcluster_id, + struct fygue_flash_cluster *fcluster +); + +#endif /* FS_FYGUE_FLASH_H */ diff --git a/src/fs/fygue/fygue.c b/src/fs/fygue/fygue.c new file mode 100644 index 0000000..e68805f --- /dev/null +++ b/src/fs/fygue/fygue.c @@ -0,0 +1,84 @@ +#include +#include "fygue.h" + +//--- +// Internals +//--- + +/* __fygue_fsinfo: internal filesystem information */ +static struct fygue_fsinfo *__fygue_fsinfo = NULL; + +//--- +// Primitives +//--- + +/* fygue_mount() - mount (if needed) and return the filesystem information + * + * notes + * - assume that this global is const after initialisation */ +int fygue_mount(struct fygue_fsinfo **fsinfo, bool refresh) +{ + if (fsinfo == NULL) + return -1; + if (__fygue_fsinfo == NULL) + { + *fsinfo = NULL; + __fygue_fsinfo = calloc(1, sizeof(struct fygue_fsinfo)); + if (__fygue_fsinfo == NULL) + return -2; + if (fygue_fat_init_cold(&(__fygue_fsinfo->fat)) != 0) + return -3; + __fygue_fsinfo->dirty = false; + } + if (refresh && __fygue_fsinfo->dirty) { + if (fygue_fat_init_hot(&(__fygue_fsinfo->fat)) != 0) + return -3; + __fygue_fsinfo->dirty = false; + } + *fsinfo = __fygue_fsinfo; + return 0; +} + +/* fygue_resolve() - try to resolve path + * + * notes + * - assume that path is clean + * - automatically mount the filesystem if needed + * - the saved pathname will not be saved in stat */ +int fygue_resolve( + char const * const path, + int *type, + struct fygue_stat *stat +) { + struct fygue_fsinfo *fsinfo; + struct fygue_fat_dirent dirent; + + if (path == NULL || path[0] != '\\') + return -1; + if (fygue_mount(&fsinfo, true) != 0) + return -2; + if (fygue_fat_resolve(&(fsinfo->fat), path, &dirent) != 0) + return -3; + (void)type; + (void)stat; + // todo: convert FAT dirent into Fygue stat + return 0; +} + +//--- +// Descriptor +//--- + +const fs_descriptor_type_t fygue_descriptor_type = { + .read = NULL, + .write = NULL, + .lseek = NULL, + .close = NULL, +}; + +const fs_descriptor_type_t fygue_dir_descriptor_type = { + .read = NULL, + .write = NULL, + .lseek = NULL, + .close = NULL, +}; diff --git a/src/fs/fygue/fygue.h b/src/fs/fygue/fygue.h index bda8de8..5659f33 100644 --- a/src/fs/fygue/fygue.h +++ b/src/fs/fygue/fygue.h @@ -1,26 +1,91 @@ #ifndef FS_FYGUE_H #define FS_FYGUE_H 1 +#ifdef __cplusplus +extern "C" { +#endif + #include #include #include #include #include +//--- +// Public global +//--- + /* File descriptor type */ extern const fs_descriptor_type_t fygue_descriptor_type; /* Directory descriptor type */ extern const fs_descriptor_type_t fygue_dir_descriptor_type; -/* Specific implementations of some standard functions */ +//--- +// Public (low-level) API +//--- +/* fygue_open() - open file or directory */ extern int fygue_open(char const *path, int flags, mode_t mode); +/* fygue_stat() - get file or directory information */ extern int fygue_stat( char const * restrict path, struct stat * restrict statbuf ); +/* fygue_syncfs() - request filesystem re-synchronisation */ extern int fygue_syncfs(void *desc); +//--- +// Internals +//--- + +#include +#include + +#define ENOTSUP_IF_NOT_FYGUE(rc) \ + if( \ + (gint[HWFS] != HWFS_FUGUE) || \ + (flags & O_WRONLY) || \ + (flags & O_RDWR) \ + ) { \ + errno = ENOTSUP; \ + return (rc); \ + } + +#include "fat/fat.h" + +/* fygue_fsinfo: internal fygue FS information */ +struct fygue_fsinfo +{ + struct fygue_fat fat; + bool dirty; +}; + +/* fygue_stat: internals file information */ +struct fygue_stat { + int type; + union { + struct { + int file; + }; + struct { + int dir; + }; + }; +}; + +/* fygue_file_descriptor: internal file descriptor information */ +struct fygue_file_descriptor +{ + bool dirty; +}; + +/* fygue_mount(): mount and return the filesystem info */ +extern int fygue_mount(struct fygue_fsinfo **fsinfo, bool refresh); + +#ifdef __cplusplus +} +#endif + #endif /* FS_FYGUE_H */ diff --git a/src/fs/fygue/fygue_open.c b/src/fs/fygue/fygue_open.c new file mode 100644 index 0000000..440fa94 --- /dev/null +++ b/src/fs/fygue/fygue_open.c @@ -0,0 +1,83 @@ +#if 0 +#include +#include +#include "../fugue/util.h" +#include "fygue.h" +#include "utils.h" + +int fygue_open(char const *path, int flags, GUNUSED mode_t mode) +{ + int rc; + + ENOTSUP_IF_NOT_FYGUE(-1); + + /* 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 */ + exists = fygue_resolve(path); + + /* 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); + if(!dp) { + rc = -1; + goto end; + } + fs_descriptor_t data = { + .type = &fugue_dir_descriptor_type, + .data = dp, + }; + return = fs_create_descriptor(&data); + } + + /* prepare Fugue/Casio path */ + uint16_t *fcpath = fs_path_normalize_fc(path); + if(fcpath == NULL) { + errno = ENOMEM; + return -1; + } + + /* 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))) { + gint_world_enter(GINT_WORLD_OS); + BFile_Remove(fcpath); + gint_world_leave(); + 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 new_file_size = 0; + gint_world_enter(GINT_WORLD_OS); + int err = BFile_Create(fcpath, BFile_File, &new_file_size); + gint_world_leave(); + if(err < 0) { + errno = bfile_error_to_errno(err); + return -1; + } + } + +end: + free(fcpath); + return rc; +} +#endif diff --git a/src/fs/fygue/fygue_syncfs.c b/src/fs/fygue/fygue_syncfs.c new file mode 100644 index 0000000..9a596cd --- /dev/null +++ b/src/fs/fygue/fygue_syncfs.c @@ -0,0 +1,16 @@ +#include "fygue.h" + +int fygue_syncfs(void *data) +{ + struct fygue_fsinfo *fsinfo; + struct fygue_file_descriptor *descriptor; + + if (data == NULL) + return -1; + if (fygue_mount(&fsinfo, false) != 0) + return -2; + descriptor = data; + descriptor->dirty = true; + fsinfo->dirty = true; + return 0; +} diff --git a/src/fs/open.c b/src/fs/open.c index 9a2cbed..ac1c4b4 100644 --- a/src/fs/open.c +++ b/src/fs/open.c @@ -22,10 +22,10 @@ int open(char const *path, int flags, ...) * descriptor because when some flags are set (e.g O_CREATE) Fygue * invoke BFile_*() syscall that perform IO operation. * - * Note that Fygue's open() primitive with perform a "lazy" open operation - * by simply ensure that the file exists and mark the file descriptor as - * dirty to force internal data refresh on the next Fygue's IO - * operation */ + * Note that Fygue's open() primitive with perform a "lazy" open + * operation by simply ensure that the file exists and mark the file + * descriptor as dirty to force internal data refresh on the next + * Fygue's IO operation */ fs_fygue_sync(); return rc; }