duskos

dusk os fork
git clone git://git.alexwennerberg.com/duskos
Log | Files | Refs | README | LICENSE

commit 2f03a9049f488bde7e9b893adafd4b99c9ff732d
parent 99ce90d831c4bc3677defc17a55abe7bbd0b8583
Author: Virgil Dupras <hsoft@hardcoded.net>
Date:   Tue, 19 Jul 2022 22:17:57 -0400

Introduce the concept of "File/Directory ID" in the File API

See doc/file.

Diffstat:
Mfs/doc/file.txt | 34++++++++++++++++++++++++++++++----
Mfs/fs/fat.fs | 8++++++++
Mfs/fs/fatlo.fs | 21+++++++++++++++++++--
Mfs/tests/fs/fat.fs | 3+++
4 files changed, 60 insertions(+), 6 deletions(-)

diff --git a/fs/doc/file.txt b/fs/doc/file.txt @@ -21,12 +21,38 @@ fclose ( hdl -- ) On top of that, the File API also define global aliases in which the current active filesystem will plug itself: -fopen ( path -- hdl ) +fchild ( dirid name -- id ) + Enumerate the contents of directory "dirid" and look for name "name". If + found, returns the ID of the child (either a file or directory), otherwise, + return 0. See below for the concept of "ID". + +fopen ( id -- hdl ) Open file at path and return a handle through which other file-related word identify the target file. Once a file isn't used anymore, it should be closed with fclose. Aborts on error. -fnewfile ( path -- direntry ) - Create a new empty file at path. Errors out if path's parent is unreachabe or - if path already exists. +fnewfile ( dirid name -- id ) + Create a new empty file named "name" in "dirid" and return the ID of the new + file. Aborts on error. + +## File ID design considerations + +When we refer to a file or directory ID, we refer to a single 32-bit number +uniquely identifying the file or directory in the volume. From this number, we +must be able to find the file or directory in the volume so that we can open it +or enumerate it. The ID of the root directory is always zero. + +That IDs are 32-bit make their manipulation straightforward. One might fear that +32-bit is not enough to identify all elements of big filesystems. + +On many filesystems, 32-bit is enough. For example, in ext4, inodes always fit +32-bit, even in 64-bit mode. + +For FAT32, it's another matter. The straightforward way to derive an ID from an +element is to return the offset of its DirEntry and divide it by 32. This means +that this ID scheme could only address 64GB volumes. +This would mean that the File API would be broken on a subset of filesystems. +Does it mean that Dusk couldn't read them? No, only that file/dir enumeration +would have to go through FS-specific tools. I think that this incovenience is +worth it if it means an overall simpler API. diff --git a/fs/fs/fat.fs b/fs/fs/fat.fs @@ -10,6 +10,14 @@ \ For now, this FS only supports FAT16 and FAT12. \ Like any filesystem in Dusk, path separator char is "/". + +\ A "direntry" is the address of a DirEntry structure in memory. These +\ references are short-lived because they're an address in the FAT sector buffer +\ which is very very often being overwritten. + +\ File and directory IDs in FAT are the offset, on disk, of their corresponding +\ DirEntry. + ?f<< fs/fatlo.fs $ffff const EOC diff --git a/fs/fs/fatlo.fs b/fs/fs/fatlo.fs @@ -94,6 +94,12 @@ here const )fnbuf : upcase ( c -- c ) dup 'a' - 26 < if $df and then ; : fnbufclr fnbuf( FNAMESZ SPC fill ; +: fnbuf! ( name -- ) + A>r fnbufclr c@+ >r >A fnbuf( begin ( dst ) + Ac@+ dup '.' = if + 2drop fnbuf( 8 + else + upcase swap c!+ then ( dst+1 ) + dup )fnbuf = if leave then next drop r>A ; : _ ( -- direntry-or-0 ) fatbuf( begin ( a ) @@ -114,6 +120,18 @@ here const )fnbuf 1 FirstRootDirSecNum RootDirSectors then ( cluster sec cnt ) readsector ( cluster ) to bufcluster ; +\ Get DirEntry address from FS ID "id" +: getdirentry ( id -- direntry ) + ?dup if + BPB_BytsPerSec /mod ( offset sec ) 1 readsector ( off ) fatbuf( + + else rootdirentry( then ; + +\ Get ID for direntry +: getid ( direntry -- id ) fatbuf( - bufsec BPB_BytsPerSec * + ; + +: fatchild ( dirid name -- id ) + fnbuf! getdirentry readdir findindir getid ; + \ Find the parent directory of "path", that is, go up directories in path until \ the last element is reached, but don't look for that last element, return \ directory's direntry instead. As this word returns, fnbuf( will be set with @@ -171,8 +189,7 @@ here const )fnbuf : FCUR_buf( ( fcur -- a ) 44 + ; : FCUR_)buf ( fcur -- a ) FCUR_buf( ClusterSize + ; : FCUR_bufpos ( fcur -- a ) dup FCUR_pos ClusterSize mod swap FCUR_buf( + ; -: FCUR_dirent ( fcur -- dirent ) - 32 + @ BPB_BytsPerSec /mod ( offset sec ) 1 readsector ( off ) fatbuf( + ; +: FCUR_dirent ( fcur -- dirent ) 32 + @ getdirentry ; : FCUR_cluster0 ( fcur -- cl ) FCUR_dirent DIR_Cluster ; create fcursors( FCursorSize FCURSORCNT * allot0 diff --git a/fs/tests/fs/fat.fs b/fs/tests/fs/fat.fs @@ -34,4 +34,7 @@ S" /newfile" fatopen ( fc ) dup FCUR_cluster0 0 #eq \ no cluster allocated yet dup S" 42" c@+ rot fatwritebuf 2 #eq ( fc ) fclose f<< /newfile 42 #eq + +\ temporary tests until I tie everything together in the File API +0 S" lib" fatchild S" str.fs" fatchild # testend