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