~vdupras/duskos

57ffa38c4a976cdcb29848c27f59d0842843ec4c — Virgil Dupras 16 days ago 693a08a
fs/fat: consolidate
2 files changed, 33 insertions(+), 26 deletions(-)

M fs/fs/fat.fs
M fs/fs/fatlo.fs
M fs/fs/fat.fs => fs/fs/fat.fs +13 -11
@@ 113,12 113,13 @@ $e5 const DIRFREE
  r> findfreedirentry dup DirEntry SZ 0 fill ( direntry )
  fnbuf( over DirEntry NAMESZ move ( direntry ) ;

: fatnewfile ( dirid name self -- id ) >r
: _newfile ( dirid name self -- id ) >r
  r@ _newentry ( dirent ) r@ writecursector r> :getid ;
current ' :newfile realias

: _makedir ( dirent -- dirent ) $10 over to DirEntry attr ;

: fatnewdir ( dirid name self -- id )
: _newdir ( dirid name self -- id )
  r! allocatecluster0 >r ( dirid name ) \ V1=self V2=cluster
  V1 _newentry ( dirent ) _makedir ( dirent )
  V2 over to DirEntry cluster V1 writecursector ( dirent )


@@ 130,6 131,7 @@ $e5 const DIRFREE
  dup DirEntry NAMESZ SPC fill '.' over c!+ '.' swap c! ( id buf )
  _makedir ( id buf ) V3 swap to DirEntry cluster
  2rdrop r> writecursector ( id ) ;
current ' :newdir realias

\ write multiple sectors from buf
: writesectors ( sec u buf self -- ) >r \ V1=self


@@ 142,11 144,13 @@ $e5 const DIRFREE
  swap r@ :FirstSectorOfCluster ( dst sec )
  swap r@ secpercluster swap r> writesectors ;

: fatinfo ( id self -- info ) FATInfo :read ;
: _info ( id self -- info ) FATInfo :read ;
current ' :info realias

\ TODO: deallocate the chain before clearing the entry
: fatremove ( id self -- )
: _remove ( id self -- )
  tuck :getdirentry ( dirent ) DIRFREE swap c! writecursector ;
current ' :remove realias

\ Read next sector if a sequential read is available, else return false.
: :nextsector? ( self -- f )


@@ 159,15 163,13 @@ $e5 const DIRFREE
  dup DirEntry :lastentry? if drop 0 else
    dup DirEntry :iterable? not if V1 _next then then ( entry ) rdrop ;

: fatiter ( dirid previd self -- id-or-0 ) >r >r ( dirid ) \ V1=self V2=previd
: _iter ( dirid previd self -- id-or-0 ) >r >r ( dirid ) \ V1=self V2=previd
  V1 :getdirentry V1 :readdir V1 :dirwin :buf( DirEntry SZ - V2 if begin ( entry )
      V1 _next dup while dup V1 :getid V2 <> while repeat then then ( entry-or-0 )
  dup if V1 _next dup if V1 :getid then then 2rdrop ;
current ' :iter realias

: :patchlo ( fs -- ) >r \ V1=fs
  ['] fatinfo r@ 12 + ! ['] fatiter r@ 20 + !
  ['] fatnewfile r@ 24 + !  ['] fatnewdir r@ 28 + ! ['] fatremove r@ 32 + !
  1 r> to flags ;
: :patchlo ( fs -- ) 1 swap to flags ;
: :mountvolume ( drv -- fs ) FAT :mountvolume dup :patchlo ;

create _FATTemplate


@@ 232,14 234,14 @@ struct+[ FATFile

  : _writebuf ( buf n self -- n )
    dup :free? if 2drop drop 0 exit then ( buf n self )
    dup >r pos over + r@ _grow ( src n )
    r! pos over + r@ _grow ( src n )
    \ TODO: this seek below doesn't seem right. The buffer should be at all times
    \ positioned properly w.r.t. pos.
    r@ pos r@ :seek
    r@ flags 2 or ( dirty ) r@ to flags
    r@ :)buf r@ :ptr - ( src n nmax )
    min ( src n ) r@ :ptr swap ( src dst n )
    dup >r move r> ( n ) r@ pos over + r> :seek ;
    r! move r> ( n ) r@ pos over + r> :seek ;
  current ' :writebuf realias

  \ TODO: deallocate truncated FATs if appropriate

M fs/fs/fatlo.fs => fs/fs/fatlo.fs +20 -15
@@ 188,6 188,10 @@ extends File struct[ FATFile
    rot min ( a n ) dup r> to+ pos ( a n ) ;

  : :close ( self -- ) dup :flush :release ;
  : :open ( direntry self -- )
    r! :hold dup V1 :fat :getid ( dirent entryoff ) \ V1=self
    r@ to entryoff DirEntry filesize r@ to size ( )
    0 to r@ pos -1 to r> clusteridx ;

  : :new ( fat -- hdl )
    0 align4 dup to' FAT lastcursor lladd ( fat newll ) drop here >r


@@ 196,28 200,29 @@ extends File struct[ FATFile
    ['] :seek , ['] :truncate , ( fat ) , 0 ( flags ) , 0 ( cluster ) ,
    -1 ( clusteridx ) , 0 ( entryoff ) ,
    here r@ to bufptr r@ bufsz allot r> ;

  : :findfreecursor ( fat -- hdl )
    dup FAT lastcursor begin ( fat ll )
      ?dup while dup CELLSZ + :free? not while llnext repeat
      nip CELLSZ + else :new then
    0 over to pos -1 over to clusteridx ;
]struct

struct+[ FAT
  \ This is the "low" part. Complete open is finalized in fs/fat
  : :fatopen ( id self -- hdl ) >r \ V1=self
    V1 :getdirentry
    V1 FATFile :findfreecursor ( dirent hdl ) r! FATFile :hold \ V2=hdl
    \ write the rest
    dup V1 :getid ( dirent entryoff )
    r@ to FATFile entryoff DirEntry filesize r@ to FATFile size ( ) r> rdrop ;
  : :findfreecursor ( self -- hdl )
    dup lastcursor begin ( fat ll )
      ?dup while dup CELLSZ + FATFile :free? not while llnext repeat
      nip CELLSZ + else FATFile :new then ;

  : :open ( id self -- hdl )
    tuck :getdirentry swap :findfreecursor ( dirent hdl )
    tuck FATFile :open ;

  alias abort :info
  alias abort :iter
  alias abort :newfile
  alias abort :newdir
  alias abort :remove

  : :mountvolume ( drv -- fs )
    dup SectorWindow :new over SectorWindow :new rot
    here >r ( fatwin dirwin rot ) \ V1=fs
    dup , 0 ( flags ) , ['] :child , ['] abort , ['] :fatopen ,
    ['] abort dup , dup , dup , ,
    dup , 0 ( flags ) , ['] :child , ['] :info , ['] :open ,
    ['] :iter , ['] :newfile , ['] :newdir , ['] :remove ,
    0 ( bufcluster ) , 0 ( lastcursor ) , rot ( fatwin ) , swap ( dirwin ) ,
    \ 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!