1 /* $NetBSD: ufs.c,v 1.78 2020/12/19 08:51:03 rin 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 - just the on-disk one. 105 */ 106 struct salfs { 107 union { 108 struct dlfs u_32; 109 struct dlfs64 u_64; 110 } lfs_dlfs_u; 111 unsigned lfs_is64 : 1, 112 lfs_dobyteswap : 1, 113 lfs_hasolddirfmt : 1; 114 }; 115 /* Get lfs accessors that use struct salfs. */ 116 #define STRUCT_LFS struct salfs 117 #include <ufs/lfs/lfs_accessors.h> 118 119 /* override this to avoid a mess with the dinode accessors */ 120 #define lfs_dino_getsize(fs, dp) ((dp)->di_size) 121 122 typedef struct salfs FS; 123 #define fs_magic lfs_dlfs_u.u_32.dlfs_magic 124 #define fs_maxsymlinklen lfs_dlfs_u.u_32.dlfs_maxsymlinklen 125 #define lfs_version lfs_dlfs_u.u_32.dlfs_version 126 127 #define FS_MAGIC LFS_MAGIC 128 #define SBLOCKSIZE LFS_SBPAD 129 #define SBLOCKOFFSET LFS_LABELPAD 130 #else 131 /* NB ufs2 doesn't use the common superblock code... */ 132 typedef struct fs FS; 133 #define FS_MAGIC FS_UFS1_MAGIC 134 #define SBLOCKOFFSET SBLOCK_UFS1 135 #endif 136 137 #if defined(LIBSA_NO_TWIDDLE) 138 #define twiddle() 139 #endif 140 141 #undef cgstart 142 #if defined(LIBSA_FFSv2) 143 #define cgstart(fc, c) cgstart_ufs2((fs), (c)) 144 #else 145 #define cgstart(fc, c) cgstart_ufs1((fs), (c)) 146 #endif 147 148 #ifndef ufs_dinode 149 #define ufs_dinode ufs1_dinode 150 #endif 151 #ifndef indp_t 152 #define indp_t int32_t 153 #endif 154 typedef uint32_t ino32_t; 155 156 #ifndef FSBTODB 157 #define FSBTODB(fs, indp) FFS_FSBTODB(fs, indp) 158 #endif 159 #ifndef UFS_NINDIR 160 #define UFS_NINDIR FFS_NINDIR 161 #endif 162 #ifndef ufs_blkoff 163 #define ufs_blkoff ffs_blkoff 164 #endif 165 #ifndef ufs_lblkno 166 #define ufs_lblkno ffs_lblkno 167 #endif 168 169 /* 170 * To avoid having a lot of filesystem-block sized buffers lurking (which 171 * could be 32k) we only keep a few entries of the indirect block map. 172 * With 8k blocks, 2^8 blocks is ~500k so we reread the indirect block 173 * ~13 times pulling in a 6M kernel. 174 * The cache size must be smaller than the smallest filesystem block, 175 * so LN2_IND_CACHE_SZ <= 9 (UFS2 and 4k blocks). 176 */ 177 #define LN2_IND_CACHE_SZ 6 178 #define IND_CACHE_SZ (1 << LN2_IND_CACHE_SZ) 179 #define IND_CACHE_MASK (IND_CACHE_SZ - 1) 180 181 /* 182 * In-core open file. 183 */ 184 struct file { 185 off_t f_seekp; /* seek pointer */ 186 FS *f_fs; /* pointer to super-block */ 187 struct ufs_dinode f_di; /* copy of on-disk inode */ 188 uint f_nishift; /* for blocks in indirect block */ 189 indp_t f_ind_cache_block; 190 indp_t f_ind_cache[IND_CACHE_SZ]; 191 192 char *f_buf; /* buffer for data block */ 193 size_t f_buf_size; /* size of data block */ 194 daddr_t f_buf_blkno; /* block number of data block */ 195 }; 196 197 static int read_inode(ino32_t, struct open_file *); 198 static int block_map(struct open_file *, indp_t, indp_t *); 199 static int buf_read_file(struct open_file *, char **, size_t *); 200 static int search_directory(const char *, int, struct open_file *, ino32_t *); 201 #ifdef LIBSA_FFSv1 202 static void ffs_oldfscompat(FS *); 203 #endif 204 #ifdef LIBSA_FFSv2 205 static int ffs_find_superblock(struct open_file *, FS *); 206 #endif 207 208 209 #ifdef LIBSA_LFS 210 /* 211 * Find an inode's block. Look it up in the ifile. Whee! 212 */ 213 static int 214 find_inode_sector(ino32_t inumber, struct open_file *f, daddr_t *isp) 215 { 216 struct file *fp = (struct file *)f->f_fsdata; 217 FS *fs = fp->f_fs; 218 daddr_t ifileent_blkno; 219 char *ent_in_buf; 220 size_t buf_after_ent; 221 size_t entsize; 222 int rc; 223 224 rc = read_inode(LFS_IFILE_INUM, f); 225 if (rc) 226 return rc; 227 228 entsize = fs->lfs_is64 ? sizeof(IFILE64) : 229 (lfs_sb_getversion(fs) > 1 ? sizeof(IFILE32) : sizeof(IFILE_V1)); 230 ifileent_blkno = 231 (inumber / lfs_sb_getifpb(fs)) + lfs_sb_getcleansz(fs) + lfs_sb_getsegtabsz(fs); 232 fp->f_seekp = (off_t)ifileent_blkno * lfs_sb_getbsize(fs) + 233 (inumber % lfs_sb_getifpb(fs)) * entsize; 234 rc = buf_read_file(f, &ent_in_buf, &buf_after_ent); 235 if (rc) 236 return rc; 237 /* make sure something's not badly wrong, but don't panic. */ 238 if (buf_after_ent < entsize) 239 return EINVAL; 240 241 *isp = FSBTODB(fs, lfs_if_getdaddr(fs, (IFILE *)ent_in_buf)); 242 if (*isp == LFS_UNUSED_DADDR) /* again, something badly wrong */ 243 return EINVAL; 244 return 0; 245 } 246 #endif 247 248 /* 249 * Read a new inode into a file structure. 250 */ 251 static int 252 read_inode(ino32_t inumber, struct open_file *f) 253 { 254 struct file *fp = (struct file *)f->f_fsdata; 255 FS *fs = fp->f_fs; 256 char *buf; 257 size_t rsize; 258 int rc; 259 daddr_t inode_sector = 0; /* XXX: gcc */ 260 #ifdef LIBSA_LFS 261 struct ufs_dinode *dip; 262 int cnt; 263 #endif 264 265 #ifdef LIBSA_LFS 266 if (inumber == LFS_IFILE_INUM) 267 inode_sector = FSBTODB(fs, lfs_sb_getidaddr(fs)); 268 else if ((rc = find_inode_sector(inumber, f, &inode_sector)) != 0) 269 return rc; 270 #else 271 inode_sector = FSBTODB(fs, ino_to_fsba(fs, inumber)); 272 #endif 273 274 /* 275 * Read inode and save it. 276 */ 277 buf = fp->f_buf; 278 twiddle(); 279 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, 280 inode_sector, fs->fs_bsize, buf, &rsize); 281 if (rc) 282 return rc; 283 if (rsize != (size_t)fs->fs_bsize) 284 return EIO; 285 286 #ifdef LIBSA_LFS 287 cnt = INOPBx(fs); 288 dip = (struct ufs_dinode *)buf + (cnt - 1); 289 for (; dip->di_inumber != inumber; --dip) { 290 /* kernel code panics, but boot blocks which panic are Bad. */ 291 if (--cnt == 0) 292 return EINVAL; 293 } 294 fp->f_di = *dip; 295 #else 296 fp->f_di = ((struct ufs_dinode *)buf)[ino_to_fsbo(fs, inumber)]; 297 #endif 298 299 /* 300 * Clear out the old buffers 301 */ 302 fp->f_ind_cache_block = ~0; 303 fp->f_buf_blkno = -1; 304 return rc; 305 } 306 307 /* 308 * Given an offset in a file, find the disk block number that 309 * contains that block. 310 */ 311 static int 312 block_map(struct open_file *f, indp_t file_block, indp_t *disk_block_p) 313 { 314 struct file *fp = (struct file *)f->f_fsdata; 315 FS *fs = fp->f_fs; 316 uint level; 317 indp_t ind_cache; 318 indp_t ind_block_num; 319 size_t rsize; 320 int rc; 321 indp_t *buf = (void *)fp->f_buf; 322 323 /* 324 * Index structure of an inode: 325 * 326 * di_db[0..UFS_NDADDR-1] hold block numbers for blocks 327 * 0..UFS_NDADDR-1 328 * 329 * di_ib[0] index block 0 is the single indirect block 330 * holds block numbers for blocks 331 * UFS_NDADDR .. UFS_NDADDR + UFS_NINDIR(fs)-1 332 * 333 * di_ib[1] index block 1 is the double indirect block 334 * holds block numbers for INDEX blocks for blocks 335 * UFS_NDADDR + UFS_NINDIR(fs) .. 336 * UFS_NDADDR + UFS_NINDIR(fs) + UFS_NINDIR(fs)**2 - 1 337 * 338 * di_ib[2] index block 2 is the triple indirect block 339 * holds block numbers for double-indirect 340 * blocks for blocks 341 * UFS_NDADDR + UFS_NINDIR(fs) + UFS_NINDIR(fs)**2 .. 342 * UFS_NDADDR + UFS_NINDIR(fs) + UFS_NINDIR(fs)**2 343 * + UFS_NINDIR(fs)**3 - 1 344 */ 345 346 if (file_block < UFS_NDADDR) { 347 /* Direct block. */ 348 *disk_block_p = fp->f_di.di_db[file_block]; 349 return 0; 350 } 351 352 file_block -= UFS_NDADDR; 353 354 ind_cache = file_block >> LN2_IND_CACHE_SZ; 355 if (ind_cache == fp->f_ind_cache_block) { 356 *disk_block_p = fp->f_ind_cache[file_block & IND_CACHE_MASK]; 357 return 0; 358 } 359 360 for (level = 0;;) { 361 level += fp->f_nishift; 362 if (file_block < (indp_t)1 << level) 363 break; 364 if (level > UFS_NIADDR * fp->f_nishift) 365 /* Block number too high */ 366 return EFBIG; 367 file_block -= (indp_t)1 << level; 368 } 369 370 ind_block_num = fp->f_di.di_ib[level / fp->f_nishift - 1]; 371 372 for (;;) { 373 level -= fp->f_nishift; 374 if (ind_block_num == 0) { 375 *disk_block_p = 0; /* missing */ 376 return 0; 377 } 378 379 twiddle(); 380 /* 381 * If we were feeling brave, we could work out the number 382 * of the disk sector and read a single disk sector instead 383 * of a filesystem block. 384 * However we don't do this very often anyway... 385 */ 386 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, 387 FSBTODB(fp->f_fs, ind_block_num), fs->fs_bsize, 388 buf, &rsize); 389 if (rc) 390 return rc; 391 if (rsize != (size_t)fs->fs_bsize) 392 return EIO; 393 ind_block_num = buf[file_block >> level]; 394 if (level == 0) 395 break; 396 file_block &= (1 << level) - 1; 397 } 398 399 /* Save the part of the block that contains this sector */ 400 memcpy(fp->f_ind_cache, &buf[file_block & ~IND_CACHE_MASK], 401 IND_CACHE_SZ * sizeof fp->f_ind_cache[0]); 402 fp->f_ind_cache_block = ind_cache; 403 404 *disk_block_p = ind_block_num; 405 406 return 0; 407 } 408 409 /* 410 * Read a portion of a file into an internal buffer. 411 * Return the location in the buffer and the amount in the buffer. 412 */ 413 static int 414 buf_read_file(struct open_file *f, char **buf_p, size_t *size_p) 415 { 416 struct file *fp = (struct file *)f->f_fsdata; 417 FS *fs = fp->f_fs; 418 long off; 419 indp_t file_block; 420 size_t block_size; 421 int rc; 422 423 off = ufs_blkoff(fs, fp->f_seekp); 424 file_block = ufs_lblkno(fs, fp->f_seekp); 425 #ifdef LIBSA_LFS 426 block_size = (size_t)dblksize(fs, &fp->f_di, (uint64_t)file_block); 427 #else 428 block_size = (size_t)ffs_sblksize(fs, (int64_t)fp->f_di.di_size, file_block); 429 #endif 430 431 if (file_block != fp->f_buf_blkno) { 432 indp_t disk_block = 0; /* XXX: gcc */ 433 rc = block_map(f, file_block, &disk_block); 434 if (rc) 435 return rc; 436 437 if (disk_block == 0) { 438 memset(fp->f_buf, 0, block_size); 439 fp->f_buf_size = block_size; 440 } else { 441 twiddle(); 442 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, 443 FSBTODB(fs, disk_block), 444 block_size, fp->f_buf, &fp->f_buf_size); 445 if (rc) 446 return rc; 447 } 448 449 fp->f_buf_blkno = file_block; 450 } 451 452 /* 453 * Return address of byte in buffer corresponding to 454 * offset, and size of remainder of buffer after that 455 * byte. 456 */ 457 *buf_p = fp->f_buf + off; 458 *size_p = block_size - off; 459 460 /* 461 * But truncate buffer at end of file. 462 */ 463 if (*size_p > fp->f_di.di_size - fp->f_seekp) 464 *size_p = fp->f_di.di_size - fp->f_seekp; 465 466 return 0; 467 } 468 469 /* 470 * Search a directory for a name and return its 471 * inode number. 472 */ 473 static int 474 search_directory(const char *name, int length, struct open_file *f, 475 ino32_t *inumber_p) 476 { 477 struct file *fp = (struct file *)f->f_fsdata; 478 struct direct *dp; 479 struct direct *edp; 480 char *buf; 481 size_t buf_size; 482 int namlen; 483 int rc; 484 485 fp->f_seekp = 0; 486 while (fp->f_seekp < (off_t)fp->f_di.di_size) { 487 rc = buf_read_file(f, &buf, &buf_size); 488 if (rc) 489 return rc; 490 491 dp = (struct direct *)buf; 492 edp = (struct direct *)(buf + buf_size); 493 for (;dp < edp; dp = (void *)((char *)dp + dp->d_reclen)) { 494 if (dp->d_reclen <= 0) 495 break; 496 if (dp->d_ino == (ino32_t)0) 497 continue; 498 #if BYTE_ORDER == LITTLE_ENDIAN 499 if (fp->f_fs->fs_maxsymlinklen <= 0) 500 namlen = dp->d_type; 501 else 502 #endif 503 namlen = dp->d_namlen; 504 if (namlen == length && 505 !memcmp(name, dp->d_name, length)) { 506 /* found entry */ 507 *inumber_p = dp->d_ino; 508 return 0; 509 } 510 } 511 fp->f_seekp += buf_size; 512 } 513 return ENOENT; 514 } 515 516 #ifdef LIBSA_FFSv2 517 518 daddr_t sblock_try[] = SBLOCKSEARCH; 519 520 static int 521 ffs_find_superblock(struct open_file *f, FS *fs) 522 { 523 int i, rc; 524 size_t buf_size; 525 526 for (i = 0; sblock_try[i] != -1; i++) { 527 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, 528 sblock_try[i] / DEV_BSIZE, SBLOCKSIZE, fs, &buf_size); 529 if (rc != 0 || buf_size != SBLOCKSIZE) 530 return rc; 531 if (fs->fs_sblockloc != sblock_try[i]) 532 /* an alternate superblock - try again */ 533 continue; 534 if (fs->fs_magic == FS_UFS2_MAGIC) { 535 return 0; 536 } 537 } 538 return EINVAL; 539 } 540 541 #endif 542 543 /* 544 * Open a file. 545 */ 546 __compactcall int 547 ufs_open(const char *path, struct open_file *f) 548 { 549 #ifndef LIBSA_FS_SINGLECOMPONENT 550 const char *cp, *ncp; 551 int c; 552 #endif 553 ino32_t inumber; 554 struct file *fp; 555 FS *fs; 556 int rc; 557 #ifndef LIBSA_NO_FS_SYMLINK 558 ino32_t parent_inumber; 559 int nlinks = 0; 560 char namebuf[MAXPATHLEN+1]; 561 char *buf; 562 #endif 563 564 /* allocate file system specific data structure */ 565 fp = alloc(sizeof(struct file)); 566 memset(fp, 0, sizeof(struct file)); 567 f->f_fsdata = (void *)fp; 568 569 /* allocate space and read super block */ 570 fs = alloc(SBLOCKSIZE); 571 fp->f_fs = fs; 572 twiddle(); 573 574 #ifdef LIBSA_FFSv2 575 rc = ffs_find_superblock(f, fs); 576 if (rc) 577 goto out; 578 #else 579 { 580 size_t buf_size; 581 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, 582 SBLOCKOFFSET / DEV_BSIZE, SBLOCKSIZE, fs, &buf_size); 583 if (rc) 584 goto out; 585 if (buf_size != SBLOCKSIZE || 586 #ifdef LIBSA_LFS 587 fs->lfs_version != REQUIRED_LFS_VERSION || 588 #endif 589 fs->fs_magic != FS_MAGIC) { 590 rc = EINVAL; 591 goto out; 592 } 593 } 594 #if defined(LIBSA_LFS) && REQUIRED_LFS_VERSION == 2 595 /* 596 * XXX We should check the second superblock and use the eldest 597 * of the two. See comments near the top of lfs_mountfs() 598 * in sys/ufs/lfs/lfs_vfsops.c. 599 * This may need a LIBSA_LFS_SMALL check as well. 600 */ 601 #endif 602 #if defined(LIBSA_LFS) 603 fs->lfs_is64 = 0; 604 fs->lfs_dobyteswap = 0; 605 fs->lfs_hasolddirfmt = (fs->fs_maxsymlinklen <= 0); 606 #endif 607 #endif 608 609 #ifdef LIBSA_FFSv1 610 ffs_oldfscompat(fs); 611 #endif 612 613 if (fs->fs_bsize > MAXBSIZE || 614 (size_t)fs->fs_bsize < sizeof(FS)) { 615 rc = EINVAL; 616 goto out; 617 } 618 619 /* 620 * Calculate indirect block levels. 621 */ 622 { 623 indp_t mult; 624 int ln2; 625 626 /* 627 * We note that the number of indirect blocks is always 628 * a power of 2. This lets us use shifts and masks instead 629 * of divide and remainder and avoinds pulling in the 630 * 64bit division routine into the boot code. 631 */ 632 mult = UFS_NINDIR(fs); 633 #ifdef DEBUG 634 if (mult & (mult - 1)) { 635 /* Hummm was't a power of 2 */ 636 rc = EINVAL; 637 goto out; 638 } 639 #endif 640 for (ln2 = 0; mult != 1; ln2++) 641 mult >>= 1; 642 643 fp->f_nishift = ln2; 644 } 645 646 /* alloc a block sized buffer used for all fs transfers */ 647 fp->f_buf = alloc(fs->fs_bsize); 648 inumber = UFS_ROOTINO; 649 if ((rc = read_inode(inumber, f)) != 0) 650 goto out; 651 652 #ifndef LIBSA_FS_SINGLECOMPONENT 653 cp = path; 654 while (*cp) { 655 656 /* 657 * Remove extra separators 658 */ 659 while (*cp == '/') 660 cp++; 661 if (*cp == '\0') 662 break; 663 664 /* 665 * Check that current node is a directory. 666 */ 667 if ((fp->f_di.di_mode & IFMT) != IFDIR) { 668 rc = ENOTDIR; 669 goto out; 670 } 671 672 /* 673 * Get next component of path name. 674 */ 675 ncp = cp; 676 while ((c = *cp) != '\0' && c != '/') 677 cp++; 678 679 /* 680 * Look up component in current directory. 681 * Save directory inumber in case we find a 682 * symbolic link. 683 */ 684 #ifndef LIBSA_NO_FS_SYMLINK 685 parent_inumber = inumber; 686 #endif 687 rc = search_directory(ncp, cp - ncp, f, &inumber); 688 if (rc) 689 goto out; 690 691 /* 692 * Open next component. 693 */ 694 if ((rc = read_inode(inumber, f)) != 0) 695 goto out; 696 697 #ifndef LIBSA_NO_FS_SYMLINK 698 /* 699 * Check for symbolic link. 700 */ 701 if ((fp->f_di.di_mode & IFMT) == IFLNK) { 702 int link_len = fp->f_di.di_size; 703 int len; 704 705 len = strlen(cp); 706 707 if (link_len + len > MAXPATHLEN || 708 ++nlinks > MAXSYMLINKS) { 709 rc = ENOENT; 710 goto out; 711 } 712 713 memmove(&namebuf[link_len], cp, len + 1); 714 715 if (link_len < fs->fs_maxsymlinklen) { 716 memcpy(namebuf, fp->f_di.di_db, link_len); 717 } else { 718 /* 719 * Read file for symbolic link 720 */ 721 size_t buf_size; 722 indp_t disk_block; 723 724 buf = fp->f_buf; 725 rc = block_map(f, (indp_t)0, &disk_block); 726 if (rc) 727 goto out; 728 729 twiddle(); 730 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, 731 F_READ, FSBTODB(fs, disk_block), 732 fs->fs_bsize, buf, &buf_size); 733 if (rc) 734 goto out; 735 736 memcpy(namebuf, buf, link_len); 737 } 738 739 /* 740 * If relative pathname, restart at parent directory. 741 * If absolute pathname, restart at root. 742 */ 743 cp = namebuf; 744 if (*cp != '/') 745 inumber = parent_inumber; 746 else 747 inumber = (ino32_t)UFS_ROOTINO; 748 749 if ((rc = read_inode(inumber, f)) != 0) 750 goto out; 751 } 752 #endif /* !LIBSA_NO_FS_SYMLINK */ 753 } 754 755 /* 756 * Found terminal component. 757 */ 758 rc = 0; 759 760 #else /* !LIBSA_FS_SINGLECOMPONENT */ 761 762 /* look up component in the current (root) directory */ 763 rc = search_directory(path, strlen(path), f, &inumber); 764 if (rc) 765 goto out; 766 767 /* open it */ 768 rc = read_inode(inumber, f); 769 770 #endif /* !LIBSA_FS_SINGLECOMPONENT */ 771 772 fp->f_seekp = 0; /* reset seek pointer */ 773 774 out: 775 if (rc) 776 ufs_close(f); 777 #ifdef FSMOD /* Only defined for lfs */ 778 else 779 fsmod = FSMOD; 780 #endif 781 return rc; 782 } 783 784 __compactcall int 785 ufs_close(struct open_file *f) 786 { 787 struct file *fp = (struct file *)f->f_fsdata; 788 789 f->f_fsdata = NULL; 790 if (fp == NULL) 791 return 0; 792 793 if (fp->f_buf) 794 dealloc(fp->f_buf, fp->f_fs->fs_bsize); 795 dealloc(fp->f_fs, SBLOCKSIZE); 796 dealloc(fp, sizeof(struct file)); 797 return 0; 798 } 799 800 /* 801 * Copy a portion of a file into kernel memory. 802 * Cross block boundaries when necessary. 803 */ 804 __compactcall int 805 ufs_read(struct open_file *f, void *start, size_t size, size_t *resid) 806 { 807 struct file *fp = (struct file *)f->f_fsdata; 808 size_t csize; 809 char *buf; 810 size_t buf_size; 811 int rc = 0; 812 char *addr = start; 813 814 while (size != 0) { 815 if (fp->f_seekp >= (off_t)fp->f_di.di_size) 816 break; 817 818 rc = buf_read_file(f, &buf, &buf_size); 819 if (rc) 820 break; 821 822 csize = size; 823 if (csize > buf_size) 824 csize = buf_size; 825 826 memcpy(addr, buf, csize); 827 828 fp->f_seekp += csize; 829 addr += csize; 830 size -= csize; 831 } 832 if (resid) 833 *resid = size; 834 return rc; 835 } 836 837 /* 838 * Not implemented. 839 */ 840 #ifndef LIBSA_NO_FS_WRITE 841 __compactcall int 842 ufs_write(struct open_file *f, void *start, size_t size, size_t *resid) 843 { 844 845 return EROFS; 846 } 847 #endif /* !LIBSA_NO_FS_WRITE */ 848 849 #ifndef LIBSA_NO_FS_SEEK 850 __compactcall off_t 851 ufs_seek(struct open_file *f, off_t offset, int where) 852 { 853 struct file *fp = (struct file *)f->f_fsdata; 854 855 switch (where) { 856 case SEEK_SET: 857 fp->f_seekp = offset; 858 break; 859 case SEEK_CUR: 860 fp->f_seekp += offset; 861 break; 862 case SEEK_END: 863 fp->f_seekp = fp->f_di.di_size - offset; 864 break; 865 default: 866 return -1; 867 } 868 return fp->f_seekp; 869 } 870 #endif /* !LIBSA_NO_FS_SEEK */ 871 872 __compactcall int 873 ufs_stat(struct open_file *f, struct stat *sb) 874 { 875 struct file *fp = (struct file *)f->f_fsdata; 876 877 /* only important stuff */ 878 memset(sb, 0, sizeof *sb); 879 sb->st_mode = fp->f_di.di_mode; 880 sb->st_uid = fp->f_di.di_uid; 881 sb->st_gid = fp->f_di.di_gid; 882 sb->st_size = fp->f_di.di_size; 883 return 0; 884 } 885 886 #if defined(LIBSA_ENABLE_LS_OP) 887 888 #include "ls.h" 889 890 static const char *const typestr[] = { 891 "unknown", 892 "FIFO", 893 "CHR", 894 0, 895 "DIR", 896 0, 897 "BLK", 898 0, 899 "REG", 900 0, 901 "LNK", 902 0, 903 "SOCK", 904 0, 905 "WHT" 906 }; 907 908 __compactcall void 909 ufs_ls(struct open_file *f, const char *pattern) 910 { 911 struct file *fp = (struct file *)f->f_fsdata; 912 char *buf; 913 size_t buf_size; 914 lsentry_t *names = NULL; 915 916 fp->f_seekp = 0; 917 while (fp->f_seekp < (off_t)fp->f_di.di_size) { 918 struct direct *dp, *edp; 919 int rc = buf_read_file(f, &buf, &buf_size); 920 if (rc) 921 goto out; 922 /* some firmware might use block size larger than DEV_BSIZE */ 923 if (buf_size < UFS_DIRBLKSIZ) 924 goto out; 925 926 dp = (struct direct *)buf; 927 edp = (struct direct *)(buf + buf_size); 928 929 for (; dp < edp; dp = (void *)((char *)dp + dp->d_reclen)) { 930 const char *t; 931 if (dp->d_ino == 0) 932 continue; 933 934 if (dp->d_type >= NELEM(typestr) || 935 !(t = typestr[dp->d_type])) { 936 /* 937 * This does not handle "old" 938 * filesystems properly. On little 939 * endian machines, we get a bogus 940 * type name if the namlen matches a 941 * valid type identifier. We could 942 * check if we read namlen "0" and 943 * handle this case specially, if 944 * there were a pressing need... 945 */ 946 printf("bad dir entry\n"); 947 goto out; 948 } 949 lsadd(&names, pattern, dp->d_name, strlen(dp->d_name), 950 dp->d_ino, t); 951 } 952 fp->f_seekp += buf_size; 953 } 954 lsprint(names); 955 out: lsfree(names); 956 } 957 #endif /* LIBSA_ENABLE_LS_OP */ 958 959 #ifdef LIBSA_FFSv1 960 /* 961 * Sanity checks for old file systems. 962 * 963 * XXX - goes away some day. 964 * Stripped of stuff libsa doesn't need..... 965 */ 966 static void 967 ffs_oldfscompat(FS *fs) 968 { 969 970 #ifdef COMPAT_UFS 971 /* 972 * Newer Solaris versions have a slightly incompatible 973 * superblock - so always calculate this values on the fly, which 974 * is good enough for libsa purposes 975 */ 976 if (fs->fs_magic == FS_UFS1_MAGIC 977 #ifndef COMPAT_SOLARIS_UFS 978 && fs->fs_old_inodefmt < FS_44INODEFMT 979 #endif 980 ) { 981 fs->fs_qbmask = ~fs->fs_bmask; 982 fs->fs_qfmask = ~fs->fs_fmask; 983 } 984 #endif 985 } 986 #endif 987