xref: /titanic_52/usr/src/psm/stand/bootblks/hsfs/common/hsfs.fth (revision c1ecd8b9404ee0d96d93f02e82c441b9bb149a3d)
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