4 \ The contents of this file are subject to the terms of the
5 \ Common Development and Distribution License (the "License").
6 \ You may not use this file except in compliance with the License.
8 \ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 \ or http://www.opensolaris.org/os/licensing.
10 \ See the License for the specific language governing permissions
11 \ and limitations under the License.
13 \ When distributing Covered Code, include this CDDL HEADER in each
14 \ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 \ If applicable, add the following below this CDDL HEADER, with the
16 \ fields enclosed by brackets "[]" replaced with your own identifying
17 \ information: Portions Copyright [yyyy] [name of copyright owner]
22 \ Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 \ Use is subject to license terms.
27 purpose: UFS file system support package
28 copyright: Copyright 2009 Sun Microsystems, Inc. All Rights Reserved
31 " /packages" get-package push-package
34 fs-pkg$ device-name diag-cr?
37 \ UFS low-level block routines
40 h# 2000 constant /max-bsize
41 d# 512 constant /disk-block
43 0 instance value dev-ih
44 0 instance value temp-block
46 : blk>byte ( block# -- byte# ) /disk-block * ;
48 : read-disk-blocks ( adr len dev-block# -- )
49 blk>byte dev-ih read-disk
54 \ UFS superblock routines
57 d# 512 constant /super-block
58 d# 16 constant super-block#
59 0 instance value super-block
61 : +sb ( index -- value ) super-block swap la+ l@ ;
62 : iblkno ( -- n ) d# 04 +sb ;
63 : cgoffset ( -- n ) d# 06 +sb ;
64 : cgmask ( -- n ) d# 07 +sb ;
65 : bsize ( -- n ) d# 12 +sb ;
66 : fragshift ( -- n ) d# 24 +sb ;
67 : fsbtodbc ( -- n ) d# 25 +sb ;
68 : inopb ( -- n ) d# 30 +sb ;
69 : ipg ( -- n ) d# 46 +sb ;
70 : fpg ( -- n ) d# 47 +sb ;
72 : /frag ( -- fragsize ) bsize fragshift rshift ;
74 : get-super-block ( -- )
75 super-block /super-block super-block# read-disk-blocks
78 : cgstart ( cg -- block# )
79 dup cgmask invert and cgoffset * swap fpg * +
81 : cgimin ( cg -- block# ) cgstart iblkno + ;
82 : blkstofrags ( #blocks -- #frags ) fragshift lshift ;
83 : lblkno ( byte-off -- lblk# ) bsize / ;
84 : blkoff ( byte-off -- blk-off ) bsize mod ;
85 : fsbtodb ( fs-blk# -- dev-blk# ) fsbtodbc lshift ;
87 : read-fs-blocks ( adr len fs-blk# -- ) fsbtodb read-disk-blocks ;
95 0 instance value inode
98 : itoo ( i# -- offset ) inopb mod ;
99 : itog ( i# -- group ) ipg / ;
100 : itod ( i# -- block# )
101 dup itog cgimin swap ipg mod inopb / blkstofrags +
104 : +i ( n -- adr ) iptr + ;
106 : ftype ( -- n ) 0 +i w@ h# f000 and ;
107 : dir? ( -- flag ) ftype h# 4000 = ;
108 : symlink? ( -- flag ) ftype h# a000 = ;
109 : regular? ( -- flag ) ftype h# 8000 = ;
111 : file-size ( -- n ) 8 +i x@ ;
112 : direct0 ( -- adr ) d# 40 +i ;
113 : indirect0 ( -- adr ) d# 88 +i ;
114 : indirect1 ( -- adr ) d# 92 +i ;
115 : indirect2 ( -- adr ) d# 96 +i ;
116 : comp? ( -- flag ) d# 100 +i l@ 4 and 0<> ;
118 0 instance value current-file
120 dup temp-block bsize rot itod ( i# adr len blk# )
122 dup itoo /inode * temp-block + inode /inode move
127 : l@++ ( ptr -- value ) dup @ l@ /l rot +! ;
129 d# 12 constant #direct
130 : #blk-addr/blk bsize /l / ;
131 : #sgl-addr #blk-addr/blk ;
132 : #dbl-addr #sgl-addr #blk-addr/blk * ;
133 \ : #tri-addr #dbl-addr #blk-addr/blk * ;
135 : >1-idx ( blk# -- idx ) #blk-addr/blk mod ;
136 : >2-idx ( blk# -- idx ) #sgl-addr / >1-idx ;
137 \ : >3-idx ( blk# -- idx ) #dbl-addr / >1-idx ;
140 \ indirect block cache
141 \ we assume reads will mostly be sequential, and only
142 \ cache the current indirect block tree
144 : get-indir ( fs-blk# var adr -- adr )
145 -rot dup >r @ over = if ( adr fs-blk# r: var )
146 r> 2drop exit ( adr )
147 then ( adr fs-blk# r: var )
148 2dup bsize swap read-fs-blocks ( adr fs-blk# r: var )
152 0 instance value indir0-adr
153 instance variable cur-indir0
154 : get-indir0 ( fs-blk# -- adr )
155 cur-indir0 indir0-adr get-indir
158 0 instance value indir1-adr
159 instance variable cur-indir1
160 : get-indir1 ( fs-blk# -- adr )
161 cur-indir1 indir1-adr get-indir
165 \ blkptr and blklim point to an array of blk#s,
166 \ whether in the inode direct block array or in
169 instance variable blkptr
170 instance variable blklim
172 : (bmap) ( lblk# -- )
173 dup #direct < if ( lblk# )
174 direct0 swap la+ blkptr ! ( )
175 direct0 #direct la+ blklim !
181 indirect0 l@ get-indir0 ( lblk# adr )
182 tuck swap >1-idx la+ blkptr ! ( adr )
183 #blk-addr/blk la+ blklim !
187 #sgl-addr - ( lblk#' )
189 indirect1 l@ get-indir0 ( lblk# adr )
190 over >2-idx la+ l@ get-indir1 ( lblk# adr' )
191 tuck swap >1-idx la+ blkptr ! ( adr )
192 #blk-addr/blk la+ blklim ! ( )
196 \ #dbl-addr - ( lblk#' )
198 \ indirect2 l@ get-indir0 ( lblk# adr )
199 \ over >3-idx la+ l@ get-indir1 ( lblk# adr' )
200 \ over >2-idx la+ l@ get-indir2 ( lblk# adr' )
201 \ tuck swap >1-idx la+ blkptr ! ( adr )
202 \ #blk-addr/blk la+ blklim ! ( )
205 ." file too large" cr drop true ( failed )
208 0 instance value cur-blk
209 : bmap ( lblk# -- fs-blk# )
210 dup cur-blk <> blkptr @ blklim @ = or if ( lblk# )
214 blkptr l@++ ( fs-blk# )
217 : read-one-block ( adr block# -- )
219 bsize swap read-fs-blocks
225 : read-partial-block ( adr len off block# -- )
227 fsbtodb blk>byte + ( adr len byte# )
235 \ UFS directory routines
238 instance variable dir-blk
239 instance variable totoff
240 instance variable dirptr
241 0 instance value dir-buf
244 dir-buf bsize dir-blk @ bmap ( adr len fs-blk# )
251 : +d ( n -- adr ) dirptr @ + ;
253 : dir-ino ( -- adr ) 0 +d l@ ;
254 : reclen ( -- adr ) 4 +d w@ ;
255 : namelen ( -- adr ) 6 +d w@ ;
256 : dir-name ( -- adr ) 8 +d ;
257 : dir-name$ ( -- file$ ) dir-name namelen ;
261 \ UFS high-level routines
263 \ After this point, the code should be independent of the disk format!
265 0 instance value search-dir
267 0 totoff ! 0 dir-blk !
268 current-file to search-dir
271 : get-dent ( -- end-of-dir? )
273 totoff @ file-size >= if
276 totoff @ blkoff 0= if
287 : dirlook ( file$ -- not-found? )
289 begin get-dent 0= while ( file$ )
290 2dup dir-name$ $= if ( file$ )
291 dir-ino iget ( file$ )
292 2drop false exit ( found )
294 repeat 2drop true ( not-found )
297 h# 200 constant /fpath-buf
298 /fpath-buf instance buffer: fpath-buf
299 : clr-fpath-buf ( -- ) fpath-buf /fpath-buf erase ;
300 : fpath-buf$ ( -- path$ ) fpath-buf cscount ;
302 : follow-symlink ( tail$ -- tail$' )
303 clr-fpath-buf ( tail$ )
304 fpath-buf file-size 0 0 read-partial-block ( tail$ )
306 " /" fpath-buf$ $append ( tail$ )
307 fpath-buf$ $append ( )
310 over c@ ascii / = if ( path$ )
311 str++ rootino ( path$' i# )
313 search-dir ( path$ i# )
318 : lookup ( path$ -- not-found? )
320 str++ rootino ( path$' i# )
322 current-file ( path$ i# )
326 ascii / left-parse-string ( path$ file$ )
328 dir? 0= if 2drop true exit then
329 dirlook if 2drop true exit then ( path$ )
331 follow-symlink ( path$' )
333 repeat ( path$ file$ )
334 2drop 2drop false ( succeeded )
337 : i#>name ( i# -- name$ )
339 begin get-dent 0= while ( i# )
340 dup dir-ino = if ( i# )
341 drop dir-name$ exit ( name$ )
343 repeat drop " ???" ( name$ )
348 \ UFS installation routines
356 \ **** Allocate memory for necessary data structures
357 : allocate-buffers ( -- )
358 alloc-size mem-alloc dup 0= if
361 dup to temp-block /max-bsize + ( adr )
362 dup to dir-buf /max-bsize + ( adr )
363 dup to indir0-adr /max-bsize + ( adr )
364 dup to indir1-adr /max-bsize + ( adr )
365 dup to super-block /super-block + ( adr )
369 : release-buffers ( -- )
370 temp-block alloc-size mem-free
379 constant /file-record
381 d# 10 constant #opens
382 #opens /file-record * constant /file-records
384 /file-records instance buffer: file-records
386 -1 instance value current-fd
387 : fd>record ( fd -- record ) /file-record * file-records + ;
390 : file-offset@ ( -- off )
391 current-fd fd>record >offset x@
394 : file-offset! ( off -- )
395 current-fd fd>record >offset x!
398 : get-slot ( -- fd false | true )
400 i fd>record >busy x@ 0= if
406 : free-slot ( fd -- )
407 0 swap fd>record >busy x!
413 dup >inode inode swap /inode move
417 : set-fd ( fd -- error? )
418 dup fd>record dup >busy x@ 0= if ( fd rec )
419 2drop true exit ( failed )
421 >inode to iptr ( fd )
422 to current-fd false ( succeeded )
426 \ get current lblk# and offset within it
427 : file-blk+off ( -- off block# )
428 file-offset@ dup blkoff swap lblkno
431 \ advance file io stack by n
432 : fio+ ( # adr len n -- #+n adr+n len-n )
433 dup file-offset@ + file-offset!
434 dup >r - -rot ( len' # adr r: n )
435 r@ + -rot ( adr' len' # r: n )
436 r> + -rot ( #' adr' len' )
439 : (cwd) ( i# -- ) tokenizer[ reveal ]tokenizer
441 \ open parent, find current name
444 \ recurse to print path components above
445 current-file (cwd) ( name$ )
446 \ and print this component
449 \ slash is both root name and separator
456 my-args dev-open dup 0= if ( 0 )
462 file-records /file-records erase
472 : open-file ( path$ -- fd true | false )
474 2drop false exit ( failed )
475 then -rot ( fd path$ )
478 drop false exit ( failed )
481 dup init-fd true ( fd succeeded )
484 : close-file ( fd -- )
488 : size-file ( fd -- size )
489 set-fd if 0 else file-size then
492 : seek-file ( off fd -- off true | false )
494 drop false exit ( failed )
497 dup file-size > if ( off )
498 drop false exit ( failed )
500 dup file-offset! true ( off succeeded )
503 : read-file ( adr len fd -- #read )
504 set-fd if ( adr len )
508 regular? 0= if 2drop 0 exit then
510 \ adjust len if reading past eof
511 dup file-offset@ + file-size > if
512 dup file-offset@ + file-size - -
514 dup 0= if nip exit then
516 0 -rot ( #read adr len )
518 \ initial partial block
519 file-offset@ blkoff ?dup if ( #read adr len off )
520 bsize swap - over min ( #read adr len len' )
521 3dup nip file-blk+off ( #read adr len len' adr len' off lblk# )
522 read-partial-block ( #read adr len len )
523 fio+ ( #read' adr' len' )
524 then ( #read adr len )
526 dup lblkno 0 ?do ( #read adr len )
527 over file-blk+off nip ( #read adr len adr lblk# )
528 read-one-block ( #read adr len )
529 bsize fio+ ( #read' adr' len' )
530 loop ( #read adr len )
532 \ final partial block
533 dup if ( #read adr len )
534 2dup file-blk+off ( #read adr len adr len off lblk# )
535 read-partial-block ( #read adr len )
536 dup fio+ ( #read' adr' 0 )
540 : cinfo-file ( fd -- bsize fsize comp? )
541 set-fd if 0 0 0 else bsize file-size comp? then
544 \ read ramdisk fcode at rd-offset
545 : get-rd ( adr len -- )
546 rd-offset dev-ih read-disk
549 \ no additional props needed for ufs
550 : bootprop ( -- ) false ;
556 current-file -rot ( i# dir$ )
559 ." no such dir" cr exit
563 ." not a dir" cr exit
570 begin get-dent 0= while