duskos

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

commit ce95a0ef822e52e0cb01dae88d7f0d4c0b654e00
parent 9370014eb52a8ed33cb00d2643b7fcddbff06009
Author: Virgil Dupras <hsoft@hardcoded.net>
Date:   Sat,  4 Feb 2023 13:09:56 -0500

Change Filesystem :iter semantics

The goal is to make it more :iterator friendly

Diffstat:
Mfs/doc/sys/file.txt | 8++++----
Mfs/fs/fat.fs | 18++++++++++++++++--
Mfs/fs/fatlo.fs | 79+++++++++++++++++++++++++++++--------------------------------------------------
Mfs/sys/file.fs | 19++++++++++---------
Mposix/glue.fs | 5+++--
Mposix/vm.c | 84+++++++++++++++++++++++++++++++++++++++++++------------------------------------
6 files changed, 108 insertions(+), 105 deletions(-)

diff --git a/fs/doc/sys/file.txt b/fs/doc/sys/file.txt @@ -51,10 +51,10 @@ drv -- Drive pointer identify the target file. Once a file isn't used anymore, it should be closed with :close. Aborts on error. -:iter ( w id fs -- ) - Iterate through all children of directory "id", ignoring "." and ".." entries. - For each child iterated upon, call word "w" which has the signature - "id fs --", "id" being the ID of the child. +:iter ( dirid previd fs -- id-or-0 ) + Given a parent id "dirid", return the child id following "previd" in it. If + previd is 0, return the first child. If no child follows "previd", return 0. + The iteration process ignores "." and ".." elements. :newfile ( dirid name fs -- id ) Create a new empty file named "name" in "dirid" and return the ID of the new diff --git a/fs/fs/fat.fs b/fs/fs/fat.fs @@ -206,9 +206,23 @@ $e5 const DIRFREE : fatremove ( id self -- ) >r r@ :getdirentry ( dirent ) DIRFREE swap c! r> writecursector ; +\ This approach to iteration is inefficient, but simple. I keep it as-is for now +\ because I'm planning on replacing the whole of fs/fat.fs with elm-chan's FAT +\ implementation at some point. +: _next ( entry self -- entry-or-0 ) >r \ V1=self + DirEntry SZ + dup V1 :)buf = if + drop V1 :nextsector? if V1 :buf( else rootdirentry( then then ( entry ) + 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 + V1 :getdirentry V1 :readdir V1 :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 ; + : _patchFS ( fs -- ) >r \ V1=fs - ['] fatinfo r@ 12 + ! ['] fatnewfile r@ 24 + ! - ['] fatnewdir r@ 28 + ! ['] fatremove r@ 32 + ! + ['] fatinfo r@ 12 + ! ['] fatiter r@ 20 + ! + ['] fatnewfile r@ 24 + ! ['] fatnewdir r@ 28 + ! ['] fatremove r@ 32 + ! ['] fatwritebuf FATFile EmptyCursor 8 + ! ['] fatflush FATFile EmptyCursor 12 + ! ['] fatflush FATFile EmptyCursor 12 + ! diff --git a/fs/fs/fatlo.fs b/fs/fs/fatlo.fs @@ -69,7 +69,7 @@ SZ HDRSZ + &+ :buf( : :)buf dup :buf( swap secsz + ; : :RootDirSectors ( self -- n ) -dup rootentcnt 32 * swap secsz /mod ( r q ) swap if 1+ then ; +dup rootentcnt 32 * swap secsz /mod ( r q ) swap bool + ; : :FirstDataSector ( self -- n ) >r r@ reservedseccnt r@ FATcnt r@ FATsz * + r> :RootDirSectors + ; : :FirstSectorOfCluster ( n self -- sec ) >r @@ -153,18 +153,19 @@ r@ reservedseccnt + r> :RootDirSectors + - ; : :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 - rot >r swap for ( buf ) \ V1=sec - V1 over _self :drv :sec@ - 1 to+ V1 _self secsz + next ( buf ) drop rdrop ; +: :readsectors ( sec u buf self -- ) >r \ V1=self + rot >r swap for ( buf ) \ V2=sec + V2 over V1 :drv :sec@ 1 to+ V2 V1 secsz + next ( buf ) drop 2rdrop ; : :readcluster ( cluster dst self -- ) >r over 2 - $fff6 > if abort" cluster out of range!" then swap r@ :FirstSectorOfCluster ( dst sec ) swap r@ secpercluster swap r> :readsectors ; +: :child ( dirid name self -- id-or-0 ) >r + fnbuf! r@ :getdirentry r@ :readdir r@ :findindir + dup if r@ :getid then rdrop ; ]struct \ File cursor @@ -185,25 +186,26 @@ extends File struct[ FATFile : _clustersize ( self -- n ) :fat :ClusterSize ; : :)buf ( self -- a ) dup :buf( swap _clustersize + ; : :free? ( self -- f ) flags not ; - : :dirty? ( self -- f ) flags 2 and ; + : :hold ( self -- ) 1 swap to flags ; + : :release ( self -- ) 0 swap to flags ; + : :dirty? ( self -- f ) flags 2 and bool ; : :bufpos ( self -- a ) dup File pos over _clustersize mod swap :buf( + ; : :dirent ( self -- dirent ) dup entryoff swap :fat :getdirentry ; : :cluster0 ( self -- cl ) :dirent DirEntry cluster ; - 0 value self \ set self to pos. If new pos crosses cluster boundaries compared to current \ pos, flush current buffer and read a new sector from disk. - : :fatseek ( pos self -- ) to self - self :free? if drop exit then ( pos ) + : :fatseek ( pos self -- ) >r \ V1=self + V1 :free? if drop exit then ( pos ) dup 0< if abort" can't seek to negative pos" then - dup self _clustersize / self clusteridx = not if - self IO :flush ( pos ) - dup self _clustersize / dup self to clusteridx ( pos idx ) - self :cluster0 ( pos idx cl ) - swap ?dup if for ( pos cl ) self :fat :FAT@ next then ( pos cl ) - dup self :buf( self :fat :readcluster ( pos cl ) - self to cluster ( pos ) - then ( pos ) self to File pos ; + dup V1 _clustersize / V1 clusteridx = not if + V1 IO :flush ( pos ) + dup V1 _clustersize / dup V1 to clusteridx ( pos idx ) + V1 :cluster0 ( pos idx cl ) + swap ?dup if for ( pos cl ) V1 :fat :FAT@ next then ( pos cl ) + dup V1 :buf( V1 :fat :readcluster ( pos cl ) + V1 to cluster ( pos ) + then ( pos ) r> to File pos ; : :fatreadbuf ( n self -- a? n ) dup :free? if 2drop 0 exit then ( n self ) @@ -215,25 +217,21 @@ extends File struct[ FATFile rot min ( a n ) dup r> to+ File pos ( a n ) ; - : :fatclose ( self -- ) dup IO :flush 0 swap to flags ; + : :fatclose ( self -- ) dup IO :flush :release ; \ these words below are "static" words not called with "self" as an argument, \ but "fat". : :cursorsize ( fat -- sz ) FAT :ClusterSize SZ + ; create EmptyCursor - \ IO 0 ( putback ) , ' :fatreadbuf , ' abort , ' drop , ' :fatclose , - \ File 0 ( pos ) , 0 ( size ) , ' :fatseek , ' abort ( truncate ) , - \ FAT fields 0 ( fat ) , 0 ( flags ) , 0 ( cluster ) , -1 ( clusteridx ) , 0 ( entryoff ) , : :createcursor ( fat -- hdl ) 0 align4 dup to' FAT lastcursor lladd ( fat newll ) - swap :cursorsize allot ( newll ) CELLSZ + ( hdl ) - 0 over to flags ( mark as "free" ) ; + swap :cursorsize allot ( newll ) CELLSZ + ( hdl ) dup :release ; : :findfreecursor ( fat -- hdl ) >r r@ FAT lastcursor begin ( ll ) @@ -244,37 +242,18 @@ extends File struct[ FATFile ]struct struct+[ FAT - : :iter ( w dirid self -- id-or-0 ) >r \ V1=self - V1 :getdirentry V1 :readdir >r ( ) \ V2=w - V1 :buf( begin ( a ) - dup DirEntry :lastentry? not while ( a ) - dup DirEntry :iterable? if ( a ) - V1 bufseccnt >r V1 bufsec >r - dup V1 :getid V1 V2 execute - r> r> V1 :readsector then ( a ) - DirEntry SZ + dup V1 :)buf = if - drop V1 :nextsector? not if - rootdirentry( ( parses as "lastentry" ) else V1 :buf( then then - repeat ( a ) drop 2rdrop ; - - : :child ( dirid name self -- id-or-0 ) >r - fnbuf! r@ :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 :getdirentry - _self FATFile :findfreecursor >r ( dirent ) - 1 to r@ FATFile flags \ mark as "used" + : :fatopen ( id self -- hdl ) >r \ V1=self + V1 :getdirentry + V1 FATFile :findfreecursor >r ( dirent ) r@ FATFile :hold \ V2=hdl \ write the rest - dup _self :buf( - - _self bufsec _self secsz * + ( dirent doffset ) - r@ to FATFile entryoff DirEntry filesize r@ to FATFile size ( ) r> ; + dup V1 :buf( - + V1 bufsec V1 secsz * + ( dirent doffset ) + r@ to FATFile entryoff DirEntry filesize r@ to FATFile size ( ) r> rdrop ; : :mountvolume ( drv -- fs ) 0 align4 here >r dup , ( drv R:fs ) 0 ( flags ) , - ['] :child , ['] abort , ['] :fatopen , ['] :iter , ['] abort , ['] abort , + ['] :child , ['] abort , ['] :fatopen , ['] abort , ['] abort , ['] abort , ['] abort , 0 ( bufsec ) , 0 ( bufseccnt ) , 0 ( bufcluster ) , 0 ( lastcursor ) , \ At this point, "here" points to the FAT-header-to-be. Read the first sector diff --git a/fs/sys/file.fs b/fs/sys/file.fs @@ -41,17 +41,18 @@ struct[ Path r@ id swap r@ fs Filesystem :newfile ( id ) r> fs swap :new ; : :newdir ( name self -- path ) >r r@ id swap r@ fs Filesystem :newdir ( id ) r> fs swap :new ; - : :iter ( w self -- ) >r - r@ id r> fs Filesystem :iter ( id ) ; - + : :iter ( w self -- ) dup fs >r swap >r ( self ) \ V1=fs V2=w + id dup >r 0 V1 Filesystem :iter ( childid ) \ V3=dirid + begin ?dup while + dup V1 V2 execute ( childid ) + V3 swap V1 Filesystem :iter repeat + 2rdrop rdrop ; + + : _dir? ( id fs -- info f ) 2dup Filesystem :info dup FSInfo dir? ; alias noop _w ( id fs info -- ) - : _ ( id fs -- ) - 2dup Filesystem :info dup FSInfo dir? if ( id fs info ) - _w else 2drop drop then ; + : _ ( id fs -- ) _dir? if _w else 2drop drop then ; : :iterdirs ( w self -- ) swap ['] _w realias ['] _ swap :iter ; - : _ ( id fs -- ) - 2dup Filesystem :info dup FSInfo dir? not if ( id fs info ) - _w else 2drop drop then ; + : _ ( id fs -- ) _dir? not if _w else 2drop drop then ; : :iterfiles ( w self -- ) swap ['] _w realias ['] _ swap :iter ; : :remove ( self -- ) dup id swap fs Filesystem :remove ; diff --git a/posix/glue.fs b/posix/glue.fs @@ -1,11 +1,12 @@ : _ doer ' , does> nip @ execute ; -_ _:child _fchild _ _:open _fopen _ _:info _finfo +_ _:child _fchild _ _:open _fopen _ _:info _finfo _ _:iter _fiter + create _POSIXFS 0 , 0 , ' _:child , ' _:info , ' _:open , - ' _fiter , + ' _:iter , ' abort , ' abort , ' abort , diff --git a/posix/vm.c b/posix/vm.c @@ -765,6 +765,10 @@ static void RUNWORD() { // op: 5c } } +static void USLEEP() { // op: 5d + usleep(ppop()); +} + /* Filesystem At POSIX level, we don't have access to the underlying FS structure such as @@ -831,6 +835,13 @@ static char* pathcat(char *p1, dword s) { return buf2; } +static dword _newfsid(char *path) { + dword res = 0; + while (fsids[++res][0]); + strcpy(fsids[res], path); + return res; +} + static void FCHILD () { // op: 60 dword s = ppop(); dword parent = ppop(); @@ -847,8 +858,7 @@ static void FCHILD () { // op: 60 ppush(0); return; } - while (fsids[++res][0]); - strcpy(fsids[res], path); + res = _newfsid(path); } ppush(res); } @@ -934,44 +944,46 @@ static void FINFO() { // op: 64 memcpy(&vm.mem[dst+13], name, strlen(name)); } -// ( w id self -- ) +static struct dirent* _next(DIR *dirp) { + struct dirent *d; + do { + d = readdir(dirp); + } while (d && ((strcmp(d->d_name, ".") == 0) || (strcmp(d->d_name, "..") == 0))); + return d; +} + +// ( dirid previd -- id-or-0 ) static void FITER() { // op: 65 DIR *dirp; struct dirent *d; - dword self = ppop(); - dword fsid = ppop(); - dword w = ppop(); - int baselen; char path[MAXPATHSZ] = {0}; - strcpy(path, getpathfromid(fsid)); + int baselen; + dword previd = ppop(); + dword dirid = ppop(); + dword curid = 0; + int matched = 0; + strcpy(path, getpathfromid(dirid)); dirp = opendir(path); - if (dirp) { - strcat(path, "/"); - baselen = strlen(path); - while(1) { - do { - d = readdir(dirp); - } while (d && ((strcmp(d->d_name, ".") == 0) || (strcmp(d->d_name, "..") == 0))); - if (!d) break; - strcpy(&path[baselen], d->d_name); - fsid = findpath(path); - if (!fsid) { - while (fsids[++fsid][0]); - strcpy(fsids[fsid], path); - } - ppush(fsid); - ppush(self); - callword(w); - if (vm.PC >= MEMSZ) break; - } - closedir(dirp); - } else { + if (!dirp) { printf("Couldn't open dir %s\n", path); vm.PC = abortaddr; + return; } + strcat(path, "/"); + baselen = strlen(path); + do { + if (curid == previd) matched = 1; + d = _next(dirp); + if (d) { + strcpy(&path[baselen], d->d_name); + curid = findpath(path); + if (!curid) curid = _newfsid(path); + } else { curid = 0; } + } while (curid && !matched); + ppush(curid); } -static void FSEEK() { // op: 66 +static void FSEEK() { // op: 67 dword hdl = ppop(); dword pos = ppop(); int res; @@ -989,10 +1001,6 @@ static void FSEEK() { // op: 66 sd(hdl+FILEPOSOFF, res); } -static void USLEEP() { // op: 67 - usleep(ppop()); -} - // ( imgname -- ) static void MOUNTDRV() { // op: 68 char buf[64] = {0}; @@ -1050,8 +1058,8 @@ static void (*ops[OPCNT])() = { OR, XOR, BOOL, NOT, LT, SHLC, SHRC, LSHIFT, RSHIFT, LITN, EXECUTEWR, EXITWR, MOVE, MOVEWR, FINDMOD, WNF, STACKCHK, MAYBEWORD, WORD, PARSE, REQ, FIND, APOS, COMPILING, - ALIASWR, STARTCOMP, STOPCOMP, COMPWORD, RUNWORD, NULL, NULL, NULL, - FCHILD, FOPEN, FREADBUF, FCLOSE, FINFO, FITER, FSEEK, USLEEP, + ALIASWR, STARTCOMP, STOPCOMP, COMPWORD, RUNWORD, USLEEP, NULL, NULL, + FCHILD, FOPEN, FREADBUF, FCLOSE, FINFO, FITER, NULL, FSEEK, MOUNTDRV, UNMOUNTDRV, DRVRD, DRVWR}; static char *opnames[OPCNT] = { @@ -1066,8 +1074,8 @@ static char *opnames[OPCNT] = { "or", "xor", "bool", "not", "<", "<<c", ">>c", "lshift", "rshift", "litn", "execute,", "exit,", "move", "move,", "findmod", "(wnf)", "stack?", "maybeword", "word", "parse", "[]=", "find", "'", "compiling", - "alias,", "]", "[", "compword", "runword", NULL, NULL, NULL, - "_fchild", "_fopen", "_freadbuf", "_fclose", "_finfo", "_fiter", "_fseek", "_usleep", + "alias,", "]", "[", "compword", "runword", "_usleep", NULL, NULL, + "_fchild", "_fopen", "_freadbuf", "_fclose", "_finfo", "_fiter", NULL, "_fseek", "_mountdrv", "_unmountdrv", "_drv@", "_drv!"}; static void oprun1() { // run next op