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 /*
27 * Basic file system reading code for standalone I/O system.
28 * Simulates a primitive UNIX I/O system (read(), write(), open(), etc).
29 * Does not support writes.
30 */
31
32 #include <sys/param.h>
33 #include <sys/sysmacros.h>
34 #include <sys/vnode.h>
35 #include <sys/fs/ufs_fsdir.h>
36 #include <sys/fs/ufs_fs.h>
37 #include <sys/fs/ufs_inode.h>
38
39 #include <sys/fs/hsfs_spec.h>
40 #include <sys/fs/hsfs_isospec.h>
41 #include <sys/fs/hsfs_node.h>
42 #include <sys/fs/hsfs_susp.h>
43 #include <sys/fs/hsfs_rrip.h>
44 #include <sys/bootvfs.h>
45 #include <sys/filep.h>
46
47 #ifdef _BOOT
48 #include "../common/util.h"
49 #else
50 #include <sys/sunddi.h>
51 #endif
52
53 #define hdbtodb(n) ((ISO_SECTOR_SIZE / DEV_BSIZE) * (n))
54
55 #define HSFS_NUM_SIG 14
56
57 #define SUSP_SP_IX 0
58 #define SUSP_CE_IX 1
59 #define SUSP_PD_IX 2
60 #define SUSP_ST_IX 3
61 #define SUSP_ER_IX 4
62 #define RRIP_PX_IX 5
63 #define RRIP_PN_IX 6
64 #define RRIP_SL_IX 7
65 #define RRIP_CL_IX 8
66 #define RRIP_PL_IX 9
67 #define RRIP_RE_IX 10
68 #define RRIP_RF_IX 11
69 #define RRIP_RR_IX 12
70 #define RRIP_NM_IX 13
71
72 #ifdef _BOOT
73 #define dprintf if (bootrd_debug) printf
74 #else
75 #define printf kobj_printf
76 #define dprintf if (bootrd_debug) kobj_printf
77
78 /* PRINTFLIKE1 */
79 extern void kobj_printf(char *, ...);
80 #endif
81
82 extern int bootrd_debug;
83 extern void *bkmem_alloc(size_t);
84 extern void bkmem_free(void *, size_t);
85 extern int cf_check_compressed(fileid_t *);
86 extern void cf_close(fileid_t *);
87 extern void cf_seek(fileid_t *, off_t, int);
88 extern int cf_read(fileid_t *, caddr_t, size_t);
89
90 struct dirstuff {
91 int loc;
92 fileid_t *filep;
93 };
94
95 struct hs_direct {
96 struct direct hs_ufs_dir;
97 struct hs_direntry hs_dir;
98 };
99
100 static uint_t root_ino = 0;
101 static struct hs_volume *hsfsp;
102 static fileid_t *head;
103
104 static char *hsfs_sig_tab[] = {
105 SUSP_SP,
106 SUSP_CE,
107 SUSP_PD,
108 SUSP_ST,
109 SUSP_ER,
110 RRIP_PX,
111 RRIP_PN,
112 RRIP_SL,
113 RRIP_CL,
114 RRIP_PL,
115 RRIP_RE,
116 RRIP_TF,
117 RRIP_RR,
118 RRIP_NM
119 };
120
121 static int hsfs_num_sig = sizeof (hsfs_sig_tab) / sizeof (hsfs_sig_tab[0]);
122
123 /*
124 * Local prototypes
125 */
126 static struct hs_direct *readdir(struct dirstuff *);
127 static uint_t parse_dir(fileid_t *, int, struct hs_direct *);
128 static uint_t parse_susp(char *, uint_t *, struct hs_direct *);
129 static ino_t dlook(char *, fileid_t *);
130 static int opendir(ino_t, fileid_t *);
131 static ino_t find(char *, fileid_t *);
132
133 static int bhsfs_mountroot(char *str);
134 static int bhsfs_unmountroot(void);
135 static int bhsfs_open(char *str, int flags);
136 static int bhsfs_close(int fd);
137 static void bhsfs_closeall(void);
138 static ssize_t bhsfs_read(int fdesc, char *buf, size_t count);
139 static off_t bhsfs_lseek(int fdesc, off_t addr, int whence);
140 static int bhsfs_fstat(int fdesc, struct bootstat *stp);
141
142 static fileid_t *
find_fp(int fd)143 find_fp(int fd)
144 {
145 fileid_t *filep = head;
146
147 if (fd >= 0) {
148 while ((filep = filep->fi_forw) != head)
149 if (fd == filep->fi_filedes)
150 return (filep->fi_taken ? filep : 0);
151 }
152
153 return (0);
154 }
155
156 static int
opendir(ino_t inode,fileid_t * filep)157 opendir(ino_t inode, fileid_t *filep)
158 {
159 struct hs_direct hsdep;
160
161 dprintf("opendir: inode = %ld\n", inode);
162 /* Set up the IO request */
163 filep->fi_offset = 0;
164 filep->fi_blocknum = hdbtodb(inode);
165 filep->fi_count = ISO_SECTOR_SIZE;
166 filep->fi_memp = 0;
167
168 if (diskread(filep))
169 return (0);
170
171 filep->fi_offset = 0;
172 filep->fi_blocknum = hdbtodb(inode);
173
174 if (inode != root_ino)
175 return (0);
176
177 if (parse_dir(filep, 0, &hsdep) > 0) {
178 struct inode *ip;
179
180 ip = filep->fi_inode;
181 if (ip == NULL)
182 ip = filep->fi_inode = bkmem_alloc(sizeof (*ip));
183
184 ip->i_size = hsdep.hs_dir.ext_size;
185 ip->i_smode = hsdep.hs_dir.mode;
186 ip->i_number = inode;
187 return (0);
188 }
189 return (1);
190 }
191
192 static ino_t
find(char * path,fileid_t * filep)193 find(char *path, fileid_t *filep)
194 {
195 char *q;
196 char c;
197 ino_t n;
198
199 n = 0;
200 dprintf("find: %s\n", path);
201 if (path == NULL || *path == '\0')
202 return (0);
203
204 if (opendir(root_ino, filep))
205 return (0);
206
207 while (*path) {
208 while (*path == '/')
209 path++;
210 q = path;
211 while (*q != '/' && *q != '\0')
212 q++;
213 c = *q;
214 *q = '\0';
215 n = dlook(path, filep);
216 *q = c;
217 path = q;
218
219 if (n != 0) {
220 if (c == '\0')
221 break;
222 if (opendir(n, filep))
223 return (0);
224 continue;
225 } else {
226 return (0);
227 }
228 }
229 return ((ino_t)n);
230 }
231
232 static ino_t
dlook(char * s,fileid_t * filep)233 dlook(char *s, fileid_t *filep)
234 {
235 struct hs_direct *hsdep;
236 struct direct *udp;
237 struct inode *ip;
238 struct dirstuff dirp;
239 int len;
240
241 dprintf("dlook: %s\n", s);
242 ip = filep->fi_inode;
243 if (s == NULL || *s == '\0')
244 return (0);
245 if ((ip->i_smode & IFMT) != IFDIR) {
246 return (0);
247 }
248 if (ip->i_size == 0) {
249 return (0);
250 }
251 len = strlen(s);
252 dirp.loc = 0;
253 dirp.filep = filep;
254 for (hsdep = readdir(&dirp); hsdep != NULL; hsdep = readdir(&dirp)) {
255 udp = &hsdep->hs_ufs_dir;
256 if (udp->d_namlen == 1 &&
257 udp->d_name[0] == '.' &&
258 udp->d_name[1] == '\0')
259 continue;
260 if (udp->d_namlen == 2 &&
261 udp->d_name[0] == '.' &&
262 udp->d_name[1] == '.' &&
263 udp->d_name[2] == '\0')
264 continue;
265 if (udp->d_namlen == len && (strcmp(s, udp->d_name)) == 0) {
266 struct inode *ip = filep->fi_inode;
267
268 filep->fi_offset = 0;
269 filep->fi_blocknum = hdbtodb(udp->d_ino);
270
271 bzero(filep->fi_inode, sizeof (struct inode));
272 ip->i_size = hsdep->hs_dir.ext_size;
273 ip->i_smode = hsdep->hs_dir.mode;
274 ip->i_number = udp->d_ino;
275 return (udp->d_ino);
276 }
277 }
278 return (0);
279 }
280
281 /*
282 * get next entry in a directory.
283 */
284 static struct hs_direct *
readdir(struct dirstuff * dirp)285 readdir(struct dirstuff *dirp)
286 {
287 static struct hs_direct hsdep;
288 struct direct *udp = &hsdep.hs_ufs_dir;
289 struct inode *ip;
290 fileid_t *filep;
291 daddr_t lbn;
292 int off;
293
294 dprintf("readdir: start\n");
295 filep = dirp->filep;
296 ip = filep->fi_inode;
297 for (;;) {
298 if (dirp->loc >= ip->i_size) {
299 return (NULL);
300 }
301 off = dirp->loc & ((1 << ISO_SECTOR_SHIFT) - 1);
302 if (off == 0) {
303 lbn = hdbtodb(dirp->loc >> ISO_SECTOR_SHIFT);
304 filep->fi_blocknum = lbn + hdbtodb(ip->i_number);
305 filep->fi_count = ISO_SECTOR_SIZE;
306 filep->fi_memp = 0;
307 if (diskread(filep)) {
308 dprintf("readdir: diskread failed\n");
309 return (NULL);
310 }
311 }
312 dirp->loc += parse_dir(filep, off, &hsdep);
313 if (udp->d_reclen == 0 && dirp->loc <= ip->i_size) {
314 dirp->loc = roundup(dirp->loc, ISO_SECTOR_SIZE);
315 continue;
316 }
317 return (&hsdep);
318 }
319 }
320
321 static int
getblock(fileid_t * filep)322 getblock(fileid_t *filep)
323 {
324 struct inode *ip = filep->fi_inode;
325 int off, size, diff;
326 daddr_t lbn;
327
328 dprintf("getblock: start\n");
329 diff = ip->i_size - filep->fi_offset;
330 if (diff <= 0)
331 return (-1);
332
333 /* which block (or frag) in the file do we read? */
334 lbn = hdbtodb(filep->fi_offset >> ISO_SECTOR_SHIFT);
335 filep->fi_blocknum = lbn + hdbtodb(ip->i_number);
336
337 off = filep->fi_offset & ((1 << ISO_SECTOR_SHIFT) - 1);
338 size = filep->fi_count = ISO_SECTOR_SIZE;
339 filep->fi_memp = 0;
340 if (diskread(filep)) /* Trap errors */
341 return (-1);
342
343 if (filep->fi_offset - off + size >= ip->i_size)
344 filep->fi_count = diff + off;
345 filep->fi_count -= off;
346 filep->fi_memp += off;
347 dprintf("getblock: end\n");
348 return (0);
349 }
350
351 static ssize_t
bhsfs_read(int fd,caddr_t buf,size_t count)352 bhsfs_read(int fd, caddr_t buf, size_t count)
353 {
354 int i, j;
355 fileid_t *filep;
356 struct inode *ip;
357 caddr_t n;
358
359 dprintf("bhsfs_read %d, ", fd);
360 dprintf("count 0x%lx\n", count);
361 filep = find_fp(fd);
362 if (filep == NULL)
363 return (-1);
364
365 ip = filep->fi_inode;
366 n = buf;
367 if ((filep->fi_flags & FI_COMPRESSED) == 0 &&
368 filep->fi_offset + count > ip->i_size)
369 count = ip->i_size - filep->fi_offset;
370
371 if ((i = count) <= 0)
372 return (0);
373
374 while (i > 0) {
375 if (filep->fi_flags & FI_COMPRESSED) {
376 if ((j = cf_read(filep, buf, count)) < 0)
377 return (0); /* encountered an error */
378 if (j < i)
379 i = j; /* short read, must have hit EOF */
380 } else {
381 if (filep->fi_count == 0) {
382 if (getblock(filep) == -1)
383 return (0);
384 }
385 j = MIN(i, filep->fi_count);
386 bcopy(filep->fi_memp, buf, (uint_t)j);
387 }
388 filep->fi_memp += j;
389 filep->fi_offset += j;
390 filep->fi_count -= j;
391 buf += j;
392 i -= j;
393 }
394
395 dprintf("bhsfs_read: read 0x%x\n", (int)(buf - n));
396 return (buf - n);
397 }
398
399 /*ARGSUSED*/
400 static int
bhsfs_mountroot(char * str)401 bhsfs_mountroot(char *str)
402 {
403 char *bufp;
404
405 if (hsfsp != NULL)
406 return (0); /* already mounted */
407
408 dprintf("mounting ramdisk as hsfs\n");
409
410 hsfsp = bkmem_alloc(sizeof (*hsfsp));
411 bzero(hsfsp, sizeof (*hsfsp));
412 head = bkmem_alloc(sizeof (*head));
413 bzero(head, sizeof (*head));
414 head->fi_back = head->fi_forw = head;
415
416 /* now read the superblock. */
417 head->fi_blocknum = hdbtodb(ISO_VOLDESC_SEC);
418 head->fi_offset = 0;
419 head->fi_count = ISO_SECTOR_SIZE;
420 head->fi_memp = head->fi_buf;
421 if (diskread(head)) {
422 printf("failed to read superblock\n");
423 bhsfs_closeall();
424 return (-1);
425 }
426
427 /* Since RRIP is based on ISO9660, that's where we start */
428 bufp = head->fi_buf;
429 if ((ISO_DESC_TYPE(bufp) != ISO_VD_PVD) ||
430 (strncmp((const char *)ISO_std_id(bufp), ISO_ID_STRING,
431 ISO_ID_STRLEN) != 0) || (ISO_STD_VER(bufp) != ISO_ID_VER)) {
432 dprintf("volume type does not match\n");
433 bhsfs_closeall();
434 return (-1);
435 }
436
437 /* Now we fill in the volume descriptor */
438 hsfsp->vol_size = ISO_VOL_SIZE(bufp);
439 hsfsp->lbn_size = ISO_BLK_SIZE(bufp);
440 hsfsp->lbn_shift = ISO_SECTOR_SHIFT;
441 hsfsp->lbn_secshift = ISO_SECTOR_SHIFT;
442 hsfsp->vol_set_size = (ushort_t)ISO_SET_SIZE(bufp);
443 hsfsp->vol_set_seq = (ushort_t)ISO_SET_SEQ(bufp);
444
445 /* Make sure we have a valid logical block size */
446 if (hsfsp->lbn_size & ~(1 << hsfsp->lbn_shift)) {
447 printf("%d invalid logical block size\n", hsfsp->lbn_size);
448 bhsfs_closeall();
449 return (-1);
450 }
451
452 /* Since an HSFS root could be located anywhere on the media! */
453 root_ino = IDE_EXT_LBN(ISO_root_dir(bufp));
454 return (0);
455 }
456
457 static int
bhsfs_unmountroot(void)458 bhsfs_unmountroot(void)
459 {
460 if (hsfsp == NULL)
461 return (-1);
462
463 bhsfs_closeall();
464
465 return (0);
466 }
467
468 /*
469 * Open a file.
470 */
471 /*ARGSUSED*/
472 int
bhsfs_open(char * str,int flags)473 bhsfs_open(char *str, int flags)
474 {
475 static int filedes = 1;
476
477 fileid_t *filep;
478 ino_t ino;
479
480 dprintf("open %s\n", str);
481 filep = (fileid_t *)bkmem_alloc(sizeof (fileid_t));
482 filep->fi_back = head->fi_back;
483 filep->fi_forw = head;
484 head->fi_back->fi_forw = filep;
485 head->fi_back = filep;
486 filep->fi_filedes = filedes++;
487 filep->fi_taken = 1;
488 filep->fi_path = (char *)bkmem_alloc(strlen(str) + 1);
489 (void) strcpy(filep->fi_path, str);
490 filep->fi_inode = NULL;
491 bzero(filep->fi_buf, MAXBSIZE);
492 filep->fi_getblock = getblock;
493 filep->fi_flags = 0;
494
495 ino = find(str, filep);
496 if (ino == 0) {
497 (void) bhsfs_close(filep->fi_filedes);
498 return (-1);
499 }
500
501 filep->fi_blocknum = hdbtodb(ino);
502 filep->fi_offset = 0;
503 filep->fi_count = 0;
504 filep->fi_memp = 0;
505
506 if (cf_check_compressed(filep) != 0)
507 return (-1);
508 dprintf("open done\n");
509 return (filep->fi_filedes);
510 }
511
512 int
bhsfs_close(int fd)513 bhsfs_close(int fd)
514 {
515 fileid_t *filep;
516
517 dprintf("close %d\n", fd);
518 if (!(filep = find_fp(fd)))
519 return (-1);
520
521 if (filep->fi_taken == 0 || filep == head) {
522 printf("File descripter %d not allocated!\n", fd);
523 return (-1);
524 }
525
526 cf_close(filep);
527 /* unlink and deallocate node */
528 filep->fi_forw->fi_back = filep->fi_back;
529 filep->fi_back->fi_forw = filep->fi_forw;
530 if (filep->fi_inode)
531 bkmem_free(filep->fi_inode, sizeof (struct inode));
532 bkmem_free(filep->fi_path, strlen(filep->fi_path) + 1);
533 bkmem_free((char *)filep, sizeof (fileid_t));
534 dprintf("close done\n");
535 return (0);
536 }
537
538 static void
bhsfs_closeall(void)539 bhsfs_closeall(void)
540 {
541 fileid_t *filep;
542
543 while ((filep = head->fi_forw) != head)
544 if (filep->fi_taken && bhsfs_close(filep->fi_filedes))
545 printf("Filesystem may be inconsistent.\n");
546
547 bkmem_free(hsfsp, sizeof (*hsfsp));
548 bkmem_free(head, sizeof (fileid_t));
549 hsfsp = NULL;
550 head = NULL;
551 }
552
553 /*
554 * This version of seek() only performs absolute seeks (whence == 0).
555 */
556 static off_t
bhsfs_lseek(int fd,off_t addr,int whence)557 bhsfs_lseek(int fd, off_t addr, int whence)
558 {
559 fileid_t *filep;
560
561 dprintf("lseek %d, ", fd);
562 dprintf("off = %lx\n", addr);
563 if (!(filep = find_fp(fd)))
564 return (-1);
565
566 if (filep->fi_flags & FI_COMPRESSED) {
567 cf_seek(filep, addr, whence);
568 } else {
569 switch (whence) {
570 case SEEK_CUR:
571 filep->fi_offset += addr;
572 break;
573 case SEEK_SET:
574 filep->fi_offset = addr;
575 break;
576 default:
577 case SEEK_END:
578 printf("lseek(): invalid whence value %d\n", whence);
579 break;
580 }
581 filep->fi_blocknum = addr / DEV_BSIZE;
582 }
583
584 filep->fi_count = 0;
585 return (0);
586 }
587
588 static int
bhsfs_fstat(int fd,struct bootstat * stp)589 bhsfs_fstat(int fd, struct bootstat *stp)
590 {
591 fileid_t *filep;
592 struct inode *ip;
593
594 if (!(filep = find_fp(fd)))
595 return (-1);
596
597 ip = filep->fi_inode;
598
599 stp->st_mode = 0;
600 stp->st_size = 0;
601
602 if (ip == NULL)
603 return (0);
604
605 switch (ip->i_smode & IFMT) {
606 case IFDIR:
607 stp->st_mode = S_IFDIR;
608 break;
609 case IFREG:
610 stp->st_mode = S_IFREG;
611 break;
612 default:
613 break;
614 }
615 /*
616 * NOTE: this size will be the compressed size for a compressed file
617 * This could confuse the caller since we decompress the file behind
618 * the scenes when the file is read.
619 */
620 stp->st_size = ip->i_size;
621
622 /* file times */
623 stp->st_atim.tv_sec = ip->i_atime.tv_sec;
624 stp->st_atim.tv_nsec = ip->i_atime.tv_usec * 1000;
625 stp->st_mtim.tv_sec = ip->i_mtime.tv_sec;
626 stp->st_mtim.tv_nsec = ip->i_mtime.tv_usec * 1000;
627 stp->st_ctim.tv_sec = ip->i_ctime.tv_sec;
628 stp->st_ctim.tv_nsec = ip->i_ctime.tv_usec * 1000;
629
630 return (0);
631
632 }
633
634
635 /*
636 * Parse a directory entry.
637 *
638 */
639 static uint_t
parse_dir(fileid_t * filep,int offset,struct hs_direct * hsdep)640 parse_dir(fileid_t *filep, int offset, struct hs_direct *hsdep)
641 {
642 char *bufp = (char *)(filep->fi_memp + offset);
643 struct direct *udp = &hsdep->hs_ufs_dir; /* ufs-style dir info */
644 struct hs_direntry *hdp = &hsdep->hs_dir; /* hsfs-style dir info */
645 uint_t ce_lbn;
646 uint_t ce_len;
647 uint_t nmlen;
648 uint_t i;
649 uchar_t c;
650
651 dprintf("parse_dir: offset = %d\n", offset);
652 /* a zero length dir entry terminates the dir block */
653 udp->d_reclen = IDE_DIR_LEN(bufp);
654 if (udp->d_reclen == 0)
655 return (0);
656
657 /* fill in some basic hsfs info */
658 hdp->ext_lbn = IDE_EXT_LBN(bufp);
659 hdp->ext_size = IDE_EXT_SIZE(bufp);
660 hdp->xar_len = IDE_XAR_LEN(bufp);
661 hdp->intlf_sz = IDE_INTRLV_SIZE(bufp);
662 hdp->intlf_sk = IDE_INTRLV_SKIP(bufp);
663 hdp->sym_link = NULL;
664
665 /* we use lbn of data extent as an inode # equivalent */
666 udp->d_ino = hdp->ext_lbn;
667
668 c = IDE_FLAGS(bufp);
669 if (IDE_REGULAR_FILE(c)) {
670 hdp->type = VREG;
671 hdp->mode = IFREG;
672 hdp->nlink = 1;
673 } else if (IDE_REGULAR_DIR(c)) {
674 hdp->type = VDIR;
675 hdp->mode = IFDIR;
676 hdp->nlink = 2;
677 } else {
678 printf("pd(): file type=0x%x unknown.\n", c);
679 }
680
681 /*
682 * Massage hsfs name, recognizing special entries for . and ..
683 * else lopping off version junk.
684 */
685
686 /* Some initial conditions */
687 nmlen = IDE_NAME_LEN(bufp);
688 c = *IDE_NAME(bufp);
689 /* Special Case: Current Directory */
690 if (nmlen == 1 && c == '\0') {
691 udp->d_name[0] = '.';
692 udp->d_name[1] = '\0';
693 udp->d_namlen = 1;
694 /* Special Case: Parent Directory */
695 } else if (nmlen == 1 && c == '\001') {
696 udp->d_name[0] = '.';
697 udp->d_name[1] = '.';
698 udp->d_name[2] = '\0';
699 udp->d_namlen = 2;
700 /* Other file name */
701 } else {
702 udp->d_namlen = 0;
703 for (i = 0; i < nmlen; i++) {
704 c = *(IDE_name(bufp)+i);
705 if (c == ';')
706 break;
707 else if (c == ' ')
708 continue;
709 else
710 udp->d_name[udp->d_namlen++] = c;
711 }
712 udp->d_name[udp->d_namlen] = '\0';
713 }
714
715 /* System Use Fields */
716 ce_len = IDE_SUA_LEN(bufp);
717
718 if (ce_len == 0)
719 return (udp->d_reclen);
720
721 /* there is an SUA for this dir entry; go parse it */
722 ce_lbn = parse_susp((char *)IDE_sys_use_area(bufp), &ce_len, hsdep);
723
724 if (ce_lbn) {
725 /*
726 * store away current position in dir,
727 * as we will be using the iobuf to reading SUA.
728 */
729 daddr_t save_bn = filep->fi_blocknum;
730 daddr_t save_offset = filep->fi_offset;
731 caddr_t save_ma = filep->fi_memp;
732 int save_cc = filep->fi_count;
733 do {
734 filep->fi_count = ISO_SECTOR_SIZE;
735 filep->fi_offset = 0;
736 filep->fi_blocknum = hdbtodb(ce_lbn);
737 filep->fi_memp = 0;
738 if (diskread(filep)) {
739 printf("failed to read cont. area\n");
740 ce_len = 0;
741 ce_lbn = 0;
742 break;
743 }
744 ce_lbn = parse_susp(filep->fi_memp, &ce_len,
745 hsdep);
746 } while (ce_lbn);
747 filep->fi_count = save_cc;
748 filep->fi_offset = save_offset;
749 filep->fi_blocknum = save_bn;
750 filep->fi_memp = save_ma;
751 }
752 return (udp->d_reclen);
753 }
754
755 /*
756 * Parse the System Use Fields in this System Use Area.
757 * Return blk number of continuation/SUA, or 0 if no continuation/not a SUA.
758 */
759 static uint_t
parse_susp(char * bufp,uint_t * len,struct hs_direct * hsdep)760 parse_susp(char *bufp, uint_t *len, struct hs_direct *hsdep)
761 {
762 struct direct *udp = &hsdep->hs_ufs_dir; /* ufs-style info */
763 char *susp;
764 uint_t cur_off = 0;
765 uint_t blk_len = *len;
766 uint_t susp_len = 0;
767 uint_t ce_lbn = 0;
768 uint_t i;
769
770 dprintf("parse_susp: len = %d\n", *len);
771 while (cur_off < blk_len) {
772 susp = (char *)(bufp + cur_off);
773
774 /*
775 * A null entry, or an entry with zero length
776 * terminates the SUSP.
777 */
778 if (susp[0] == '\0' || susp[1] == '\0' ||
779 (susp_len = SUF_LEN(susp)) == 0)
780 break;
781
782 /*
783 * Compare current entry to all known signatures.
784 */
785 for (i = 0; i < hsfs_num_sig; i++)
786 if (strncmp(hsfs_sig_tab[i], susp, SUF_SIG_LEN) == 0)
787 break;
788 switch (i) {
789 case SUSP_CE_IX:
790 /*
791 * CE signature: continuation of SUSP.
792 * will want to return new lbn, len.
793 */
794 ce_lbn = CE_BLK_LOC(susp);
795 *len = CE_CONT_LEN(susp);
796 break;
797 case RRIP_NM_IX:
798 /* NM signature: POSIX-style file name */
799 if (!RRIP_NAME_FLAGS(susp)) {
800 udp->d_namlen = RRIP_NAME_LEN(susp);
801 bcopy((char *)RRIP_name(susp),
802 udp->d_name, udp->d_namlen);
803 udp->d_name[udp->d_namlen] = '\0';
804 }
805 break;
806 case HSFS_NUM_SIG:
807 /* couldn't find a legit susp, terminate loop */
808 case SUSP_ST_IX:
809 /* ST signature: terminates SUSP */
810 return (ce_lbn);
811 case SUSP_SP_IX:
812 case RRIP_RR_IX:
813 default:
814 break;
815 }
816 cur_off += susp_len;
817 }
818 return (ce_lbn);
819 }
820
821 struct boot_fs_ops bhsfs_ops = {
822 "boot_hsfs",
823 bhsfs_mountroot,
824 bhsfs_unmountroot,
825 bhsfs_open,
826 bhsfs_close,
827 bhsfs_read,
828 bhsfs_lseek,
829 bhsfs_fstat,
830 NULL
831 };
832