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