mirror of
https://git.planet-casio.com/Lephenixnoir/gint.git
synced 2025-07-04 03:26:37 +02:00
fygue: (WIP) add syncfs support + add FAT/Flash backend + prepare open() primitive
This commit is contained in:
parent
b40a6b3fa8
commit
6d99494d30
15 changed files with 1599 additions and 5 deletions
|
@ -259,6 +259,17 @@ set(SOURCES
|
||||||
src/touch/adconv.c
|
src/touch/adconv.c
|
||||||
src/touch/touch.c
|
src/touch/touch.c
|
||||||
src/touch/driver.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)
|
set(ASSETS_FX src/font5x7.png src/gdb/icons-i1msb.png)
|
||||||
|
|
46
src/fs/fygue/fat/cluster.c
Normal file
46
src/fs/fygue/fat/cluster.c
Normal file
|
@ -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;
|
||||||
|
}
|
114
src/fs/fygue/fat/fat.h
Normal file
114
src/fs/fygue/fat/fat.h
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
#ifndef FS_FYGUE_FAT_H
|
||||||
|
#define FS_FYGUE_FAT_H 1
|
||||||
|
|
||||||
|
#include <gint/defs/types.h>
|
||||||
|
|
||||||
|
#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 */
|
195
src/fs/fygue/fat/initialize.c
Normal file
195
src/fs/fygue/fat/initialize.c
Normal file
|
@ -0,0 +1,195 @@
|
||||||
|
/*
|
||||||
|
** fygue/fat/initialize - FAT initialization
|
||||||
|
*/
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <gint/defs/attributes.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
419
src/fs/fygue/fat/readdir.c
Normal file
419
src/fs/fygue/fat/readdir.c
Normal file
|
@ -0,0 +1,419 @@
|
||||||
|
/*
|
||||||
|
** fygue/fat/readdir - readdir primitive
|
||||||
|
*/
|
||||||
|
#include <alloca.h>
|
||||||
|
|
||||||
|
#include <gint/defs/attributes.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
128
src/fs/fygue/fat/resolve.c
Normal file
128
src/fs/fygue/fat/resolve.c
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
#include <string.h>
|
||||||
|
#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;
|
||||||
|
}
|
23
src/fs/fygue/fat/sector.c
Normal file
23
src/fs/fygue/fat/sector.c
Normal file
|
@ -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
|
||||||
|
);
|
||||||
|
}
|
191
src/fs/fygue/flash/cluster.c
Normal file
191
src/fs/fygue/flash/cluster.c
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
/*
|
||||||
|
** fygue/_flash/cluster - flash cluster handling
|
||||||
|
*/
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <gint/defs/attributes.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
152
src/fs/fygue/flash/cmap.c
Normal file
152
src/fs/fygue/flash/cmap.c
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
/*
|
||||||
|
** fygue/flash/cmap - flash cluster map
|
||||||
|
*/
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <gint/defs/attributes.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
67
src/fs/fygue/flash/flash.h
Normal file
67
src/fs/fygue/flash/flash.h
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
#ifndef FS_FYGUE_FLASH_H
|
||||||
|
#define FS_FYGUE_FLASH_H 1
|
||||||
|
|
||||||
|
#include <gint/defs/types.h>
|
||||||
|
|
||||||
|
/* __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 */
|
84
src/fs/fygue/fygue.c
Normal file
84
src/fs/fygue/fygue.c
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#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,
|
||||||
|
};
|
|
@ -1,26 +1,91 @@
|
||||||
#ifndef FS_FYGUE_H
|
#ifndef FS_FYGUE_H
|
||||||
#define FS_FYGUE_H 1
|
#define FS_FYGUE_H 1
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <gint/fs.h>
|
#include <gint/fs.h>
|
||||||
|
|
||||||
|
//---
|
||||||
|
// Public global
|
||||||
|
//---
|
||||||
|
|
||||||
/* File descriptor type */
|
/* File descriptor type */
|
||||||
extern const fs_descriptor_type_t fygue_descriptor_type;
|
extern const fs_descriptor_type_t fygue_descriptor_type;
|
||||||
/* Directory descriptor type */
|
/* Directory descriptor type */
|
||||||
extern const fs_descriptor_type_t fygue_dir_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);
|
extern int fygue_open(char const *path, int flags, mode_t mode);
|
||||||
|
|
||||||
|
/* fygue_stat() - get file or directory information */
|
||||||
extern int fygue_stat(
|
extern int fygue_stat(
|
||||||
char const * restrict path,
|
char const * restrict path,
|
||||||
struct stat * restrict statbuf
|
struct stat * restrict statbuf
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/* fygue_syncfs() - request filesystem re-synchronisation */
|
||||||
extern int fygue_syncfs(void *desc);
|
extern int fygue_syncfs(void *desc);
|
||||||
|
|
||||||
|
//---
|
||||||
|
// Internals
|
||||||
|
//---
|
||||||
|
|
||||||
|
#include <gint/hardware.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#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 */
|
#endif /* FS_FYGUE_H */
|
||||||
|
|
83
src/fs/fygue/fygue_open.c
Normal file
83
src/fs/fygue/fygue_open.c
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
#if 0
|
||||||
|
#include <gint/gint.h>
|
||||||
|
#include <gint/bfile.h>
|
||||||
|
#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
|
16
src/fs/fygue/fygue_syncfs.c
Normal file
16
src/fs/fygue/fygue_syncfs.c
Normal file
|
@ -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;
|
||||||
|
}
|
|
@ -22,10 +22,10 @@ int open(char const *path, int flags, ...)
|
||||||
* descriptor because when some flags are set (e.g O_CREATE) Fygue
|
* descriptor because when some flags are set (e.g O_CREATE) Fygue
|
||||||
* invoke BFile_*() syscall that perform IO operation.
|
* invoke BFile_*() syscall that perform IO operation.
|
||||||
*
|
*
|
||||||
* Note that Fygue's open() primitive with perform a "lazy" open operation
|
* Note that Fygue's open() primitive with perform a "lazy" open
|
||||||
* by simply ensure that the file exists and mark the file descriptor as
|
* operation by simply ensure that the file exists and mark the file
|
||||||
* dirty to force internal data refresh on the next Fygue's IO
|
* descriptor as dirty to force internal data refresh on the next
|
||||||
* operation */
|
* Fygue's IO operation */
|
||||||
fs_fygue_sync();
|
fs_fygue_sync();
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue