3909N/A\ ident "%Z%%M% %I% %E% SMI"
0N/A\ Copyright 2007 Sun Microsystems, Inc. All rights reserved.
0N/A\ Use is subject to license terms.
0N/A\ The contents of this file are subject to the terms of the
2362N/A\ Common Development and Distribution License (the "License").
0N/A\ You may not use this file except in compliance with the License.
0N/A\ See the License for the specific language governing permissions
0N/A\ and limitations under the License.
0N/A\ When distributing Covered Code, include this CDDL HEADER in each
0N/A\ If applicable, add the following below this CDDL HEADER, with the
0N/A\ fields enclosed by brackets "[]" replaced with your own identifying
2362N/A\ information: Portions Copyright [yyyy] [name of copyright owner]
0N/Aid: %Z%%M% %I% %E% SMI
0N/Apurpose: HSFS file system support package for NewBoot
0N/Acopyright: Copyright 2006 Sun Microsystems, Inc. All Rights Reserved
0N/A\ High Sierra, Rock Ridge (CD-ROM) file system reader and boot block
0N/A" /packages" get-package push-package
0N/A fs-pkg$ device-name diag-cr?
0N/A 0 instance value dir-buf
0N/A 0 instance value sua-buf
0N/A 0 instance value ce-buf
0N/A \ HSFS volume descriptor routines
0N/A \ unaligned load of 2-byte item
dup c@ swap char+ ( c0 adr+1 )
\ unaligned store of 2-byte item
swap wbsplit swap 2 pick c! swap char+ c!
\ unaligned load of 4-byte item
dup xw@ swap wa1+ ( w0 adr+2 )
\ unaligned store of 4-byte item
swap lwsplit swap 2 pick xw! swap wa1+ xw!
d# 16 constant vol-desc-sector# ( -- n )
." invalid access of +vd" cr abort
: root-dir ( -- n ) d# 156 +vd ;
: /block ( -- n ) d# 128 +vd xw@ ;
: byte>blkoff ( byte-off -- block-off ) /block mod ;
vol-desc /sector vol-desc-sector# /sector * dev-ih read-disk
: read-fs-blocks ( adr len fs-blk# -- ) /block * dev-ih read-disk ;
\ HSFS directory routines
\ Current directory variables.
instance variable cdir-blk \ Current directory device block ptr.
instance variable cdir-blk0 \ Current directory block0.
instance variable cdir-offset \ Current directory logical offset.
instance variable cdir-size \ Current directory logical size.
instance variable cdir-ptr \ Current directory entry pointer.
false instance value cdir-rescan \ Rescan current directory for symlink.
\ Access of current directory entry.
: +dr ( n -- adr ) cdir-ptr @ + ;
: dir-entrylen ( -- n ) d# 0 +dr c@ ;
: dir-block0 ( -- n ) d# 2 +dr xl@ ;
: dir-filesize ( -- n ) d# 10 +dr xl@ ;
: dir-flags ( -- n ) d# 25 +dr c@ ;
: dir-filenamelen ( -- n ) d# 32 +dr c@ ;
: dir-filename ( -- adr ) d# 33 +dr ;
: dir-isdir? ( -- flag ) dir-flags h# 02 and 0<> ;
: dir-file$ ( -- adr len ) dir-filename dir-filenamelen ;
: dir-sualen ( -- len ) dir-entrylen d# 33 - dir-filenamelen - ;
\ ISO name, including dot & dot-dot check
: dir-iso$ ( -- adr len )
dir-filename c@ ( name[0] )
false instance value symlink?
dir-buf /block cdir-blk @ read-fs-blocks
: froot ( -- ) root-dir cdir-ptr ! ;
\ SUAs - System Use Area in directory entry (Rock Ridge
\ Immediately follows directory entry name rounded up to
: +suf ( n -- adr ) sua-ptr + ;
: suf-sig ( -- adr len ) sua-ptr 2 ;
: suf-len ( -- len ) 2 +suf c@ ;
: suf-dat ( -- data ) 5 +suf ;
: suf-ce-lbn ( -- lbn ) 4 +suf xl@ ;
: suf-ce-offset ( -- offset ) d# 12 +suf xl@ ;
: suf-ce-len ( -- len ) d# 20 +suf xl@ ;
dir-file$ + /w roundup to sua-ptr
sua-len suf-len - to sua-len
: suf-nm$ ( -- adr len ) suf-dat suf-len 5 - ;
\ Continuation suffix handling. When a 'CE' suffix is seen,
\ record the CE parameters (logical block#, offset and length
\ of continuation). We process the CE continuation only after
\ we've finished processing the current SUA area.
instance variable ce-offset
suf-ce-offset ce-offset !
: suf-ce-process ( -- error? )
sua-buf ce-len @ ce-lbn @ read-fs-blocks
0 ce-len ! 0 ce-lbn ! 0 ce-offset !
/buf-len instance buffer: suf-sl-buf
false instance value symlink-need-sep
\ Format of Rock Ridge symlinks needs to be munged to unix-style
\ name. Format is: <flag><nbytes>file-name<flag><nbytes>filename...
\ where \ <flag> is flag byte (0=filename, 2=current dir, 4=parent
\ dir, 8=root dir) and <nbytes> is one-byte byte count (zero for
: suf-copy-to-symlinkbuf ( name$ -- )
false to symlink-need-sep
suf-sl-buf -rot bounds do ( dst )
i c@ dup 2 = if ( dst 2 )
drop ascii . over c! char+ 2 ( dst' inc )
else dup 4 = if ( dst 4 )
drop " .." 2 pick swap move ( dst )
else dup 8 = if ( dst 8 )
drop ascii / over c! char+ 2 ( dst' inc )
false to symlink-need-sep
." unknown SL flag: " .x cr abort
i char+ dup c@ >r ( dst src+1 R:nbytes )
char+ over r@ move ( dst R:nbytes )
\ Saved 'NM' prefix buffer.
/buf-len instance buffer: suf-nm-buf
0 instance value suf-nm-size
\ Return the Rock Ridge file name associated with the current
\ dirent ('NM' suffix). Otherwise returns standard iso filename.
\ Marks whether returned filename is a symbolic link ('SL' suffix)
\ and also processes continuations ('CE' suffix).
: rr-file$ ( -- adr len )
\ select start of sua, record sua offset
suf-nm-buf suf-nm-size ( NM$ )
suf-sig ( sig-adr sig-len )
suf-nm$ to suf-nm-size ( sig-adr sig-len suf-nm-adr )
suf-nm-buf suf-nm-size move
suf-nm$ suf-copy-to-symlinkbuf
\ HSFS high-level routines
\ Used for rescanning current directory for symbolic links.
\ Initializes current directory settings from current directory
\ entry pointer or for rescan. If it's not a rescan, we have
\ access to the actual directory entry, so we can check whether
\ it's a directory or not here.
: init-dent ( -- error? )
dir-block0 dup cdir-blk ! cdir-blk0 !
\ Check for end of directory, return true if we're past the EOF.
cdir-offset @ cdir-size @ >= if
\ If we're at a block boundary, get the next block. Otherwise
\ increment the directory pointer.
cdir-offset @ byte>blkoff 0= if
\ If dir-entrylen is not zero, increment the current directory
\ file offset. Otherwise, a dir-entrylen of zero indicates
\ the end of a dir block, so round up cdir-offset to fetch the
cdir-offset @ /block roundup cdir-offset !
\ Look through current directory for file name 'file$'.
\ Will leave current directory entry (cdir-ptr) pointing
\ to matched entry on success.
: dirlook ( file$ -- error? )
begin get-dent 0= while ( file$ )
2dup rr-file$ $= if ( file$ )
2drop false exit ( succeeded )
repeat 2drop true ( failed )
/buf-len instance buffer: symlink-buf
: symlink-buf$ ( -- path$ ) symlink-buf cscount ;
: follow-symlink ( tail$ -- tail$' )
\ copy symlink value (plus null) to buf
suf-sl-buf cscount 1+ symlink-buf swap move
" /" symlink-buf$ $append ( tail$ )
over c@ ascii / = if ( path$ )
: lookup ( path$ -- error? )
ascii / left-parse-string ( path$ file$ )
dup while ( path$ file$ )
2drop true exit ( failed )
follow-symlink ( path$' )
2drop 2drop false ( succeeded )
\ HSFS installation routines
\ Allocate memory for necessary data structures. Need to
\ read volume desriptor sector in order to get /block value.
: initialize ( -- error? )
/sector mem-alloc to vol-desc
/block mem-alloc to dir-buf
/block mem-alloc to sua-buf
/block mem-alloc to ce-buf
vol-desc /sector mem-free
#opens /file-record * constant /file-records
/file-records instance buffer: file-records
-1 instance value current-fd
: fd>record ( fd -- record ) /file-record * file-records + ;
: set-fd ( fd -- error? )
dup 0 #opens 1 - between 0= if
dup fd>record >block0 x@ 0= if
: file-offset@ ( -- off )
current-fd fd>record >offset x@
: file-offset! ( off -- )
current-fd fd>record >offset x!
current-fd fd>record >filesize x@
current-fd fd>record >filesize x!
: file-block0@ ( -- block0 )
current-fd fd>record >block0 x@
: file-block0! ( block0 -- )
current-fd fd>record >block0 x!
: get-slot ( -- fd false | true )
i fd>record >block0 x@ 0= if
\ initializes the open structure with information from
\ the inode (on UFS) or directory entry (from HSFS).
my-args dev-open dup 0= if ( 0 )
file-records /file-records erase
: open-file ( path$ -- fd true | false )
2drop false exit ( failed )
drop false exit ( failed )
dup init-fd true ( fd success )
: read-file ( adr len fd -- #read )
\ Check if fd is valid, if it is set current-fd.
\ Adjust len if less than len bytes remain.
file-size@ file-offset@ - min ( adr len' )
\ Check for invalid length read.
dup 0<= if 2drop 0 exit then
\ Compute physical device byte offset.
file-block0@ /block * file-offset@ + ( len adr len off )
dev-ih read-disk ( #read )
: seek-file ( off fd -- error? )
drop false exit ( failed )
dup file-size@ > if ( off )
drop false exit ( failed )
dup file-offset! true ( off succeeded )
: size-file ( fd -- size )
\ we don't support compression (yet)
: cinfo-file ( fd -- bsize fsize comp? )
set-fd if 0 0 0 else /block file-size@ 0 then
\ read ramdisk fcode at rd-offset
rd-offset dev-ih read-disk
\ no additional props needed for hsfs
: bootprop ( -- ) false ;
type ." Not a directory" cr
." size " dir-filesize .x