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