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 * 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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