[openfirmware] r1247 - ofw/fs/ext2fs
svn at openfirmware.info
svn at openfirmware.info
Wed Jul 22 09:12:17 CEST 2009
Author: wmb
Date: 2009-07-22 09:12:17 +0200 (Wed, 22 Jul 2009)
New Revision: 1247
Modified:
ofw/fs/ext2fs/dir.fth
ofw/fs/ext2fs/methods.fth
Log:
OLPC trac #9409 - fixed ext2 symlink problems.
Modified: ofw/fs/ext2fs/dir.fth
===================================================================
--- ofw/fs/ext2fs/dir.fth 2009-07-20 21:39:07 UTC (rev 1246)
+++ ofw/fs/ext2fs/dir.fth 2009-07-22 07:12:17 UTC (rev 1247)
@@ -8,7 +8,6 @@
variable diroff
variable totoff
-variable current-dir
: get-dirblk ( -- end? )
lblk# bsize * file-size >= if true exit then
@@ -40,6 +39,14 @@
: lblk#++ ( -- ) lblk# 1+ to lblk# ;
+: dirent-vars ( -- diroff totoff lblk# inode# )
+ diroff @ totoff @ lblk# inode#
+;
+: restore-dirent ( diroff totoff lblk# inode# -- )
+ to inode# to lblk# totoff ! diroff !
+ get-dirblk drop
+;
+
\ **** Select the next directory entry
: next-dirent ( -- end? )
dirent-len@ dup diroff +! totoff +!
@@ -80,7 +87,6 @@
;
\ On entry:
-\ current-dir @ is the inode of the directory file
\ dir-block# is the physical block number of the first directory block
\ diroff @ is 0
\ On successful exit:
@@ -162,7 +168,6 @@
else
\ First dirent in block; zap its inode
0 dirent-inode!
-
then
update
false
@@ -183,90 +188,164 @@
r> dirent-inode@ init-inode
;
+: linkpath ( -- a )
+ file-acl if bsize 9 rshift else 0 then ( #acl-blocks )
+ #blks-held <> if \ long symbolic link path
+ direct0 int@ block
+ else \ short symbolic link path
+ direct0
+ then
+;
+
+\ --
+
+1 constant regular-type
+2 constant dir-type
+7 constant symlink-type
+
+\ Information that we need about the working file/directory
+\ The working file changes at each level of a path search
+
+0 instance value wd-inum \ Inumber of directory to search
+0 instance value wf-inum \ Inumber of file or directory found
+0 instance value wf-type \ Type - 4 for directory, d# 10 for symlink, etc
+
+char \ instance value delimiter
+
+defer $resolve-path
+d# 1024 constant /symlink \ Max length of a symbolic link
+
+: set-root ( -- )
+ root-dir# to wd-inum root-dir# to wf-inum dir-type to wf-type
+;
+
+: strip\ ( name$ -- name$' )
+ dup 0<> if ( name$ )
+ over c@ delimiter = if ( name$ )
+ 1 /string ( name$ )
+ set-root ( name$ )
+ then ( name$ )
+ then ( name$ )
+;
+
+: set-inode ( inode# -- )
+ to inode#
+ 0 to lblk#
+;
+
+: first-dirent ( dir-inode# -- end? ) \ Adapted from (init-dir)
+ set-inode
+ get-dirblk if true exit then
+ 0 diroff ! 0 totoff ! ( )
+ false ( )
+;
+
\ On entry:
-\ current-dir @ is the inode of the directory file
+\ inode# is the inode of the directory file
\ dir-block# is the physical block number of the first directory block
\ diroff @ and totoff @ are 0
\ On successful exit:
\ dir-block# is the physical block number of the current directory block
\ diroff @ is the within-block offset of the directory entry that matches name$
\ totoff @ is the overall offset of the directory entry that matches name$
-: lookup ( name$ -- not-found? )
- begin
- dirent-inode@ if \ inode=0 for a deleted dirent at the beginning of a block
- 2dup file-name $= if 2drop false exit then
+
+: $find-name ( name$ dir-inum -- error? )
+ first-dirent ( end? )
+ begin 0= while ( name$ )
+ \ dirent-inode@ = 0 means a deleted dirent at the beginning
+ \ of a block; skip those
+ dirent-inode@ if ( name$ )
+ 2dup file-name ( name$ name$ this-name$ )
+ $= if
+ dirent-inode@ to wf-inum ( name$ )
+ dirent-type@ to wf-type ( name$ )
+ 2drop false exit
+ then ( name$ )
then
- next-dirent
- until
- 2drop true
+ next-dirent ( name$ end? )
+ repeat ( name$ )
+
+ 2drop ( )
+ true
;
-defer init-dir
-
-: $chdir ( path$ -- error? )
- begin dup while ( path$ )
- [char] \ left-parse-string ( tail$ head$ )
- dup 0= if ( tail$ head$ ) \ Begins with \
- 2drop ( tail$ )
- root-dir# init-dir if 2drop true exit then
- else ( tail$ head$ )
- lookup if 2drop true exit then
- dir? 0= if 2drop true exit then
- file-handle init-dir if 2drop true exit then
- then ( tail$ )
- repeat ( path$ )
- 2drop false
+: symlink-resolution$ ( inum -- data$ )
+ to inode#
+ linkpath dup cstrlen
;
-\ replace / with \ in a string
-: >OFW-path ( adr len -- )
- bounds do i c@ ascii / = if ascii \ i c! then loop
+\ The work file is a symlink. Resolve it to a new dirent
+: dir-link ( -- error? )
+ delimiter >r [char] / to delimiter ( r: delim )
+
+ \ Allocate temporary space for the symlink value (new name)
+ /symlink alloc-mem >r ( r: delim dst )
+
+ \ Copy the symlink resolution to the temporary buffer
+ wf-inum symlink-resolution$ ( src len r: delim dst )
+ tuck r@ swap move ( len r: delim dst )
+
+ r@ swap $resolve-path ( error? r: delim dst )
+
+ r> /symlink free-mem ( error? r: delim )
+ r> to delimiter ( error? )
;
-: linkpath ( -- a )
- file-acl if bsize 9 rshift else 0 then ( #acl-blocks )
- #blks-held <> if \ long symbolic link path
- direct0 int@ block
- else \ short symbolic link path
- direct0
- then
+\ On successful exit, wf-inum is the inode# of the last path component,
+\ wf-type is its type, and wd-inum is inode# of the last directory encountered
+
+: ($resolve-path) ( path$ -- error? )
+ dir-type to wf-type
+ \ strip\ sets wd-inum if the path begins with the delimiter
+ begin strip\ dup while ( path$ )
+ wf-type case ( path$ c: type )
+ dir-type of ( path$ )
+ delimiter left-parse-string ( rem$' head$ )
+ \ $find-name sets wf-inum and wf-type to the pathname component
+ wd-inum $find-name if 2drop true exit then ( rem$ )
+ wf-type dir-type = if ( rem$ )
+ wf-inum to wd-inum ( rem$ )
+ then ( rem$ )
+ endof ( rem$ )
+
+ symlink-type of ( rem$ )
+ \ dir-link recursively calls $resolve-path, setting
+ \ wf-inum and wf-type to the symlink's last component
+ dir-link if 2drop true exit then ( rem$ )
+ endof ( rem$ )
+ ( default ) ( rem$ c: type )
+
+ \ The parent is an ordinary file or something else that
+ \ can't be treated as a directory
+ 3drop true exit
+ endcase ( rem$ )
+ repeat ( rem$ )
+ 2drop false ( false )
;
-variable parent-dir
+' ($resolve-path) to $resolve-path
-: select-file ( i# -- error? )
- to inode#
- symlink? if ( )
- linkpath dup cstrlen 2dup >OFW-path ascii \ split-after ( file$ path\$ )
- dup if ( file$ path\$ )
- \ Path component is present
- parent-dir @ init-dir if 4drop true exit then ( file$ path\$ )
- $chdir if 2drop true exit then ( file$ )
- else ( file$ path\$ )
- \ Path component is absent
- 2drop current-dir @ init-dir if 2drop true exit then ( file$ )
- then ( file$ )
- dup 0= if 2drop false exit then ( file$ )
- lookup if true exit then ( )
-
- file-handle recurse
- else ( )
- 0 to lblk# false ( )
- then ( )
+: $find-file ( name$ -- error? )
+ $resolve-path if true exit then ( )
+
+ begin
+ \ We now have the dirent for the file at the end of the string
+ wf-type case
+ dir-type of wf-inum to wd-inum false exit endof \ Directory
+ regular-type of false exit endof \ Regular file
+ symlink-type of dir-link if true exit then endof \ Link
+ ( default ) \ Anything else (special file) is error
+ drop true exit
+ endcase
+ again
;
+\ --
-\ **** Select the directory file
-: (init-dir) ( i# -- error? )
- \ Save the current directory because we will need to return to it
- \ in case we encounter a relative symlink.
- current-dir @ parent-dir ! ( i# )
- dup current-dir ! ( i# )
- select-file if true exit then ( )
- get-dirblk if true exit then ( )
- 0 diroff ! 0 totoff ! ( )
- false ( )
+: $chdir ( path$ -- error? )
+ $find-file if true exit then
+ wf-type dir-type <> if true exit then
+ wd-inum first-dirent
;
-' (init-dir) to init-dir
\ Delete a file, given its inode. Does not affect the directory entry, if any.
: idelete ( inode# -- )
@@ -286,7 +365,7 @@
file-handle 0= if true exit then
inode# >r
- file-handle select-file if r> drop true exit then
+ file-handle set-inode if r> drop true exit then
file? 0= if r> drop true exit then \ XXX handle symlinks
\ is this the only link?
@@ -297,7 +376,6 @@
1- link-count!
then
-
r> to inode#
\ delete directory entry
del-dirent ( error? )
@@ -331,11 +409,12 @@
;
: $readlink ( name$ -- true | link$ false )
- lookup if true exit then
-
- inode# >r file-handle to inode#
- linkpath dup cstrlen false
- r> to inode#
+ dirent-vars 2>r 2>r
+ $resolve-path if 2r> 2r> restore-dirent true exit then
+ wf-type symlink-type <> if 2r> 2r> restore-dirent true exit then
+
+ wf-inum symlink-resolution$ false
+ 2r> 2r> restore-dirent
;
headers
Modified: ofw/fs/ext2fs/methods.fth
===================================================================
--- ofw/fs/ext2fs/methods.fth 2009-07-20 21:39:07 UTC (rev 1246)
+++ ofw/fs/ext2fs/methods.fth 2009-07-22 07:12:17 UTC (rev 1247)
@@ -13,7 +13,7 @@
o# 100666 ($create)
;
\ XXX note: increment link count in parent
-: $mkdir ( name$ -- )
+: $mkdir ( name$ -- error? )
o# 40777 ($create) if true exit then
file-handle to inode#
@@ -21,17 +21,17 @@
file-size h# 400 + file-size!
dup direct0 int! update ( block# )
block bsize erase update \ flush
- current-dir @ >r
- inode# init-dir
+ wd-inum >r
+ inode# first-dirent if r> drop true exit then
" ." d# 12 inode# set-dirent
d# 12 diroff !
- " .." bsize d# 12 - r> set-dirent
+ " .." bsize d# 12 - r> set-dirent
false ( error? )
diroff off
;
: $delete ( name$ -- error? )
- lookup if true exit then ( )
+ $find-file if true exit then ( )
(delete-file)
;
@@ -39,10 +39,11 @@
\ XXX note: decrement link count in parent
: $rmdir ( name$ -- error? ) \ XXX UNTESTED
- lookup if true exit then ( )
+ $find-file if true exit then ( )
+ wf-type dir-type <> if true exit then ( )
inode# >r \ save parent directory
- file-handle select-file if r> drop true exit then
+ file-handle set-inode if r> drop true exit then
dir? 0= if r> drop true exit then
(delete-files) file-handle if r> drop true exit then \ still some left
@@ -102,16 +103,17 @@
then ( actual addr )
lblk# write-file-block ( actual )
- \ XXX I am sceptical about this line.
+ \ XXX I am skeptical about this line.
dup 0> if lblk#++ then ( actual )
true to modified?
\ flush \ XXX kludge for tests
;
: $ext2fsopen ( adr len mode -- false | fid fmode size align close seek write read true )
- -rot lookup if drop false exit then ( mode adr len )
+ -rot $find-file if drop false exit then ( mode )
+ wf-type regular-type <> if drop false exit then ( mode )
- file-handle select-file if drop false exit then ( mode )
+ file-handle set-inode ( mode )
false to modified?
>r
@@ -134,7 +136,7 @@
my-args " <NoFile>" $= if true exit then
\ Start out in the root directory
- root-dir# init-dir if release-buffers false exit then
+ set-root
my-args ascii \ split-after ( file$ path$ )
$chdir if 2drop release-buffers false exit then ( file$ )
More information about the openfirmware
mailing list