From b089b00882c30eefb8633f382e1085a10f59c542 Mon Sep 17 00:00:00 2001 From: Yann MAGNIN Date: Thu, 20 Apr 2023 16:25:05 +0200 Subject: [PATCH] fsctl - v0.0.0-1 : project architecture + fugue root dirent handling (WIP) *common* | add build system | add neovim ALE configuration | first Fugue File System abstraction (maxi WIP) | first menus (ROM, FS info, FAT viewer, ...) (WIP) --- .gitignore | 17 ++++ .nvimrc | 58 +++++++++++++ CMakeLists.txt | 41 +++++++++ assets-cg/icon-cg.xcf | Bin 0 -> 55168 bytes assets-cg/icon-sel.png | Bin 0 -> 3536 bytes assets-cg/icon-uns.png | Bin 0 -> 1700 bytes include/fsctl/fugue.h | 24 ++++++ include/fsctl/fugue/bits/dir.h | 26 ++++++ include/fsctl/fugue/bits/fat.h | 94 +++++++++++++++++++++ include/fsctl/fugue/bits/file.h | 20 +++++ include/fsctl/fugue/bits/fs.h | 48 +++++++++++ include/fsctl/fugue/cluster.h | 16 ++++ include/fsctl/fugue/dirent.h | 21 +++++ include/fsctl/fugue/fat.h | 13 +++ include/fsctl/fugue/sector.h | 16 ++++ include/fsctl/fugue/utils.h | 16 ++++ include/fsctl/menu.h | 4 + include/fsctl/menu/fat.h | 13 +++ include/fsctl/menu/info.h | 13 +++ include/fsctl/menu/list.h | 13 +++ include/fsctl/menu/rom.h | 13 +++ include/fsctl/utils/display.h | 47 +++++++++++ include/fsctl/utils/fs_table.h | 47 +++++++++++ src/fugue/core/cluster.c | 43 ++++++++++ src/fugue/core/dirent.c | 85 +++++++++++++++++++ src/fugue/core/fat.c | 74 ++++++++++++++++ src/fugue/core/sector.c | 89 ++++++++++++++++++++ src/fugue/dir.c | 144 ++++++++++++++++++++++++++++++++ src/fugue/mount.c | 103 +++++++++++++++++++++++ src/main.c | 54 ++++++++++++ src/menu/fat.c | 96 +++++++++++++++++++++ src/menu/info.c | 59 +++++++++++++ src/menu/list.c | 46 ++++++++++ src/menu/rom.c | 103 +++++++++++++++++++++++ src/utils/fs_table.c | 123 +++++++++++++++++++++++++++ 35 files changed, 1579 insertions(+) create mode 100644 .gitignore create mode 100644 .nvimrc create mode 100644 CMakeLists.txt create mode 100644 assets-cg/icon-cg.xcf create mode 100644 assets-cg/icon-sel.png create mode 100644 assets-cg/icon-uns.png create mode 100644 include/fsctl/fugue.h create mode 100644 include/fsctl/fugue/bits/dir.h create mode 100644 include/fsctl/fugue/bits/fat.h create mode 100644 include/fsctl/fugue/bits/file.h create mode 100644 include/fsctl/fugue/bits/fs.h create mode 100644 include/fsctl/fugue/cluster.h create mode 100644 include/fsctl/fugue/dirent.h create mode 100644 include/fsctl/fugue/fat.h create mode 100644 include/fsctl/fugue/sector.h create mode 100644 include/fsctl/fugue/utils.h create mode 100644 include/fsctl/menu.h create mode 100644 include/fsctl/menu/fat.h create mode 100644 include/fsctl/menu/info.h create mode 100644 include/fsctl/menu/list.h create mode 100644 include/fsctl/menu/rom.h create mode 100644 include/fsctl/utils/display.h create mode 100644 include/fsctl/utils/fs_table.h create mode 100644 src/fugue/core/cluster.c create mode 100644 src/fugue/core/dirent.c create mode 100644 src/fugue/core/fat.c create mode 100644 src/fugue/core/sector.c create mode 100644 src/fugue/dir.c create mode 100644 src/fugue/mount.c create mode 100644 src/main.c create mode 100644 src/menu/fat.c create mode 100644 src/menu/info.c create mode 100644 src/menu/list.c create mode 100644 src/menu/rom.c create mode 100644 src/utils/fs_table.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..587e79b --- /dev/null +++ b/.gitignore @@ -0,0 +1,17 @@ +# Build files +/build-fx +/build-cg +/build-cg-push +/*.g1a +/*.g3a + +# Python bytecode +__pycache__/ + +# Common IDE files +*.sublime-project +*.sublime-workspace +.vscode + +# custom +commit.txt diff --git a/.nvimrc b/.nvimrc new file mode 100644 index 0000000..9d47202 --- /dev/null +++ b/.nvimrc @@ -0,0 +1,58 @@ +" Force-display trailing whitespaces +highlight ExtraWhitespace ctermbg=red guibg=red +match ExtraWhitespace /\s\+$/ +autocmd BufWinEnter * match ExtraWhitespace /\s\+$/ +autocmd InsertEnter * match ExtraWhitespace /\s\+\%#\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 Ol}iESO+rylvHuUZ)lew_ literal 0 HcmV?d00001 diff --git a/assets-cg/icon-sel.png b/assets-cg/icon-sel.png new file mode 100644 index 0000000000000000000000000000000000000000..0ce3029cc00aea4c3cfad161c6f2bd7b60f68f1f GIT binary patch literal 3536 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 KMNUMnLSTaFG`Vj8 literal 0 HcmV?d00001 diff --git a/assets-cg/icon-uns.png b/assets-cg/icon-uns.png new file mode 100644 index 0000000000000000000000000000000000000000..039c096cc2ab31206abf45b5867ee55594d732ae GIT binary patch literal 1700 zcmV;V23z@wP)F&-TE@ZP=eefJ$8 zG^>ga5(r-rB{fNk2(U0=+M;`!NPYc7ayIb-#~Yw{-%9pMfi* zT+WRi9s!MRNU z000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2j>F}6bvucs67h+00fvxL_t(|+U=XY zZxlxu#vkA9m+!Ew80iQQ3XBwmNLEn3&PGV2GELwQKok@%sHt;TgocU^iGl)&DoTfF zOoMHq;DhibB!nVNq<}3M47O$C-JO}^XxP))U}w zqtO6WW|boZ1e}0V5%B+Q8F2?Z&au3@hJjoTORK9&Ka2|j(=b}bTnOb~h6@hUFk8l4 zaOL$r7qCsEW$bhH>kGzVSZ2#uF!k#n*s~isG_bE!LeX&|&l!kHDI2bfCodM^GKMwR zg~z$pUG$g_$FkuuKa~nR--lz{@ceY^w|s_zZDGr2sn#>sg*7+`=DJ$zijIR_!^7B7 za4>Q3AifwHQnQqW=|_@0BhTh8n;Q=2TQ3h8n;Q=2TQ3h8n;Q=2TQ3 zh8n;Q=5$pq>UF&HJpA)=Q62c|#s-*%_sU9_q3bGLhOVo08M?00W$3y}_c+I^n0>FS zDJ86G*~4{|9_8UWN{{kz9i>NkxUSMOi-l=CJZZyJQFhXXsiN$p4O2(i+X6g|hs!G0 z^>A6`x*jg8yb}-46nK({tExNB!&TKC=i#dAj`Q%o1fJyKs_O0}hbMWss=7PL;h6!a z9G)?7%He(J;h$3u?+Xv798NiWTXMM3%N*`8zX|^IFGm3YS7v6LpSR&2e5xUas*pG!;`yrn#V4m`&|isH*$C!@UB=&lCs0&Bzw3rGn;tMrRf_ub8Iql zURHJh8$io=s#1-FfBug@W0l?Q2cS$99<~y>4ow_xo)cIL5B+;=tX#(9S}oR20N`=0 zhKtn-E?m1F`J@^6x(xr@pMK6v;hA~3ip9teJaSrTXE9qo!@|P{EzrY%6-kiWdARNk z=&7Z&%i(b;L{2LK>?B(Wd$oM5U|Sd~moZhTHZ7waRr)$ngpDHQxR|iPDQ{8I28dW-~^nC ufD>>k0#3lG2si;J;8X;hfKw6hey$IZ=p>OU@Ebt@0000 +#include + +#include "fsctl/fugue/bits/fs.h" + +/* fugue_dir : Fugue directory abstraction */ +struct fugue_dir +{ + /* middle-level information */ + uintptr_t current_dir_addr; + uintptr_t cluster_addr_start; + uintptr_t cluster_addr_end; + uint32_t cluster_idx; + + /* low-level information */ + struct { + fugue_fs_t fs; + } _private; + +}; +typedef struct fugue_dir fugue_dir_t; + +#endif /* FSCTL_FUGUE_BITS_DIR_H */ diff --git a/include/fsctl/fugue/bits/fat.h b/include/fsctl/fugue/bits/fat.h new file mode 100644 index 0000000..61738a9 --- /dev/null +++ b/include/fsctl/fugue/bits/fat.h @@ -0,0 +1,94 @@ +#ifndef FSCTL_FUGUE_BITS_FAT_H +#define FSCTL_FUGUE_BITS_FAT_H 1 + +#include +#include + +/* struct fugue_fat_vbr : Volume Boot Record (hardcoded for Fugue) */ +struct fugue_fat_vbr +{ + // 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]; +} __attribute__((packed)); + +/* FUGUE_DIR_ATTR_* : Attribute information */ +#define FUGUE_DIR_ATTR_RDONLY 0x01 +#define FUGUE_DIR_ATTR_HIDDEN 0x02 +#define FUGUE_DIR_ATTR_SYSTEM 0x04 +#define FUGUE_DIR_ATTR_VOLUME 0x08 +#define FUGUE_DIR_ATTR_DIR 0x10 +#define FUGUE_DIR_ATTR_ARCHIVE 0x20 +#define FUGUE_DIR_ATTR_DEVICE 0x40 +#define FUGUE_DIR_ATTR_LFN 0x0f + +/* fugue_fat_dir : directory strcuture information */ +struct fugue_fat_dir +{ + uint8_t DIR_Name[8]; + uint8_t DIR_Exts[3]; + uint8_t DIR_Attr; + uint8_t _unknown0[1+1+2+2+2]; + uint16_t DIR_FstClusHI; + uint8_t _unknown1[2+2]; + uint16_t DIR_FstClusLO; + uint32_t DIR_FileSize; +} __attribute__((packed)); + +/* fugue_fat_dir_name : Fugue directory name strcuture */ +struct fugue_fat_dir_name +{ + struct { + uint8_t :2; + uint8_t last :1; + uint8_t :1; + uint8_t id :4; + } DIR_Secquence; + 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; +} __attribute__((packed)); + + + +#endif /* FSCTL_FUGUE_BITS_FAT_H */ diff --git a/include/fsctl/fugue/bits/file.h b/include/fsctl/fugue/bits/file.h new file mode 100644 index 0000000..44025dc --- /dev/null +++ b/include/fsctl/fugue/bits/file.h @@ -0,0 +1,20 @@ +#ifndef FSCTL_FUGUE_BITS_FILE_H +#define FSCTL_FUGUE_BITS_FILE_H 1 + +#include +#include + +/* FUGUE_FILE_TYPE_* : supported file types */ +#define FUGUE_FILE_TYPE_DIR 0x01 +#define FUGUE_FILE_TYPE_FILE 0x02 + +/* struct fugue_file : Fugue file abstraction */ +struct fugue_file +{ + char name[210]; + int type; + uint32_t size; +}; +typedef struct fugue_file fugue_file_t; + +#endif /* FSCTL_FUGUE_BITS_FILE_H */ diff --git a/include/fsctl/fugue/bits/fs.h b/include/fsctl/fugue/bits/fs.h new file mode 100644 index 0000000..a343fc0 --- /dev/null +++ b/include/fsctl/fugue/bits/fs.h @@ -0,0 +1,48 @@ +#ifndef FSCTL_FUGUE_BITS_FS_H +#define FSCTL_FUGUE_BITS_FS_H 1 + +#include +#include + +/* fugue_fs : Fugue File System abstraction */ +struct fugue_fs +{ + /* fs properties */ + struct { + char const *type; + size_t capacity; + size_t free; + size_t used; + int cluster_nb; + int cluster_resv; + int cluster_free; + int cluster_dead; + int cluster_used; + int cluster_error; + size_t cluster_size; + int cluster_nb_sector; + int sector_size; + int sector_data_nb; + int sector_root_nb; + size_t fats_size; + size_t fat0_size; + size_t fat1_size; + int fat_sec; + } props; + + /* debug-level information */ + struct { + int a; //TODO + } _logs; + + /* memory related and low-level information */ + struct { + struct fugue_fat_vbr *vbr; + void *fat0; + void *fat1; + void *root; + } _private; +}; +typedef struct fugue_fs fugue_fs_t; + +#endif /* FSCTL_FUGUE_BITS_FS_H */ diff --git a/include/fsctl/fugue/cluster.h b/include/fsctl/fugue/cluster.h new file mode 100644 index 0000000..fef40cb --- /dev/null +++ b/include/fsctl/fugue/cluster.h @@ -0,0 +1,16 @@ +#ifndef FSCTL_FUGUE_CLUSTER_H +#define FSCTL_FUGUE_CLUSTER_H 1 + +#include "fsctl/fugue/bits/fs.h" + +//--- +// Public +//--- + +/* fugue_cluster_is_valid() : check cluster validity */ +extern int fugue_cluster_is_valid(fugue_fs_t *fs, int cluster_idx); + +/* fugue_cluster_find_next() : find the next cluster address if available */ +extern uintptr_t fugue_cluster_find_next(fugue_fs_t *fs, uint32_t cluster_idx); + +#endif /* FSCTL_FUGUE_CLUSTER_H */ diff --git a/include/fsctl/fugue/dirent.h b/include/fsctl/fugue/dirent.h new file mode 100644 index 0000000..224907f --- /dev/null +++ b/include/fsctl/fugue/dirent.h @@ -0,0 +1,21 @@ +#ifndef FSCTL_FUGUE_DIRENT_H +#define FSCTL_FUGUE_DIRENT_H 1 + +#include "fsctl/fugue/bits/dir.h" +#include "fsctl/fugue/bits/file.h" + +//--- +// API +//--- + +/* fugue_dirent_dir_fetch() : fetch the current dir blob and walk to next */ +extern void *fugue_dirent_dir_fetch(fugue_dir_t *dirent); + +/* fugue_dirent_name_fetch() : fetch fragment */ +extern int fugue_dirent_name_fetch( + fugue_dir_t *dirent, + fugue_file_t *file, + void *dir +); + +#endif /* FSCTL_FUGUE_DIRENT_H */ diff --git a/include/fsctl/fugue/fat.h b/include/fsctl/fugue/fat.h new file mode 100644 index 0000000..ce82d74 --- /dev/null +++ b/include/fsctl/fugue/fat.h @@ -0,0 +1,13 @@ +#ifndef FSCTL_FUGUE_FAT_H +#define FSCTL_FUGUE_FAT_H 1 + +#include "fsctl/fugue/bits/fs.h" + +//--- +// API +//--- + +/* fugue_fat_is_vaild() : Check the complet FATs validity */ +extern int fugue_fat_is_vaild(fugue_fs_t *fs); + +#endif /* FSCTL_FUGUE_FAT_H */ diff --git a/include/fsctl/fugue/sector.h b/include/fsctl/fugue/sector.h new file mode 100644 index 0000000..90f1bf8 --- /dev/null +++ b/include/fsctl/fugue/sector.h @@ -0,0 +1,16 @@ +#ifndef FSCTL_FUGUE_SECTOR_H +#define FSCTL_FUGUE_SECTOR_H 1 + +#include "fsctl/fugue/bits/fat.h" + +//--- +// Public +//--- + +/* fugue_sector_is_vbr() : check if the given address is a potential VBR */ +extern int fugue_sector_is_vbr(struct fugue_fat_vbr *vbr); + +/* fugue_sector_is_invalid() : check if the sector is invalide */ +extern int fugue_sector_is_invalid(void *sector); + +#endif /* FSCTL_FUGUE_SECTOR_H */ diff --git a/include/fsctl/fugue/utils.h b/include/fsctl/fugue/utils.h new file mode 100644 index 0000000..bb4e984 --- /dev/null +++ b/include/fsctl/fugue/utils.h @@ -0,0 +1,16 @@ +#ifndef FSCTL_FUGUE_UTILS_H +#define FSCTL_FUGUE_UTILS_H 1 + +/* FAT_TO_WORD() : helper for 16bit value */ +#define FAT_WORD(x) \ + (((x & 0xff00) >> 8) | ((x & 0x00ff) << 8)) + +/* FAT_LONG() : helper for 32bit value */ +#define FAT_LONG(x) ( \ + ((x & 0xff000000) >> 24) \ + | ((x & 0x00ff0000) >> 8) \ + | ((x & 0x0000ff00) << 8) \ + | ((x & 0x000000ff) << 24) \ +) + +#endif /* FSCTL_FUGUE_UTILS_H */ diff --git a/include/fsctl/menu.h b/include/fsctl/menu.h new file mode 100644 index 0000000..bd04faa --- /dev/null +++ b/include/fsctl/menu.h @@ -0,0 +1,4 @@ +#include "fsctl/menu/fat.h" +#include "fsctl/menu/rom.h" +#include "fsctl/menu/info.h" +#include "fsctl/menu/list.h" diff --git a/include/fsctl/menu/fat.h b/include/fsctl/menu/fat.h new file mode 100644 index 0000000..3ec7573 --- /dev/null +++ b/include/fsctl/menu/fat.h @@ -0,0 +1,13 @@ +#ifndef FSCTL_MENU_FAT_H +#define FSCTL_MENU_FAT_H 1 + +/* fat_menu_init() : init menu */ +extern void fat_menu_init(void); + +/* fat_menu_display() : display menu */ +extern void fat_menu_display(void); + +/* fat_menu_keyboard() : handle keyboard */ +extern void fat_menu_keyboard(int key); + +#endif /* FSCTL_MENU_FAT_H */ diff --git a/include/fsctl/menu/info.h b/include/fsctl/menu/info.h new file mode 100644 index 0000000..140a2c0 --- /dev/null +++ b/include/fsctl/menu/info.h @@ -0,0 +1,13 @@ +#ifndef FSCTL_MENU_INFO_H +#define FSCTL_MENU_INFO_H 1 + +/* info_menu_init() : init menu */ +extern void info_menu_init(void); + +/* info_menu_display() : display menu */ +extern void info_menu_display(void); + +/* info_menu_keyboard() : handle keyboard */ +extern void info_menu_keyboard(int key); + +#endif /* FSCTL_MENU_INFO_H */ diff --git a/include/fsctl/menu/list.h b/include/fsctl/menu/list.h new file mode 100644 index 0000000..3dcfd02 --- /dev/null +++ b/include/fsctl/menu/list.h @@ -0,0 +1,13 @@ +#ifndef FSCTL_MENU_LIST_H +#define FSCTL_MENU_LIST_H 1 + +/* list_menu_init() : init menu */ +extern void list_menu_init(void); + +/* list_menu_display() : display menu */ +extern void list_menu_display(void); + +/* list_menu_keyboard() : handle keyboard */ +extern void list_menu_keyboard(int key); + +#endif /* FSCTL_MENU_LIST_H */ diff --git a/include/fsctl/menu/rom.h b/include/fsctl/menu/rom.h new file mode 100644 index 0000000..259e703 --- /dev/null +++ b/include/fsctl/menu/rom.h @@ -0,0 +1,13 @@ +#ifndef FSCTL_MENU_ROM_H +#define FSCTL_MENU_ROM_H 1 + +/* rom_menu_init() : init menu */ +extern void rom_menu_init(void); + +/* rom_menu_display() : display menu */ +extern void rom_menu_display(void); + +/* rom_menu_keyboard() : handle keyboard */ +extern void rom_menu_keyboard(int key); + +#endif /* FSCTL_MENU_ROM_H */ diff --git a/include/fsctl/utils/display.h b/include/fsctl/utils/display.h new file mode 100644 index 0000000..3c06189 --- /dev/null +++ b/include/fsctl/utils/display.h @@ -0,0 +1,47 @@ +#ifndef FSCTL_MENU_UTILS_H +#define FSCTL_MENU_UTILS_H 1 + +#include +#include + +//--- +// Helpers +//--- + +#define _printXY(x, y, ...) \ + dprint((x * 10) + 3, (y * 12) + 5, C_BLACK, __VA_ARGS__) + +#define _rectXY(x, y, color) \ + drect_border( \ + (x * 12) + 3 + 85, \ + (y * 12) + 3, \ + (x * 12) + 3 + 85 + 12, \ + (y * 12) + 3 + 12, \ + color, \ + 1, \ + C_BLACK \ + ) + +#define _lrectXY(x, y, color) \ + drect_border( \ + (x * 48) + 3 + 85, \ + (y * 12) + 3, \ + (x * 48) + 3 + 85 + 48, \ + (y * 12) + 3 + 12, \ + color, \ + 1, \ + C_BLACK \ + ) +#define _lrectTextXY(x, y, hex) \ + dprint_opt( \ + (x * 48) + 3 + 85 + 24, \ + (y * 12) + 3 + 6, \ + C_BLACK, \ + C_NONE, \ + DTEXT_CENTER, \ + DTEXT_MIDDLE, \ + "%04X", \ + hex \ +) + +#endif /* FUGUE_MENU_ROM_H */ diff --git a/include/fsctl/utils/fs_table.h b/include/fsctl/utils/fs_table.h new file mode 100644 index 0000000..614980d --- /dev/null +++ b/include/fsctl/utils/fs_table.h @@ -0,0 +1,47 @@ +#ifndef FSCTL_UTILS_FS_TABLE_H +#define FSCTL_UTILS_FS_TABLE_H 1 + +#include +#include + +#include "fsctl/fugue/bits/fs.h" + +//--- +// Types +//--- + +/* struct fs_table : FS table entry information */ +struct fs_table +{ + bool is_valid; + uintptr_t vbr; + fugue_fs_t fs; +}; +typedef struct fs_table fs_table_t; + +//--- +// API +//--- + +/* fs_table_init() : initialize FS table */ +extern void fs_table_init(void); + +/* fs_table_update() : try to update internal fs table */ +extern int fs_table_update(fugue_fs_t *fs); + +/* fs_table_info() : get fs table information */ +extern int fs_table_info(fugue_fs_t *fs, int *fs_idx, int *nb_fs); + +/* fs_table_dtitle() : display FS table title menu */ +extern void fs_table_dtitle(void); + +/* fs_table_select() : select a FS if available */ +extern int fs_table_select(int idx); + +/* fs_table_select_left() : try to change to the idx - 1 */ +extern int fs_table_select_left(void); + +/* fs_table_select_right() : try to change to the idx + 1 */ +extern int fs_table_select_right(void); + +#endif /* FSCTL_UTILS_FS_TABLE_H */ diff --git a/src/fugue/core/cluster.c b/src/fugue/core/cluster.c new file mode 100644 index 0000000..0509466 --- /dev/null +++ b/src/fugue/core/cluster.c @@ -0,0 +1,43 @@ +#include "fsctl/fugue/cluster.h" +#include "fsctl/fugue/sector.h" +#include "fsctl/fugue/utils.h" + +//--- +// Public +//--- + +/* fugue_cluster_is_valid() : check cluster validity */ +//TODO : support FAT12 / FAT32 +int fugue_cluster_is_valid(fugue_fs_t *fs, int cluster_idx) +{ + void *sector; + uint16_t id; + + id = FAT_WORD(((uint16_t *)fs->_private.fat0)[cluster_idx]); + if (id == 0x0000) + return 0; + if (cluster_idx == 0) + return 0; + + /* special check for the root fake cluster */ + if (cluster_idx == 1) + { + if (id != 0xffff) + return -1; + return 0; + } + + cluster_idx -= 2; + sector = (void*)((uintptr_t)(fs->props.cluster_nb_sector * cluster_idx)); + sector = (void*)((uintptr_t)sector + fs->props.sector_root_nb); + sector = (void*)((uintptr_t)sector * 512); + sector = (void*)((uintptr_t)sector + (uintptr_t)fs->_private.root); + + for (int i = 0 ; i < fs->props.cluster_nb_sector ; i++) + { + if (fugue_sector_is_invalid(sector)) + return -2; + sector = (void *)((uintptr_t)sector + 512); + } + return 0; +} diff --git a/src/fugue/core/dirent.c b/src/fugue/core/dirent.c new file mode 100644 index 0000000..f368b5b --- /dev/null +++ b/src/fugue/core/dirent.c @@ -0,0 +1,85 @@ +#include "fsctl/fugue/dirent.h" +#include "fsctl/fugue/cluster.h" +#include "fsctl/fugue/bits/fat.h" + +//--- +// Internals +//--- + +/* _fugue_dirent_checksum() : Fugue checksum handling */ +static uint8_t _fugue_dirent_checksum(uintptr_t directory) +{ + uint8_t *block; + uint8_t checksum; + int a; + int b; + + checksum = 0; + block = (void *)directory; + for (int i = 0 ; i < 11 ; ++i) + { + checksum = checksum & 0xff; + a = checksum / 2; + b = checksum * 128; + checksum = a | b; + checksum = checksum + block[i]; + } + checksum = checksum & 0xff; + return checksum; +} + +//--- +// Public +//--- + +/* fugue_dirent_dir_fetch() : fetch the current dir blob and walk to next */ +void *fugue_dirent_dir_fetch(fugue_dir_t *dirent) +{ + void *dir; + + dir = (void*)dirent->current_dir_addr; + if (dir == NULL) + return NULL; + + dirent->current_dir_addr += 32; + if (dirent->current_dir_addr < dirent->cluster_addr_end) + return dir; + + dirent->cluster_addr_start = fugue_cluster_find_next( + &dirent->_private.fs, + dirent->cluster_idx + ); + dirent->cluster_addr_end = dirent->cluster_addr_start; + if (dirent->cluster_addr_start != 0x00000000) + dirent->cluster_addr_end += dirent->_private.fs.props.cluster_size; + return dir; +} + +/* fugue_dirent_name_fetch() : fetch fragment */ +int fugue_dirent_name_fetch(fugue_dir_t *dirent, fugue_file_t *file, void *dir) +{ + struct fugue_fat_dir_name *lfn; + + lfn = (void *)dir; + + //--- + // check directory block validity + //--- + + if (lfn->DIR_Attr != FUGUE_DIR_ATTR_LFN) + return -1; + if (lfn->DIR_Type != 0x00) + return -2; + if (lfn->DIR_FstClus != 0x0000) + return -3; + //TODO : check Secquence validity + if (lfn->checksum != _fugue_dirent_checksum(dirent->current_dir_addr)) + return -5; + + //--- + // Dump name fragment + //--- + + //TODO: dump + return -1; +} diff --git a/src/fugue/core/fat.c b/src/fugue/core/fat.c new file mode 100644 index 0000000..dfe3f55 --- /dev/null +++ b/src/fugue/core/fat.c @@ -0,0 +1,74 @@ +#include "fsctl/fugue/fat.h" +#include "fsctl/fugue/sector.h" +#include "fsctl/fugue/utils.h" + +//--- +// Public +//--- + +/* fugue_fat_is_vaild() : Check the complet FATs validity */ +int fugue_fat_is_vaild(fugue_fs_t *fs) +{ + uint16_t *cluster_map; + uint32_t *sector; + uint16_t cluster; + + /* check FATID and root value */ + sector = (void *)fs->_private.fat0; + if (((uint8_t*)sector)[0] != 0xf8 || ((uint8_t*)sector)[1] != 0xff) + return -1; + if (((uint8_t*)sector)[2] != 0xff || ((uint8_t*)sector)[3] != 0xff) + return -1; + sector = (void *)fs->_private.fat1; + if (((uint8_t*)sector)[0] != 0xf8 || ((uint8_t*)sector)[1] != 0xff) + return -1; + if (((uint8_t*)sector)[2] != 0xff || ((uint8_t*)sector)[3] != 0xff) + return -1; + + /* check complet valid FAT + * @note + * - full Fugue FAT area take 5120 bytes -> 10x512 -> 10 sectors + * - also check the root reserved sectors */ + sector = (void*)fs->_private.fat0; + for (int i = 0 ; i < 10 + fs->props.sector_root_nb ; i++) + { + if (fugue_sector_is_invalid(sector)) + return -1; + sector = (void *)((uintptr_t)sector + 512); + } + + /* follows each cluster and check that all sector are used */ + cluster_map = (void *)fs->_private.fat1; + fs->props.cluster_resv = 0; + fs->props.cluster_free = 0; + fs->props.cluster_used = 0; + fs->props.cluster_dead = 0; + fs->props.cluster_error = 0; + for (int i = 1 ; i < 256 ; i++) + { + cluster = FAT_WORD(cluster_map[i]); + if (cluster == 0x0000) { + fs->props.cluster_free += 1; + continue; + } + if (cluster == 0x0001) { + fs->props.cluster_resv += 1; + continue; + } + if (cluster == 0xfff7) { + fs->props.cluster_dead += 1; + continue; + } + if (cluster >= 0xfff8) { + fs->props.cluster_used += 1; + continue; + } + if (cluster < (fs->props.cluster_nb + 1)) { + fs->props.cluster_used += 1; + continue; + } + fs->props.cluster_error += 1; + fs->props.test = cluster; + } + return 0; +} diff --git a/src/fugue/core/sector.c b/src/fugue/core/sector.c new file mode 100644 index 0000000..bbecca1 --- /dev/null +++ b/src/fugue/core/sector.c @@ -0,0 +1,89 @@ +#include + +#include "fsctl/fugue/sector.h" +#include "fsctl/fugue/utils.h" + +//--- +// Public +//--- + +/* fugue_sector_is_vbr() : check if the given address is a potential VBR */ +int fugue_sector_is_vbr(struct fugue_fat_vbr *vbr) +{ + static const struct fugue_fat_vbr fugue_fat_vbr = { + /* common boot information */ + .BS_jmpBoot = { 0xeb, 0x3c, 0x90 }, + .BS_OEMName = "MSDOS5.0", + + /* BIOS Parameter Block */ + .BPB_BytsPerSec = 512, + .BPB_SecPerClus = 8, // <--- not hardcoded by Casio + .BPB_RsvdSecCnt = 0, // <--- not hardcoded by Casio + .BPB_NumFATs = 2, + .BPB_RootEntCnt = 0, // <--- not hardcoded by Casio + .BPB_TotSec16 = 0, // <--- not hardcoded + .BPB_Media = 0xf8, + .BPB_FATSz16 = 0, // <--- not hardcoded + .BPB_SecPerTrk = 0, // <--- not hardcoded + .BPB_HiddSec = 0, // <--- not hardcoded + .BPB_TotSec32 = 0, // <--- not hardcoded + + /* Extended BIOS Parameter Block */ + .BS_DrvNum = 0x80, + .BS_Reserved1 = 0, + .BS_BootSig = 0x29, + .BS_VolID = {0x00, 0x00, 0x00, 0x00}, + .BS_VolLab = "CASIO ", + .BS_FilSysType = "FAT16 ", + + /* signature */ + .Signature_word = {0x55, 0xaa} + }; + + //--- + // VBR global hardcoded value check + //--- + + /* check common boot information */ + if (memcmp(vbr, &fugue_fat_vbr, 11) != 0) + return -1; + + /* check BIOS Parameter Block */ + if (FAT_WORD(vbr->BPB_BytsPerSec) != fugue_fat_vbr.BPB_BytsPerSec) + return -1; + if (vbr->BPB_NumFATs != fugue_fat_vbr.BPB_NumFATs) + return -1; + if (vbr->BPB_Media != fugue_fat_vbr.BPB_Media) + return -1; + + /* check Extended BIOS Parameter Block */ + if (memcmp(&(vbr->BS_DrvNum), &(fugue_fat_vbr.BS_DrvNum), 474) != 0) + return -1; + + /* check signature */ + if (vbr->Signature_word[0] != fugue_fat_vbr.Signature_word[0]) + return -1; + if (vbr->Signature_word[1] != fugue_fat_vbr.Signature_word[1]) + return -1; + + //--- + // FAT validity check + //--- + + return 0; +} + +/* fugue_sector_is_invalid() : check if the sector is invalide */ +int fugue_sector_is_invalid(void *sector) +{ + int x; + + for (x = 0 ; x < 512 / 2 ; x++) + { + if (((uint32_t *)sector)[x] != 0xffffffff) + break; + } + if (x >= (512 / 4)) + return -1; + return 0; +} diff --git a/src/fugue/dir.c b/src/fugue/dir.c new file mode 100644 index 0000000..644a993 --- /dev/null +++ b/src/fugue/dir.c @@ -0,0 +1,144 @@ +#include + +#include "fsctl/fugue.h" +#include "fsctl/fugue/bits/fat.h" +#include "fsctl/fugue/dirent.h" +#include "fsctl/fugue/utils.h" +#include "fsctl/utils/fs_table.h" + +//--- +// Internals +//--- + +//--- +// Public +//--- + +/* fugue_fs_opendir() : opendir-like function */ +int fugue_fs_opendir(fugue_dir_t *dir) +{ + fugue_fs_t fs; + + if (dir == NULL) + return -1; + if (fs_table_info(&fs, NULL, NULL) != 0) + return -2; + memset(dir, 0x00, sizeof(fugue_dir_t)); + memcpy(&dir->_private.fs, &fs, sizeof(fugue_fs_t)); + dir->current_dir_addr = (uintptr_t)fs._private.root; + dir->cluster_addr = (uintptr_t)fs._private.root; + dir->cluster_size = fs.props.sector_root_nb * 512; + return 0; +} + +/* fugue_fs_readdir() : readdir-like function */ +int fugue_fs_readdir(fugue_dir_t *dirent, fugue_file_t *file) +{ + struct fugue_fat_dir *dir; + fugue_dir_t dirent_backup; + bool error; + bool vfat; + + if (dirent == NULL) + return -1; + if (file == NULL) + return -1; + if (dirent->current_dir_addr == 0x00000000) + return -2; + + memset(file, 0x00, sizeof(fugue_file_t)); + memcpy(&dirent_backup, dirent, sizeof(fugue_dir_t)); + + vfat = false; + error = false; + while (error == false) + { + /* fetch the current FAT directory and walk */ + dir = fugue_dirent_dir_fetch(dirent); + if (dir == NULL) { + error = true; + continue; + } + + //--- + // handle special name behaviour + //--- + + switch(dir->DIR_Name[0]) + { + /* handle free directory */ + case 0x00: + //fugue_logger_warn("opendir: wierd empty directory block ") + error = true; + continue; + + /* dot and dotdot special file */ + case '.': + if (memcmp(dir->DIR_Name, ". ", 2) == 0) + memcpy(file->name, ".", 2); + if (memcmp(dir->DIR_Name, ".. ", 3) == 0) + memcpy(file->name, "..", 3); + if (vfat == true) + //fugue_logger_warn("opendir: wierd directory block ") + file->type = FUGUE_FILE_TYPE_DIR; + file->size = FAT_LONG(dir->DIR_FileSize); + return 0; + + /* removed entry */ + case 0x05: + case 0xe5: + //fugue_logger_notice("opendir : removed entry"); + memset(file, 0x00, sizeof(fugue_file_t)); + vfat = false; + continue; + } + + //--- + // handle directory attribute + //--- + + switch(dir->DIR_Attr) + { + /* handle file name fragment */ + case FUGUE_DIR_ATTR_VNAME: + fugue_dirent_name_fetch(dirent, file); + vfat = true; + break; + + /* file handling */ + case FUGUE_DIR_ATTR_RDONLY: + case FUGUE_DIR_ATTR_HIDDEN: + case FUGUE_DIR_ATTR_SYSTEM: + case FUGUE_DIR_ATTR_DIR: + case FUGUE_DIR_ATTR_ARCHIVE: + case FUGUE_DIR_ATTR_DEVICE: + //TODO : file type + file->type = FUGUE_FILE_TYPE_FILE; + file->size = FAT_LONG(dir->DIR_FileSize); + return 0; + + /* other attribute not handled */ + default: + //fugue_logger_warn("opendir : unsupported attribute ") + error = true; + break; + } + } + + /* error handling */ + memcpy(dirent, &dirent_backup, sizeof(fugue_dir_t)); + memset(file, 0x00, sizeof(fugue_file_t)); + return -1; +} + +/* fugue_fs_closedir() : closedir-like function */ +int fugue_fs_closedir(fugue_dir_t *dir) +{ + if (dir == NULL) + return -1; + memset(dir, 0x00, sizeof(fugue_dir_t)); + dir->current_dir_addr = 0x00000000; + dir->cluster_addr = 0x00000000; + dir->cluster_size = 0; + return 0; +} diff --git a/src/fugue/mount.c b/src/fugue/mount.c new file mode 100644 index 0000000..240fb75 --- /dev/null +++ b/src/fugue/mount.c @@ -0,0 +1,103 @@ +#include + +#include "fsctl/fugue.h" +#include "fsctl/fugue/sector.h" +#include "fsctl/fugue/utils.h" +#include "fsctl/fugue/fat.h" + +//--- +// Public +//--- + +/* fugue_fs_mount() : try to initialize the FS */ +int fugue_fs_mount(fugue_fs_t *fsinfo, void *addr) +{ + fugue_fs_t fs; + struct fugue_fat_vbr *vbr; + uintptr_t FAT0_addr; + uintptr_t FAT1_addr; + int CountofClusters; + int RootDirSectors; + int TotCapacity; + int DataSec; + void *type; + int FATz; + + if (fugue_sector_is_vbr(addr) != 0) + return -1; + vbr = addr; + + //--- + // determine the number of cluster + // @note + // - hardcoded for FAT12 and FAT16 + //--- + + RootDirSectors = FAT_WORD(vbr->BPB_RootEntCnt) * 32; + RootDirSectors += FAT_WORD(vbr->BPB_BytsPerSec) - 1; + RootDirSectors /= FAT_WORD(vbr->BPB_BytsPerSec); + + DataSec = FAT_WORD(vbr->BPB_RsvdSecCnt); + DataSec += FAT_WORD(vbr->BPB_FATSz16) * vbr->BPB_NumFATs; + DataSec += RootDirSectors; + DataSec = FAT_WORD(vbr->BPB_TotSec16) - DataSec; + + CountofClusters = DataSec; + CountofClusters /= vbr->BPB_SecPerClus; + + TotCapacity = DataSec; + TotCapacity *= FAT_WORD(vbr->BPB_BytsPerSec); + + if (CountofClusters < 4085) { + type = "FAT12"; + } else if (CountofClusters < 65525) { + type = "FAT16"; + } else { + type = "FAT32"; + } + + //--- + // Analysing FAT intergrity + // @note + // - hardcoded for two Fugue + // - Fugue seems use a static offset of its FAT : 5120 (10 sectors) + // - Fugue doesn't have same sized FAT (FAT0=4608 && FAT1=512) + //--- + + //FATz = FAT_WORD(vbr->BPB_FATSz16); + //FATz *= FAT_WORD(vbr->BPB_BytsPerSec); + //FATz *= vbr->BPB_NumFATs; + FATz = 5120; + + FAT0_addr = FAT_WORD(vbr->BPB_RsvdSecCnt); + FAT0_addr *= FAT_WORD(vbr->BPB_BytsPerSec); + FAT0_addr += (uintptr_t)vbr; + + FAT1_addr = 4608; + FAT1_addr += FAT0_addr; + + //--- + // Save calculated information + //--- + + memset(&fs, 0x00, sizeof(fugue_fs_t)); + fs._private.vbr = addr; + fs.props.type = type; + fs.props.sector_data_nb = DataSec; + fs.props.sector_root_nb = RootDirSectors; + fs.props.cluster_nb = CountofClusters; + fs.props.cluster_size = vbr->BPB_SecPerClus * 512; + fs.props.cluster_nb_sector = vbr->BPB_SecPerClus; + fs.props.capacity = TotCapacity; + fs.props.fats_size = FATz; + fs.props.fat0_size = 4608; + fs.props.fat1_size = 512; + fs._private.fat0 = (void*)FAT0_addr; + fs._private.fat1 = (void*)FAT1_addr; + fs._private.root = (void*)(FAT0_addr + FATz); + + if (fugue_fat_is_vaild(&fs) != 0) + return -1; + memcpy(fsinfo, &fs, sizeof(fugue_fs_t)); + return 0; +} diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..4a04643 --- /dev/null +++ b/src/main.c @@ -0,0 +1,54 @@ +#include +#include +#include + +#include "fsctl/menu.h" + +//--- +// Public +//--- + +int main(void) +{ + int key; + int tab; + + rom_menu_init(); + info_menu_init(); + fat_menu_init(); + list_menu_init(); + + tab = 0; + while (1) + { + dclear(C_WHITE); + if (tab == 0) { rom_menu_display(); } + if (tab == 1) { info_menu_display(); } + if (tab == 2) { fat_menu_display(); } + if (tab == 3) { list_menu_display(); } + dupdate(); + + switch (key = getkey().key) + { + case KEY_F1: + tab = 0; + break; + case KEY_F2: + tab = 1; + break; + case KEY_F3: + tab = 2; + break; + case KEY_F4: + tab = 3; + break; + default: + if (tab == 0) { rom_menu_keyboard(key); } + if (tab == 1) { info_menu_keyboard(key); } + if (tab == 2) { fat_menu_keyboard(key); } + if (tab == 3) { list_menu_keyboard(key); } + } + } + + return 1; +} diff --git a/src/menu/fat.c b/src/menu/fat.c new file mode 100644 index 0000000..af9c147 --- /dev/null +++ b/src/menu/fat.c @@ -0,0 +1,96 @@ +#include + +#include +#include + +#include "fsctl/menu.h" +#include "fsctl/fugue.h" +#include "fsctl/fugue/cluster.h" +#include "fsctl/fugue/utils.h" +#include "fsctl/utils/fs_table.h" +#include "fsctl/utils/display.h" + +//--- +// internals +//--- + +/* internal information */ +static int clus_idx = 0; + +/* fat_cluster_is_valid() : check cluster information */ +static int fat_cluster_is_valid(fugue_fs_t *fs, int idx) +{ + switch (fugue_cluster_is_valid(fs, idx)) + { + case 0: + return C_WHITE; + default: + return C_RED; + } +} + +//--- +// Public +//--- + +/* fat_menu_init() : init menu */ +void fat_menu_init(void) +{ + clus_idx = 0; +} + +/* fat1_menu_display() : display menu */ +void fat_menu_display(void) +{ + fugue_fs_t fs; + uint16_t *table; + int idx; + + fs_table_dtitle(); + if (fs_table_info(&fs, NULL, NULL) != 0) + return; + + idx = clus_idx; + table = fs._private.fat1; + for (int y = 1 ; y < 18 ; y++) + { + _printXY(0, y, "%p", &table[idx]); + for (int x = 0 ; x < 6 ; x++) + { + _lrectXY(x, y, fat_cluster_is_valid(&fs, idx)); + _lrectTextXY(x, y, FAT_WORD(table[idx])); + idx += 1; + } + } +} + +/* fat_menu_keyboard() : handle keyboard */ +void fat_menu_keyboard(int key) +{ + switch (key) + { + case KEY_SHIFT: + clus_idx += 6; + break; + case KEY_ALPHA: + clus_idx -= 6; + break; + case KEY_EXIT: + clus_idx = 0; + break; + case KEY_DOWN: + clus_idx += 6 * 17; + break; + case KEY_UP: + clus_idx -= 6 * 17; + break; + case KEY_LEFT: + fs_table_select_left(); + break; + case KEY_RIGHT: + fs_table_select_right(); + break; + } + if (clus_idx < 0) + clus_idx = 0; +} diff --git a/src/menu/info.c b/src/menu/info.c new file mode 100644 index 0000000..3f22432 --- /dev/null +++ b/src/menu/info.c @@ -0,0 +1,59 @@ +#include + +#include "fsctl/menu/info.h" +#include "fsctl/fugue.h" +#include "fsctl/utils/display.h" +#include "fsctl/utils/fs_table.h" + +//--- +// Public +//--- + +/* info_menu_init() : init menu */ +void info_menu_init(void) +{ + ; +} + +/* info_menu_display() : display menu */ +//TODO : logger display +void info_menu_display(void) +{ + fugue_fs_t fs; + int y; + + fs_table_dtitle(); + if (fs_table_info(&fs, NULL, NULL) != 0) + return; + + y = 0; + _printXY(0, ++y, "FS type = %s", fs.props.type); + _printXY(0, ++y, "capacity = %d", fs.props.capacity); + _printXY(0, ++y, "cluster free = %d", fs.props.cluster_free); + _printXY(0, ++y, "cluster used = %d", fs.props.cluster_used); + _printXY(0, ++y, "cluster dead = %d", fs.props.cluster_dead); + _printXY(0, ++y, "cluster errs = %d", fs.props.cluster_error); + _printXY(0, ++y, "cluster resv = %d", fs.props.cluster_resv); + _printXY(0, ++y, "cluster number = %d", fs.props.cluster_nb); + _printXY(0, ++y, "cluster number = %x", fs.props.cluster_nb); + _printXY(0, ++y, "FAT0 = %p", fs._private.fat0); + _printXY(0, ++y, "FAT1 = %p", fs._private.fat1); + _printXY(0, ++y, "FATs size = %d", fs.props.fats_size); + _printXY(0, ++y, "FAT0 size = %d", fs.props.fat0_size); + _printXY(0, ++y, "FAT1 size = %d", fs.props.fat1_size); + _printXY(0, ++y, "Root addr = %p", fs._private.root); +} + +/* info_menu_keyboard() : handle keyboard */ +void info_menu_keyboard(int key) +{ + switch(key) + { + case KEY_LEFT: + fs_table_select_left(); + break; + case KEY_RIGHT: + fs_table_select_right(); + break; + } +} diff --git a/src/menu/list.c b/src/menu/list.c new file mode 100644 index 0000000..9ad8b06 --- /dev/null +++ b/src/menu/list.c @@ -0,0 +1,46 @@ +#include "fsctl/menu.h" +#include "fsctl/fugue.h" +#include "fsctl/utils/fs_table.h" +#include "fsctl/utils/display.h" + +//--- +// Public +//--- + +/* list_menu_init() : init menu */ +void list_menu_init(void) +{ + ; +} + +/* fat1_menu_display() : display menu */ +void list_menu_display(void) +{ + fugue_dir_t dir; + fugue_file_t file; + int y; + + fs_table_dtitle(); + + y = 0; + fugue_fs_opendir(&dir); + while (fugue_fs_readdir(&dir, &file) == 0) + { + _printXY(0, ++y, "(%d) %s", file.size, file.name); + } + fugue_fs_closedir(&dir); +} + +/* list_menu_keyboard() : handle keyboard */ +void list_menu_keyboard(int key) +{ + switch(key) + { + case KEY_LEFT: + fs_table_select_left(); + break; + case KEY_RIGHT: + fs_table_select_right(); + break; + } +} diff --git a/src/menu/rom.c b/src/menu/rom.c new file mode 100644 index 0000000..2a5934b --- /dev/null +++ b/src/menu/rom.c @@ -0,0 +1,103 @@ +#include "fsctl/menu.h" +#include "fsctl/fugue.h" +#include "fsctl/utils/fs_table.h" +#include "fsctl/utils/display.h" + +//--- +// internals +//--- + +/* internal information */ +static uintptr_t addr_base; +static uintptr_t addr_test; + +/* sector_is_vbr() : check VBR validity */ +static int sector_is_vbr(int *color, struct fugue_fat_vbr *vbr) +{ + fugue_fs_t fs; + + if (fugue_fs_mount(&fs, vbr) == 0) { + *color = C_GREEN; + fs_table_update(&fs); + return 0; + } + return -1; +} + +/* sector_is_unused() : check if the sector has been erased */ +static int sector_is_unused(int *color, uint32_t *addr) +{ + for (int i = 0 ; i < 512 / 4 ; i++) { + if (addr[i] != 0xffffffff) + return -1; + } + *color = C_RED; + return 0; +} + +/* sector_check() : check various operation on sector */ +static int sector_check(void *addr) +{ + int color; + + if ( + sector_is_unused(&color, addr) != 0 + && sector_is_vbr(&color, addr) != 0 + ) + return C_WHITE; + return color; +} + +//--- +// Public +//--- + +/* rom_menu_init() : init menu */ +void rom_menu_init(void) +{ + /* skip first 16Mo (OS stuff) */ + addr_base = 0xa1000000; + addr_test = 0xa1000000; +} + +/* rom_menu_display() : display menu */ +void rom_menu_display(void) +{ + addr_test = addr_base; + for (int y = 0 ; y < 18 ; y++) + { + _printXY(0, y, "%p", addr_test); + for (int x = 0 ; x < 25 ; x++) + { + _rectXY(x, y, sector_check((void *)addr_test)); + addr_test += 512; + if (addr_test >= 0xa2000000) + return; + } + } +} + +/* rom_menu_keyboard() : handle keyboard */ +void rom_menu_keyboard(int key) +{ + switch (key) + { + case KEY_DOWN: + addr_base += 25 * 512; + break; + case KEY_UP: + addr_base -= 25 * 512; + break; + case KEY_EXIT: + addr_base = 0xa0000000; + break; + case KEY_RIGHT: + addr_base += 25 * 18 * 512; + break; + case KEY_LEFT: + addr_base -= 25 * 18 * 512; + break; + } + if (addr_base < 0xa0000000) + addr_base = 0xa0000000; +} diff --git a/src/utils/fs_table.c b/src/utils/fs_table.c new file mode 100644 index 0000000..c702148 --- /dev/null +++ b/src/utils/fs_table.c @@ -0,0 +1,123 @@ +#include +#include + +#include + +#include "fsctl/utils/fs_table.h" + +//--- +// Internals +//--- + +/* fs_table_list : FS table list */ +static struct { + fs_table_t *table; + int idx; + int slots; +} fs_table; + +/* fs_table_append() : append the new vbr information */ +static int fs_table_append(fugue_fs_t *fs) +{ + fs_table_t *check; + + check = reallocarray( + fs_table.table, + fs_table.slots + 1, + sizeof(fs_table_t) + ); + if (check == NULL) + return -1; + + memcpy(&check[fs_table.slots].fs, fs, sizeof(fugue_fs_t)); + fs_table.table = check; + fs_table.slots = fs_table.slots + 1; + if (fs_table.idx < 0) + fs_table.idx = 0; + return 0; +} + +//--- +// Public +//--- + +/* fs_table_init() : initialize FS table */ +void fs_table_init(void) +{ + fs_table.table = NULL; + fs_table.idx = -1, + fs_table.slots = 0; +} + +/* fs_table_update() : try to update internal fs table */ +int fs_table_update(fugue_fs_t *fs) +{ + for (int i = 0 ; i < fs_table.slots ; i++) + { + if (fs_table.table[i].fs._private.vbr == fs->_private.vbr) + return 0; + } + return fs_table_append(fs); +} + +/* fs_table_info() : get fs table information */ +int fs_table_info(fugue_fs_t *fs, int *fs_idx, int *nb_fs) +{ + if (fs_table.table == NULL) + return -1; + if (fs != NULL) + memcpy(fs, &fs_table.table[fs_table.idx].fs, sizeof(fugue_fs_t)); + if (fs_idx != NULL) + *fs_idx = fs_table.idx; + if (nb_fs != NULL) + *nb_fs = fs_table.slots; + return 0; +} + +/* fs_table_dtitle() : display FS table title menu */ +void fs_table_dtitle(void) +{ + fugue_fs_t *fs; + + if (fs_table.table == NULL) + { + dprint(2, 2, C_BLACK, "No File System found"); + drect(0, 0, DWIDTH, 14, C_INVERT); + return; + } + + fs = &fs_table.table[fs_table.idx].fs; + dprint(2, 2, C_BLACK, "VBR: %p", fs->_private.vbr); + dprint_opt( + DWIDTH, 2, + C_BLACK, C_NONE, + DTEXT_RIGHT, DTEXT_TOP, + "%d/%d", + fs_table.idx + 1, + fs_table.slots + ); + drect(0, 0, DWIDTH, 13, C_INVERT); +} + +/* fs_table_select() : select a FS if available */ +int fs_table_select(int idx) +{ + if (fs_table.table == NULL) + return -1; + if (idx >= fs_table.slots) + return -2; + fs_table.idx = idx; + return 0; +} + +/* fs_table_select_left() : try to change to the idx - 1 */ +int fs_table_select_left(void) +{ + return fs_table_select(fs_table.idx - 1); +} + +/* fs_table_select_right() : try to change to the idx + 1 */ +int fs_table_select_right(void) +{ + return fs_table_select(fs_table.idx + 1); +}