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