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 27id: %Z%%M% %I% %E% SMI 28purpose: HSFS file system support package for NewBoot 29copyright: Copyright 2006 Sun Microsystems, Inc. All Rights Reserved 30 31\ High Sierra, Rock Ridge (CD-ROM) file system reader and boot block 32 33headers 34" /packages" get-package push-package 35 36new-device 37 fs-pkg$ device-name diag-cr? 38 39 \ 40 \ HSFS variables 41 \ 42 0 instance value dev-ih 43 0 instance value vol-desc 44 0 instance value dir-buf 45 0 instance value sua-buf 46 0 instance value ce-buf 47 48 \ 49 \ HSFS volume descriptor routines 50 \ 51 52 \ unaligned load of 2-byte item 53 : xw@ ( adr -- n ) 54 dup c@ swap char+ ( c0 adr+1 ) 55 c@ ( c0 c1 ) 56 bwjoin 57 ; 58 59 \ unaligned store of 2-byte item 60 : xw! ( n adr -- ) 61 swap wbsplit swap 2 pick c! swap char+ c! 62 ; 63 64 \ unaligned load of 4-byte item 65 : xl@ ( adr -- n ) 66 dup xw@ swap wa1+ ( w0 adr+2 ) 67 xw@ ( w0 w1 ) 68 wljoin 69 ; 70 \ unaligned store of 4-byte item 71 : xl! ( n adr -- ) 72 swap lwsplit swap 2 pick xw! swap wa1+ xw! 73 ; 74 75 d# 2048 constant /sector 76 d# 16 constant vol-desc-sector# ( -- n ) 77 78 : +vd ( index -- adr ) 79 vol-desc 0= if 80 ." invalid access of +vd" cr abort 81 then 82 vol-desc + 83 ; 84 85 : root-dir ( -- n ) d# 156 +vd ; 86 : /block ( -- n ) d# 128 +vd xw@ ; 87 : byte>blkoff ( byte-off -- block-off ) /block mod ; 88 89 : get-vol-desc ( -- ) 90 vol-desc /sector vol-desc-sector# /sector * dev-ih read-disk 91 ; 92 93 : read-fs-blocks ( adr len fs-blk# -- ) /block * dev-ih read-disk ; 94 95 \ 96 \ HSFS directory routines 97 \ 98 99 \ Current directory variables. 100 instance variable cdir-blk \ Current directory device block ptr. 101 instance variable cdir-blk0 \ Current directory block0. 102 instance variable cdir-offset \ Current directory logical offset. 103 instance variable cdir-size \ Current directory logical size. 104 instance variable cdir-ptr \ Current directory entry pointer. 105 false instance value cdir-rescan \ Rescan current directory for symlink. 106 107 \ Access of current directory entry. 108 : +dr ( n -- adr ) cdir-ptr @ + ; 109 110 : dir-entrylen ( -- n ) d# 0 +dr c@ ; 111 : dir-block0 ( -- n ) d# 2 +dr xl@ ; 112 : dir-block0! ( n -- ) d# 2 +dr xl! ; 113 : dir-filesize ( -- n ) d# 10 +dr xl@ ; 114 : dir-filesize! ( n -- ) d# 10 +dr xl! ; 115 : dir-flags ( -- n ) d# 25 +dr c@ ; 116 : dir-flags! ( n -- ) d# 25 +dr c! ; 117 : dir-filenamelen ( -- n ) d# 32 +dr c@ ; 118 : dir-filename ( -- adr ) d# 33 +dr ; 119 120 : dir-isdir? ( -- flag ) dir-flags h# 02 and 0<> ; 121 : dir-setdir ( -- ) h# 02 dir-flags! ; 122 : dir-file$ ( -- adr len ) dir-filename dir-filenamelen ; 123 : dir-sualen ( -- len ) dir-entrylen d# 33 - dir-filenamelen - ; 124 125 false instance value symlink? 126 127 : get-dirblk ( -- ) 128 dir-buf /block cdir-blk @ read-fs-blocks 129 1 cdir-blk +! 130 ; 131 132 : root-dir? ( -- flag ) root-dir cdir-ptr = ; 133 : froot ( -- ) root-dir cdir-ptr ! ; 134 135 \ 136 \ SUAs - System Use Area in directory entry (Rock Ridge 137 \ Extensions to High Sierra/ISO 9660 Format). 138 \ Immediately follows directory entry name rounded up to 139 \ a half-word boundary. 140 \ 141 0 instance value sua-ptr 142 0 instance value sua-len 143 144 : +suf ( n -- adr ) sua-ptr + ; 145 : suf-sig ( -- adr len ) sua-ptr 2 ; 146 : suf-len ( -- len ) 2 +suf c@ ; 147 : suf-dat ( -- data ) 5 +suf ; 148 : suf-ce-lbn ( -- lbn ) 4 +suf xl@ ; 149 : suf-ce-offset ( -- offset ) d# 12 +suf xl@ ; 150 : suf-ce-len ( -- len ) d# 20 +suf xl@ ; 151 152 : init-sua ( -- ) 153 dir-file$ + /w roundup to sua-ptr 154 dir-sualen to sua-len 155 ; 156 157 : next-suf ( -- ) 158 sua-len suf-len - to sua-len 159 suf-len +suf to sua-ptr 160 ; 161 162 : end-sua ( -- end? ) 163 sua-len 4 < 164 ; 165 166 : suf-nm$ ( -- adr len ) suf-dat suf-len 5 - ; 167 168 \ Continuation suffix handling. When a 'CE' suffix is seen, 169 \ record the CE parameters (logical block#, offset and length 170 \ of continuation). We process the CE continuation only after 171 \ we've finished processing the current SUA area. 172 instance variable ce-lbn 173 instance variable ce-offset 174 instance variable ce-len 175 : suf-ce-set ( -- ) 176 suf-ce-lbn ce-lbn ! 177 suf-ce-offset ce-offset ! 178 suf-ce-len ce-len ! 179 ; 180 181 : suf-ce-process ( -- error? ) 182 ce-lbn @ 0= if 183 true 184 else 185 sua-buf ce-len @ ce-lbn @ read-fs-blocks 186 sua-buf to sua-ptr 187 ce-len @ to sua-len 188 0 ce-len ! 0 ce-lbn ! 0 ce-offset ! 189 false 190 then 191 ; 192 193 /buf-len instance buffer: suf-sl-buf 194 false instance value symlink-need-sep 195 196 \ Format of Rock Ridge symlinks needs to be munged to unix-style 197 \ name. Format is: <flag><nbytes>file-name<flag><nbytes>filename... 198 \ where \ <flag> is flag byte (0=filename, 2=current dir, 4=parent 199 \ dir, 8=root dir) and <nbytes> is one-byte byte count (zero for 200 \ !filename). 201 : suf-copy-to-symlinkbuf ( name$ -- ) 202 false to symlink-need-sep 203 suf-sl-buf -rot bounds do ( dst ) 204 symlink-need-sep if 205 ascii / over c! char+ 206 then 207 true to symlink-need-sep 208 i c@ dup 2 = if ( dst 2 ) 209 \ CURRENT (".") 210 drop ascii . over c! char+ 2 ( dst' inc ) 211 else dup 4 = if ( dst 4 ) 212 \ PARENT ("..") 213 drop " .." 2 pick swap move ( dst ) 214 wa1+ 2 ( dst' inc ) 215 else dup 8 = if ( dst 8 ) 216 \ ROOT ("/") 217 drop ascii / over c! char+ 2 ( dst' inc ) 218 false to symlink-need-sep 219 else dup 0<> if 220 ." unknown SL flag: " .x cr abort 221 else ( dst c ) 222 drop ( dst ) 223 i char+ dup c@ >r ( dst src+1 R:nbytes ) 224 char+ over r@ move ( dst R:nbytes ) 225 r@ + ( dst' R:nbytes ) 226 r> wa1+ ( dst' inc ) 227 then then then then 228 +loop ( dst ) 229 0 swap c! 230 ; 231 232 \ Saved 'NM' prefix buffer. 233 /buf-len instance buffer: suf-nm-buf 234 0 instance value suf-nm-size 235 236 \ Return the Rock Ridge file name associated with the current 237 \ dirent ('NM' suffix). Otherwise returns standard iso filename. 238 \ Marks whether returned filename is a symbolic link ('SL' suffix) 239 \ and also processes continuations ('CE' suffix). 240 : rr-file$ ( -- adr len ) 241 false to symlink? 242 0 to suf-nm-size 243 244 \ select start of sua, record sua offset 245 init-sua 246 begin 247 end-sua if 248 suf-ce-process if 249 suf-nm-size if 250 suf-nm-buf suf-nm-size 251 else 252 dir-file$ 253 then 254 exit 255 then 256 then 257 suf-sig ( sig-adr sig-len ) 258 2dup " NM" $= if 259 suf-nm$ to suf-nm-size ( sig-adr sig-len suf-nm-adr ) 260 suf-nm-buf suf-nm-size move 261 then ( sig-adr sig-len ) 262 2dup " SL" $= if 263 true to symlink? 264 suf-nm$ suf-copy-to-symlinkbuf 265 then 266 2dup " CE" $= if 267 suf-ce-set 268 then ( sig-adr sig-len ) 269 2drop next-suf ( ) 270 again 271 ; 272 273 \ 274 \ HSFS high-level routines 275 \ 276 277 \ Used for rescanning current directory for symbolic links. 278 279 \ Initializes current directory settings from current directory 280 \ entry pointer or for rescan. If it's not a rescan, we have 281 \ access to the actual directory entry, so we can check whether 282 \ it's a directory or not here. 283 : init-dent ( -- error? ) 284 cdir-rescan if 285 false to cdir-rescan 286 cdir-blk0 @ cdir-blk ! 287 else 288 dir-isdir? 0= if 289 true exit 290 then 291 dir-block0 dup cdir-blk ! cdir-blk0 ! 292 dir-filesize cdir-size ! 293 then ( blk0 size ) 294 0 cdir-offset ! 295 false 296 ; 297 298 : get-dent ( -- error? ) 299 begin 300 \ Check for end of directory, return true if we're past the EOF. 301 cdir-offset @ cdir-size @ >= if 302 true exit 303 then 304 305 \ If we're at a block boundary, get the next block. Otherwise 306 \ increment the directory pointer. 307 cdir-offset @ byte>blkoff 0= if 308 get-dirblk 309 dir-buf cdir-ptr ! 310 else 311 dir-entrylen cdir-ptr +! 312 then 313 314 \ If dir-entrylen is not zero, increment the current directory 315 \ file offset. Otherwise, a dir-entrylen of zero indicates 316 \ the end of a dir block, so round up cdir-offset to fetch the 317 \ next one 318 dir-entrylen ?dup if 319 cdir-offset +! true 320 else 321 cdir-offset @ /block roundup cdir-offset ! 322 false 323 then 324 until false 325 ; 326 327 \ directory stack 328 struct 329 /x field >dirs-size 330 /x field >dirs-block0 331 constant /dirs-stack 332 333 d# 10 constant #dirs-stack 334 #dirs-stack /dirs-stack * instance buffer: dirs-stack 335 instance variable dirs-stackp 336 337 : dirs-init ( -- ) 338 dirs-stack dirs-stackp ! 339 ; 340 : dirs-push ( -- ) 341 dir-isdir? if 342 dirs-stackp @ 343 cdir-blk0 @ over >dirs-block0 ! 344 cdir-size @ over >dirs-size ! 345 /dirs-stack + dirs-stackp ! 346 then 347 ; 348 : dirs-pop ( -- ) 349 dirs-stackp @ dup dirs-stack = if 350 froot exit 351 then 352 /dirs-stack - 353 dup >dirs-block0 @ dir-block0! 354 dup >dirs-size @ dir-filesize! 355 dirs-stackp ! 356 dir-setdir 357 ; 358 359 \ Look through current directory for file name 'file$'. 360 \ Will leave current directory entry (cdir-ptr) pointing 361 \ to matched entry on success. 362 : dirlook ( file$ -- error? ) 363 init-dent if 364 true exit 365 then 366 2dup " .." $= if 367 2drop dirs-pop false exit 368 then 369 2dup " ." $= if 370 2drop true to cdir-rescan false exit 371 then 372 373 begin get-dent 0= while ( file$ ) 374 2dup rr-file$ $= if ( file$ ) 375 2drop dirs-push false exit ( succeeded ) 376 then ( file$ ) 377 repeat 2drop true ( failed ) 378 ; 379 380 /buf-len instance buffer: symlink-buf 381 : symlink-buf$ ( -- path$ ) symlink-buf cscount ; 382 383 : follow-symlink ( tail$ -- tail$' ) 384 385 \ copy symlink value (plus null) to buf 386 suf-sl-buf cscount 1+ symlink-buf swap move 387 false to symlink? 388 389 \ append to current path 390 ?dup if ( tail$ ) 391 " /" symlink-buf$ $append ( tail$ ) 392 symlink-buf$ $append ( ) 393 else drop then ( ) 394 symlink-buf$ ( path$ ) 395 over c@ ascii / = if ( path$ ) 396 froot str++ ( path$' ) 397 else 398 true to cdir-rescan 399 then ( path$ ) 400 ; 401 402 : lookup ( path$ -- error? ) 403 dirs-init 404 over c@ ascii / = if 405 froot str++ ( path$' ) 406 then ( path$ ) 407 begin ( path$ ) 408 ascii / left-parse-string ( path$ file$ ) 409 dup while ( path$ file$ ) 410 dirlook if 411 2drop true exit ( failed ) 412 then ( path$ ) 413 symlink? if 414 follow-symlink ( path$' ) 415 then ( path$ ) 416 repeat ( path$ file$ ) 417 2drop 2drop false ( succeeded ) 418 ; 419 420 421 \ 422 \ HSFS installation routines 423 \ 424 425 \ Allocate memory for necessary data structures. Need to 426 \ read volume desriptor sector in order to get /block value. 427 : initialize ( -- error? ) 428 /sector mem-alloc to vol-desc 429 get-vol-desc 430 /block mem-alloc to dir-buf 431 /block mem-alloc to sua-buf 432 /block mem-alloc to ce-buf 433 ; 434 435 : release-buffers ( -- ) 436 ce-buf /block mem-free 437 sua-buf /block mem-free 438 dir-buf /block mem-free 439 vol-desc /sector mem-free 440 0 to vol-desc 441 ; 442 443 444 \ HSFS file interface 445 struct 446 /x field >filesize 447 /x field >offset 448 /x field >block0 449 constant /file-record 450 451 d# 10 constant #opens 452 #opens /file-record * constant /file-records 453 454 /file-records instance buffer: file-records 455 456 -1 instance value current-fd 457 458 : fd>record ( fd -- record ) /file-record * file-records + ; 459 460 : set-fd ( fd -- error? ) 461 dup 0 #opens 1 - between 0= if 462 drop true exit 463 then 464 dup fd>record >block0 x@ 0= if 465 drop true exit 466 then 467 to current-fd false 468 ; 469 470 : file-offset@ ( -- off ) 471 current-fd fd>record >offset x@ 472 ; 473 474 : file-offset! ( off -- ) 475 current-fd fd>record >offset x! 476 ; 477 478 : file-size@ ( -- size ) 479 current-fd fd>record >filesize x@ 480 ; 481 482 : file-size! ( size -- ) 483 current-fd fd>record >filesize x! 484 ; 485 486 : file-block0@ ( -- block0 ) 487 current-fd fd>record >block0 x@ 488 ; 489 490 : file-block0! ( block0 -- ) 491 current-fd fd>record >block0 x! 492 ; 493 494 : get-slot ( -- fd false | true ) 495 #opens 0 do 496 i fd>record >block0 x@ 0= if 497 i false unloop exit 498 then 499 loop true 500 ; 501 502 : free-slot ( fd -- ) 503 set-fd 0= if 504 0 file-offset! 505 0 file-size! 506 0 file-block0! 507 then 508 ; 509 510 \ initializes the open structure with information from 511 \ the inode (on UFS) or directory entry (from HSFS). 512 : init-fd ( fd -- ) 513 to current-fd 514 dir-block0 file-block0! 515 dir-filesize file-size! 516 0 file-offset! 517 ; 518 519 external 520 521 : open ( -- okay? ) 522 my-args dev-open dup 0= if ( 0 ) 523 exit ( failed ) 524 then to dev-ih 525 526 initialize froot 527 file-records /file-records erase 528 true ( succeeded ) 529 ; 530 531 : close ( -- ) 532 dev-ih dev-close 533 release-buffers 534 ; 535 536 : open-file ( path$ -- fd true | false ) 537 get-slot if 538 2drop false exit ( failed ) 539 then -rot ( fd path$ ) 540 541 lookup if ( fd ) 542 drop false exit ( failed ) 543 then 544 545 dup init-fd true ( fd success ) 546 ; 547 548 : close-file ( fd -- ) 549 free-slot ( ) 550 ; 551 552 : read-file ( adr len fd -- #read ) 553 554 \ Check if fd is valid, if it is set current-fd. 555 set-fd if 556 2drop 0 exit 557 then ( adr len ) 558 559 \ Adjust len if less than len bytes remain. 560 file-size@ file-offset@ - min ( adr len' ) 561 562 \ Check for invalid length read. 563 dup 0<= if 2drop 0 exit then 564 565 \ Compute physical device byte offset. 566 tuck ( len adr len ) 567 file-block0@ /block * file-offset@ + ( len adr len off ) 568 dev-ih read-disk ( #read ) 569 ; 570 571 : seek-file ( off fd -- error? ) 572 set-fd if ( off ) 573 drop false exit ( failed ) 574 then ( off ) 575 576 dup file-size@ > if ( off ) 577 drop false exit ( failed ) 578 then ( off ) 579 dup file-offset! true ( off succeeded ) 580 ; 581 582 : size-file ( fd -- size ) 583 set-fd if 584 0 585 else 586 file-size@ 587 then 588 ; 589 590 \ we don't support compression (yet) 591 : cinfo-file ( fd -- bsize fsize comp? ) 592 set-fd if 0 0 0 else /block file-size@ 0 then 593 ; 594 595 \ read ramdisk fcode at rd-offset 596 : get-rd ( adr len -- ) 597 rd-offset dev-ih read-disk 598 ; 599 600 \ no additional props needed for hsfs 601 : bootprop ( -- ) false ; 602 603 \ debug words 604 : chdir ( path$ -- ) 605 2dup lookup if 606 type ." Not found" cr 607 else 608 dir-isdir? 0= if 609 type ." Not a directory" cr 610 else 611 type 612 ." blk0 " 613 cdir-blk0 @ .x 614 ." size " 615 cdir-size @ .x 616 cr 617 then 618 then 619 ; 620 621 : dir ( -- ) 622 init-dent 623 begin get-dent 0= while 624 rr-file$ type 625 ." flags " dir-flags .x 626 ." blk0 " dir-block0 .x 627 ." size " dir-filesize .x 628 cr 629 repeat 630 true to cdir-rescan 631 ; 632 633 634finish-device 635pop-package 636 637