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