duskos

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

commit d3bd3445140e5d38127e8442c36d4ea5b63bbb32
parent 275e538432a025e26838b82a73dae3ae4435e0a0
Author: Virgil Dupras <hsoft@hardcoded.net>
Date:   Mon, 15 Aug 2022 14:14:49 -0400

fs/fat: add :info

Diffstat:
Mfs/doc/file.txt | 25+++++++++++++++++--------
Mfs/fs/fat.fs | 27+++++++++++++++++++++++++--
Mfs/fs/fatlo.fs | 108++++++++++++++++++++++++++++++++++++++++----------------------------------------
Mfs/sys/file.fs | 6++++++
Mfs/tests/fs/fat.fs | 9+++++----
Mfs/xcomp/bootlo.fs | 1+
Mposix/glue.fs | 1+
7 files changed, 109 insertions(+), 68 deletions(-)

diff --git a/fs/doc/file.txt b/fs/doc/file.txt @@ -33,20 +33,17 @@ bar.fs file "bar.fs" in active directory When the code refers to a filesystem, it does so through a definite structure: -4b Drive pointer (see doc/drive) -4b :child -4b :open -4b :newfile -( whatever data the FS implementation needs ) - -The word pointers have the specifications below. For each of these words, "fs" -refers to a filesystem, a pointer to the structure decribed above. +drv -- Drive pointer (see doc/drive) :child ( dirid name fs -- 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". +:info ( id fs -- info ) + Returns a FSInfo structure (described below) corresponding to the specified + ID. This structure is a singleton and is only valid until the next :info call. + :open ( id fs -- 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 @@ -56,6 +53,11 @@ refers to a filesystem, a pointer to the structure decribed above. Create a new empty file named "name" in "dirid" and return the ID of the new file. Aborts on error. +... followed by whatever data the FS implementation needs. + +In each method, "fs" refers to a filesystem, a pointer to the structure decribed +above. + ## File API The File API is a specialization of the I/O API (doc/io) for accessing files in @@ -75,6 +77,13 @@ These words have the following meaning: Close handle and free its resources. When a handle is closed, operations on it become noops (read return 0, writes/seeks do nothing) +## FSInfo API + +The structure retured by ":info" above goes as follow: + +name -- a pointer to a string +size -- size of the file, 0 if dir +dir? -- whether the element is a Directory ## Common API On top of those words, the File subsystem implements those words: diff --git a/fs/fs/fat.fs b/fs/fs/fat.fs @@ -19,7 +19,27 @@ \ DirEntry. \ TODO: in my big FAT refactoring, I broke this section. Fix it. -?f<< fs/fatlo.fs +?f<< /fs/fatlo.fs +?f<< /lib/str.fs + +extends FSInfo struct[ FATInfo + create _buf DirEntry NAMESZ 1+ 1+ allot + create _struct _buf ( name ) , 0 ( size ) , 0 ( dir? ) , + create _rootname 6 c, ," (root)" + create _root _rootname , 0 , 1 , + : spcidx ( name -- idx ) SPC swap DirEntry NAMESZ [c]? ; + : :read ( id fat -- info ) + over not if 2drop _root exit then + _buf DirEntry NAMESZ 1+ SPC fill + _FAT :getdirentry dup _buf 1+ DirEntry EXTIDX move ( dirent ) + _buf 1+ spcidx ( dirent namelen ) + over DirEntry EXTIDX + c@ SPC = not if ( dirent namelen ) + over DirEntry EXTIDX + swap _buf + 1+ '.' swap c!+ ( dir src dst ) + DirEntry EXTSZ move else drop then ( dirent ) + _buf 1+ spcidx ( dirent len ) _buf c! ( dirent ) + \ TODO: read size and dir? + drop _struct ; +]struct extends FATLO struct[ FAT $ffff const EOC @@ -127,8 +147,11 @@ $ffff const EOC : fatopen ( id self -- hdl ) FATLO :fatopen ['] fatwritebuf over 4 + ! ['] fatflush over 8 + ! ; +: fatinfo ( id self -- info ) FATInfo :read ; + : :mountvolume ( drv -- fs ) - FATLO :mountvolume ['] fatopen over 8 + ! ['] fatnewfile over 12 + ! ; + FATLO :mountvolume ['] fatinfo over 8 + ! ['] fatopen over 12 + ! + ['] fatnewfile over 16 + ! ; create _FATTemplate ( jmp ) $eb c, $3c c, $90 c, ( OEMName ) ," DuskFAT " ( BytsPerSec ) 0 c, 0 c, diff --git a/fs/fs/fatlo.fs b/fs/fs/fatlo.fs @@ -12,8 +12,35 @@ \ See fs/fat.fs for complete implementation details. +struct[ DirEntry + 32 const SZ + 11 const NAMESZ + 8 const EXTIDX + 3 const EXTSZ + : :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( 32 allot0 +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 + +: 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( DirEntry EXTIDX + else + upcase swap c!+ then ( dst+1 ) + dup )fnbuf = if leave then next drop r>A ; \ 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 @@ -45,6 +72,8 @@ 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 * @@ -89,12 +118,33 @@ 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 * + ; + 0 value _self \ read multiple sectors in buf : :readsectors ( sec u buf self -- ) to _self @@ -109,32 +159,6 @@ r@ :buf( r> Filesystem :drv :sec@ ; ]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 @@ -215,33 +239,9 @@ extends File struct[ FATFile ]struct 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 ; + fnbuf! r@ _FAT :getdirentry r@ _FAT :readdir r@ _FAT :findindir + dup if r@ _FAT :getid then rdrop ; 0 value _self \ This is the "low" part. Complete open is finalized in fs/fat @@ -256,7 +256,7 @@ extends _FAT struct[ FATLO : :mountvolume ( drv -- fs ) align4 here >r dup , ( drv R:fs ) - ['] :child , ['] :fatopen , ['] abort , ( drv ) + ['] :child , ['] abort , ['] :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! diff --git a/fs/sys/file.fs b/fs/sys/file.fs @@ -1,6 +1,12 @@ \ File subsystem, see doc/file 0 S" lib" activefs :child S" io.fs" activefs :child fload +struct[ FSInfo + sfield name + sfield size + sfield dir? +]struct + 26 const MAXFSCNT create filesystems MAXFSCNT CELLSZ * allot0 ' activefs structbind' filesystems ! \ record our boot FS in the list diff --git a/fs/tests/fs/fat.fs b/fs/tests/fs/fat.fs @@ -9,12 +9,13 @@ mydrv 16 1 1 TOTSEC 17 - FAT newFAT12 mydrv FAT :mountvolume value myfat ' activefs structbind' @ value oldfs myfat ' activefs rebind -0 S" newfile" activefs :newfile # -S" /newfile" findpath# ( fsid ) \ found! +0 S" foo.fs" activefs :newfile # +S" /foo.fs" findpath# ( fsid ) \ found! +dup activefs :info ( fsid info ) +FSInfo name S" FOO.FS" #s= activefs :open ( hdl ) dup FATFile :cluster0 0 #eq \ no cluster allocated yet dup S" 42" c@+ rot File :writebuf 2 #eq ( fc ) File :close -f<< /newfile 42 #eq +f<< /foo.fs 42 #eq oldfs ' activefs rebind testend - diff --git a/fs/xcomp/bootlo.fs b/fs/xcomp/bootlo.fs @@ -230,6 +230,7 @@ struct[ IO struct[ Filesystem sfield drv smethod :child + smethod :info smethod :open smethod :newfile : :drv compile drv [compile] Drive ; immediate diff --git a/posix/glue.fs b/posix/glue.fs @@ -3,6 +3,7 @@ create _POSIXFS ' abort , ' _:child , + ' abort , ' _:open , ' abort ,