commit 79c0f79e7d3f0a1bc4d053dcd3a410fec232434a
parent 2f03a9049f488bde7e9b893adafd4b99c9ff732d
Author: Virgil Dupras <hsoft@hardcoded.net>
Date: Wed, 20 Jul 2022 07:17:34 -0400
sys/file: implement chdir findpathdir and findpath
This will allow to offload complexity from FS implementations.
Diffstat:
7 files changed, 67 insertions(+), 17 deletions(-)
diff --git a/fs/doc/file.txt b/fs/doc/file.txt
@@ -35,6 +35,24 @@ fnewfile ( dirid name -- id )
Create a new empty file named "name" in "dirid" and return the ID of the new
file. Aborts on error.
+## Common API
+
+On top of those words, the File subsystem implements those words:
+
+chdir ( path -- )
+ Change current directory to path. In subsequent path finds, if the path
+ doesn't start with "/", the search will start from this directory.
+ Aborts if path is not found.
+
+findpathdir ( path -- dirid? name-or-0 )
+ Find FS ID corresponding to the directory part of the path.
+ Returns the id of the directory as well as the name of the last part of the
+ path. If dir is not found, name is 0 and dirid is not on PS.
+ "name" becomes invalid on the next findpathdir call.
+
+findpath ( path -- id-or-0 )
+ Find FS ID corresponding to path or 0 if not found.
+
## File ID design considerations
When we refer to a file or directory ID, we refer to a single 32-bit number
diff --git a/fs/fs/fatlo.fs b/fs/fs/fatlo.fs
@@ -95,7 +95,9 @@ 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 )
+ 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 )
@@ -110,8 +112,8 @@ here const )fnbuf
\ Find current fnbuf( in current dir buffer and return a dir entry.
: findindir ( -- direntry )
begin
- _ ?dup not while nextsector? not if abort" file not found" then
- repeat ;
+ _ ?dup not while nextsector? while
+ repeat ( not found ) 0 then ;
\ Read specified "direntry" in fatbuf(
: readdir ( direntry -- )
@@ -129,8 +131,8 @@ here const )fnbuf
\ Get ID for direntry
: getid ( direntry -- id ) fatbuf( - bufsec BPB_BytsPerSec * + ;
-: fatchild ( dirid name -- id )
- fnbuf! getdirentry readdir findindir getid ;
+: fatchild ( dirid name -- id-or-0 )
+ fnbuf! getdirentry readdir findindir dup if getid then ;
\ 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
diff --git a/fs/sys/file.fs b/fs/sys/file.fs
@@ -3,14 +3,34 @@
?f<< /lib/with.fs
?f<< /lib/io.fs
+0 value curdir
+create _buf $100 allot
+
+: findpathdir ( path -- dirid? name-or-0 )
+ A>r 0 _buf c!+ >A c@+ ( a len )
+ over c@ '/' = if 1- >r 1+ 0 ( root ) else >r curdir then swap
+ begin ( dirid a )
+ c@+ dup '/' = if ( dirid a c )
+ drop swap _buf fchild ( a dirid )
+ ?dup not if drop 0 r~ r>A exit then swap ( dirid a )
+ 0 _buf c!+ >A
+ else ( dirid a c )
+ Ac!+ _buf c@ 1+ _buf c! then
+ next ( dirid a ) drop _buf r>A ;
+
+: findpath ( path -- id-or-0 )
+ findpathdir ?dup if fchild else 0 then ;
+
+: chdir ( path -- ) findpath ?dup if to curdir else abort" not found" then ;
+
+: fseek ( pos hdl -- ) dup 12 + @ execute ;
+: fclose ( hdl -- ) dup 16 + @ execute ;
+
\ We need a private scratchpad here because some cursors can be quite
\ long-lived. If we use the system scratchpad, short-lived data will overwrite
\ our cursors.
$200 scratchpad$ filespad
-: fseek ( pos hdl -- ) dup 12 + @ execute ;
-: fclose ( hdl -- ) dup 16 + @ execute ;
-
\ This creates a "f<" reader with the file descriptor embedded in it. This
\ allows for a straightforward override of input/output words.
: [f<] ( curfd -- word )
diff --git a/fs/tests/fs/fat.fs b/fs/tests/fs/fat.fs
@@ -18,14 +18,6 @@ $ffd over fatseek
dup fatgetc 'E' #eq dup fatgetc 'O' #eq dup fatgetc 'F' #eq
dup fatgetc -1 #eq
fatclose
-\ test chdir and relative find
-S" lib" fatchdir
-S" str.fs" fatfindpath # \ found!
-S" /lib/str.fs" fatfindpath # \ found!
-\ can we come back one level?
-S" .." fatchdir
-S" lib/str.fs" fatfindpath # \ found!
-S" /lib/str.fs" fatfindpath # \ found!
\ can we create a new file?
S" newfile" fatnewfile #
S" /newfile" fatfindpath # \ found!
diff --git a/fs/tests/sys/all.fs b/fs/tests/sys/all.fs
@@ -1,2 +1,3 @@
\ Run all sys test suites
-f<< tests/sys/drive.fs
+f<< /tests/sys/drive.fs
+f<< /tests/sys/file.fs
diff --git a/fs/tests/sys/file.fs b/fs/tests/sys/file.fs
@@ -0,0 +1,16 @@
+?f<< tests/harness.fs
+?f<< sys/file.fs
+testbegin
+\ Tests for sys/file
+\ test chdir and relative find
+S" lib" chdir
+S" str.fs" findpath # \ found!
+S" /lib/str.fs" findpath # \ found!
+\ can we come back one level?
+S" .." chdir
+S" lib/str.fs" findpath # \ found!
+S" /lib/str.fs" findpath # \ found!
+\ what if it doesn't exist?
+S" lib/nope.fs" findpath not # \ not found!
+S" /nope.fs" findpath not # \ not found!
+testend
diff --git a/fs/xcomp/glue2.fs b/fs/xcomp/glue2.fs
@@ -1,3 +1,4 @@
bootfile xcomp/glue2.fs
\ Glue code that goes between the filesystem part and boothi
alias fatopenlo fopen
+alias fatchild fchild