1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #pragma ident "%Z%%M% %I% %E% SMI"
27
28 /*
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.
32 */
33
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>
40
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>
48
49 #ifdef _BOOT
50 #include "../common/util.h"
51 #else
52 #include <sys/sunddi.h>
53 #endif
54
55 #define hdbtodb(n) ((ISO_SECTOR_SIZE / DEV_BSIZE) * (n))
56
57 #define HSFS_NUM_SIG 14
58
59 #define SUSP_SP_IX 0
60 #define SUSP_CE_IX 1
61 #define SUSP_PD_IX 2
62 #define SUSP_ST_IX 3
63 #define SUSP_ER_IX 4
64 #define RRIP_PX_IX 5
65 #define RRIP_PN_IX 6
66 #define RRIP_SL_IX 7
67 #define RRIP_CL_IX 8
68 #define RRIP_PL_IX 9
69 #define RRIP_RE_IX 10
70 #define RRIP_RF_IX 11
71 #define RRIP_RR_IX 12
72 #define RRIP_NM_IX 13
73
74 #ifdef _BOOT
75 #define dprintf if (bootrd_debug) printf
76 #else
77 #define printf kobj_printf
78 #define dprintf if (bootrd_debug) kobj_printf
79
80 /* PRINTFLIKE1 */
81 extern void kobj_printf(char *, ...);
82 #endif
83
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);
91
92 struct dirstuff {
93 int loc;
94 fileid_t *filep;
95 };
96
97 struct hs_direct {
98 struct direct hs_ufs_dir;
99 struct hs_direntry hs_dir;
100 };
101
102 static uint_t root_ino = 0;
103 static struct hs_volume *hsfsp;
104 static fileid_t *head;
105
106 static char *hsfs_sig_tab[] = {
107 SUSP_SP,
108 SUSP_CE,
109 SUSP_PD,
110 SUSP_ST,
111 SUSP_ER,
112 RRIP_PX,
113 RRIP_PN,
114 RRIP_SL,
115 RRIP_CL,
116 RRIP_PL,
117 RRIP_RE,
118 RRIP_TF,
119 RRIP_RR,
120 RRIP_NM
121 };
122
123 static int hsfs_num_sig = sizeof (hsfs_sig_tab) / sizeof (hsfs_sig_tab[0]);
124
125 /*
126 * Local prototypes
127 */
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 *);
134
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);
143
144 static fileid_t *
find_fp(int fd)145 find_fp(int fd)
146 {
147 fileid_t *filep = head;
148
149 if (fd >= 0) {
150 while ((filep = filep->fi_forw) != head)
151 if (fd == filep->fi_filedes)
152 return (filep->fi_taken ? filep : 0);
153 }
154
155 return (0);
156 }
157
158 static int
opendir(ino_t inode,fileid_t * filep)159 opendir(ino_t inode, fileid_t *filep)
160 {
161 struct hs_direct hsdep;
162
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;
168 filep->fi_memp = 0;
169
170 if (diskread(filep))
171 return (0);
172
173 filep->fi_offset = 0;
174 filep->fi_blocknum = hdbtodb(inode);
175
176 if (inode != root_ino)
177 return (0);
178
179 if (parse_dir(filep, 0, &hsdep) > 0) {
180 struct inode *ip;
181
182 ip = filep->fi_inode;
183 if (ip == NULL)
184 ip = filep->fi_inode = bkmem_alloc(sizeof (*ip));
185
186 ip->i_size = hsdep.hs_dir.ext_size;
187 ip->i_smode = hsdep.hs_dir.mode;
188 ip->i_number = inode;
189 return (0);
190 }
191 return (1);
192 }
193
194 static ino_t
find(char * path,fileid_t * filep)195 find(char *path, fileid_t *filep)
196 {
197 char *q;
198 char c;
199 ino_t n;
200
201 dprintf("find: %s\n", path);
202 if (path == NULL || *path == '\0')
203 return (0);
204
205 if (opendir(root_ino, filep))
206 return (0);
207
208 while (*path) {
209 while (*path == '/')
210 path++;
211 q = path;
212 while (*q != '/' && *q != '\0')
213 q++;
214 c = *q;
215 *q = '\0';
216 n = dlook(path, filep);
217 *q = c;
218 path = q;
219
220 if (n != 0) {
221 if (c == '\0')
222 break;
223 if (opendir(n, filep))
224 return (0);
225 continue;
226 } else {
227 return (0);
228 }
229 }
230 return ((ino_t)n);
231 }
232
233 static ino_t
dlook(char * s,fileid_t * filep)234 dlook(char *s, fileid_t *filep)
235 {
236 struct hs_direct *hsdep;
237 struct direct *udp;
238 struct inode *ip;
239 struct dirstuff dirp;
240 int len;
241
242 dprintf("dlook: %s\n", s);
243 ip = filep->fi_inode;
244 if (s == NULL || *s == '\0')
245 return (0);
246 if ((ip->i_smode & IFMT) != IFDIR) {
247 return (0);
248 }
249 if (ip->i_size == 0) {
250 return (0);
251 }
252 len = strlen(s);
253 dirp.loc = 0;
254 dirp.filep = filep;
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')
260 continue;
261 if (udp->d_namlen == 2 &&
262 udp->d_name[0] == '.' &&
263 udp->d_name[1] == '.' &&
264 udp->d_name[2] == '\0')
265 continue;
266 if (udp->d_namlen == len && (strcmp(s, udp->d_name)) == 0) {
267 struct inode *ip = filep->fi_inode;
268
269 filep->fi_offset = 0;
270 filep->fi_blocknum = hdbtodb(udp->d_ino);
271
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;
276 return (udp->d_ino);
277 }
278 }
279 return (0);
280 }
281
282 /*
283 * get next entry in a directory.
284 */
285 static struct hs_direct *
readdir(struct dirstuff * dirp)286 readdir(struct dirstuff *dirp)
287 {
288 static struct hs_direct hsdep;
289 struct direct *udp = &hsdep.hs_ufs_dir;
290 struct inode *ip;
291 fileid_t *filep;
292 daddr_t lbn;
293 int off;
294
295 dprintf("readdir: start\n");
296 filep = dirp->filep;
297 ip = filep->fi_inode;
298 for (;;) {
299 if (dirp->loc >= ip->i_size) {
300 return (NULL);
301 }
302 off = dirp->loc & ((1 << ISO_SECTOR_SHIFT) - 1);
303 if (off == 0) {
304 lbn = hdbtodb(dirp->loc >> ISO_SECTOR_SHIFT);
305 filep->fi_blocknum = lbn + hdbtodb(ip->i_number);
306 filep->fi_count = ISO_SECTOR_SIZE;
307 filep->fi_memp = 0;
308 if (diskread(filep)) {
309 dprintf("readdir: diskread failed\n");
310 return (NULL);
311 }
312 }
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);
316 continue;
317 }
318 return (&hsdep);
319 }
320 }
321
322 static int
getblock(fileid_t * filep)323 getblock(fileid_t *filep)
324 {
325 struct inode *ip = filep->fi_inode;
326 int off, size, diff;
327 daddr_t lbn;
328
329 dprintf("getblock: start\n");
330 diff = ip->i_size - filep->fi_offset;
331 if (diff <= 0)
332 return (-1);
333
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);
337
338 off = filep->fi_offset & ((1 << ISO_SECTOR_SHIFT) - 1);
339 size = filep->fi_count = ISO_SECTOR_SIZE;
340 filep->fi_memp = 0;
341 if (diskread(filep)) /* Trap errors */
342 return (-1);
343
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");
349 return (0);
350 }
351
352 static ssize_t
bhsfs_read(int fd,caddr_t buf,size_t count)353 bhsfs_read(int fd, caddr_t buf, size_t count)
354 {
355 int i, j;
356 fileid_t *filep;
357 struct inode *ip;
358 caddr_t n;
359
360 dprintf("bhsfs_read %d, ", fd);
361 dprintf("count 0x%lx\n", count);
362 filep = find_fp(fd);
363 if (filep == NULL)
364 return (-1);
365
366 ip = filep->fi_inode;
367 n = buf;
368 if ((filep->fi_flags & FI_COMPRESSED) == 0 &&
369 filep->fi_offset + count > ip->i_size)
370 count = ip->i_size - filep->fi_offset;
371
372 if ((i = count) <= 0)
373 return (0);
374
375 while (i > 0) {
376 if (filep->fi_flags & FI_COMPRESSED) {
377 if ((j = cf_read(filep, buf, count)) < 0)
378 return (0); /* encountered an error */
379 if (j < i)
380 i = j; /* short read, must have hit EOF */
381 } else {
382 if (filep->fi_count == 0) {
383 if (getblock(filep) == -1)
384 return (0);
385 }
386 j = MIN(i, filep->fi_count);
387 bcopy(filep->fi_memp, buf, (uint_t)j);
388 }
389 filep->fi_memp += j;
390 filep->fi_offset += j;
391 filep->fi_count -= j;
392 buf += j;
393 i -= j;
394 }
395
396 dprintf("bhsfs_read: read 0x%x\n", (int)(buf - n));
397 return (buf - n);
398 }
399
400 /*ARGSUSED*/
401 static int
bhsfs_mountroot(char * str)402 bhsfs_mountroot(char *str)
403 {
404 char *bufp;
405
406 if (hsfsp != NULL)
407 return (0); /* already mounted */
408
409 dprintf("mounting ramdisk as hsfs\n");
410
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;
416
417 /* now read the superblock. */
418 head->fi_blocknum = hdbtodb(ISO_VOLDESC_SEC);
419 head->fi_offset = 0;
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");
424 bhsfs_closeall();
425 return (-1);
426 }
427
428 /* Since RRIP is based on ISO9660, that's where we start */
429 bufp = head->fi_buf;
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");
434 bhsfs_closeall();
435 return (-1);
436 }
437
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);
445
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);
449 bhsfs_closeall();
450 return (-1);
451 }
452
453 /* Since an HSFS root could be located anywhere on the media! */
454 root_ino = IDE_EXT_LBN(ISO_root_dir(bufp));
455 return (0);
456 }
457
458 static int
bhsfs_unmountroot(void)459 bhsfs_unmountroot(void)
460 {
461 if (hsfsp == NULL)
462 return (-1);
463
464 bhsfs_closeall();
465
466 return (0);
467 }
468
469 /*
470 * Open a file.
471 */
472 /*ARGSUSED*/
473 int
bhsfs_open(char * str,int flags)474 bhsfs_open(char *str, int flags)
475 {
476 static int filedes = 1;
477
478 fileid_t *filep;
479 ino_t ino;
480
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++;
488 filep->fi_taken = 1;
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;
494 filep->fi_flags = 0;
495
496 ino = find(str, filep);
497 if (ino == 0) {
498 (void) bhsfs_close(filep->fi_filedes);
499 return (-1);
500 }
501
502 filep->fi_blocknum = hdbtodb(ino);
503 filep->fi_offset = 0;
504 filep->fi_count = 0;
505 filep->fi_memp = 0;
506
507 if (cf_check_compressed(filep) != 0)
508 return (-1);
509 dprintf("open done\n");
510 return (filep->fi_filedes);
511 }
512
513 int
bhsfs_close(int fd)514 bhsfs_close(int fd)
515 {
516 fileid_t *filep;
517
518 dprintf("close %d\n", fd);
519 if (!(filep = find_fp(fd)))
520 return (-1);
521
522 if (filep->fi_taken == 0 || filep == head) {
523 printf("File descripter %d not allocated!\n", fd);
524 return (-1);
525 }
526
527 cf_close(filep);
528 /* unlink and deallocate node */
529 filep->fi_forw->fi_back = filep->fi_back;
530 filep->fi_back->fi_forw = filep->fi_forw;
531 if (filep->fi_inode)
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");
536 return (0);
537 }
538
539 static void
bhsfs_closeall(void)540 bhsfs_closeall(void)
541 {
542 fileid_t *filep;
543
544 while ((filep = head->fi_forw) != head)
545 if (filep->fi_taken && bhsfs_close(filep->fi_filedes))
546 printf("Filesystem may be inconsistent.\n");
547
548 bkmem_free(hsfsp, sizeof (*hsfsp));
549 bkmem_free(head, sizeof (fileid_t));
550 hsfsp = NULL;
551 head = NULL;
552 }
553
554 /*
555 * This version of seek() only performs absolute seeks (whence == 0).
556 */
557 static off_t
bhsfs_lseek(int fd,off_t addr,int whence)558 bhsfs_lseek(int fd, off_t addr, int whence)
559 {
560 fileid_t *filep;
561
562 dprintf("lseek %d, ", fd);
563 dprintf("off = %lx\n", addr);
564 if (!(filep = find_fp(fd)))
565 return (-1);
566
567 if (filep->fi_flags & FI_COMPRESSED) {
568 cf_seek(filep, addr, whence);
569 } else {
570 switch (whence) {
571 case SEEK_CUR:
572 filep->fi_offset += addr;
573 break;
574 case SEEK_SET:
575 filep->fi_offset = addr;
576 break;
577 default:
578 case SEEK_END:
579 printf("lseek(): invalid whence value %d\n", whence);
580 break;
581 }
582 filep->fi_blocknum = addr / DEV_BSIZE;
583 }
584
585 filep->fi_count = 0;
586 return (0);
587 }
588
589 static int
bhsfs_fstat(int fd,struct bootstat * stp)590 bhsfs_fstat(int fd, struct bootstat *stp)
591 {
592 fileid_t *filep;
593 struct inode *ip;
594
595 if (!(filep = find_fp(fd)))
596 return (-1);
597
598 ip = filep->fi_inode;
599
600 stp->st_mode = 0;
601 stp->st_size = 0;
602
603 if (ip == NULL)
604 return (0);
605
606 switch (ip->i_smode & IFMT) {
607 case IFDIR:
608 stp->st_mode = S_IFDIR;
609 break;
610 case IFREG:
611 stp->st_mode = S_IFREG;
612 break;
613 default:
614 break;
615 }
616 /*
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.
620 */
621 stp->st_size = ip->i_size;
622
623 /* file times */
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;
630
631 return (0);
632
633 }
634
635
636 /*
637 * Parse a directory entry.
638 *
639 */
640 static uint_t
parse_dir(fileid_t * filep,int offset,struct hs_direct * hsdep)641 parse_dir(fileid_t *filep, int offset, struct hs_direct *hsdep)
642 {
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 */
646 uint_t ce_lbn;
647 uint_t ce_len;
648 uint_t nmlen;
649 uint_t i;
650 uchar_t c;
651
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)
656 return (0);
657
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;
665
666 /* we use lbn of data extent as an inode # equivalent */
667 udp->d_ino = hdp->ext_lbn;
668
669 c = IDE_FLAGS(bufp);
670 if (IDE_REGULAR_FILE(c)) {
671 hdp->type = VREG;
672 hdp->mode = IFREG;
673 hdp->nlink = 1;
674 } else if (IDE_REGULAR_DIR(c)) {
675 hdp->type = VDIR;
676 hdp->mode = IFDIR;
677 hdp->nlink = 2;
678 } else {
679 printf("pd(): file type=0x%x unknown.\n", c);
680 }
681
682 /*
683 * Massage hsfs name, recognizing special entries for . and ..
684 * else lopping off version junk.
685 */
686
687 /* Some initial conditions */
688 nmlen = IDE_NAME_LEN(bufp);
689 c = *IDE_NAME(bufp);
690 /* Special Case: Current Directory */
691 if (nmlen == 1 && c == '\0') {
692 udp->d_name[0] = '.';
693 udp->d_name[1] = '\0';
694 udp->d_namlen = 1;
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';
700 udp->d_namlen = 2;
701 /* Other file name */
702 } else {
703 udp->d_namlen = 0;
704 for (i = 0; i < nmlen; i++) {
705 c = *(IDE_name(bufp)+i);
706 if (c == ';')
707 break;
708 else if (c == ' ')
709 continue;
710 else
711 udp->d_name[udp->d_namlen++] = c;
712 }
713 udp->d_name[udp->d_namlen] = '\0';
714 }
715
716 /* System Use Fields */
717 ce_len = IDE_SUA_LEN(bufp);
718
719 if (ce_len == 0)
720 return (udp->d_reclen);
721
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);
724
725 if (ce_lbn) {
726 /*
727 * store away current position in dir,
728 * as we will be using the iobuf to reading SUA.
729 */
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;
734 do {
735 filep->fi_count = ISO_SECTOR_SIZE;
736 filep->fi_offset = 0;
737 filep->fi_blocknum = hdbtodb(ce_lbn);
738 filep->fi_memp = 0;
739 if (diskread(filep)) {
740 printf("failed to read cont. area\n");
741 ce_len = 0;
742 ce_lbn = 0;
743 break;
744 }
745 ce_lbn = parse_susp(filep->fi_memp, &ce_len,
746 hsdep);
747 } while (ce_lbn);
748 filep->fi_count = save_cc;
749 filep->fi_offset = save_offset;
750 filep->fi_blocknum = save_bn;
751 filep->fi_memp = save_ma;
752 }
753 return (udp->d_reclen);
754 }
755
756 /*
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.
759 */
760 static uint_t
parse_susp(char * bufp,uint_t * len,struct hs_direct * hsdep)761 parse_susp(char *bufp, uint_t *len, struct hs_direct *hsdep)
762 {
763 struct direct *udp = &hsdep->hs_ufs_dir; /* ufs-style info */
764 char *susp;
765 uint_t cur_off = 0;
766 uint_t blk_len = *len;
767 uint_t susp_len = 0;
768 uint_t ce_lbn = 0;
769 uint_t i;
770
771 dprintf("parse_susp: len = %d\n", *len);
772 while (cur_off < blk_len) {
773 susp = (char *)(bufp + cur_off);
774
775 /*
776 * A null entry, or an entry with zero length
777 * terminates the SUSP.
778 */
779 if (susp[0] == '\0' || susp[1] == '\0' ||
780 (susp_len = SUF_LEN(susp)) == 0)
781 break;
782
783 /*
784 * Compare current entry to all known signatures.
785 */
786 for (i = 0; i < hsfs_num_sig; i++)
787 if (strncmp(hsfs_sig_tab[i], susp, SUF_SIG_LEN) == 0)
788 break;
789 switch (i) {
790 case SUSP_CE_IX:
791 /*
792 * CE signature: continuation of SUSP.
793 * will want to return new lbn, len.
794 */
795 ce_lbn = CE_BLK_LOC(susp);
796 *len = CE_CONT_LEN(susp);
797 break;
798 case RRIP_NM_IX:
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';
805 }
806 break;
807 case HSFS_NUM_SIG:
808 /* couldn't find a legit susp, terminate loop */
809 case SUSP_ST_IX:
810 /* ST signature: terminates SUSP */
811 return (ce_lbn);
812 case SUSP_SP_IX:
813 case RRIP_RR_IX:
814 default:
815 break;
816 }
817 cur_off += susp_len;
818 }
819 return (ce_lbn);
820 }
821
822 struct boot_fs_ops bhsfs_ops = {
823 "boot_hsfs",
824 bhsfs_mountroot,
825 bhsfs_unmountroot,
826 bhsfs_open,
827 bhsfs_close,
828 bhsfs_read,
829 bhsfs_lseek,
830 bhsfs_fstat,
831 NULL
832 };
833