1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #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 36 #include <sys/stat.h> 37 #include <sys/bootvfs.h> 38 #include <sys/bootdebug.h> 39 #include <sys/salib.h> 40 #include <sys/sacache.h> 41 42 43 int print_cache_stats = 0; 44 45 /* 46 * This fd is used when talking to the device file itself. 47 */ 48 static fileid_t *head; 49 /* 50 * hooks into ufs logging support 51 */ 52 extern void lufs_boot_init(fileid_t *); 53 extern void lufs_closeall(void); 54 extern void lufs_merge_deltas(fileid_t *); 55 56 /* Only got one of these...ergo, only 1 fs open at once */ 57 /* static */ 58 devid_t *ufs_devp; 59 60 struct dirinfo { 61 int loc; 62 fileid_t *fi; 63 }; 64 65 /* 66 * Function prototypes 67 */ 68 static int boot_ufs_mountroot(char *str); 69 static int boot_ufs_unmountroot(void); 70 static int boot_ufs_open(char *filename, int flags); 71 static int boot_ufs_close(int fd); 72 static ssize_t boot_ufs_read(int fd, caddr_t buf, size_t size); 73 static off_t boot_ufs_lseek(int, off_t, int); 74 static int boot_ufs_fstat(int fd, struct bootstat *stp); 75 static void boot_ufs_closeall(int flag); 76 static int boot_ufs_getdents(int fd, struct dirent *dep, unsigned size); 77 78 struct boot_fs_ops boot_ufs_ops = { 79 "ufs", 80 boot_ufs_mountroot, 81 boot_ufs_unmountroot, 82 boot_ufs_open, 83 boot_ufs_close, 84 boot_ufs_read, 85 boot_ufs_lseek, 86 boot_ufs_fstat, 87 boot_ufs_closeall, 88 boot_ufs_getdents 89 }; 90 91 static ino_t find(fileid_t *filep, char *path); 92 static ino_t dlook(fileid_t *filep, char *path); 93 static daddr32_t sbmap(fileid_t *filep, daddr32_t bn); 94 static struct direct *readdir(struct dirinfo *dstuff); 95 96 /* These are the pools of buffers, etc. */ 97 #define NBUFS (NIADDR+1) 98 /* Compilers like to play with alignment, so force the issue here */ 99 static union { 100 char *blk[NBUFS]; 101 daddr32_t *dummy; 102 } b; 103 daddr32_t blknos[NBUFS]; 104 105 /* 106 * There is only 1 open (mounted) device at any given time. 107 * So we can keep a single, global devp file descriptor to 108 * use to index into the di[] array. This is not true for the 109 * fi[] array. We can have more than one file open at once, 110 * so there is no global fd for the fi[]. 111 * The user program must save the fd passed back from open() 112 * and use it to do subsequent read()'s. 113 */ 114 115 static int 116 openi(fileid_t *filep, ino_t inode) 117 { 118 int retval; 119 struct dinode *dp; 120 devid_t *devp = filep->fi_devp; 121 122 /* Try the inode cache first */ 123 if ((filep->fi_inode = get_icache(devp->di_dcookie, inode)) != NULL) 124 return (0); 125 /* Nope, not there so lets read it off the disk. */ 126 filep->fi_offset = 0; 127 filep->fi_blocknum = fsbtodb(&devp->un_fs.di_fs, 128 itod(&devp->un_fs.di_fs, inode)); 129 130 /* never more than 1 disk block */ 131 filep->fi_count = devp->un_fs.di_fs.fs_bsize; 132 filep->fi_memp = filep->fi_buf; 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 lufs_merge_deltas(filep); 140 } 141 142 dp = (struct dinode *)filep->fi_memp; 143 filep->fi_inode = (struct inode *) 144 bkmem_alloc(sizeof (struct inode)); 145 bzero((char *)filep->fi_inode, sizeof (struct inode)); 146 filep->fi_inode->i_ic = 147 dp[itoo(&devp->un_fs.di_fs, inode)].di_un.di_icom; 148 filep->fi_inode->i_number = inode; 149 if (set_ricache(devp->di_dcookie, inode, (void *)filep->fi_inode, 150 sizeof (struct inode))) 151 filep->fi_inode->i_flag = FI_NOCACHE; 152 return (0); 153 } 154 155 static fileid_t * 156 find_fp(int fd) 157 { 158 fileid_t *filep = head; 159 160 if (fd >= 0) { 161 while ((filep = filep->fi_forw) != head) 162 if (fd == filep->fi_filedes) 163 return (filep->fi_taken ? filep : 0); 164 } 165 166 return (0); 167 } 168 169 static ino_t 170 find(fileid_t *filep, char *path) 171 { 172 char *q; 173 char c; 174 ino_t inode; 175 char lpath[MAXPATHLEN]; 176 char *lpathp = lpath; 177 int len, r; 178 devid_t *devp; 179 180 if (path == NULL || *path == '\0') { 181 printf("null path\n"); 182 return ((ino_t)0); 183 } 184 185 bzero(lpath, sizeof (lpath)); 186 bcopy(path, lpath, strlen(path)); 187 devp = filep->fi_devp; 188 while (*lpathp) { 189 /* if at the beginning of pathname get root inode */ 190 r = (lpathp == lpath); 191 if (r && openi(filep, (ino_t)UFSROOTINO)) 192 return ((ino_t)0); 193 while (*lpathp == '/') 194 lpathp++; /* skip leading slashes */ 195 q = lpathp; 196 while (*q != '/' && *q != '\0') 197 q++; /* find end of component */ 198 c = *q; 199 *q = '\0'; /* terminate component */ 200 201 /* Bail out early if opening root */ 202 if (r && (*lpathp == '\0')) 203 return ((ino_t)UFSROOTINO); 204 if ((inode = dlook(filep, lpathp)) != 0) { 205 if (openi(filep, inode)) 206 return ((ino_t)0); 207 if ((filep->fi_inode->i_smode & IFMT) == IFLNK) { 208 filep->fi_blocknum = 209 fsbtodb(&devp->un_fs.di_fs, 210 filep->fi_inode->i_db[0]); 211 filep->fi_count = DEV_BSIZE; 212 /* check the block cache */ 213 if ((filep->fi_memp = get_bcache(filep)) 214 == NULL) { 215 if (set_bcache(filep)) 216 return ((ino_t)0); 217 lufs_merge_deltas(filep); 218 } 219 len = strlen(filep->fi_memp); 220 if (filep->fi_memp[0] == '/') 221 /* absolute link */ 222 lpathp = lpath; 223 /* copy rest of unprocessed path up */ 224 bcopy(q, lpathp + len, strlen(q + 1) + 2); 225 /* point to unprocessed path */ 226 *(lpathp + len) = c; 227 /* prepend link in before unprocessed path */ 228 bcopy(filep->fi_memp, lpathp, len); 229 lpathp = lpath; 230 continue; 231 } else 232 *q = c; 233 if (c == '\0') 234 break; 235 lpathp = q; 236 continue; 237 } else { 238 return ((ino_t)0); 239 } 240 } 241 return (inode); 242 } 243 244 /* 245 * Map <file, file logical block> into a file system block number. 246 * Reads indirect blocks as needed to find the block. Returns zero when 247 * block isn't there; returns negative fsbn when block is uninitialized. 248 */ 249 static daddr32_t 250 sbmap(fileid_t *filep, daddr32_t bn) 251 { 252 struct inode *inodep; 253 int i, j, sh; 254 daddr32_t nb, *bap; 255 daddr32_t *db; 256 devid_t *devp; 257 258 devp = filep->fi_devp; 259 inodep = filep->fi_inode; 260 db = inodep->i_db; 261 262 /* 263 * blocks 0..NDADDR are direct blocks 264 */ 265 if (bn < NDADDR) { 266 nb = db[bn]; 267 return (nb); 268 } 269 270 /* 271 * addresses NIADDR have single and double indirect blocks. 272 * the first step is to determine how many levels of indirection. 273 */ 274 sh = 1; 275 bn -= NDADDR; 276 for (j = NIADDR; j > 0; j--) { 277 sh *= NINDIR(&devp->un_fs.di_fs); 278 if (bn < sh) 279 break; 280 bn -= sh; 281 } 282 if (j == 0) { 283 return ((daddr32_t)0); 284 } 285 286 /* 287 * fetch the first indirect block address from the inode 288 */ 289 nb = inodep->i_ib[NIADDR - j]; 290 if (nb == 0) { 291 return ((daddr32_t)0); 292 } 293 294 /* 295 * fetch through the indirect blocks 296 */ 297 for (; j <= NIADDR; j++) { 298 if (blknos[j] != nb) { 299 filep->fi_blocknum = fsbtodb(&devp->un_fs.di_fs, nb); 300 filep->fi_count = devp->un_fs.di_fs.fs_bsize; 301 /* First look through the disk block cache */ 302 if ((filep->fi_memp = get_bcache(filep)) == NULL) { 303 if (set_bcache(filep)) /* Gotta do I/O */ 304 return (0); 305 lufs_merge_deltas(filep); 306 } 307 b.blk[j] = filep->fi_memp; 308 blknos[j] = nb; 309 } 310 bap = (daddr32_t *)b.blk[j]; 311 sh /= NINDIR(&devp->un_fs.di_fs); 312 i = (bn / sh) % NINDIR(&devp->un_fs.di_fs); 313 nb = bap[i]; 314 if (nb == 0) { 315 return ((daddr32_t)0); 316 } 317 } 318 return (nb); 319 } 320 321 static ino_t 322 dlook(fileid_t *filep, char *path) 323 { 324 devid_t *devp = filep->fi_devp; 325 struct direct *dp; 326 struct inode *ip; 327 struct dirinfo dirp; 328 int len; 329 ino_t in; 330 #ifdef DEBUG 331 static int warned = 0; 332 #endif 333 334 ip = filep->fi_inode; 335 if (path == NULL || *path == '\0') 336 return (0); 337 if ((ip->i_smode & IFMT) != IFDIR) 338 return (0); 339 if (ip->i_size == 0) 340 return (0); 341 len = strlen(path); 342 343 /* 344 * First look through the directory entry cache 345 */ 346 if ((in = get_dcache(devp->di_dcookie, path, ip->i_number)) != 0) 347 return (in); 348 349 /* 350 * If the entire directory is cached, return failure 351 */ 352 if (ip->i_flag & FI_CACHED) 353 return (0); 354 355 /* 356 * Otherwise, read the entire directory into the cache 357 */ 358 in = 0; 359 dirp.loc = 0; 360 dirp.fi = filep; 361 if (!(ip->i_flag & FI_NOCACHE)) 362 ip->i_flag |= FI_CACHED; 363 for (dp = readdir(&dirp); dp != NULL; dp = readdir(&dirp)) { 364 if (dp->d_ino == 0) 365 continue; 366 if (dp->d_namlen == len && strcmp(path, dp->d_name) == 0) 367 in = dp->d_ino; 368 369 /* 370 * Allow "*" to print all names at that level, w/out match 371 */ 372 if (strcmp(path, "*") == 0) 373 printf("%s\n", dp->d_name); 374 375 if (ip->i_flag & FI_NOCACHE) 376 continue; 377 378 /* 379 * Put this entry into the cache. If the entry has been 380 * partially cached, check before inserting. This should be 381 * rare if sized correctly 382 */ 383 if ((ip->i_flag & FI_PARTIAL_CACHE) && 384 (get_dcache(devp->di_dcookie, dp->d_name, dp->d_ino) != 0)) 385 continue; 386 387 if (set_rdcache(devp->di_dcookie, dp->d_name, ip->i_number, 388 dp->d_ino)) { 389 ip->i_flag &= ~FI_CACHED; 390 ip->i_flag |= FI_PARTIAL_CACHE; 391 #ifdef DEBUG 392 if (!warned) { 393 printf("ufsboot: directory cache too small\n"); 394 warned++; 395 } 396 #endif 397 } 398 } 399 return (in); 400 } 401 402 /* 403 * get next entry in a directory. 404 */ 405 struct direct * 406 readdir(struct dirinfo *dstuff) 407 { 408 struct direct *dp; 409 fileid_t *filep; 410 daddr32_t lbn, d; 411 int off; 412 devid_t *devp; 413 414 filep = dstuff->fi; 415 devp = filep->fi_devp; 416 for (;;) { 417 if (dstuff->loc >= filep->fi_inode->i_size) { 418 return (NULL); 419 } 420 off = blkoff(&devp->un_fs.di_fs, dstuff->loc); 421 if (off == 0) { 422 lbn = lblkno(&devp->un_fs.di_fs, dstuff->loc); 423 d = sbmap(filep, lbn); 424 425 if (d <= 0) 426 return (NULL); 427 428 filep->fi_blocknum = fsbtodb(&devp->un_fs.di_fs, d); 429 filep->fi_count = 430 blksize(&devp->un_fs.di_fs, filep->fi_inode, lbn); 431 /* check the block cache */ 432 if ((filep->fi_memp = get_bcache(filep)) == NULL) { 433 if (set_bcache(filep)) 434 return (NULL); 435 lufs_merge_deltas(filep); 436 } 437 } 438 dp = (struct direct *)(filep->fi_memp + off); 439 dstuff->loc += dp->d_reclen; 440 if (dp->d_ino == 0) 441 continue; 442 return (dp); 443 } 444 } 445 446 /* 447 * Get the next block of data from the file. If possible, dma right into 448 * user's buffer 449 */ 450 static int 451 getblock(fileid_t *filep, caddr_t buf, int count, int *rcount) 452 { 453 struct fs *fs; 454 caddr_t p; 455 int off, size, diff, zeroize; 456 daddr32_t lbn, fsbn; 457 devid_t *devp; 458 #ifndef i386 459 static int pos; 460 static char ind[] = "|/-\\"; /* that's entertainment? */ 461 static int blks_read; 462 #endif 463 devp = filep->fi_devp; 464 p = filep->fi_memp; 465 if ((signed)filep->fi_count <= 0) { 466 467 /* find the amt left to be read in the file */ 468 diff = filep->fi_inode->i_size - filep->fi_offset; 469 if (diff <= 0) { 470 printf("Short read\n"); 471 return (-1); 472 } 473 474 fs = &devp->un_fs.di_fs; 475 /* which block (or frag) in the file do we read? */ 476 lbn = lblkno(fs, filep->fi_offset); 477 478 /* which physical block on the device do we read? */ 479 fsbn = sbmap(filep, lbn); 480 481 /* 482 * zero fsbn -> unallocated hole. 483 * negative fsbn -> allocated but uninitialized. 484 * since we only read from the fs, treat both the same. 485 */ 486 zeroize = (fsbn <= 0); 487 488 filep->fi_blocknum = fsbtodb(fs, fsbn); 489 490 off = blkoff(fs, filep->fi_offset); 491 492 /* either blksize or fragsize */ 493 size = blksize(fs, filep->fi_inode, lbn); 494 filep->fi_count = size; 495 filep->fi_memp = filep->fi_buf; 496 497 /* 498 * optimization if we are reading large blocks of data then 499 * we can go directly to user's buffer 500 */ 501 *rcount = 0; 502 if (off == 0 && count >= size) { 503 filep->fi_memp = buf; 504 if (zeroize) { 505 bzero(buf, size); 506 } else if (diskread(filep)) { 507 return (-1); 508 } 509 *rcount = size; 510 filep->fi_count = 0; 511 read_opt++; 512 #ifndef i386 513 if ((blks_read++ & 0x3) == 0) 514 printf("%c\b", ind[pos++ & 3]); 515 #endif 516 return (0); 517 } else { 518 if (zeroize) { 519 bzero(filep->fi_memp, size); 520 } else if (diskread(filep)) 521 return (-1); 522 } 523 524 /* 525 * round and round she goes (though not on every block.. 526 * - OBP's take a fair bit of time to actually print stuff) 527 * On x86, the screen oriented bootconf program doesn't 528 * want this noise... 529 */ 530 #ifndef i386 531 if ((blks_read++ & 0x3) == 0) 532 printf("%c\b", ind[pos++ & 3]); 533 #endif 534 535 if (filep->fi_offset - off + size >= filep->fi_inode->i_size) 536 filep->fi_count = diff + off; 537 filep->fi_count -= off; 538 p = &filep->fi_memp[off]; 539 } 540 filep->fi_memp = p; 541 return (0); 542 } 543 544 545 /* 546 * This is the high-level read function. It works like this. 547 * We assume that our IO device buffers up some amount of 548 * data and that we can get a ptr to it. Thus we need 549 * to actually call the device func about filesize/blocksize times 550 * and this greatly increases our IO speed. When we already 551 * have data in the buffer, we just return that data (with bcopy() ). 552 */ 553 554 static ssize_t 555 boot_ufs_read(int fd, caddr_t buf, size_t count) 556 { 557 size_t i, j; 558 caddr_t n; 559 int rcount; 560 fileid_t *filep; 561 562 if (!(filep = find_fp(fd))) { 563 return (-1); 564 } 565 566 if (filep->fi_offset + count > filep->fi_inode->i_size) 567 count = filep->fi_inode->i_size - filep->fi_offset; 568 569 /* that was easy */ 570 if ((i = count) == 0) 571 return (0); 572 573 n = buf; 574 while (i > 0) { 575 /* If we need to reload the buffer, do so */ 576 if ((j = filep->fi_count) == 0) { 577 getblock(filep, buf, i, &rcount); 578 i -= rcount; 579 buf += rcount; 580 filep->fi_offset += rcount; 581 } else { 582 /* else just bcopy from our buffer */ 583 j = MIN(i, j); 584 bcopy(filep->fi_memp, buf, (unsigned)j); 585 buf += j; 586 filep->fi_memp += j; 587 filep->fi_offset += j; 588 filep->fi_count -= j; 589 i -= j; 590 } 591 } 592 return (buf - n); 593 } 594 595 /* 596 * This routine will open a device as it is known by the V2 OBP. 597 * Interface Defn: 598 * err = boot_ufs_mountroot(string); 599 * err = 0 on success 600 * err = -1 on failure 601 * string: char string describing the properties of the device. 602 * We must not dork with any fi[]'s here. Save that for later. 603 */ 604 605 static int 606 boot_ufs_mountroot(char *str) 607 { 608 int h; 609 610 /* 611 * Open the device and setup the read of the ufs superblock 612 * only the first time mountroot is called. Subsequent calls 613 * to mountroot succeed immediatly 614 */ 615 if (ufs_devp == NULL) { 616 617 /* 618 * Encode the knowledge that we normally boot from the 'a' 619 * slice of the leaf device on the OBP path; we also permit 620 * a 'nolabel' device, i.e. the entire device. Since v2path 621 * points to 'str' as well, changing str should have the 622 * desired result. 623 */ 624 if (strchr(str, ':') == NULL) { 625 (void) strcat(str, ":a"); 626 } 627 h = prom_open(str); 628 if (h == 0) { 629 printf("Cannot open %s\n", str); 630 return (-1); 631 } 632 633 ufs_devp = (devid_t *)bkmem_alloc(sizeof (devid_t)); 634 ufs_devp->di_taken = 1; 635 ufs_devp->di_dcookie = h; 636 ufs_devp->di_desc = (char *)bkmem_alloc(strlen(str) + 1); 637 (void) strcpy(ufs_devp->di_desc, str); 638 bzero(ufs_devp->un_fs.dummy, SBSIZE); 639 head = (fileid_t *)bkmem_alloc(sizeof (fileid_t)); 640 head->fi_back = head->fi_forw = head; 641 head->fi_filedes = 0; 642 head->fi_taken = 0; 643 644 /* Setup read of the superblock */ 645 head->fi_devp = ufs_devp; 646 head->fi_blocknum = SBLOCK; 647 head->fi_count = (uint_t)SBSIZE; 648 head->fi_memp = (caddr_t)&(ufs_devp->un_fs.di_fs); 649 head->fi_offset = 0; 650 651 if (diskread(head) || 652 ufs_devp->un_fs.di_fs.fs_magic != FS_MAGIC) { 653 boot_ufs_closeall(1); 654 return (-1); 655 } 656 lufs_boot_init(head); 657 } 658 return (0); 659 } 660 661 /* 662 * Unmount the currently mounted root fs. In practice, this means 663 * closing all open files and releasing resources. All of this 664 * is done by boot_ufs_closeall(). 665 */ 666 667 int 668 boot_ufs_unmountroot(void) 669 { 670 if (ufs_devp == NULL) 671 return (-1); 672 673 boot_ufs_closeall(1); 674 675 return (0); 676 } 677 678 /* 679 * We allocate an fd here for use when talking 680 * to the file itself. 681 */ 682 683 /*ARGSUSED*/ 684 static int 685 boot_ufs_open(char *filename, int flags) 686 { 687 fileid_t *filep; 688 ino_t inode; 689 static int filedes = 1; 690 691 /* build and link a new file descriptor */ 692 filep = (fileid_t *)bkmem_alloc(sizeof (fileid_t)); 693 filep->fi_back = head->fi_back; 694 filep->fi_forw = head; 695 head->fi_back->fi_forw = filep; 696 head->fi_back = filep; 697 filep->fi_filedes = filedes++; 698 filep->fi_taken = 1; 699 filep->fi_path = (char *)bkmem_alloc(strlen(filename) + 1); 700 (void) strcpy(filep->fi_path, filename); 701 filep->fi_devp = ufs_devp; /* dev is already "mounted" */ 702 filep->fi_inode = NULL; 703 bzero(filep->fi_buf, MAXBSIZE); 704 705 inode = find(filep, filename); 706 if (inode == (ino_t)0) { 707 boot_ufs_close(filep->fi_filedes); 708 return (-1); 709 } 710 if (openi(filep, inode)) { 711 boot_ufs_close(filep->fi_filedes); 712 return (-1); 713 } 714 715 filep->fi_offset = filep->fi_count = 0; 716 717 return (filep->fi_filedes); 718 } 719 720 /* 721 * We don't do any IO here. 722 * We just play games with the device pointers. 723 */ 724 725 static off_t 726 boot_ufs_lseek(int fd, off_t addr, int whence) 727 { 728 fileid_t *filep; 729 730 /* Make sure user knows what file he is talking to */ 731 if (!(filep = find_fp(fd))) 732 return (-1); 733 734 switch (whence) { 735 case SEEK_CUR: 736 filep->fi_offset += addr; 737 break; 738 case SEEK_SET: 739 filep->fi_offset = addr; 740 break; 741 default: 742 case SEEK_END: 743 printf("ufs_lseek(): invalid whence value %d\n", whence); 744 break; 745 } 746 747 filep->fi_blocknum = addr / DEV_BSIZE; 748 filep->fi_count = 0; 749 750 return (0); 751 } 752 753 /* 754 * ufs_fstat() only supports size, mode, and times at present time. 755 */ 756 757 static int 758 boot_ufs_fstat(int fd, struct bootstat *stp) 759 { 760 fileid_t *filep; 761 struct inode *ip; 762 763 if (!(filep = find_fp(fd))) 764 return (-1); 765 766 ip = filep->fi_inode; 767 768 stp->st_mode = 0; 769 stp->st_size = 0; 770 771 if (ip == NULL) 772 return (0); 773 774 switch (ip->i_smode & IFMT) { 775 case IFDIR: 776 stp->st_mode = S_IFDIR; 777 break; 778 case IFLNK: 779 stp->st_mode = S_IFLNK; 780 break; 781 case IFREG: 782 stp->st_mode = S_IFREG; 783 break; 784 default: 785 break; 786 } 787 stp->st_size = ip->i_size; 788 stp->st_atim.tv_sec = ip->i_atime.tv_sec; 789 stp->st_atim.tv_nsec = ip->i_atime.tv_usec * 1000; 790 stp->st_mtim.tv_sec = ip->i_mtime.tv_sec; 791 stp->st_mtim.tv_nsec = ip->i_mtime.tv_usec * 1000; 792 stp->st_ctim.tv_sec = ip->i_ctime.tv_sec; 793 stp->st_ctim.tv_nsec = ip->i_ctime.tv_usec * 1000; 794 795 return (0); 796 } 797 798 static int 799 boot_ufs_close(int fd) 800 { 801 fileid_t *filep; 802 803 /* Make sure user knows what file he is talking to */ 804 if (!(filep = find_fp(fd))) 805 return (-1); 806 807 if (filep->fi_taken && (filep != head)) { 808 /* Clear the ranks */ 809 bkmem_free(filep->fi_path, strlen(filep->fi_path)+1); 810 filep->fi_blocknum = filep->fi_count = filep->fi_offset = 0; 811 filep->fi_memp = (caddr_t)0; 812 filep->fi_devp = 0; 813 filep->fi_taken = 0; 814 815 /* unlink and deallocate node */ 816 filep->fi_forw->fi_back = filep->fi_back; 817 filep->fi_back->fi_forw = filep->fi_forw; 818 bkmem_free((char *)filep, sizeof (fileid_t)); 819 820 return (0); 821 } else { 822 /* Big problem */ 823 printf("\nFile descrip %d not allocated!", fd); 824 return (-1); 825 } 826 } 827 828 /*ARGSUSED*/ 829 static void 830 boot_ufs_closeall(int flag) 831 { 832 fileid_t *filep = head; 833 834 while ((filep = filep->fi_forw) != head) 835 if (filep->fi_taken) 836 if (boot_ufs_close(filep->fi_filedes)) 837 prom_panic("Filesystem may be inconsistent.\n"); 838 839 release_cache(ufs_devp->di_dcookie); 840 (void) prom_close(ufs_devp->di_dcookie); 841 ufs_devp->di_taken = 0; 842 if (verbosemode & print_cache_stats) 843 print_cache_data(); 844 lufs_closeall(); 845 bkmem_free((char *)ufs_devp, sizeof (devid_t)); 846 bkmem_free((char *)head, sizeof (fileid_t)); 847 ufs_devp = (devid_t *)NULL; 848 head = (fileid_t *)NULL; 849 } 850 851 static int 852 boot_ufs_getdents(int fd, struct dirent *dep, unsigned size) 853 { 854 /* 855 * Read directory entries from the file open on "fd" into the 856 * "size"-byte buffer at "dep" until the buffer is exhausted 857 * or we reach EOF on the directory. Returns the number of 858 * entries read. 859 */ 860 int n; 861 fileid_t *fp; 862 unsigned long oldoff, oldblok; 863 864 #define SLOP (sizeof (struct dirent) - (int)&((struct dirent *)0)->d_name[1]) 865 866 if (fp = find_fp(fd)) { 867 /* 868 * File is open, check type to make sure it's a directory. 869 */ 870 871 while ((fp->fi_inode->i_smode & IFMT) == IFLNK) { 872 /* 873 * If file is a symbolic link, we'll follow 874 * it JIC it points to a directory! 875 */ 876 fileid_t fx; 877 char pn[MAXPATHLEN]; 878 fp->fi_count = DEV_BSIZE; 879 fp->fi_blocknum = fsbtodb(&fp->fi_devp->un_fs.di_fs, 880 fp->fi_inode->i_db[0]); 881 882 /* 883 * Return failure if: 884 * (a) we get an I/O error reading the path name. 885 * (b) the path name points to a non-existant file, 886 * (c) we get an I/O error reading the target inode. 887 */ 888 if ((fp->fi_memp = get_bcache(fp)) == NULL) { 889 if (set_bcache(fp)) 890 return (-1); 891 lufs_merge_deltas(fp); 892 } 893 if (!(n = find(&fx, strcpy(pn, fp->fi_memp))) || 894 openi(fp = &fx, n)) { 895 return (-1); 896 } 897 } 898 899 if ((fp->fi_inode->i_smode & IFMT) == IFDIR) { 900 /* 901 * If target file is a directory, go ahead 902 * and read it. This consists of making 903 * repeated calls to readdir() until we reach 904 * end-of-file or run out of buffer space. 905 */ 906 int cnt = 0; 907 struct direct *dp; 908 struct dirinfo dir; 909 910 dir.fi = fp; 911 oldblok = fp->fi_blocknum; 912 dir.loc = oldoff = fp->fi_offset; 913 914 for (dp = readdir(&dir); dp; dp = readdir(&dir)) { 915 /* 916 * Read all directory entries in the file ... 917 */ 918 919 if (dp->d_ino) { 920 /* 921 * Next entry is valid. 922 * Compute name length and 923 * break loop if there's not 924 * enough space in the output 925 * buffer for the next entry. 926 * 927 * NOTE: "SLOP" is the number 928 * of bytes inserted into the 929 * dirent struct's "d_name" 930 * field by the compiler to 931 * preserve alignment. 932 */ 933 dep->d_ino = dp->d_ino; 934 n = strlen(dp->d_name); 935 n = roundup((sizeof (struct dirent) + 936 ((n > SLOP) ? n : 0)), 937 sizeof (off_t)); 938 939 if (n > size) 940 break; /* user buffer is full */ 941 942 oldblok = fp->fi_blocknum; 943 oldoff = dir.loc; 944 size -= n; 945 cnt += 1; 946 947 (void) strcpy(dep->d_name, dp->d_name); 948 dep->d_off = dir.loc; 949 dep->d_reclen = (ushort_t)n; 950 951 dep = (struct dirent *) 952 ((char *)dep + n); 953 } 954 } 955 /* 956 * Remember where we left off for next time 957 */ 958 fp->fi_blocknum = oldblok; 959 fp->fi_offset = oldoff; 960 961 return (cnt); 962 } 963 } 964 965 #undef SLOP 966 967 return (-1); 968 } 969