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