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