1 /* $NetBSD: ufs.c,v 1.54 2008/11/19 12:36:41 ad Exp $ */ 2 3 /*- 4 * Copyright (c) 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * The Mach Operating System project at Carnegie-Mellon University. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * 35 * Copyright (c) 1990, 1991 Carnegie Mellon University 36 * All Rights Reserved. 37 * 38 * Author: David Golub 39 * 40 * Permission to use, copy, modify and distribute this software and its 41 * documentation is hereby granted, provided that both the copyright 42 * notice and this permission notice appear in all copies of the 43 * software, derivative works or modified versions, and any portions 44 * thereof, and that both notices appear in supporting documentation. 45 * 46 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 47 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 48 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 49 * 50 * Carnegie Mellon requests users of this software to return to 51 * 52 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 53 * School of Computer Science 54 * Carnegie Mellon University 55 * Pittsburgh PA 15213-3890 56 * 57 * any improvements or extensions that they make and grant Carnegie the 58 * rights to redistribute these changes. 59 */ 60 61 /* 62 * Stand-alone file reading package for UFS and LFS filesystems. 63 */ 64 65 #include <sys/param.h> 66 #include <sys/time.h> 67 #include <ufs/ufs/dinode.h> 68 #include <ufs/ufs/dir.h> 69 #ifdef LIBSA_LFS 70 #include <sys/queue.h> 71 #include <sys/condvar.h> 72 #include <sys/mount.h> /* XXX for MNAMELEN */ 73 #include <ufs/lfs/lfs.h> 74 #else 75 #include <ufs/ffs/fs.h> 76 #endif 77 #ifdef _STANDALONE 78 #include <lib/libkern/libkern.h> 79 #else 80 #include <string.h> 81 #endif 82 83 #include "stand.h" 84 #ifdef LIBSA_LFS 85 #include "lfs.h" 86 #else 87 #include "ufs.h" 88 #endif 89 90 /* If this file is compiled by itself, build ufs (aka ffsv1) support */ 91 #if !defined(LIBSA_FFSv2) && !defined(LIBSA_LFS) 92 #define LIBSA_FFSv1 93 #endif 94 95 #if defined(LIBSA_FS_SINGLECOMPONENT) && !defined(LIBSA_NO_FS_SYMLINK) 96 #define LIBSA_NO_FS_SYMLINK 97 #endif 98 #if defined(COMPAT_UFS) && defined(LIBSA_NO_COMPAT_UFS) 99 #undef COMPAT_UFS 100 #endif 101 102 #ifdef LIBSA_LFS 103 /* 104 * In-core LFS superblock. This exists only to placate the macros in lfs.h, 105 */ 106 struct fs { 107 struct dlfs lfs_dlfs; 108 }; 109 #define fs_magic lfs_magic 110 #define fs_maxsymlinklen lfs_maxsymlinklen 111 112 #define FS_MAGIC LFS_MAGIC 113 #define SBLOCKSIZE LFS_SBPAD 114 #define SBLOCKOFFSET LFS_LABELPAD 115 #else 116 /* NB ufs2 doesn't use the common suberblock code... */ 117 #define FS_MAGIC FS_UFS1_MAGIC 118 #define SBLOCKOFFSET SBLOCK_UFS1 119 #endif 120 121 #if defined(LIBSA_NO_TWIDDLE) 122 #define twiddle() 123 #endif 124 125 #undef cgstart 126 #if defined(LIBSA_FFSv2) 127 #define cgstart(fc, c) cgstart_ufs2((fs), (c)) 128 #else 129 #define cgstart(fc, c) cgstart_ufs1((fs), (c)) 130 #endif 131 132 #ifndef ufs_dinode 133 #define ufs_dinode ufs1_dinode 134 #endif 135 #ifndef indp_t 136 #define indp_t int32_t 137 #endif 138 typedef uint32_t ino32_t; 139 #ifndef FSBTODB 140 #define FSBTODB(fs, indp) fsbtodb(fs, indp) 141 #endif 142 143 /* 144 * To avoid having a lot of filesystem-block sized buffers lurking (which 145 * could be 32k) we only keep a few entries of the indirect block map. 146 * With 8k blocks, 2^8 blocks is ~500k so we reread the indirect block 147 * ~13 times pulling in a 6M kernel. 148 * The cache size must be smaller than the smallest filesystem block, 149 * so LN2_IND_CACHE_SZ <= 9 (UFS2 and 4k blocks). 150 */ 151 #define LN2_IND_CACHE_SZ 6 152 #define IND_CACHE_SZ (1 << LN2_IND_CACHE_SZ) 153 #define IND_CACHE_MASK (IND_CACHE_SZ - 1) 154 155 /* 156 * In-core open file. 157 */ 158 struct file { 159 off_t f_seekp; /* seek pointer */ 160 struct fs *f_fs; /* pointer to super-block */ 161 struct ufs_dinode f_di; /* copy of on-disk inode */ 162 uint f_nishift; /* for blocks in indirect block */ 163 indp_t f_ind_cache_block; 164 indp_t f_ind_cache[IND_CACHE_SZ]; 165 166 char *f_buf; /* buffer for data block */ 167 size_t f_buf_size; /* size of data block */ 168 daddr_t f_buf_blkno; /* block number of data block */ 169 }; 170 171 static int read_inode(ino32_t, struct open_file *); 172 static int block_map(struct open_file *, indp_t, indp_t *); 173 static int buf_read_file(struct open_file *, char **, size_t *); 174 static int search_directory(const char *, int, struct open_file *, ino32_t *); 175 #ifdef LIBSA_FFSv1 176 static void ffs_oldfscompat(struct fs *); 177 #endif 178 #ifdef LIBSA_FFSv2 179 static int ffs_find_superblock(struct open_file *, struct fs *); 180 #endif 181 182 #ifdef LIBSA_LFS 183 /* 184 * Find an inode's block. Look it up in the ifile. Whee! 185 */ 186 static int 187 find_inode_sector(ino32_t inumber, struct open_file *f, daddr_t *isp) 188 { 189 struct file *fp = (struct file *)f->f_fsdata; 190 struct fs *fs = fp->f_fs; 191 daddr_t ifileent_blkno; 192 char *ent_in_buf; 193 size_t buf_after_ent; 194 int rc; 195 196 rc = read_inode(fs->lfs_ifile, f); 197 if (rc) 198 return rc; 199 200 ifileent_blkno = 201 (inumber / fs->lfs_ifpb) + fs->lfs_cleansz + fs->lfs_segtabsz; 202 fp->f_seekp = (off_t)ifileent_blkno * fs->fs_bsize + 203 (inumber % fs->lfs_ifpb) * sizeof (IFILE_Vx); 204 rc = buf_read_file(f, &ent_in_buf, &buf_after_ent); 205 if (rc) 206 return rc; 207 /* make sure something's not badly wrong, but don't panic. */ 208 if (buf_after_ent < sizeof (IFILE_Vx)) 209 return EINVAL; 210 211 *isp = FSBTODB(fs, ((IFILE_Vx *)ent_in_buf)->if_daddr); 212 if (*isp == LFS_UNUSED_DADDR) /* again, something badly wrong */ 213 return EINVAL; 214 return 0; 215 } 216 #endif 217 218 /* 219 * Read a new inode into a file structure. 220 */ 221 static int 222 read_inode(ino32_t inumber, struct open_file *f) 223 { 224 struct file *fp = (struct file *)f->f_fsdata; 225 struct fs *fs = fp->f_fs; 226 char *buf; 227 size_t rsize; 228 int rc; 229 daddr_t inode_sector; 230 #ifdef LIBSA_LFS 231 struct ufs_dinode *dip; 232 int cnt; 233 #endif 234 235 #ifdef LIBSA_LFS 236 if (inumber == fs->lfs_ifile) 237 inode_sector = FSBTODB(fs, fs->lfs_idaddr); 238 else if ((rc = find_inode_sector(inumber, f, &inode_sector)) != 0) 239 return rc; 240 #else 241 inode_sector = FSBTODB(fs, ino_to_fsba(fs, inumber)); 242 #endif 243 244 /* 245 * Read inode and save it. 246 */ 247 buf = fp->f_buf; 248 twiddle(); 249 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, 250 inode_sector, fs->fs_bsize, buf, &rsize); 251 if (rc) 252 return rc; 253 if (rsize != fs->fs_bsize) 254 return EIO; 255 256 #ifdef LIBSA_LFS 257 cnt = INOPBx(fs); 258 dip = (struct ufs_dinode *)buf + (cnt - 1); 259 for (; dip->di_inumber != inumber; --dip) { 260 /* kernel code panics, but boot blocks which panic are Bad. */ 261 if (--cnt == 0) 262 return EINVAL; 263 } 264 fp->f_di = *dip; 265 #else 266 fp->f_di = ((struct ufs_dinode *)buf)[ino_to_fsbo(fs, inumber)]; 267 #endif 268 269 /* 270 * Clear out the old buffers 271 */ 272 fp->f_ind_cache_block = ~0; 273 fp->f_buf_blkno = -1; 274 return rc; 275 } 276 277 /* 278 * Given an offset in a file, find the disk block number that 279 * contains that block. 280 */ 281 static int 282 block_map(struct open_file *f, indp_t file_block, indp_t *disk_block_p) 283 { 284 struct file *fp = (struct file *)f->f_fsdata; 285 struct fs *fs = fp->f_fs; 286 uint level; 287 indp_t ind_cache; 288 indp_t ind_block_num; 289 size_t rsize; 290 int rc; 291 indp_t *buf = (void *)fp->f_buf; 292 293 /* 294 * Index structure of an inode: 295 * 296 * di_db[0..NDADDR-1] hold block numbers for blocks 297 * 0..NDADDR-1 298 * 299 * di_ib[0] index block 0 is the single indirect block 300 * holds block numbers for blocks 301 * NDADDR .. NDADDR + NINDIR(fs)-1 302 * 303 * di_ib[1] index block 1 is the double indirect block 304 * holds block numbers for INDEX blocks for blocks 305 * NDADDR + NINDIR(fs) .. 306 * NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1 307 * 308 * di_ib[2] index block 2 is the triple indirect block 309 * holds block numbers for double-indirect 310 * blocks for blocks 311 * NDADDR + NINDIR(fs) + NINDIR(fs)**2 .. 312 * NDADDR + NINDIR(fs) + NINDIR(fs)**2 313 * + NINDIR(fs)**3 - 1 314 */ 315 316 if (file_block < NDADDR) { 317 /* Direct block. */ 318 *disk_block_p = fp->f_di.di_db[file_block]; 319 return 0; 320 } 321 322 file_block -= NDADDR; 323 324 ind_cache = file_block >> LN2_IND_CACHE_SZ; 325 if (ind_cache == fp->f_ind_cache_block) { 326 *disk_block_p = fp->f_ind_cache[file_block & IND_CACHE_MASK]; 327 return 0; 328 } 329 330 for (level = 0;;) { 331 level += fp->f_nishift; 332 if (file_block < (indp_t)1 << level) 333 break; 334 if (level > NIADDR * fp->f_nishift) 335 /* Block number too high */ 336 return EFBIG; 337 file_block -= (indp_t)1 << level; 338 } 339 340 ind_block_num = fp->f_di.di_ib[level / fp->f_nishift - 1]; 341 342 for (;;) { 343 level -= fp->f_nishift; 344 if (ind_block_num == 0) { 345 *disk_block_p = 0; /* missing */ 346 return 0; 347 } 348 349 twiddle(); 350 /* 351 * If we were feeling brave, we could work out the number 352 * of the disk sector and read a single disk sector instead 353 * of a filesystem block. 354 * However we don't do this very often anyway... 355 */ 356 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, 357 FSBTODB(fp->f_fs, ind_block_num), fs->fs_bsize, 358 buf, &rsize); 359 if (rc) 360 return rc; 361 if (rsize != fs->fs_bsize) 362 return EIO; 363 ind_block_num = buf[file_block >> level]; 364 if (level == 0) 365 break; 366 file_block &= (1 << level) - 1; 367 } 368 369 /* Save the part of the block that contains this sector */ 370 memcpy(fp->f_ind_cache, &buf[file_block & ~IND_CACHE_MASK], 371 IND_CACHE_SZ * sizeof fp->f_ind_cache[0]); 372 fp->f_ind_cache_block = ind_cache; 373 374 *disk_block_p = ind_block_num; 375 376 return 0; 377 } 378 379 /* 380 * Read a portion of a file into an internal buffer. 381 * Return the location in the buffer and the amount in the buffer. 382 */ 383 static int 384 buf_read_file(struct open_file *f, char **buf_p, size_t *size_p) 385 { 386 struct file *fp = (struct file *)f->f_fsdata; 387 struct fs *fs = fp->f_fs; 388 long off; 389 indp_t file_block; 390 indp_t disk_block; 391 size_t block_size; 392 int rc; 393 394 off = blkoff(fs, fp->f_seekp); 395 file_block = lblkno(fs, fp->f_seekp); 396 #ifdef LIBSA_LFS 397 block_size = dblksize(fs, &fp->f_di, file_block); 398 #else 399 block_size = sblksize(fs, (int64_t)fp->f_di.di_size, file_block); 400 #endif 401 402 if (file_block != fp->f_buf_blkno) { 403 rc = block_map(f, file_block, &disk_block); 404 if (rc) 405 return rc; 406 407 if (disk_block == 0) { 408 memset(fp->f_buf, 0, block_size); 409 fp->f_buf_size = block_size; 410 } else { 411 twiddle(); 412 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, 413 FSBTODB(fs, disk_block), 414 block_size, fp->f_buf, &fp->f_buf_size); 415 if (rc) 416 return rc; 417 } 418 419 fp->f_buf_blkno = file_block; 420 } 421 422 /* 423 * Return address of byte in buffer corresponding to 424 * offset, and size of remainder of buffer after that 425 * byte. 426 */ 427 *buf_p = fp->f_buf + off; 428 *size_p = block_size - off; 429 430 /* 431 * But truncate buffer at end of file. 432 */ 433 if (*size_p > fp->f_di.di_size - fp->f_seekp) 434 *size_p = fp->f_di.di_size - fp->f_seekp; 435 436 return 0; 437 } 438 439 /* 440 * Search a directory for a name and return its 441 * inode number. 442 */ 443 static int 444 search_directory(const char *name, int length, struct open_file *f, 445 ino32_t *inumber_p) 446 { 447 struct file *fp = (struct file *)f->f_fsdata; 448 struct direct *dp; 449 struct direct *edp; 450 char *buf; 451 size_t buf_size; 452 int namlen; 453 int rc; 454 455 fp->f_seekp = 0; 456 while (fp->f_seekp < (off_t)fp->f_di.di_size) { 457 rc = buf_read_file(f, &buf, &buf_size); 458 if (rc) 459 return rc; 460 461 dp = (struct direct *)buf; 462 edp = (struct direct *)(buf + buf_size); 463 for (;dp < edp; dp = (void *)((char *)dp + dp->d_reclen)) { 464 if (dp->d_reclen <= 0) 465 break; 466 if (dp->d_ino == (ino32_t)0) 467 continue; 468 #if BYTE_ORDER == LITTLE_ENDIAN 469 if (fp->f_fs->fs_maxsymlinklen <= 0) 470 namlen = dp->d_type; 471 else 472 #endif 473 namlen = dp->d_namlen; 474 if (namlen == length && 475 !memcmp(name, dp->d_name, length)) { 476 /* found entry */ 477 *inumber_p = dp->d_ino; 478 return 0; 479 } 480 } 481 fp->f_seekp += buf_size; 482 } 483 return ENOENT; 484 } 485 486 #ifdef LIBSA_FFSv2 487 488 daddr_t sblock_try[] = SBLOCKSEARCH; 489 490 static int 491 ffs_find_superblock(struct open_file *f, struct fs *fs) 492 { 493 int i, rc; 494 size_t buf_size; 495 496 for (i = 0; sblock_try[i] != -1; i++) { 497 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, 498 sblock_try[i] / DEV_BSIZE, SBLOCKSIZE, fs, &buf_size); 499 if (rc != 0 || buf_size != SBLOCKSIZE) 500 return rc; 501 if (fs->fs_sblockloc != sblock_try[i]) 502 /* an alternate superblock - try again */ 503 continue; 504 if (fs->fs_magic == FS_UFS2_MAGIC) { 505 return 0; 506 } 507 } 508 return EINVAL; 509 } 510 511 #endif 512 513 /* 514 * Open a file. 515 */ 516 int 517 ufs_open(const char *path, struct open_file *f) 518 { 519 #ifndef LIBSA_FS_SINGLECOMPONENT 520 const char *cp, *ncp; 521 int c; 522 #endif 523 ino32_t inumber; 524 struct file *fp; 525 struct fs *fs; 526 int rc; 527 #ifndef LIBSA_NO_FS_SYMLINK 528 ino32_t parent_inumber; 529 int nlinks = 0; 530 char namebuf[MAXPATHLEN+1]; 531 char *buf; 532 #endif 533 534 /* allocate file system specific data structure */ 535 fp = alloc(sizeof(struct file)); 536 memset(fp, 0, sizeof(struct file)); 537 f->f_fsdata = (void *)fp; 538 539 /* allocate space and read super block */ 540 fs = alloc(SBLOCKSIZE); 541 fp->f_fs = fs; 542 twiddle(); 543 544 #ifdef LIBSA_FFSv2 545 rc = ffs_find_superblock(f, fs); 546 if (rc) 547 goto out; 548 #else 549 { 550 size_t buf_size; 551 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, 552 SBLOCKOFFSET / DEV_BSIZE, SBLOCKSIZE, fs, &buf_size); 553 if (rc) 554 goto out; 555 if (buf_size != SBLOCKSIZE || 556 #ifdef LIBSA_FFS 557 fs->lfs_version != REQUIRED_LFS_VERSION || 558 #endif 559 fs->fs_magic != FS_MAGIC) { 560 rc = EINVAL; 561 goto out; 562 } 563 } 564 #if defined(LIBSA_LFS) && REQUIRED_LFS_VERSION == 2 565 /* 566 * XXX We should check the second superblock and use the eldest 567 * of the two. See comments near the top of lfs_mountfs() 568 * in sys/ufs/lfs/lfs_vfsops.c. 569 * This may need a LIBSA_LFS_SMALL check as well. 570 */ 571 #endif 572 #endif 573 574 #ifdef LIBSA_FFSv1 575 ffs_oldfscompat(fs); 576 #endif 577 578 if (fs->fs_bsize > MAXBSIZE || 579 (size_t)fs->fs_bsize < sizeof(struct fs)) { 580 rc = EINVAL; 581 goto out; 582 } 583 584 /* 585 * Calculate indirect block levels. 586 */ 587 { 588 indp_t mult; 589 int ln2; 590 591 /* 592 * We note that the number of indirect blocks is always 593 * a power of 2. This lets us use shifts and masks instead 594 * of divide and remainder and avoinds pulling in the 595 * 64bit division routine into the boot code. 596 */ 597 mult = NINDIR(fs); 598 #ifdef DEBUG 599 if (mult & (mult - 1)) { 600 /* Hummm was't a power of 2 */ 601 rc = EINVAL; 602 goto out; 603 } 604 #endif 605 for (ln2 = 0; mult != 1; ln2++) 606 mult >>= 1; 607 608 fp->f_nishift = ln2; 609 } 610 611 /* alloc a block sized buffer used for all fs transfers */ 612 fp->f_buf = alloc(fs->fs_bsize); 613 inumber = ROOTINO; 614 if ((rc = read_inode(inumber, f)) != 0) 615 goto out; 616 617 #ifndef LIBSA_FS_SINGLECOMPONENT 618 cp = path; 619 while (*cp) { 620 621 /* 622 * Remove extra separators 623 */ 624 while (*cp == '/') 625 cp++; 626 if (*cp == '\0') 627 break; 628 629 /* 630 * Check that current node is a directory. 631 */ 632 if ((fp->f_di.di_mode & IFMT) != IFDIR) { 633 rc = ENOTDIR; 634 goto out; 635 } 636 637 /* 638 * Get next component of path name. 639 */ 640 ncp = cp; 641 while ((c = *cp) != '\0' && c != '/') 642 cp++; 643 644 /* 645 * Look up component in current directory. 646 * Save directory inumber in case we find a 647 * symbolic link. 648 */ 649 #ifndef LIBSA_NO_FS_SYMLINK 650 parent_inumber = inumber; 651 #endif 652 rc = search_directory(ncp, cp - ncp, f, &inumber); 653 if (rc) 654 goto out; 655 656 /* 657 * Open next component. 658 */ 659 if ((rc = read_inode(inumber, f)) != 0) 660 goto out; 661 662 #ifndef LIBSA_NO_FS_SYMLINK 663 /* 664 * Check for symbolic link. 665 */ 666 if ((fp->f_di.di_mode & IFMT) == IFLNK) { 667 int link_len = fp->f_di.di_size; 668 int len; 669 670 len = strlen(cp); 671 672 if (link_len + len > MAXPATHLEN || 673 ++nlinks > MAXSYMLINKS) { 674 rc = ENOENT; 675 goto out; 676 } 677 678 memmove(&namebuf[link_len], cp, len + 1); 679 680 if (link_len < fs->fs_maxsymlinklen) { 681 memcpy(namebuf, fp->f_di.di_db, link_len); 682 } else { 683 /* 684 * Read file for symbolic link 685 */ 686 size_t buf_size; 687 indp_t disk_block; 688 689 buf = fp->f_buf; 690 rc = block_map(f, (indp_t)0, &disk_block); 691 if (rc) 692 goto out; 693 694 twiddle(); 695 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, 696 F_READ, FSBTODB(fs, disk_block), 697 fs->fs_bsize, buf, &buf_size); 698 if (rc) 699 goto out; 700 701 memcpy(namebuf, buf, link_len); 702 } 703 704 /* 705 * If relative pathname, restart at parent directory. 706 * If absolute pathname, restart at root. 707 */ 708 cp = namebuf; 709 if (*cp != '/') 710 inumber = parent_inumber; 711 else 712 inumber = (ino32_t)ROOTINO; 713 714 if ((rc = read_inode(inumber, f)) != 0) 715 goto out; 716 } 717 #endif /* !LIBSA_NO_FS_SYMLINK */ 718 } 719 720 /* 721 * Found terminal component. 722 */ 723 rc = 0; 724 725 #else /* !LIBSA_FS_SINGLECOMPONENT */ 726 727 /* look up component in the current (root) directory */ 728 rc = search_directory(path, strlen(path), f, &inumber); 729 if (rc) 730 goto out; 731 732 /* open it */ 733 rc = read_inode(inumber, f); 734 735 #endif /* !LIBSA_FS_SINGLECOMPONENT */ 736 737 fp->f_seekp = 0; /* reset seek pointer */ 738 739 out: 740 if (rc) 741 ufs_close(f); 742 else { 743 #ifdef FSMOD 744 fsmod = FSMOD; 745 #endif 746 #ifdef FSMOD2 747 fsmod2 = FSMOD2; 748 #endif 749 } 750 return rc; 751 } 752 753 int 754 ufs_close(struct open_file *f) 755 { 756 struct file *fp = (struct file *)f->f_fsdata; 757 758 f->f_fsdata = NULL; 759 if (fp == NULL) 760 return 0; 761 762 if (fp->f_buf) 763 dealloc(fp->f_buf, fp->f_fs->fs_bsize); 764 dealloc(fp->f_fs, SBLOCKSIZE); 765 dealloc(fp, sizeof(struct file)); 766 return 0; 767 } 768 769 /* 770 * Copy a portion of a file into kernel memory. 771 * Cross block boundaries when necessary. 772 */ 773 int 774 ufs_read(struct open_file *f, void *start, size_t size, size_t *resid) 775 { 776 struct file *fp = (struct file *)f->f_fsdata; 777 size_t csize; 778 char *buf; 779 size_t buf_size; 780 int rc = 0; 781 char *addr = start; 782 783 while (size != 0) { 784 if (fp->f_seekp >= (off_t)fp->f_di.di_size) 785 break; 786 787 rc = buf_read_file(f, &buf, &buf_size); 788 if (rc) 789 break; 790 791 csize = size; 792 if (csize > buf_size) 793 csize = buf_size; 794 795 memcpy(addr, buf, csize); 796 797 fp->f_seekp += csize; 798 addr += csize; 799 size -= csize; 800 } 801 if (resid) 802 *resid = size; 803 return rc; 804 } 805 806 /* 807 * Not implemented. 808 */ 809 #ifndef LIBSA_NO_FS_WRITE 810 int 811 ufs_write(struct open_file *f, void *start, size_t size, size_t *resid) 812 { 813 814 return EROFS; 815 } 816 #endif /* !LIBSA_NO_FS_WRITE */ 817 818 #ifndef LIBSA_NO_FS_SEEK 819 off_t 820 ufs_seek(struct open_file *f, off_t offset, int where) 821 { 822 struct file *fp = (struct file *)f->f_fsdata; 823 824 switch (where) { 825 case SEEK_SET: 826 fp->f_seekp = offset; 827 break; 828 case SEEK_CUR: 829 fp->f_seekp += offset; 830 break; 831 case SEEK_END: 832 fp->f_seekp = fp->f_di.di_size - offset; 833 break; 834 default: 835 return -1; 836 } 837 return fp->f_seekp; 838 } 839 #endif /* !LIBSA_NO_FS_SEEK */ 840 841 int 842 ufs_stat(struct open_file *f, struct stat *sb) 843 { 844 struct file *fp = (struct file *)f->f_fsdata; 845 846 /* only important stuff */ 847 memset(sb, 0, sizeof *sb); 848 sb->st_mode = fp->f_di.di_mode; 849 sb->st_uid = fp->f_di.di_uid; 850 sb->st_gid = fp->f_di.di_gid; 851 sb->st_size = fp->f_di.di_size; 852 return 0; 853 } 854 855 #ifdef LIBSA_FFSv1 856 /* 857 * Sanity checks for old file systems. 858 * 859 * XXX - goes away some day. 860 * Stripped of stuff libsa doesn't need..... 861 */ 862 static void 863 ffs_oldfscompat(struct fs *fs) 864 { 865 866 #ifdef COMPAT_UFS 867 /* 868 * Newer Solaris versions have a slightly incompatible 869 * superblock - so always calculate this values on the fly, which 870 * is good enough for libsa purposes 871 */ 872 if (fs->fs_magic == FS_UFS1_MAGIC 873 #ifndef COMPAT_SOLARIS_UFS 874 && fs->fs_old_inodefmt < FS_44INODEFMT 875 #endif 876 ) { 877 fs->fs_qbmask = ~fs->fs_bmask; 878 fs->fs_qfmask = ~fs->fs_fmask; 879 } 880 #endif 881 } 882 #endif 883