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