duskos

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

commit 275e538432a025e26838b82a73dae3ae4435e0a0
parent e6c21f63613c8a6bb2d019ff3ed723f7c828c6cf
Author: Virgil Dupras <hsoft@hardcoded.net>
Date:   Mon, 15 Aug 2022 12:52:41 -0400

fs/fat: move things around a bit

Split FATLO in 2, allowing the DirEntry struct to be squeezed between the two
parts. Directory enumeration is coming and I need wiggle room.

Diffstat:
Mfs/fs/fat.fs | 57++++++++++++++++++++++++++++-----------------------------
Mfs/fs/fatlo.fs | 176++++++++++++++++++++++++++++++++++++++++---------------------------------------
Mfs/tests/fs/fat.fs | 2+-
Mfs/xcomp/pc/glue.fs | 2+-
4 files changed, 120 insertions(+), 117 deletions(-)

diff --git a/fs/fs/fat.fs b/fs/fs/fat.fs @@ -21,62 +21,62 @@ \ TODO: in my big FAT refactoring, I broke this section. Fix it. ?f<< fs/fatlo.fs -extends FAT struct[ FATHI +extends FATLO struct[ FAT $ffff const EOC : writecursector ( self -- ) - dup FAT bufsec over FAT :buf( rot ( sec dst self ) FAT :drv :sec! ; + dup FATLO bufsec over FATLO :buf( rot ( sec dst self ) FATLO :drv :sec! ; : FAT12! ( entry cluster self -- ) >r - dup r@ FAT :FAT@ ( entry cl old ) over r@ FAT :FAT12' ( entry cl old a ) + dup r@ FATLO :FAT@ ( entry cl old ) over r@ FATLO :FAT12' ( entry cl old a ) ( entry cl a n ) swap rot 1 and if ( entry a old ) $f and rot 4 lshift or ( a n ) else ( entry a old ) $f000 and rot $fff and or then ( a n ) - over w! ( a ) r@ FAT :)buf 1- = if \ end-of-sector cross-over! - r@ FAT bufsec 1+ r@ FAT :drv :sec@ - r@ FAT :)buf 1+ c@ r@ FAT :buf( c! - r@ FAT bufsec 1+ r@ FAT :drv :sec! then rdrop ; -: FAT16! ( entry cluster self -- ) FAT :FAT16' w! ; + over w! ( a ) r@ FATLO :)buf 1- = if \ end-of-sector cross-over! + r@ FATLO bufsec 1+ r@ FATLO :drv :sec@ + r@ FATLO :)buf 1+ c@ r@ FATLO :buf( c! + r@ FATLO bufsec 1+ r@ FATLO :drv :sec! then rdrop ; +: FAT16! ( entry cluster self -- ) FATLO :FAT16' w! ; : FAT! ( entry cluster self -- ) - dup FAT :FAT12? if dup FAT12! else dup FAT16! then writecursector ; + dup FATLO :FAT12? if dup FAT12! else dup FAT16! then writecursector ; : zerocluster ( cluster self -- ) - dup FAT :buf( over FAT secsz 0 fill ( cluster self ) - tuck FAT :FirstSectorOfCluster ( self sec ) - over FAT secpercluster >r begin ( self sec ) - over dup FAT :buf( swap FAT :drv :sec! 1+ next 2drop ; + dup FATLO :buf( over FATLO secsz 0 fill ( cluster self ) + tuck FATLO :FirstSectorOfCluster ( self sec ) + over FATLO secpercluster >r begin ( self sec ) + over dup FATLO :buf( swap FATLO :drv :sec! 1+ next 2drop ; \ find a free cluster in the FAT : findfreecluster ( self -- cluster ) - 1 begin ( self cl ) 1+ 2dup swap FAT :FAT@ not until ( self cl ) nip ; + 1 begin ( self cl ) 1+ 2dup swap FATLO :FAT@ not until ( self cl ) nip ; \ Get next FAT entry and if it's EOC, allocate a new one : FAT@+ ( cluster self -- entry ) >r - dup r@ FAT :FAT@ ( cl ncl ) dup r@ FAT :EOC? if + dup r@ FATLO :FAT@ ( cl ncl ) dup r@ FATLO :EOC? if drop r@ findfreecluster ( cl ncl ) 2dup swap r@ FAT! ( cl ncl ) r@ EOC swap r@ FAT! else nip then rdrop ; \ try to find in current buffer : _findinsec ( self -- a-or-0 ) >r - r@ FAT :buf( begin ( a ) + r@ FATLO :buf( begin ( a ) dup c@ dup $e5 = swap not or if ( free! ) rdrop exit then - DirEntry SZ + dup r@ FAT :)buf >= until rdrop drop 0 ; + DirEntry SZ + dup r@ FATLO :)buf >= until rdrop drop 0 ; \ find free dir entry in current buffer : findfreedirentry ( self -- direntry ) begin dup _findinsec ?dup not while ( self ) - dup FAT :nextsector? while + dup FATLO :nextsector? while repeat \ nothing found, we have to extend the chain ( self ) dup r> findfreecluster dup r@ zerocluster ( newcl ) - dup r@ FAT bufcluster r@ FAT! ( newcl ) r@ EOC swap r@ FAT! - r@ FAT :nextsector? ( has to work ) r> FAT :buf( + dup r@ FATLO bufcluster r@ FAT! ( newcl ) r@ EOC swap r@ FAT! + r@ FATLO :nextsector? ( has to work ) r> FATLO :buf( else ( self a ) nip then ; : fatnewfile ( dirid name self -- direntry ) >r - fnbuf! ( dirid ) r@ FAT :getdirentry r@ FAT :readdir ( ) + fnbuf! ( dirid ) r@ FATLO :getdirentry r@ FATLO :readdir ( ) r@ findfreedirentry dup DirEntry SZ 0 fill ( direntry ) fnbuf( over DirEntry NAMESZ move r> writecursector ( direntry ) ; @@ -84,13 +84,13 @@ $ffff const EOC \ write multiple sectors from buf : writesectors ( sec u buf self -- ) to self A>r swap >r swap >A begin ( buf ) - A> over self FAT :drv :sec! A+ self FAT :drv secsz + next ( buf ) + A> over self FATLO :drv :sec! A+ self FATLO :drv secsz + next ( buf ) drop r>A ; : writecluster ( cluster src self -- ) >r over 2 - $fff6 > if abort" cluster out of range!" then - swap r@ FAT :FirstSectorOfCluster ( dst sec ) - swap r@ FAT secpercluster swap r> writesectors ; + swap r@ FATLO :FirstSectorOfCluster ( dst sec ) + swap r@ FATLO secpercluster swap r> writesectors ; : fatflush ( self -- ) >r r@ FATFile :dirty? not if rdrop exit then ( ) @@ -112,7 +112,7 @@ $ffff const EOC ?dup not if self fat findfreecluster then ( cluster0 ) self :dirent 2dup DirEntry cluster! ( custer0 dirent ) self size swap to DirEntry filesize self fat writecursector ( cluster0 ) - self size self fat FAT :ClusterSize / ?dup if + self size self fat FATLO :ClusterSize / ?dup if >r begin ( cluster ) self fat FAT@+ next then ( cluster ) drop ; : fatwritebuf ( buf n self -- n ) @@ -125,10 +125,10 @@ $ffff const EOC dup >r move r> ( n ) ; : fatopen ( id self -- hdl ) - FATFS:open ['] fatwritebuf over 4 + ! ['] fatflush over 8 + ! ; + FATLO :fatopen ['] fatwritebuf over 4 + ! ['] fatflush over 8 + ! ; -: :mountVolume ( drv -- fs ) - mountFATvolume ['] fatopen over 8 + ! ['] fatnewfile over 12 + ! ; +: :mountvolume ( drv -- fs ) + FATLO :mountvolume ['] fatopen over 8 + ! ['] fatnewfile over 12 + ! ; create _FATTemplate ( jmp ) $eb c, $3c c, $90 c, ( OEMName ) ," DuskFAT " ( BytsPerSec ) 0 c, 0 c, @@ -167,4 +167,3 @@ create _FATTemplate $fffff0 here ! ( drv ) rsvdsec here rot Drive :sec! ; ]struct -alias FATHI FAT immediate diff --git a/fs/fs/fatlo.fs b/fs/fs/fatlo.fs @@ -12,41 +12,19 @@ \ See fs/fat.fs for complete implementation details. -struct[ DirEntry - 32 const SZ - 11 const NAMESZ - : :name[] ( self -- sa sl ) NAMESZ ; - 26 &+w@ cluster - : cluster! ( n self -- ) 26 + w! ; - 28 field filesize -]struct - \ Just a dummy entry so that we can reference the root directory as a "direntry" -create rootdirentry( DirEntry SZ allot0 -\ directory entry of currently selected directory. If first byte is 0, this -\ means that we're on the root dir -create curdir( DirEntry SZ allot0 -create fnbuf( DirEntry NAMESZ allot -here const )fnbuf +create rootdirentry( 32 allot0 -: upcase ( c -- c ) dup 'a' - 26 < if $df and then ; -: fnbufclr fnbuf( DirEntry NAMESZ SPC fill ; -: fnbuf! ( name -- ) - fnbufclr dup S" ." s= over S" .." s= or if - c@+ ( a len ) fnbuf( swap move exit then - A>r 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 ; - -extends Filesystem struct[ FAT +\ The FAT struct in this unit is split in 2. The first part contains code needed +\ by FATFile, and the second part contains the rest of the code for FATLO. This +\ allows some of the FATLO code to depend on code in FATFile. +extends Filesystem struct[ _FAT sfield bufsec \ sector number of current buf sfield bufseccnt \ number of sectors ahead for sequential read sfield bufcluster \ cluster number of current buf sfield lastcursor -' FAT structsz const SZ +' _FAT structsz const SZ SZ &+ :hdr( SZ $0b + &+w@ secsz \ in bytes SZ $0d + &+c@ secpercluster @@ -67,8 +45,6 @@ r@ reservedseccnt r@ FATcnt r@ FATsz * + r> :RootDirSectors + ; : :FirstSectorOfCluster ( n self -- sec ) >r dup << r@ secsz r@ FATsz * >= if abort" cluster out of range" then 1- 1- r@ secpercluster * r> :FirstDataSector + ; -: :FirstRootDirSecNum ( self -- n ) >r -r@ reservedseccnt r@ FATcnt r> FATsz * + ; : :ClusterSize dup secpercluster swap secsz * ; : :DataSec ( self -- n ) >r r@ seccnt r@ FATsz r@ FATcnt * @@ -113,38 +89,12 @@ r@ :buf( r> Filesystem :drv :sec@ ; r@ secpercluster r> :readsector 1 then then ; -\ Find current fnbuf( in current dir buffer and return a dir entry. -: :findindir ( self -- direntry ) >r - begin - r@ :buf( begin ( a ) - dup r@ :)buf < while ( a ) - fnbuf( over DirEntry :name[] []= not while ( a ) DirEntry SZ + repeat - ( success ) else ( not found ) drop 0 then ( a ) - ?dup not while r@ :nextsector? while - repeat ( not found ) 0 then rdrop ; - -\ Read specified "direntry" in :buf( -: :readdir ( direntry self -- ) >r - DirEntry cluster ?dup if \ not root entry - dup r@ :FirstSectorOfCluster r@ secpercluster else \ root entry - 1 r@ :FirstRootDirSecNum r@ :RootDirSectors then ( cluster sec cnt ) - r@ :readsector ( cluster ) to r> bufcluster ; - \ Get DirEntry address from FS ID "id" : :getdirentry ( id self -- direntry ) over if dup >r secsz /mod ( offset sec ) 1 r@ :readsector ( off ) r> :buf( + else 2drop rootdirentry( then ; -\ Get ID for direntry -: :getid ( direntry self -- id ) - dup >r :buf( - r@ bufsec r> secsz * + ; - -: :child ( dirid name self -- id-or-0 ) >r - fnbuf! r@ :getdirentry r@ :readdir r@ :findindir - dup if r@ :getid then rdrop ; -current value :child' - 0 value _self \ read multiple sectors in buf : :readsectors ( sec u buf self -- ) to _self @@ -159,6 +109,32 @@ current value :child' ]struct +struct[ DirEntry + 32 const SZ + 11 const NAMESZ + : :name[] ( self -- sa sl ) NAMESZ ; + 26 &+w@ cluster + : cluster! ( n self -- ) 26 + w! ; + 28 field filesize +]struct + +\ directory entry of currently selected directory. If first byte is 0, this +\ means that we're on the root dir +create curdir( DirEntry SZ allot0 +create fnbuf( DirEntry NAMESZ allot +here const )fnbuf + +: upcase ( c -- c ) dup 'a' - 26 < if $df and then ; +: fnbufclr fnbuf( DirEntry NAMESZ SPC fill ; +: fnbuf! ( name -- ) + fnbufclr dup S" ." s= over S" .." s= or if + c@+ ( a len ) fnbuf( swap move exit then + A>r 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 ; + \ File cursor extends File struct[ FATFile sfield fat @@ -176,7 +152,7 @@ extends File struct[ FATFile ' FATFile structsz const SZ \ beginning of a buffer with the size :ClusterSize SZ &+ :buf( - : :fat compile fat [compile] FAT ; immediate + : :fat compile fat [compile] _FAT ; immediate : _clustersize ( self -- n ) :fat :ClusterSize ; : :)buf ( self -- a ) dup :buf( swap _clustersize + ; : :free? ( self -- f ) flags not ; @@ -214,7 +190,7 @@ extends File struct[ FATFile \ these words below are "static" words not called with "self" as an argument, \ but "fat". - : :cursorsize ( fat -- sz ) FAT :ClusterSize SZ + ; + : :cursorsize ( fat -- sz ) _FAT :ClusterSize SZ + ; create _EmptyCursor \ IO handle methods: :readbuf, :writebuf, :flush @@ -226,41 +202,69 @@ extends File struct[ FATFile 0 ( size ) , 0 ( entryoff ) , : :createcursor ( fat -- hdl ) - align4 dup to' FAT lastcursor llinsert ( fat newll ) + align4 dup to' _FAT lastcursor llinsert ( fat newll ) swap :cursorsize allot ( newll ) CELLSZ + ( hdl ) 0 over to flags ( mark as "free" ) ; : :findfreecursor ( fat -- hdl ) >r - r@ FAT lastcursor begin ( ll ) + r@ _FAT lastcursor begin ( ll ) ?dup while dup CELLSZ + :free? not while llnext repeat CELLSZ + else r@ :createcursor then _EmptyCursor over SZ move r> over to fat ; ]struct -\ TODO: support more than one FAT FS at once - -0 value _self -\ This is the "low" part. Complete open is finalized in fs/fat -: FATFS:open ( id self -- hdl ) to _self - _self FAT :getdirentry - _self FATFile :findfreecursor >r ( dirent ) - 1 to r@ FATFile flags \ mark as "used" - \ write the rest - dup _self FAT :buf( - _self FAT bufsec _self FAT secsz * + ( dirent doffset ) - r@ to FATFile entryoff DirEntry filesize r@ to FATFile size ( ) r> ; - -: mountFATvolume ( drv -- fs ) - align4 here >r dup , ( drv R:fs ) - FAT :child' , ['] FATFS:open , ['] abort , ( drv ) - 0 , 0 , 0 , 0 , ( drv ) - \ At this point, "here" points to the FAT-header-to-be. Read the first sector - \ directly in "here": we'll have the header right here! - dup 0 here rot Drive :sec@ ( drv ) - FAT HDRSZ allot ( drv ) - \ Verify that the header makes sense - r@ FAT secsz swap Drive secsz over = not if - abort" Drive sector size not matching drive!" then ( secsz ) - \ Allocate buffer. 1+ is for the extra byte for FAT12 cross-sector exception - 1+ allot r> ( fs ) ; - +extends _FAT struct[ FATLO + : :FirstRootDirSecNum ( self -- n ) >r + r@ _FAT reservedseccnt r@ _FAT FATcnt r> _FAT FATsz * + ; + + \ Find current fnbuf( in current dir buffer and return a dir entry. + : :findindir ( self -- direntry ) >r + begin + r@ _FAT :buf( begin ( a ) + dup r@ _FAT :)buf < while ( a ) + fnbuf( over DirEntry :name[] []= not while ( a ) DirEntry SZ + repeat + ( success ) else ( not found ) drop 0 then ( a ) + ?dup not while r@ _FAT :nextsector? while + repeat ( not found ) 0 then rdrop ; + + \ Read specified "direntry" in :buf( + : :readdir ( direntry self -- ) >r + DirEntry cluster ?dup if \ not root entry + dup r@ _FAT :FirstSectorOfCluster r@ _FAT secpercluster else \ root entry + 1 r@ :FirstRootDirSecNum r@ _FAT :RootDirSectors then ( cluster sec cnt ) + r@ _FAT :readsector ( cluster ) to r> _FAT bufcluster ; + + \ Get ID for direntry + : :getid ( direntry self -- id ) + dup >r _FAT :buf( - r@ _FAT bufsec r> _FAT secsz * + ; + + : :child ( dirid name self -- id-or-0 ) >r + fnbuf! r@ _FAT :getdirentry r@ :readdir r@ :findindir + dup if r@ :getid then rdrop ; + + 0 value _self + \ This is the "low" part. Complete open is finalized in fs/fat + : :fatopen ( id self -- hdl ) to _self + _self _FAT :getdirentry + _self FATFile :findfreecursor >r ( dirent ) + 1 to r@ FATFile flags \ mark as "used" + \ write the rest + dup _self _FAT :buf( - + _self _FAT bufsec _self _FAT secsz * + ( dirent doffset ) + r@ to FATFile entryoff DirEntry filesize r@ to FATFile size ( ) r> ; + + : :mountvolume ( drv -- fs ) + align4 here >r dup , ( drv R:fs ) + ['] :child , ['] :fatopen , ['] abort , ( drv ) + 0 , 0 , 0 , 0 , ( drv ) + \ At this point, "here" points to the FAT-header-to-be. Read the first sector + \ directly in "here": we'll have the header right here! + dup 0 here rot Drive :sec@ ( drv ) + _FAT HDRSZ allot ( drv ) + \ Verify that the header makes sense + r@ _FAT secsz swap Drive secsz over = not if + abort" Drive sector size not matching drive!" then ( secsz ) + \ Allocate buffer. 1+ is for the extra byte for FAT12 cross-sector exception + 1+ allot r> ( fs ) ; +]struct diff --git a/fs/tests/fs/fat.fs b/fs/tests/fs/fat.fs @@ -6,7 +6,7 @@ testbegin 100 const TOTSEC 512 TOTSEC RAMDrive :new value mydrv mydrv 16 1 1 TOTSEC 17 - FAT newFAT12 -mydrv FAT :mountVolume value myfat +mydrv FAT :mountvolume value myfat ' activefs structbind' @ value oldfs myfat ' activefs rebind 0 S" newfile" activefs :newfile # diff --git a/fs/xcomp/pc/glue.fs b/fs/xcomp/pc/glue.fs @@ -1,5 +1,5 @@ \ Glue code that goes between the filesystem part and boothi -INT13hDrive mountFATvolume ( fs ) ' activefs rebind +INT13hDrive FATLO :mountvolume ( fs ) ' activefs rebind 0 S" drv" activefs :child S" pc" activefs :child S" int13h.fs" activefs :child floaded, 0 S" fs" activefs :child S" fatlo.fs" activefs :child floaded,