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.
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.
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]
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
29 * Basic file system reading code for standalone I/O system.
30 * Simulates a primitive UNIX I/O system (read(), write(), open(), etc).
31 * Does not support writes.
34 #include <sys/param.h>
35 #include <sys/sysmacros.h>
36 #include <sys/vnode.h>
37 #include <sys/fs/ufs_fsdir.h>
38 #include <sys/fs/ufs_fs.h>
39 #include <sys/fs/ufs_inode.h>
41 #include <sys/fs/hsfs_spec.h>
42 #include <sys/fs/hsfs_isospec.h>
43 #include <sys/fs/hsfs_node.h>
44 #include <sys/fs/hsfs_susp.h>
45 #include <sys/fs/hsfs_rrip.h>
46 #include <sys/bootvfs.h>
47 #include <sys/filep.h>
50 #include "../common/util.h"
52 #include <sys/sunddi.h>
55 #define hdbtodb(n) ((ISO_SECTOR_SIZE / DEV_BSIZE) * (n))
57 #define HSFS_NUM_SIG 14
75 #define dprintf if (bootrd_debug) printf
77 #define printf kobj_printf
78 #define dprintf if (bootrd_debug) kobj_printf
81 extern void kobj_printf(char *, ...);
84 extern int bootrd_debug
;
85 extern void *bkmem_alloc(size_t);
86 extern void bkmem_free(void *, size_t);
87 extern int cf_check_compressed(fileid_t
*);
88 extern void cf_close(fileid_t
*);
89 extern void cf_seek(fileid_t
*, off_t
, int);
90 extern int cf_read(fileid_t
*, caddr_t
, size_t);
98 struct direct hs_ufs_dir
;
99 struct hs_direntry hs_dir
;
102 static uint_t root_ino
= 0;
103 static struct hs_volume
*hsfsp
;
104 static fileid_t
*head
;
106 static char *hsfs_sig_tab
[] = {
123 static int hsfs_num_sig
= sizeof (hsfs_sig_tab
) / sizeof (hsfs_sig_tab
[0]);
128 static struct hs_direct
*readdir(struct dirstuff
*);
129 static uint_t
parse_dir(fileid_t
*, int, struct hs_direct
*);
130 static uint_t
parse_susp(char *, uint_t
*, struct hs_direct
*);
131 static ino_t
dlook(char *, fileid_t
*);
132 static int opendir(ino_t
, fileid_t
*);
133 static ino_t
find(char *, fileid_t
*);
135 static int bhsfs_mountroot(char *str
);
136 static int bhsfs_unmountroot(void);
137 static int bhsfs_open(char *str
, int flags
);
138 static int bhsfs_close(int fd
);
139 static void bhsfs_closeall(void);
140 static ssize_t
bhsfs_read(int fdesc
, char *buf
, size_t count
);
141 static off_t
bhsfs_lseek(int fdesc
, off_t addr
, int whence
);
142 static int bhsfs_fstat(int fdesc
, struct bootstat
*stp
);
147 fileid_t
*filep
= head
;
150 while ((filep
= filep
->fi_forw
) != head
)
151 if (fd
== filep
->fi_filedes
)
152 return (filep
->fi_taken
? filep
: 0);
159 opendir(ino_t inode
, fileid_t
*filep
)
161 struct hs_direct hsdep
;
163 dprintf("opendir: inode = %ld\n", inode
);
164 /* Set up the IO request */
165 filep
->fi_offset
= 0;
166 filep
->fi_blocknum
= hdbtodb(inode
);
167 filep
->fi_count
= ISO_SECTOR_SIZE
;
173 filep
->fi_offset
= 0;
174 filep
->fi_blocknum
= hdbtodb(inode
);
176 if (inode
!= root_ino
)
179 if (parse_dir(filep
, 0, &hsdep
) > 0) {
182 ip
= filep
->fi_inode
;
184 ip
= filep
->fi_inode
= bkmem_alloc(sizeof (*ip
));
186 ip
->i_size
= hsdep
.hs_dir
.ext_size
;
187 ip
->i_smode
= hsdep
.hs_dir
.mode
;
188 ip
->i_number
= inode
;
195 find(char *path
, fileid_t
*filep
)
201 dprintf("find: %s\n", path
);
202 if (path
== NULL
|| *path
== '\0')
205 if (opendir(root_ino
, filep
))
212 while (*q
!= '/' && *q
!= '\0')
216 n
= dlook(path
, filep
);
223 if (opendir(n
, filep
))
234 dlook(char *s
, fileid_t
*filep
)
236 struct hs_direct
*hsdep
;
239 struct dirstuff dirp
;
242 dprintf("dlook: %s\n", s
);
243 ip
= filep
->fi_inode
;
244 if (s
== NULL
|| *s
== '\0')
246 if ((ip
->i_smode
& IFMT
) != IFDIR
) {
249 if (ip
->i_size
== 0) {
255 for (hsdep
= readdir(&dirp
); hsdep
!= NULL
; hsdep
= readdir(&dirp
)) {
256 udp
= &hsdep
->hs_ufs_dir
;
257 if (udp
->d_namlen
== 1 &&
258 udp
->d_name
[0] == '.' &&
259 udp
->d_name
[1] == '\0')
261 if (udp
->d_namlen
== 2 &&
262 udp
->d_name
[0] == '.' &&
263 udp
->d_name
[1] == '.' &&
264 udp
->d_name
[2] == '\0')
266 if (udp
->d_namlen
== len
&& (strcmp(s
, udp
->d_name
)) == 0) {
267 struct inode
*ip
= filep
->fi_inode
;
269 filep
->fi_offset
= 0;
270 filep
->fi_blocknum
= hdbtodb(udp
->d_ino
);
272 bzero(filep
->fi_inode
, sizeof (struct inode
));
273 ip
->i_size
= hsdep
->hs_dir
.ext_size
;
274 ip
->i_smode
= hsdep
->hs_dir
.mode
;
275 ip
->i_number
= udp
->d_ino
;
283 * get next entry in a directory.
285 static struct hs_direct
*
286 readdir(struct dirstuff
*dirp
)
288 static struct hs_direct hsdep
;
289 struct direct
*udp
= &hsdep
.hs_ufs_dir
;
295 dprintf("readdir: start\n");
297 ip
= filep
->fi_inode
;
299 if (dirp
->loc
>= ip
->i_size
) {
302 off
= dirp
->loc
& ((1 << ISO_SECTOR_SHIFT
) - 1);
304 lbn
= hdbtodb(dirp
->loc
>> ISO_SECTOR_SHIFT
);
305 filep
->fi_blocknum
= lbn
+ hdbtodb(ip
->i_number
);
306 filep
->fi_count
= ISO_SECTOR_SIZE
;
308 if (diskread(filep
)) {
309 dprintf("readdir: diskread failed\n");
313 dirp
->loc
+= parse_dir(filep
, off
, &hsdep
);
314 if (udp
->d_reclen
== 0 && dirp
->loc
<= ip
->i_size
) {
315 dirp
->loc
= roundup(dirp
->loc
, ISO_SECTOR_SIZE
);
323 getblock(fileid_t
*filep
)
325 struct inode
*ip
= filep
->fi_inode
;
329 dprintf("getblock: start\n");
330 diff
= ip
->i_size
- filep
->fi_offset
;
334 /* which block (or frag) in the file do we read? */
335 lbn
= hdbtodb(filep
->fi_offset
>> ISO_SECTOR_SHIFT
);
336 filep
->fi_blocknum
= lbn
+ hdbtodb(ip
->i_number
);
338 off
= filep
->fi_offset
& ((1 << ISO_SECTOR_SHIFT
) - 1);
339 size
= filep
->fi_count
= ISO_SECTOR_SIZE
;
341 if (diskread(filep
)) /* Trap errors */
344 if (filep
->fi_offset
- off
+ size
>= ip
->i_size
)
345 filep
->fi_count
= diff
+ off
;
346 filep
->fi_count
-= off
;
347 filep
->fi_memp
+= off
;
348 dprintf("getblock: end\n");
353 bhsfs_read(int fd
, caddr_t buf
, size_t count
)
360 dprintf("bhsfs_read %d, ", fd
);
361 dprintf("count 0x%lx\n", count
);
366 ip
= filep
->fi_inode
;
368 if ((filep
->fi_flags
& FI_COMPRESSED
) == 0 &&
369 filep
->fi_offset
+ count
> ip
->i_size
)
370 count
= ip
->i_size
- filep
->fi_offset
;
372 if ((i
= count
) <= 0)
376 if (filep
->fi_flags
& FI_COMPRESSED
) {
377 if ((j
= cf_read(filep
, buf
, count
)) < 0)
378 return (0); /* encountered an error */
380 i
= j
; /* short read, must have hit EOF */
382 if (filep
->fi_count
== 0) {
383 if (getblock(filep
) == -1)
386 j
= MIN(i
, filep
->fi_count
);
387 bcopy(filep
->fi_memp
, buf
, (uint_t
)j
);
390 filep
->fi_offset
+= j
;
391 filep
->fi_count
-= j
;
396 dprintf("bhsfs_read: read 0x%x\n", (int)(buf
- n
));
402 bhsfs_mountroot(char *str
)
407 return (0); /* already mounted */
409 dprintf("mounting ramdisk as hsfs\n");
411 hsfsp
= bkmem_alloc(sizeof (*hsfsp
));
412 bzero(hsfsp
, sizeof (*hsfsp
));
413 head
= bkmem_alloc(sizeof (*head
));
414 bzero(head
, sizeof (*head
));
415 head
->fi_back
= head
->fi_forw
= head
;
417 /* now read the superblock. */
418 head
->fi_blocknum
= hdbtodb(ISO_VOLDESC_SEC
);
420 head
->fi_count
= ISO_SECTOR_SIZE
;
421 head
->fi_memp
= head
->fi_buf
;
422 if (diskread(head
)) {
423 printf("failed to read superblock\n");
428 /* Since RRIP is based on ISO9660, that's where we start */
430 if ((ISO_DESC_TYPE(bufp
) != ISO_VD_PVD
) ||
431 (strncmp((const char *)ISO_std_id(bufp
), ISO_ID_STRING
,
432 ISO_ID_STRLEN
) != 0) || (ISO_STD_VER(bufp
) != ISO_ID_VER
)) {
433 dprintf("volume type does not match\n");
438 /* Now we fill in the volume descriptor */
439 hsfsp
->vol_size
= ISO_VOL_SIZE(bufp
);
440 hsfsp
->lbn_size
= ISO_BLK_SIZE(bufp
);
441 hsfsp
->lbn_shift
= ISO_SECTOR_SHIFT
;
442 hsfsp
->lbn_secshift
= ISO_SECTOR_SHIFT
;
443 hsfsp
->vol_set_size
= (ushort_t
)ISO_SET_SIZE(bufp
);
444 hsfsp
->vol_set_seq
= (ushort_t
)ISO_SET_SEQ(bufp
);
446 /* Make sure we have a valid logical block size */
447 if (hsfsp
->lbn_size
& ~(1 << hsfsp
->lbn_shift
)) {
448 printf("%d invalid logical block size\n", hsfsp
->lbn_size
);
453 /* Since an HSFS root could be located anywhere on the media! */
454 root_ino
= IDE_EXT_LBN(ISO_root_dir(bufp
));
459 bhsfs_unmountroot(void)
474 bhsfs_open(char *str
, int flags
)
476 static int filedes
= 1;
481 dprintf("open %s\n", str
);
482 filep
= (fileid_t
*)bkmem_alloc(sizeof (fileid_t
));
483 filep
->fi_back
= head
->fi_back
;
484 filep
->fi_forw
= head
;
485 head
->fi_back
->fi_forw
= filep
;
486 head
->fi_back
= filep
;
487 filep
->fi_filedes
= filedes
++;
489 filep
->fi_path
= (char *)bkmem_alloc(strlen(str
) + 1);
490 (void) strcpy(filep
->fi_path
, str
);
491 filep
->fi_inode
= NULL
;
492 bzero(filep
->fi_buf
, MAXBSIZE
);
493 filep
->fi_getblock
= getblock
;
496 ino
= find(str
, filep
);
498 (void) bhsfs_close(filep
->fi_filedes
);
502 filep
->fi_blocknum
= hdbtodb(ino
);
503 filep
->fi_offset
= 0;
507 if (cf_check_compressed(filep
) != 0)
509 dprintf("open done\n");
510 return (filep
->fi_filedes
);
518 dprintf("close %d\n", fd
);
519 if (!(filep
= find_fp(fd
)))
522 if (filep
->fi_taken
== 0 || filep
== head
) {
523 printf("File descripter %d not allocated!\n", fd
);
528 /* unlink and deallocate node */
529 filep
->fi_forw
->fi_back
= filep
->fi_back
;
530 filep
->fi_back
->fi_forw
= filep
->fi_forw
;
532 bkmem_free(filep
->fi_inode
, sizeof (struct inode
));
533 bkmem_free(filep
->fi_path
, strlen(filep
->fi_path
) + 1);
534 bkmem_free((char *)filep
, sizeof (fileid_t
));
535 dprintf("close done\n");
544 while ((filep
= head
->fi_forw
) != head
)
545 if (filep
->fi_taken
&& bhsfs_close(filep
->fi_filedes
))
546 printf("Filesystem may be inconsistent.\n");
548 bkmem_free(hsfsp
, sizeof (*hsfsp
));
549 bkmem_free(head
, sizeof (fileid_t
));
555 * This version of seek() only performs absolute seeks (whence == 0).
558 bhsfs_lseek(int fd
, off_t addr
, int whence
)
562 dprintf("lseek %d, ", fd
);
563 dprintf("off = %lx\n", addr
);
564 if (!(filep
= find_fp(fd
)))
567 if (filep
->fi_flags
& FI_COMPRESSED
) {
568 cf_seek(filep
, addr
, whence
);
572 filep
->fi_offset
+= addr
;
575 filep
->fi_offset
= addr
;
579 printf("lseek(): invalid whence value %d\n", whence
);
582 filep
->fi_blocknum
= addr
/ DEV_BSIZE
;
590 bhsfs_fstat(int fd
, struct bootstat
*stp
)
595 if (!(filep
= find_fp(fd
)))
598 ip
= filep
->fi_inode
;
606 switch (ip
->i_smode
& IFMT
) {
608 stp
->st_mode
= S_IFDIR
;
611 stp
->st_mode
= S_IFREG
;
617 * NOTE: this size will be the compressed size for a compressed file
618 * This could confuse the caller since we decompress the file behind
619 * the scenes when the file is read.
621 stp
->st_size
= ip
->i_size
;
624 stp
->st_atim
.tv_sec
= ip
->i_atime
.tv_sec
;
625 stp
->st_atim
.tv_nsec
= ip
->i_atime
.tv_usec
* 1000;
626 stp
->st_mtim
.tv_sec
= ip
->i_mtime
.tv_sec
;
627 stp
->st_mtim
.tv_nsec
= ip
->i_mtime
.tv_usec
* 1000;
628 stp
->st_ctim
.tv_sec
= ip
->i_ctime
.tv_sec
;
629 stp
->st_ctim
.tv_nsec
= ip
->i_ctime
.tv_usec
* 1000;
637 * Parse a directory entry.
641 parse_dir(fileid_t
*filep
, int offset
, struct hs_direct
*hsdep
)
643 char *bufp
= (char *)(filep
->fi_memp
+ offset
);
644 struct direct
*udp
= &hsdep
->hs_ufs_dir
; /* ufs-style dir info */
645 struct hs_direntry
*hdp
= &hsdep
->hs_dir
; /* hsfs-style dir info */
652 dprintf("parse_dir: offset = %d\n", offset
);
653 /* a zero length dir entry terminates the dir block */
654 udp
->d_reclen
= IDE_DIR_LEN(bufp
);
655 if (udp
->d_reclen
== 0)
658 /* fill in some basic hsfs info */
659 hdp
->ext_lbn
= IDE_EXT_LBN(bufp
);
660 hdp
->ext_size
= IDE_EXT_SIZE(bufp
);
661 hdp
->xar_len
= IDE_XAR_LEN(bufp
);
662 hdp
->intlf_sz
= IDE_INTRLV_SIZE(bufp
);
663 hdp
->intlf_sk
= IDE_INTRLV_SKIP(bufp
);
664 hdp
->sym_link
= NULL
;
666 /* we use lbn of data extent as an inode # equivalent */
667 udp
->d_ino
= hdp
->ext_lbn
;
670 if (IDE_REGULAR_FILE(c
)) {
674 } else if (IDE_REGULAR_DIR(c
)) {
679 printf("pd(): file type=0x%x unknown.\n", c
);
683 * Massage hsfs name, recognizing special entries for . and ..
684 * else lopping off version junk.
687 /* Some initial conditions */
688 nmlen
= IDE_NAME_LEN(bufp
);
690 /* Special Case: Current Directory */
691 if (nmlen
== 1 && c
== '\0') {
692 udp
->d_name
[0] = '.';
693 udp
->d_name
[1] = '\0';
695 /* Special Case: Parent Directory */
696 } else if (nmlen
== 1 && c
== '\001') {
697 udp
->d_name
[0] = '.';
698 udp
->d_name
[1] = '.';
699 udp
->d_name
[2] = '\0';
701 /* Other file name */
704 for (i
= 0; i
< nmlen
; i
++) {
705 c
= *(IDE_name(bufp
)+i
);
711 udp
->d_name
[udp
->d_namlen
++] = c
;
713 udp
->d_name
[udp
->d_namlen
] = '\0';
716 /* System Use Fields */
717 ce_len
= IDE_SUA_LEN(bufp
);
720 return (udp
->d_reclen
);
722 /* there is an SUA for this dir entry; go parse it */
723 ce_lbn
= parse_susp((char *)IDE_sys_use_area(bufp
), &ce_len
, hsdep
);
727 * store away current position in dir,
728 * as we will be using the iobuf to reading SUA.
730 daddr_t save_bn
= filep
->fi_blocknum
;
731 daddr_t save_offset
= filep
->fi_offset
;
732 caddr_t save_ma
= filep
->fi_memp
;
733 int save_cc
= filep
->fi_count
;
735 filep
->fi_count
= ISO_SECTOR_SIZE
;
736 filep
->fi_offset
= 0;
737 filep
->fi_blocknum
= hdbtodb(ce_lbn
);
739 if (diskread(filep
)) {
740 printf("failed to read cont. area\n");
745 ce_lbn
= parse_susp(filep
->fi_memp
, &ce_len
,
748 filep
->fi_count
= save_cc
;
749 filep
->fi_offset
= save_offset
;
750 filep
->fi_blocknum
= save_bn
;
751 filep
->fi_memp
= save_ma
;
753 return (udp
->d_reclen
);
757 * Parse the System Use Fields in this System Use Area.
758 * Return blk number of continuation/SUA, or 0 if no continuation/not a SUA.
761 parse_susp(char *bufp
, uint_t
*len
, struct hs_direct
*hsdep
)
763 struct direct
*udp
= &hsdep
->hs_ufs_dir
; /* ufs-style info */
766 uint_t blk_len
= *len
;
771 dprintf("parse_susp: len = %d\n", *len
);
772 while (cur_off
< blk_len
) {
773 susp
= (char *)(bufp
+ cur_off
);
776 * A null entry, or an entry with zero length
777 * terminates the SUSP.
779 if (susp
[0] == '\0' || susp
[1] == '\0' ||
780 (susp_len
= SUF_LEN(susp
)) == 0)
784 * Compare current entry to all known signatures.
786 for (i
= 0; i
< hsfs_num_sig
; i
++)
787 if (strncmp(hsfs_sig_tab
[i
], susp
, SUF_SIG_LEN
) == 0)
792 * CE signature: continuation of SUSP.
793 * will want to return new lbn, len.
795 ce_lbn
= CE_BLK_LOC(susp
);
796 *len
= CE_CONT_LEN(susp
);
799 /* NM signature: POSIX-style file name */
800 if (!RRIP_NAME_FLAGS(susp
)) {
801 udp
->d_namlen
= RRIP_NAME_LEN(susp
);
802 bcopy((char *)RRIP_name(susp
),
803 udp
->d_name
, udp
->d_namlen
);
804 udp
->d_name
[udp
->d_namlen
] = '\0';
808 /* couldn't find a legit susp, terminate loop */
810 /* ST signature: terminates SUSP */
822 struct boot_fs_ops bhsfs_ops
= {