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