1\ 2\ CDDL HEADER START 3\ 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. 7\ 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. 12\ 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] 18\ 19\ CDDL HEADER END 20\ 21\ 22\ Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23\ Use is subject to license terms. 24\ 25 26 27purpose: UFS file system support package 28copyright: Copyright 2009 Sun Microsystems, Inc. All Rights Reserved 29 30headers 31" /packages" get-package push-package 32 33new-device 34 fs-pkg$ device-name diag-cr? 35 36 \ 37 \ UFS low-level block routines 38 \ 39 40 h# 2000 constant /max-bsize 41 d# 512 constant /disk-block 42 43 0 instance value dev-ih 44 0 instance value temp-block 45 46 : blk>byte ( block# -- byte# ) /disk-block * ; 47 48 : read-disk-blocks ( adr len dev-block# -- ) 49 blk>byte dev-ih read-disk 50 ; 51 52 53 \ 54 \ UFS superblock routines 55 \ 56 57 d# 512 constant /super-block 58 d# 16 constant super-block# 59 0 instance value super-block 60 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 ; 71 72 : /frag ( -- fragsize ) bsize fragshift rshift ; 73 74 : get-super-block ( -- ) 75 super-block /super-block super-block# read-disk-blocks 76 ; 77 78 : cgstart ( cg -- block# ) 79 dup cgmask invert and cgoffset * swap fpg * + 80 ; 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 ; 86 87 : read-fs-blocks ( adr len fs-blk# -- ) fsbtodb read-disk-blocks ; 88 89 90 \ 91 \ UFS inode routines 92 \ 93 94 h# 80 constant /inode 95 0 instance value inode 96 0 instance value iptr 97 98 : itoo ( i# -- offset ) inopb mod ; 99 : itog ( i# -- group ) ipg / ; 100 : itod ( i# -- block# ) 101 dup itog cgimin swap ipg mod inopb / blkstofrags + 102 ; 103 104 : +i ( n -- adr ) iptr + ; 105 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 = ; 110 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<> ; 117 118 0 instance value current-file 119 : iget ( i# -- ) 120 dup temp-block bsize rot itod ( i# adr len blk# ) 121 read-fs-blocks 122 dup itoo /inode * temp-block + inode /inode move 123 inode to iptr 124 to current-file ( ) 125 ; 126 127 : l@++ ( ptr -- value ) dup @ l@ /l rot +! ; 128 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 * ; 134 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 ; 138 139 \ 140 \ indirect block cache 141 \ we assume reads will mostly be sequential, and only 142 \ cache the current indirect block tree 143 \ 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 ) 149 r> ! ( adr ) 150 ; 151 152 0 instance value indir0-adr 153 instance variable cur-indir0 154 : get-indir0 ( fs-blk# -- adr ) 155 cur-indir0 indir0-adr get-indir 156 ; 157 158 0 instance value indir1-adr 159 instance variable cur-indir1 160 : get-indir1 ( fs-blk# -- adr ) 161 cur-indir1 indir1-adr get-indir 162 ; 163 164 \ 165 \ blkptr and blklim point to an array of blk#s, 166 \ whether in the inode direct block array or in 167 \ an indirect block 168 \ 169 instance variable blkptr 170 instance variable blklim 171 172 : (bmap) ( lblk# -- ) 173 dup #direct < if ( lblk# ) 174 direct0 swap la+ blkptr ! ( ) 175 direct0 #direct la+ blklim ! 176 exit 177 then ( lblk# ) 178 179 #direct - ( lblk#' ) 180 dup #sgl-addr < if 181 indirect0 l@ get-indir0 ( lblk# adr ) 182 tuck swap >1-idx la+ blkptr ! ( adr ) 183 #blk-addr/blk la+ blklim ! 184 exit 185 then ( lblk# ) 186 187 #sgl-addr - ( lblk#' ) 188 dup #dbl-addr < if 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 ! ( ) 193 exit 194 then ( lblk# ) 195 196\ #dbl-addr - ( lblk#' ) 197\ dup #tri-addr < if 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 ! ( ) 203\ exit 204\ then ( lblk# ) 205 ." file too large" cr drop true ( failed ) 206 ; 207 208 0 instance value cur-blk 209 : bmap ( lblk# -- fs-blk# ) 210 dup cur-blk <> blkptr @ blklim @ = or if ( lblk# ) 211 dup (bmap) ( lblk# ) 212 then ( lblk# ) 213 1+ to cur-blk ( ) 214 blkptr l@++ ( fs-blk# ) 215 ; 216 217 : read-one-block ( adr block# -- ) 218 bmap ?dup if 219 bsize swap read-fs-blocks 220 else 221 bsize erase 222 then 223 ; 224 225 : read-partial-block ( adr len off block# -- ) 226 bmap ?dup if 227 fsbtodb blk>byte + ( adr len byte# ) 228 dev-ih read-disk 229 else 230 drop erase 231 then 232 ; 233 234 \ 235 \ UFS directory routines 236 \ 237 238 instance variable dir-blk 239 instance variable totoff 240 instance variable dirptr 241 0 instance value dir-buf 242 243 : get-dirblk ( -- ) 244 dir-buf bsize dir-blk @ bmap ( adr len fs-blk# ) 245 read-fs-blocks ( ) 246 1 dir-blk +! 247 ; 248 249 2 constant rootino 250 251 : +d ( n -- adr ) dirptr @ + ; 252 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 ; 258 259 260 \ 261 \ UFS high-level routines 262 \ 263 \ After this point, the code should be independent of the disk format! 264 265 0 instance value search-dir 266 : init-dent 267 0 totoff ! 0 dir-blk ! 268 current-file to search-dir 269 ; 270 271 : get-dent ( -- end-of-dir? ) 272 begin 273 totoff @ file-size >= if 274 true exit 275 then 276 totoff @ blkoff 0= if 277 get-dirblk 278 dir-buf dirptr ! 279 else 280 reclen dirptr +! 281 then 282 reclen totoff +! 283 dir-ino 0<> 284 until false 285 ; 286 287 : dirlook ( file$ -- not-found? ) 288 init-dent 289 begin get-dent 0= while ( file$ ) 290 2dup dir-name$ $= if ( file$ ) 291 dir-ino iget ( file$ ) 292 2drop false exit ( found ) 293 then ( file$ ) 294 repeat 2drop true ( not-found ) 295 ; 296 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 ; 301 302 : follow-symlink ( tail$ -- tail$' ) 303 clr-fpath-buf ( tail$ ) 304 fpath-buf file-size 0 0 read-partial-block ( tail$ ) 305 ?dup if ( tail$ ) 306 " /" fpath-buf$ $append ( tail$ ) 307 fpath-buf$ $append ( ) 308 else drop then ( ) 309 fpath-buf$ ( path$ ) 310 over c@ ascii / = if ( path$ ) 311 str++ rootino ( path$' i# ) 312 else ( path$ ) 313 search-dir ( path$ i# ) 314 then ( path$ i# ) 315 iget ( path$ ) 316 ; 317 318 : lookup ( path$ -- not-found? ) 319 over c@ ascii / = if 320 str++ rootino ( path$' i# ) 321 else 322 current-file ( path$ i# ) 323 then ( path$ i# ) 324 iget ( path$ ) 325 begin ( path$ ) 326 ascii / left-parse-string ( path$ file$ ) 327 dup while 328 dir? 0= if 2drop true exit then 329 dirlook if 2drop true exit then ( path$ ) 330 symlink? if 331 follow-symlink ( path$' ) 332 then ( path$ ) 333 repeat ( path$ file$ ) 334 2drop 2drop false ( succeeded ) 335 ; 336 337 : i#>name ( i# -- name$ ) 338 init-dent ( i# ) 339 begin get-dent 0= while ( i# ) 340 dup dir-ino = if ( i# ) 341 drop dir-name$ exit ( name$ ) 342 then ( i# ) 343 repeat drop " ???" ( name$ ) 344 ; 345 346 347 \ 348 \ UFS installation routines 349 \ 350 351 /max-bsize 4 * 352 /super-block + 353 /inode + 354 constant alloc-size 355 356 \ **** Allocate memory for necessary data structures 357 : allocate-buffers ( -- ) 358 alloc-size mem-alloc dup 0= if 359 ." no memory" abort 360 then ( adr ) 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 ) 366 to inode ( ) 367 ; 368 369 : release-buffers ( -- ) 370 temp-block alloc-size mem-free 371 ; 372 373 \ UFS file interface 374 375 struct 376 /x field >busy 377 /x field >offset 378 /inode field >inode 379 constant /file-record 380 381 d# 10 constant #opens 382 #opens /file-record * constant /file-records 383 384 /file-records instance buffer: file-records 385 386 -1 instance value current-fd 387 : fd>record ( fd -- record ) /file-record * file-records + ; 388 389 390 : file-offset@ ( -- off ) 391 current-fd fd>record >offset x@ 392 ; 393 394 : file-offset! ( off -- ) 395 current-fd fd>record >offset x! 396 ; 397 398 : get-slot ( -- fd false | true ) 399 #opens 0 do 400 i fd>record >busy x@ 0= if 401 i false unloop exit 402 then 403 loop true 404 ; 405 406 : free-slot ( fd -- ) 407 0 swap fd>record >busy x! 408 ; 409 410 : init-fd ( fd -- ) 411 fd>record ( rec ) 412 dup >busy 1 swap x! 413 dup >inode inode swap /inode move 414 >offset 0 swap x! 415 ; 416 417 : set-fd ( fd -- error? ) 418 dup fd>record dup >busy x@ 0= if ( fd rec ) 419 2drop true exit ( failed ) 420 then 421 >inode to iptr ( fd ) 422 to current-fd false ( succeeded ) 423 ; 424 425 426 \ get current lblk# and offset within it 427 : file-blk+off ( -- off block# ) 428 file-offset@ dup blkoff swap lblkno 429 ; 430 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' ) 437 ; 438 439 : (cwd) ( i# -- ) tokenizer[ reveal ]tokenizer 440 dup rootino <> if 441 \ open parent, find current name 442 " .." lookup drop 443 i#>name ( name$ ) 444 \ recurse to print path components above 445 current-file (cwd) ( name$ ) 446 \ and print this component 447 type ( ) 448 else drop then ( ) 449 \ slash is both root name and separator 450 ." /" 451 ; 452 453 external 454 455 : open ( -- okay? ) 456 my-args dev-open dup 0= if ( 0 ) 457 exit ( failed ) 458 then to dev-ih 459 460 allocate-buffers 461 get-super-block 462 file-records /file-records erase 463 true ( succeeded ) 464 ; 465 466 : close ( -- ) 467 dev-ih dev-close 468 0 to dev-ih 469 release-buffers 470 ; 471 472 : open-file ( path$ -- fd true | false ) 473 get-slot if 474 2drop false exit ( failed ) 475 then -rot ( fd path$ ) 476 477 lookup if ( fd ) 478 drop false exit ( failed ) 479 then 480 481 dup init-fd true ( fd succeeded ) 482 ; 483 484 : close-file ( fd -- ) 485 free-slot ( ) 486 ; 487 488 : size-file ( fd -- size ) 489 set-fd if 0 else file-size then 490 ; 491 492 : seek-file ( off fd -- off true | false ) 493 set-fd if ( off ) 494 drop false exit ( failed ) 495 then ( off ) 496 497 dup file-size > if ( off ) 498 drop false exit ( failed ) 499 then ( off ) 500 dup file-offset! true ( off succeeded ) 501 ; 502 503 : read-file ( adr len fd -- #read ) 504 set-fd if ( adr len ) 505 2drop 0 exit ( 0 ) 506 then ( adr len ) 507 508 regular? 0= if 2drop 0 exit then 509 510 \ adjust len if reading past eof 511 dup file-offset@ + file-size > if 512 dup file-offset@ + file-size - - 513 then 514 dup 0= if nip exit then 515 516 0 -rot ( #read adr len ) 517 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 ) 525 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 ) 531 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 ) 537 then 2drop ( #read ) 538 ; 539 540 : cinfo-file ( fd -- bsize fsize comp? ) 541 set-fd if 0 0 0 else bsize file-size comp? then 542 ; 543 544 \ read ramdisk fcode at rd-offset 545 : get-rd ( adr len -- ) 546 rd-offset dev-ih read-disk 547 ; 548 549 \ no additional props needed for ufs 550 : bootprop ( -- ) false ; 551 552 \ debug words 553 headers 554 555 : chdir ( dir$ -- ) 556 current-file -rot ( i# dir$ ) 557 lookup if ( i# ) 558 to current-file ( ) 559 ." no such dir" cr exit 560 then ( i# ) 561 dir? 0= if ( i# ) 562 to current-file ( ) 563 ." not a dir" cr exit 564 then drop ( ) 565 ; 566 567 : dir ( -- ) 568 current-file iget 569 init-dent 570 begin get-dent 0= while 571 dir-name$ type cr 572 repeat 573 ; 574 575 : cwd ( -- ) 576 current-file ( i# ) 577 dup (cwd) cr ( i# ) 578 iget ( ) 579 ; 580 581finish-device 582pop-package 583