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 #include <sys/param.h> 27 #include <sys/vnode.h> 28 #include <sys/fs/ufs_fsdir.h> 29 #include <sys/fs/ufs_fs.h> 30 #include <sys/fs/ufs_inode.h> 31 #include <sys/sysmacros.h> 32 #include <sys/promif.h> 33 #include <sys/filep.h> 34 #include <sys/salib.h> 35 #include <sys/sacache.h> 36 37 #include <sys/fs/hsfs_spec.h> 38 #include <sys/fs/hsfs_isospec.h> 39 #include <sys/fs/hsfs_node.h> 40 #include <sys/fs/hsfs_susp.h> 41 #include <sys/fs/hsfs_rrip.h> 42 43 #include "hsfs_sig.h" 44 45 #include <sys/stat.h> 46 #include <sys/bootvfs.h> 47 #include <sys/bootconf.h> 48 #include <sys/bootdebug.h> 49 50 #define hdbtodb(n) ((ISO_SECTOR_SIZE / DEV_BSIZE) * (n)) 51 52 #define THE_EPOCH 1970 53 #define END_OF_TIME 2099 54 55 /* May not need this... */ 56 static uint_t sua_offset = 0; 57 58 /* The root inode on an HSFS filesystem can be anywhere! */ 59 static uint_t root_ino = 0; /* This is both a flag and a value */ 60 61 static fileid_t *head; 62 63 /* Only got one of these...ergo, only 1 fs open at once */ 64 static devid_t *devp; 65 66 struct dirinfo { 67 int loc; 68 fileid_t *fi; 69 }; 70 71 struct hs_direct { 72 struct direct hs_ufs_dir; 73 struct hs_direntry hs_dir; 74 }; 75 76 /* 77 * Function prototypes 78 */ 79 80 static int boot_hsfs_mountroot(char *str); 81 static int boot_hsfs_unmountroot(void); 82 static int boot_hsfs_open(char *filename, int flags); 83 static int boot_hsfs_close(int fd); 84 static ssize_t boot_hsfs_read(int fd, caddr_t buf, size_t size); 85 static off_t boot_hsfs_lseek(int, off_t, int); 86 static int boot_hsfs_fstat(int fd, struct bootstat *stp); 87 static void boot_hsfs_closeall(int flag); 88 static int boot_hsfs_getdents(int fd, struct dirent *dep, unsigned size); 89 90 struct boot_fs_ops boot_hsfs_ops = { 91 "hsfs", 92 boot_hsfs_mountroot, 93 boot_hsfs_unmountroot, 94 boot_hsfs_open, 95 boot_hsfs_close, 96 boot_hsfs_read, 97 boot_hsfs_lseek, 98 boot_hsfs_fstat, 99 boot_hsfs_closeall, 100 boot_hsfs_getdents 101 }; 102 103 static ino_t find(fileid_t *, char *); 104 static ino_t dlook(fileid_t *, char *); 105 static int opendir(fileid_t *, ino_t); 106 static struct hs_direct *readdir(struct dirinfo *); 107 static uint_t parse_dir(fileid_t *, int, struct hs_direct *); 108 static uint_t parse_susp(char *, uint_t *, struct hs_direct *); 109 static void hs_seti(fileid_t *, struct hs_direct *, ino_t); 110 static void hs_dodates(enum hs_vol_type, struct hs_direntry *, char *); 111 static time_t hs_date_to_gmtime(int, int, int, int); 112 113 /* 114 * There is only 1 open (mounted) device at any given time. 115 * So we can keep a single, global devp file descriptor to 116 * use to index into the di[] array. This is not true for the 117 * fi[] array. We can have more than one file open at once, 118 * so there is no global fd for the fi[]. 119 * The user program must save the fd passed back from open() 120 * and use it to do subsequent read()'s. 121 */ 122 123 static int 124 opendir(fileid_t *filep, ino_t inode) 125 { 126 struct hs_direct hsdep; 127 int retval; 128 129 /* Set up the saio request */ 130 filep->fi_offset = 0; 131 filep->fi_blocknum = hdbtodb(inode); 132 filep->fi_count = ISO_SECTOR_SIZE; 133 134 /* Maybe the block is in the disk block cache */ 135 if ((filep->fi_memp = get_bcache(filep)) == NULL) { 136 /* Not in the block cache so read it from disk */ 137 if (retval = set_bcache(filep)) { 138 return (retval); 139 } 140 } 141 142 filep->fi_offset = 0; 143 filep->fi_blocknum = hdbtodb(inode); 144 145 if (inode != root_ino) 146 return (0); 147 148 if ((int)(parse_dir(filep, 0, &hsdep)) > 0) { 149 hs_seti(filep, &hsdep, inode); 150 return (0); 151 } 152 return (1); 153 } 154 155 static ino_t 156 find(fileid_t *filep, char *path) 157 { 158 register char *q; 159 char c; 160 ino_t inode; 161 162 if (path == NULL || *path == '\0') { 163 printf("null path\n"); 164 return (0); 165 } 166 167 if ((boothowto & RB_DEBUG) && (boothowto & RB_VERBOSE)) 168 printf("find(): path=<%s>\n", path); 169 170 /* Read the ROOT directory */ 171 if (opendir(filep, inode = root_ino)) { 172 printf("find(): root_ino opendir() failed!\n"); 173 return ((ino_t)-1); 174 } 175 176 while (*path) { 177 while (*path == '/') 178 path++; 179 if (*(q = path) == '\0') 180 break; 181 while (*q != '/' && *q != '\0') 182 q++; 183 c = *q; 184 *q = '\0'; 185 186 if ((inode = dlook(filep, path)) != 0) { 187 if (c == '\0') 188 break; 189 if (opendir(filep, inode)) { 190 printf("find(): opendir(%d) failed!\n", inode); 191 *q = c; 192 return ((ino_t)-1); 193 } 194 *q = c; 195 path = q; 196 continue; 197 } else { 198 *q = c; 199 return (0); 200 } 201 } 202 return (inode); 203 } 204 205 static fileid_t * 206 find_fp(int fd) 207 { 208 fileid_t *filep = head; 209 210 if (fd >= 0) { 211 while ((filep = filep->fi_forw) != head) 212 if (fd == filep->fi_filedes) 213 return (filep->fi_taken ? filep : 0); 214 } 215 216 return (0); 217 } 218 219 static ino_t 220 dlook(fileid_t *filep, char *path) 221 { 222 int dv = filep->fi_devp->di_dcookie; 223 register struct hs_direct *hsdep; 224 register struct direct *udp; 225 register struct inode *ip; 226 struct dirinfo dirp; 227 register int len; 228 ino_t in; 229 230 ip = filep->fi_inode; 231 if (path == NULL || *path == '\0') 232 return (0); 233 if ((ip->i_smode & IFMT) != IFDIR) { 234 return (0); 235 } 236 if (ip->i_size == 0) { 237 return (0); 238 } 239 len = strlen(path); 240 /* first look through the directory entry cache */ 241 if (in = get_dcache(dv, path, ip->i_number)) { 242 if ((filep->fi_inode = get_icache(dv, in)) != NULL) { 243 filep->fi_offset = 0; 244 filep->fi_blocknum = hdbtodb(in); 245 return (in); 246 } 247 } 248 dirp.loc = 0; 249 dirp.fi = filep; 250 for (hsdep = readdir(&dirp); hsdep != NULL; hsdep = readdir(&dirp)) { 251 udp = &hsdep->hs_ufs_dir; 252 if (udp->d_namlen == 1 && 253 udp->d_name[0] == '.' && 254 udp->d_name[1] == '\0') 255 continue; 256 if (udp->d_namlen == 2 && 257 udp->d_name[0] == '.' && 258 udp->d_name[1] == '.' && 259 udp->d_name[2] == '\0') 260 continue; 261 if (udp->d_namlen == len && (strcmp(path, udp->d_name) == 0)) { 262 set_dcache(dv, path, ip->i_number, udp->d_ino); 263 hs_seti(filep, hsdep, udp->d_ino); 264 filep->fi_offset = 0; 265 filep->fi_blocknum = hdbtodb(udp->d_ino); 266 /* put this entry into the cache */ 267 return (udp->d_ino); 268 } 269 /* Allow "*" to print all names at that level, w/out match */ 270 if (strcmp(path, "*") == 0) 271 printf("%s\n", udp->d_name); 272 } 273 return (0); 274 } 275 276 /* 277 * get next entry in a directory. 278 */ 279 static struct hs_direct * 280 readdir(struct dirinfo *dirp) 281 { 282 static struct hs_direct hsdep; 283 register struct direct *udp = &hsdep.hs_ufs_dir; 284 register struct inode *ip; 285 register fileid_t *filep; 286 register daddr_t lbn; 287 register int off; 288 289 filep = dirp->fi; 290 ip = filep->fi_inode; 291 for (;;) { 292 if (dirp->loc >= ip->i_size) { 293 return (NULL); 294 } 295 off = dirp->loc & ((1 << ISO_SECTOR_SHIFT) - 1); 296 if (off == 0) { 297 lbn = hdbtodb(dirp->loc >> ISO_SECTOR_SHIFT); 298 filep->fi_blocknum = lbn + hdbtodb(ip->i_number); 299 filep->fi_count = ISO_SECTOR_SIZE; 300 /* check the block cache */ 301 if ((filep->fi_memp = get_bcache(filep)) == 0) 302 if (set_bcache(filep)) 303 return ((struct hs_direct *)-1); 304 } 305 dirp->loc += parse_dir(filep, off, &hsdep); 306 if (udp->d_reclen == 0 && dirp->loc <= ip->i_size) { 307 dirp->loc = roundup(dirp->loc, ISO_SECTOR_SIZE); 308 continue; 309 } 310 return (&hsdep); 311 } 312 } 313 314 /* 315 * Get the next block of data from the file. If possible, dma right into 316 * user's buffer 317 */ 318 static int 319 getblock(fileid_t *filep, caddr_t buf, int count, int *rcount) 320 { 321 register struct inode *ip; 322 register caddr_t p; 323 register int off, size, diff; 324 register daddr_t lbn; 325 static int pos; 326 static char ind[] = "|/-\\"; /* that's entertainment? */ 327 static int blks_read; 328 329 ip = filep->fi_inode; 330 p = filep->fi_memp; 331 if ((signed)filep->fi_count <= 0) { 332 333 /* find the amt left to be read in the file */ 334 diff = ip->i_size - filep->fi_offset; 335 if (diff <= 0) { 336 printf("Short read\n"); 337 return (-1); 338 } 339 340 /* which block (or frag) in the file do we read? */ 341 lbn = hdbtodb(filep->fi_offset >> ISO_SECTOR_SHIFT); 342 343 /* which physical block on the device do we read? */ 344 filep->fi_blocknum = lbn + hdbtodb(ip->i_number); 345 346 off = filep->fi_offset & ((1 << ISO_SECTOR_SHIFT) - 1); 347 348 size = sizeof (filep->fi_buf); 349 if (size > ISO_SECTOR_SIZE) 350 size = ISO_SECTOR_SIZE; 351 352 filep->fi_count = size; 353 filep->fi_memp = filep->fi_buf; 354 355 /* 356 * optimization if we are reading large blocks of data then 357 * we can go directly to user's buffer 358 */ 359 *rcount = 0; 360 if (off == 0 && count >= size) { 361 filep->fi_memp = buf; 362 if (diskread(filep)) { 363 return (-1); 364 } 365 *rcount = size; 366 filep->fi_count = 0; 367 read_opt++; 368 if ((blks_read++ & 0x3) == 0) 369 printf("%c\b", ind[pos++ & 3]); 370 return (0); 371 } else 372 if (diskread(filep)) 373 return (-1); 374 375 /* 376 * round and round she goes (though not on every block.. 377 * - OBP's take a fair bit of time to actually print stuff) 378 */ 379 if ((blks_read++ & 0x3) == 0) 380 printf("%c\b", ind[pos++ & 3]); 381 382 if (filep->fi_offset - off + size >= ip->i_size) 383 filep->fi_count = diff + off; 384 filep->fi_count -= off; 385 p = &filep->fi_memp[off]; 386 } 387 filep->fi_memp = p; 388 return (0); 389 } 390 391 392 /* 393 * This is the high-level read function. It works like this. 394 * We assume that our IO device buffers up some amount of 395 * data ant that we can get a ptr to it. Thus we need 396 * to actually call the device func about filesize/blocksize times 397 * and this greatly increases our IO speed. When we already 398 * have data in the buffer, we just return that data (with bcopy() ). 399 */ 400 401 static ssize_t 402 boot_hsfs_read(int fd, caddr_t buf, size_t count) 403 { 404 size_t i, j; 405 struct inode *ip; 406 caddr_t n; 407 fileid_t *filep; 408 int rcount; 409 410 if (!(filep = find_fp(fd))) { 411 return (-1); 412 } 413 414 ip = filep->fi_inode; 415 416 if (filep->fi_offset + count > ip->i_size) 417 count = ip->i_size - filep->fi_offset; 418 419 /* that was easy */ 420 if ((i = count) == 0) 421 return (0); 422 423 n = buf; 424 while (i > 0) { 425 /* If we need to reload the buffer, do so */ 426 if ((j = filep->fi_count) == 0) { 427 (void) getblock(filep, buf, i, &rcount); 428 i -= rcount; 429 buf += rcount; 430 filep->fi_offset += rcount; 431 } else { 432 /* else just bcopy from our buffer */ 433 j = MIN(i, j); 434 bcopy(filep->fi_memp, buf, (unsigned)j); 435 buf += j; 436 filep->fi_memp += j; 437 filep->fi_offset += j; 438 filep->fi_count -= j; 439 i -= j; 440 } 441 } 442 return (buf - n); 443 } 444 445 /* 446 * This routine will open a device as it is known by the 447 * V2 OBP. 448 * Interface Defn: 449 * err = mountroot(string); 450 * err: 0 on success 451 * -1 on failure 452 * string: char string describing the properties of the device. 453 * We must not dork with any fi[]'s here. Save that for later. 454 */ 455 456 static int 457 boot_hsfs_mountroot(char *str) 458 { 459 ihandle_t h; 460 struct hs_volume *fsp; 461 char *bufp; 462 463 if ((boothowto & RB_DEBUG) && (boothowto & RB_VERBOSE)) 464 printf("mountroot()\n"); 465 466 /* 467 * If already mounted, just return success. 468 */ 469 if (root_ino != 0) { 470 return (0); 471 } 472 473 h = prom_open(str); 474 475 if (h == 0) { 476 printf("Cannot open %s\n", str); 477 return (-1); 478 } 479 480 devp = (devid_t *)bkmem_alloc(sizeof (devid_t)); 481 devp->di_taken = 1; 482 devp->di_dcookie = h; 483 devp->di_desc = (char *)bkmem_alloc(strlen(str) + 1); 484 (void) strcpy(devp->di_desc, str); 485 bzero(devp->un_fs.dummy, sizeof (devp->un_fs.dummy)); 486 head = (fileid_t *)bkmem_alloc(sizeof (fileid_t)); 487 head->fi_back = head->fi_forw = head; 488 head->fi_filedes = 0; 489 head->fi_taken = 0; 490 491 /* Setup read of the "superblock" */ 492 bzero(head->fi_buf, sizeof (head->fi_buf)); 493 head->fi_devp = devp; 494 head->fi_blocknum = hdbtodb(ISO_VOLDESC_SEC); 495 head->fi_count = ISO_SECTOR_SIZE; 496 head->fi_memp = head->fi_buf; 497 head->fi_offset = 0; 498 499 if (diskread(head)) { 500 printf("mountroot(): read super block failed!\n"); 501 boot_hsfs_closeall(1); 502 return (-1); 503 } 504 505 bufp = head->fi_memp; 506 fsp = (struct hs_volume *)devp->un_fs.dummy; 507 /* Since RRIP is based on ISO9660, that's where we start */ 508 509 if (ISO_DESC_TYPE(bufp) != ISO_VD_PVD || 510 strncmp((char *)(ISO_std_id(bufp)), (char *)(ISO_ID_STRING), 511 ISO_ID_STRLEN) != 0 || ISO_STD_VER(bufp) != ISO_ID_VER) { 512 boot_hsfs_closeall(1); 513 return (-1); 514 } 515 516 /* Now we fill in the volume descriptor */ 517 fsp->vol_size = ISO_VOL_SIZE(bufp); 518 fsp->lbn_size = ISO_BLK_SIZE(bufp); 519 fsp->lbn_shift = ISO_SECTOR_SHIFT; 520 fsp->lbn_secshift = ISO_SECTOR_SHIFT; 521 fsp->vol_set_size = (ushort_t)ISO_SET_SIZE(bufp); 522 fsp->vol_set_seq = (ushort_t)ISO_SET_SEQ(bufp); 523 524 /* Make sure we have a valid logical block size */ 525 if (fsp->lbn_size & ~(1 << fsp->lbn_shift)) { 526 printf("%d byte logical block size invalid.\n", fsp->lbn_size); 527 boot_hsfs_closeall(1); 528 return (-1); 529 } 530 531 /* Since an HSFS root could be located anywhere on the media! */ 532 root_ino = IDE_EXT_LBN(ISO_root_dir(bufp)); 533 534 if ((boothowto & RB_DEBUG) && (boothowto & RB_VERBOSE)) { 535 int i; 536 537 printf("root_ino=%d\n", root_ino); 538 printf("ID="); 539 for (i = 0; i < ISO_ID_STRLEN; i++) 540 printf("%c", *(ISO_std_id(bufp)+i)); 541 printf(" VS=%d\n", fsp->vol_size); 542 } 543 544 return (0); 545 } 546 547 /* 548 * Unmount the currently mounted root fs. In practice, this means 549 * closing all open files and releasing resources. All of this 550 * is done by boot_hsfs_closeall(). 551 */ 552 553 int 554 boot_hsfs_unmountroot(void) 555 { 556 if (root_ino == 0) 557 return (-1); 558 559 boot_hsfs_closeall(1); 560 561 return (0); 562 } 563 564 /* 565 * We allocate an fd here for use when talking 566 * to the file itself. 567 */ 568 569 /*ARGSUSED*/ 570 static int 571 boot_hsfs_open(char *filename, int flags) 572 { 573 fileid_t *filep; 574 ino_t inode; 575 static int filedes = 1; 576 577 /* build and link a new file descriptor */ 578 filep = (fileid_t *)bkmem_alloc(sizeof (fileid_t)); 579 filep->fi_back = head->fi_back; 580 filep->fi_forw = head; 581 head->fi_back->fi_forw = filep; 582 head->fi_back = filep; 583 584 filep->fi_filedes = filedes++; 585 filep->fi_taken = 1; 586 filep->fi_path = (char *)bkmem_alloc(strlen(filename) + 1); 587 (void) strcpy(filep->fi_path, filename); 588 filep->fi_devp = devp; /* dev is already "mounted" */ 589 590 filep->fi_inode = 0; 591 592 inode = find(filep, filename); 593 if (inode == (ino_t)0) { 594 if ((boothowto & RB_DEBUG) && (boothowto & RB_VERBOSE)) 595 printf("open(%s) ENOENT\n", filename); 596 (void) boot_hsfs_close(filep->fi_filedes); 597 return (-1); 598 } 599 600 filep->fi_blocknum = hdbtodb(inode); 601 filep->fi_offset = filep->fi_count = 0; 602 603 if ((boothowto & RB_DEBUG) && (boothowto & RB_VERBOSE)) 604 printf("open(%s) fd=%d\n", filename, filep->fi_filedes); 605 return (filep->fi_filedes); 606 } 607 608 /* 609 * hsfs_fstat() only supports size, mode and times at present time. 610 */ 611 612 static int 613 boot_hsfs_fstat(int fd, struct bootstat *stp) 614 { 615 fileid_t *filep; 616 struct inode *ip; 617 618 if (!(filep = find_fp(fd))) 619 return (-1); 620 621 ip = filep->fi_inode; 622 623 stp->st_mode = 0; 624 stp->st_size = 0; 625 626 if (ip == NULL) 627 return (0); 628 629 switch (ip->i_smode & IFMT) { 630 case IFDIR: 631 stp->st_mode = S_IFDIR; 632 break; 633 case IFREG: 634 stp->st_mode = S_IFREG; 635 break; 636 default: 637 break; 638 } 639 stp->st_size = ip->i_size; 640 641 /* file times */ 642 stp->st_atim.tv_sec = ip->i_atime.tv_sec; 643 stp->st_atim.tv_nsec = ip->i_atime.tv_usec * 1000; 644 stp->st_mtim.tv_sec = ip->i_mtime.tv_sec; 645 stp->st_mtim.tv_nsec = ip->i_mtime.tv_usec * 1000; 646 stp->st_ctim.tv_sec = ip->i_ctime.tv_sec; 647 stp->st_ctim.tv_nsec = ip->i_ctime.tv_usec * 1000; 648 649 return (0); 650 } 651 652 /* 653 * We don't do any IO here. 654 * We just play games with the device pointers. 655 */ 656 657 /*ARGSUSED*/ 658 static off_t 659 boot_hsfs_lseek(int fd, off_t addr, int whence) 660 { 661 fileid_t *filep; 662 663 if (!(filep = find_fp(fd))) 664 return (-1); 665 666 filep->fi_offset = addr; 667 filep->fi_blocknum = addr / DEV_BSIZE; 668 filep->fi_count = 0; 669 670 return (0); 671 } 672 673 static int 674 boot_hsfs_close(int fd) 675 { 676 fileid_t *filep; 677 678 if ((boothowto & RB_DEBUG) && (boothowto & RB_VERBOSE)) 679 printf("close(%d)\n", fd); 680 681 if (filep = find_fp(fd)) { 682 /* Clear the ranks */ 683 bkmem_free(filep->fi_path, strlen(filep->fi_path)+1); 684 filep->fi_blocknum = filep->fi_count = filep->fi_offset = 0; 685 filep->fi_memp = (caddr_t)0; 686 filep->fi_devp = 0; 687 filep->fi_taken = 0; 688 689 /* unlink and deallocate node */ 690 filep->fi_forw->fi_back = filep->fi_back; 691 filep->fi_back->fi_forw = filep->fi_forw; 692 bkmem_free((char *)filep, sizeof (fileid_t)); 693 694 return (0); 695 } else { 696 /* Big problem */ 697 printf("\nFile descrip %d not allocated!", fd); 698 return (-1); 699 } 700 } 701 702 /* closeall is now idempotent */ 703 /*ARGSUSED*/ 704 static void 705 boot_hsfs_closeall(int flag) 706 { 707 fileid_t *filep = head; 708 extern int verbosemode; 709 710 if (devp == NULL) { 711 if (head) 712 prom_panic("boot_hsfs_closeall: head != NULL.\n"); 713 return; 714 } 715 716 while ((filep = filep->fi_forw) != head) 717 if (filep->fi_taken) 718 if (boot_hsfs_close(filep->fi_filedes)) 719 prom_panic("Filesystem may be inconsistent.\n"); 720 721 722 release_cache(devp->di_dcookie); 723 (void) prom_close(devp->di_dcookie); 724 devp->di_taken = 0; 725 if (verbosemode) 726 print_cache_data(); 727 bkmem_free((char *)devp, sizeof (devid_t)); 728 bkmem_free((char *)head, sizeof (fileid_t)); 729 root_ino = 0; 730 devp = NULL; 731 head = NULL; 732 } 733 734 static uint_t 735 parse_dir(fileid_t *filep, int offset, struct hs_direct *hsdep) 736 { 737 char *bufp = (char *)(filep->fi_memp + offset); 738 struct direct *udp = &hsdep->hs_ufs_dir; 739 struct hs_direntry *hdp = &hsdep->hs_dir; 740 uint_t ce_lbn; 741 uint_t ce_len; 742 uint_t nmlen; 743 uint_t i; 744 uchar_t c; 745 int ret_code = 0; 746 747 if ((udp->d_reclen = IDE_DIR_LEN(bufp)) == 0) 748 return (0); 749 750 hdp->ext_lbn = IDE_EXT_LBN(bufp); 751 hdp->ext_size = IDE_EXT_SIZE(bufp); 752 hs_dodates(HS_VOL_TYPE_ISO, hdp, bufp); 753 hdp->xar_len = IDE_XAR_LEN(bufp); 754 hdp->intlf_sz = IDE_INTRLV_SIZE(bufp); 755 hdp->intlf_sk = IDE_INTRLV_SKIP(bufp); 756 hdp->sym_link = NULL; 757 758 udp->d_ino = hdp->ext_lbn; 759 760 c = IDE_FLAGS(bufp); 761 if (IDE_REGULAR_FILE(c)) { 762 hdp->type = VREG; 763 hdp->mode = IFREG; 764 hdp->nlink = 1; 765 } else if (IDE_REGULAR_DIR(c)) { 766 hdp->type = VDIR; 767 hdp->mode = IFDIR; 768 hdp->nlink = 2; 769 } else { 770 printf("parse_dir(): file type=0x%x unknown.\n", c); 771 return ((uint_t)-1); 772 } 773 774 /* Some initial conditions */ 775 nmlen = IDE_NAME_LEN(bufp); 776 c = *IDE_NAME(bufp); 777 /* Special Case: Current Directory */ 778 if (nmlen == 1 && c == '\0') { 779 udp->d_name[0] = '.'; 780 udp->d_name[1] = '\0'; 781 udp->d_namlen = 1; 782 /* Special Case: Parent Directory */ 783 } else if (nmlen == 1 && c == '\001') { 784 udp->d_name[0] = '.'; 785 udp->d_name[1] = '.'; 786 udp->d_name[2] = '\0'; 787 udp->d_namlen = 2; 788 /* Other file name */ 789 } else { 790 udp->d_namlen = 0; 791 for (i = 0; i < nmlen; i++) { 792 c = *(IDE_name(bufp)+i); 793 if (c == ';') 794 break; 795 else if (c == ' ') 796 continue; 797 else 798 udp->d_name[udp->d_namlen++] = c; 799 } 800 udp->d_name[udp->d_namlen] = '\0'; 801 } 802 /* System Use Fields */ 803 ce_len = IDE_SUA_LEN(bufp); 804 ce_lbn = 0; 805 if ((int)(ce_len) > 0) { 806 ce_lbn = parse_susp((char *)IDE_sys_use_area(bufp), 807 &ce_len, hsdep); 808 while (ce_lbn) { 809 daddr_t save_blocknum = filep->fi_blocknum; 810 daddr_t save_offset = filep->fi_offset; 811 caddr_t save_memp = filep->fi_memp; 812 uint_t save_count = filep->fi_count; 813 814 #ifdef noisy 815 print_io_req(filep, "parse_dir(): [I]"); 816 #endif /* noisy */ 817 818 filep->fi_blocknum = hdbtodb(ce_lbn); 819 filep->fi_offset = 0; 820 filep->fi_count = ISO_SECTOR_SIZE; 821 822 #ifdef noisy 823 print_io_req(filep, "parse_dir(): [0]"); 824 #endif /* noisy */ 825 826 if ((filep->fi_memp = get_bcache(filep)) == 0) 827 ret_code = set_bcache(filep); 828 829 #ifdef noisy 830 print_io_req(filep, "parse_dir(): [1]"); 831 #endif /* noisy */ 832 833 if (ret_code) { 834 filep->fi_blocknum = save_blocknum; 835 filep->fi_offset = save_offset; 836 filep->fi_memp = save_memp; 837 filep->fi_count = save_count; 838 printf("parse_dir(): " 839 "set_bcache() failed (%d)\n", ret_code); 840 break; 841 } 842 ce_lbn = parse_susp(filep->fi_memp, &ce_len, hsdep); 843 844 filep->fi_blocknum = save_blocknum; 845 filep->fi_offset = save_offset; 846 filep->fi_memp = save_memp; 847 filep->fi_count = save_count; 848 849 #ifdef noisy 850 print_io_req(filep, "parse_dir(): [2]"); 851 #endif /* noisy */ 852 } 853 } 854 855 return (udp->d_reclen); 856 } 857 858 static uint_t 859 parse_susp(char *bufp, uint_t *ce_len, struct hs_direct *hsdep) 860 { 861 struct direct *udp = &hsdep->hs_ufs_dir; 862 uchar_t *susp; 863 uint_t cur_off = 0; 864 uint_t blk_len = *ce_len; 865 uint_t susp_len = 0; 866 uint_t ce_lbn = 0; 867 uint_t i; 868 869 while (cur_off < blk_len) { 870 susp = (uchar_t *)(bufp + cur_off); 871 if (susp[0] == '\0' || susp[1] == '\0') 872 break; 873 susp_len = SUF_LEN(susp); 874 if (susp_len == 0) 875 break; 876 for (i = 0; i < hsfs_num_sig; i++) { 877 if (strncmp(hsfs_sig_tab[i], 878 (char *)susp, SUF_SIG_LEN) == 0) { 879 #ifdef noisy 880 if ((boothowto & RB_DEBUG) && 881 (boothowto & RB_VERBOSE)) 882 printf(" SUSP_%c%c %d\n", 883 susp[0], susp[1], susp_len); 884 #endif /* noisy */ 885 switch (i) { 886 case SUSP_SP_IX: 887 if (CHECK_BYTES_OK(susp)) { 888 sua_offset = 889 SP_SUA_OFFSET(susp); 890 #ifdef lint 891 /* this may not be needed */ 892 i = (int)sua_offset; 893 #endif /* lint */ 894 } 895 break; 896 897 case SUSP_CE_IX: 898 ce_lbn = CE_BLK_LOC(susp); 899 *ce_len = CE_CONT_LEN(susp); 900 #ifdef noisy 901 if ((boothowto & RB_DEBUG) && 902 (boothowto & RB_VERBOSE)) 903 printf("parse_susp(): " 904 "CE: ce_lbn = %d " 905 "ce_len=%d\n", 906 ce_lbn, *ce_len); 907 #endif /* noisy */ 908 break; 909 910 case SUSP_ST_IX: 911 printf("parse_susp(): ST: returning " 912 "%d\n", ce_lbn); 913 return (ce_lbn); 914 915 case RRIP_SL_IX: 916 #ifdef noisy 917 if ((boothowto & RB_DEBUG) && 918 (boothowto & RB_VERBOSE)) 919 printf("parse_susp(): " 920 "******* SL *******\n"); 921 #endif /* noisy */ 922 break; 923 924 case RRIP_RR_IX: 925 break; 926 927 case RRIP_NM_IX: 928 if (!RRIP_NAME_FLAGS(susp)) { 929 udp->d_namlen = 930 RRIP_NAME_LEN(susp); 931 bcopy((char *)RRIP_name(susp), 932 (char *)udp->d_name, 933 udp->d_namlen); 934 udp->d_name 935 [udp->d_namlen] = '\0'; 936 } 937 break; 938 } 939 cur_off += susp_len; 940 break; 941 } 942 } 943 if (i > hsfs_num_sig) { 944 printf("parse_susp(): Bad SUSP\n"); 945 cur_off = blk_len; 946 break; 947 } 948 } 949 return (ce_lbn); 950 } 951 952 static void 953 hs_seti(fileid_t *filep, struct hs_direct *hsdep, ino_t inode) 954 { 955 register struct inode *ip; 956 int dv = filep->fi_devp->di_dcookie; 957 958 /* Try the inode cache first */ 959 if ((filep->fi_inode = get_icache(dv, inode)) != NULL) 960 return; 961 962 filep->fi_inode = (struct inode *)bkmem_alloc(sizeof (struct inode)); 963 ip = filep->fi_inode; 964 bzero((char *)ip, sizeof (struct inode)); 965 ip->i_size = hsdep->hs_dir.ext_size; 966 ip->i_smode = hsdep->hs_dir.mode; 967 ip->i_number = inode; 968 ip->i_atime.tv_sec = hsdep->hs_dir.adate.tv_sec; 969 ip->i_atime.tv_usec = hsdep->hs_dir.adate.tv_usec; 970 ip->i_ctime.tv_sec = hsdep->hs_dir.cdate.tv_sec; 971 ip->i_ctime.tv_usec = hsdep->hs_dir.cdate.tv_usec; 972 ip->i_mtime.tv_sec = hsdep->hs_dir.mdate.tv_sec; 973 ip->i_mtime.tv_usec = hsdep->hs_dir.mdate.tv_usec; 974 set_icache(dv, inode, ip, sizeof (struct inode)); 975 } 976 977 #ifdef noisy 978 static void 979 print_io_req(fileid_t *filep, char *str) 980 { 981 printf("%s o=%d b=%d c=%d m=%x\n", 982 str, 983 filep->fi_offset, 984 filep->fi_blocknum, 985 filep->fi_count, 986 (uint_t)filep->fi_memp); 987 } 988 #endif /* noisy */ 989 990 static int 991 boot_hsfs_getdents(int fd, struct dirent *dep, unsigned size) 992 { 993 /* 994 * Read directory entries from the file open on "fd" into the 995 * "size"-byte buffer at "dep" until the buffer is exhausted 996 * or we reach EOF on the directory. Returns the number of 997 * entries read. 998 */ 999 int n; 1000 int cnt = 0; 1001 struct dirinfo dir; 1002 struct hs_direct *hdp; 1003 unsigned long oldoff, oldblok; 1004 1005 #define SLOP (sizeof (struct dirent) - offsetof(struct dirent, d_name[1])) 1006 1007 if (!(dir.fi = find_fp(fd)) || 1008 ((dir.fi->fi_inode->i_smode & IFMT) != IFDIR)) { 1009 /* 1010 * Bogus file descriptor, bail out now! 1011 */ 1012 return (-1); 1013 } 1014 1015 oldoff = dir.loc = dir.fi->fi_offset; 1016 oldblok = dir.fi->fi_blocknum; 1017 1018 for (hdp = readdir(&dir); hdp; hdp = readdir(&dir)) { 1019 /* 1020 * Compute name length and break loop if there's not 1021 * enough space in the output buffer for the next 1022 * entry. 1023 * 1024 * NOTE: "SLOP" is the number of bytes inserted into the dirent 1025 * struct's "d_name" field by the compiler to preserve 1026 * alignment. 1027 */ 1028 n = strlen(hdp->hs_ufs_dir.d_name); 1029 n = roundup((sizeof (struct dirent) + ((n > SLOP) ? n : 0)), 1030 sizeof (off_t)); 1031 1032 if (n > size) { 1033 dir.fi->fi_blocknum = oldblok; 1034 dir.fi->fi_offset = oldoff; 1035 break; 1036 } 1037 1038 oldblok = dir.fi->fi_blocknum; 1039 oldoff = dir.loc; 1040 size -= n; 1041 cnt += 1; 1042 1043 (void) strlcpy(dep->d_name, hdp->hs_ufs_dir.d_name, 1044 strlen(hdp->hs_ufs_dir.d_name) + 1); 1045 dep->d_ino = hdp->hs_ufs_dir.d_ino; 1046 dep->d_off = dir.loc; 1047 dep->d_reclen = (unsigned short)n; 1048 1049 dep = (struct dirent *)((char *)dep + n); 1050 } 1051 1052 #undef SLOP 1053 1054 return (cnt); 1055 } 1056 1057 static void 1058 hs_dodates(enum hs_vol_type type, struct hs_direntry *hdp, char *bufp) 1059 { 1060 if (type == HS_VOL_TYPE_HS) { 1061 hs_parse_dirdate(HDE_cdate(bufp), &hdp->cdate); 1062 hs_parse_dirdate(HDE_cdate(bufp), &hdp->adate); 1063 hs_parse_dirdate(HDE_cdate(bufp), &hdp->mdate); 1064 } else if (type == HS_VOL_TYPE_ISO) { 1065 hs_parse_dirdate(IDE_cdate(bufp), &hdp->cdate); 1066 hs_parse_dirdate(IDE_cdate(bufp), &hdp->adate); 1067 hs_parse_dirdate(IDE_cdate(bufp), &hdp->mdate); 1068 } else 1069 prom_panic("hs_dodates: bad volume type"); 1070 } 1071 1072 /* 1073 * hs_parse_dirdate 1074 * 1075 * Parse the short 'directory-format' date into a Unix timeval. 1076 * This is the date format used in Directory Entries. 1077 * 1078 * If the date is not representable, make something up. 1079 */ 1080 void 1081 hs_parse_dirdate(uchar_t *dp, struct timeval *tvp) 1082 { 1083 int year, month, day, hour, minute, sec, gmtoff; 1084 1085 year = HDE_DATE_YEAR(dp); 1086 month = HDE_DATE_MONTH(dp); 1087 day = HDE_DATE_DAY(dp); 1088 hour = HDE_DATE_HOUR(dp); 1089 minute = HDE_DATE_MIN(dp); 1090 sec = HDE_DATE_SEC(dp); 1091 gmtoff = HDE_DATE_GMTOFF(dp); 1092 1093 tvp->tv_usec = 0; 1094 if (year < THE_EPOCH) { 1095 tvp->tv_sec = 0; 1096 } else { 1097 tvp->tv_sec = hs_date_to_gmtime(year, month, day, gmtoff); 1098 if (tvp->tv_sec != -1) { 1099 tvp->tv_sec += ((hour * 60) + minute) * 60 + sec; 1100 } 1101 } 1102 1103 return; 1104 1105 } 1106 1107 /* 1108 * hs_parse_longdate 1109 * 1110 * Parse the long 'user-oriented' date into a Unix timeval. 1111 * This is the date format used in the Volume Descriptor. 1112 * 1113 * If the date is not representable, make something up. 1114 */ 1115 void 1116 hs_parse_longdate(uchar_t *dp, struct timeval *tvp) 1117 { 1118 int year, month, day, hour, minute, sec, gmtoff; 1119 1120 year = HSV_DATE_YEAR(dp); 1121 month = HSV_DATE_MONTH(dp); 1122 day = HSV_DATE_DAY(dp); 1123 hour = HSV_DATE_HOUR(dp); 1124 minute = HSV_DATE_MIN(dp); 1125 sec = HSV_DATE_SEC(dp); 1126 gmtoff = HSV_DATE_GMTOFF(dp); 1127 1128 tvp->tv_usec = 0; 1129 if (year < THE_EPOCH) { 1130 tvp->tv_sec = 0; 1131 } else { 1132 tvp->tv_sec = hs_date_to_gmtime(year, month, day, gmtoff); 1133 if (tvp->tv_sec != -1) { 1134 tvp->tv_sec += ((hour * 60) + minute) * 60 + sec; 1135 tvp->tv_usec = HSV_DATE_HSEC(dp) * 10000; 1136 } 1137 } 1138 1139 } 1140 1141 /* cumulative number of seconds per month, non-leap and leap-year versions */ 1142 static time_t cum_sec[] = { 1143 0x0, 0x28de80, 0x4dc880, 0x76a700, 0x9e3400, 0xc71280, 1144 0xee9f80, 0x1177e00, 0x1405c80, 0x167e980, 0x190c800, 0x1b85500 1145 }; 1146 static time_t cum_sec_leap[] = { 1147 0x0, 0x28de80, 0x4f1a00, 0x77f880, 0x9f8580, 0xc86400, 1148 0xeff100, 0x118cf80, 0x141ae00, 0x1693b00, 0x1921980, 0x1b9a680 1149 }; 1150 #define SEC_PER_DAY 0x15180 1151 #define SEC_PER_YEAR 0x1e13380 1152 1153 /* 1154 * hs_date_to_gmtime 1155 * 1156 * Convert year(1970-2099)/month(1-12)/day(1-31) to seconds-since-1970/1/1. 1157 * 1158 * Returns -1 if the date is out of range. 1159 */ 1160 static time_t 1161 hs_date_to_gmtime(int year, int mon, int day, int gmtoff) 1162 { 1163 time_t sum; 1164 time_t *cp; 1165 int y; 1166 1167 if ((year < THE_EPOCH) || (year > END_OF_TIME) || 1168 (mon < 1) || (mon > 12) || 1169 (day < 1) || (day > 31)) 1170 return (-1); 1171 1172 /* 1173 * Figure seconds until this year and correct for leap years. 1174 * Note: 2000 is a leap year but not 2100. 1175 */ 1176 y = year - THE_EPOCH; 1177 sum = y * SEC_PER_YEAR; 1178 sum += ((y + 1) / 4) * SEC_PER_DAY; 1179 /* 1180 * Point to the correct table for this year and 1181 * add in seconds until this month. 1182 */ 1183 cp = ((y + 2) % 4) ? cum_sec : cum_sec_leap; 1184 sum += cp[mon - 1]; 1185 /* 1186 * Add in seconds until 0:00 of this day. 1187 * (days-per-month validation is not done here) 1188 */ 1189 sum += (day - 1) * SEC_PER_DAY; 1190 sum -= (gmtoff * 15 * 60); 1191 return (sum); 1192 } 1193