ufs.c revision 84221
1/* $NetBSD: ufs.c,v 1.20 1998/03/01 07:15:39 ross 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#include <sys/cdefs.h> 66__FBSDID("$FreeBSD: head/lib/libstand/ufs.c 84221 2001-09-30 22:28:01Z dillon $"); 67 68/* 69 * Stand-alone file reading package. 70 */ 71 72#include <sys/param.h> 73#include <sys/time.h> 74#include <ufs/ufs/dinode.h> 75#include <ufs/ufs/dir.h> 76#include <ufs/ffs/fs.h> 77#include "stand.h" 78#include "string.h" 79 80#ifdef __alpha__ 81#define COMPAT_UFS /* DUX has old format file systems */ 82#endif 83 84static int ufs_open(const char *path, struct open_file *f); 85static int ufs_close(struct open_file *f); 86static int ufs_read(struct open_file *f, void *buf, size_t size, size_t *resid); 87static off_t ufs_seek(struct open_file *f, off_t offset, int where); 88static int ufs_stat(struct open_file *f, struct stat *sb); 89static int ufs_readdir(struct open_file *f, struct dirent *d); 90 91struct fs_ops ufs_fsops = { 92 "ufs", 93 ufs_open, 94 ufs_close, 95 ufs_read, 96 null_write, 97 ufs_seek, 98 ufs_stat, 99 ufs_readdir 100}; 101 102/* 103 * In-core open file. 104 */ 105struct file { 106 off_t f_seekp; /* seek pointer */ 107 struct fs *f_fs; /* pointer to super-block */ 108 struct dinode f_di; /* copy of on-disk inode */ 109 int f_nindir[NIADDR]; 110 /* number of blocks mapped by 111 indirect block at level i */ 112 char *f_blk[NIADDR]; /* buffer for indirect block at 113 level i */ 114 size_t f_blksize[NIADDR]; 115 /* size of buffer */ 116 daddr_t f_blkno[NIADDR];/* disk address of block in buffer */ 117 char *f_buf; /* buffer for data block */ 118 size_t f_buf_size; /* size of data block */ 119 daddr_t f_buf_blkno; /* block number of data block */ 120}; 121 122static int read_inode(ino_t, struct open_file *); 123static int block_map(struct open_file *, daddr_t, daddr_t *); 124static int buf_read_file(struct open_file *, char **, size_t *); 125static int search_directory(char *, struct open_file *, ino_t *); 126#ifdef COMPAT_UFS 127static void ffs_oldfscompat(struct fs *); 128#endif 129 130/* 131 * Read a new inode into a file structure. 132 */ 133static int 134read_inode(inumber, f) 135 ino_t inumber; 136 struct open_file *f; 137{ 138 register struct file *fp = (struct file *)f->f_fsdata; 139 register struct fs *fs = fp->f_fs; 140 char *buf; 141 size_t rsize; 142 int rc; 143 144 if (fs == NULL) 145 panic("fs == NULL"); 146 147 /* 148 * Read inode and save it. 149 */ 150 buf = malloc(fs->fs_bsize); 151 twiddle(); 152 rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 153 fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize, 154 buf, &rsize); 155 if (rc) 156 goto out; 157 if (rsize != fs->fs_bsize) { 158 rc = EIO; 159 goto out; 160 } 161 162 { 163 register struct dinode *dp; 164 165 dp = (struct dinode *)buf; 166 fp->f_di = dp[ino_to_fsbo(fs, inumber)]; 167 } 168 169 /* 170 * Clear out the old buffers 171 */ 172 { 173 register int level; 174 175 for (level = 0; level < NIADDR; level++) 176 fp->f_blkno[level] = -1; 177 fp->f_buf_blkno = -1; 178 } 179out: 180 free(buf); 181 return (rc); 182} 183 184/* 185 * Given an offset in a file, find the disk block number that 186 * contains that block. 187 */ 188static int 189block_map(f, file_block, disk_block_p) 190 struct open_file *f; 191 daddr_t file_block; 192 daddr_t *disk_block_p; /* out */ 193{ 194 register struct file *fp = (struct file *)f->f_fsdata; 195 register struct fs *fs = fp->f_fs; 196 int level; 197 int idx; 198 daddr_t ind_block_num; 199 daddr_t *ind_p; 200 int rc; 201 202 /* 203 * Index structure of an inode: 204 * 205 * di_db[0..NDADDR-1] hold block numbers for blocks 206 * 0..NDADDR-1 207 * 208 * di_ib[0] index block 0 is the single indirect block 209 * holds block numbers for blocks 210 * NDADDR .. NDADDR + NINDIR(fs)-1 211 * 212 * di_ib[1] index block 1 is the double indirect block 213 * holds block numbers for INDEX blocks for blocks 214 * NDADDR + NINDIR(fs) .. 215 * NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1 216 * 217 * di_ib[2] index block 2 is the triple indirect block 218 * holds block numbers for double-indirect 219 * blocks for blocks 220 * NDADDR + NINDIR(fs) + NINDIR(fs)**2 .. 221 * NDADDR + NINDIR(fs) + NINDIR(fs)**2 222 * + NINDIR(fs)**3 - 1 223 */ 224 225 if (file_block < NDADDR) { 226 /* Direct block. */ 227 *disk_block_p = fp->f_di.di_db[file_block]; 228 return (0); 229 } 230 231 file_block -= NDADDR; 232 233 /* 234 * nindir[0] = NINDIR 235 * nindir[1] = NINDIR**2 236 * nindir[2] = NINDIR**3 237 * etc 238 */ 239 for (level = 0; level < NIADDR; level++) { 240 if (file_block < fp->f_nindir[level]) 241 break; 242 file_block -= fp->f_nindir[level]; 243 } 244 if (level == NIADDR) { 245 /* Block number too high */ 246 return (EFBIG); 247 } 248 249 ind_block_num = fp->f_di.di_ib[level]; 250 251 for (; level >= 0; level--) { 252 if (ind_block_num == 0) { 253 *disk_block_p = 0; /* missing */ 254 return (0); 255 } 256 257 if (fp->f_blkno[level] != ind_block_num) { 258 if (fp->f_blk[level] == (char *)0) 259 fp->f_blk[level] = 260 malloc(fs->fs_bsize); 261 twiddle(); 262 rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 263 fsbtodb(fp->f_fs, ind_block_num), 264 fs->fs_bsize, 265 fp->f_blk[level], 266 &fp->f_blksize[level]); 267 if (rc) 268 return (rc); 269 if (fp->f_blksize[level] != fs->fs_bsize) 270 return (EIO); 271 fp->f_blkno[level] = ind_block_num; 272 } 273 274 ind_p = (daddr_t *)fp->f_blk[level]; 275 276 if (level > 0) { 277 idx = file_block / fp->f_nindir[level - 1]; 278 file_block %= fp->f_nindir[level - 1]; 279 } else 280 idx = file_block; 281 282 ind_block_num = ind_p[idx]; 283 } 284 285 *disk_block_p = ind_block_num; 286 287 return (0); 288} 289 290/* 291 * Read a portion of a file into an internal buffer. Return 292 * the location in the buffer and the amount in the buffer. 293 */ 294static int 295buf_read_file(f, buf_p, size_p) 296 struct open_file *f; 297 char **buf_p; /* out */ 298 size_t *size_p; /* out */ 299{ 300 register struct file *fp = (struct file *)f->f_fsdata; 301 register struct fs *fs = fp->f_fs; 302 long off; 303 register daddr_t file_block; 304 daddr_t disk_block; 305 size_t block_size; 306 int rc; 307 308 off = blkoff(fs, fp->f_seekp); 309 file_block = lblkno(fs, fp->f_seekp); 310 block_size = dblksize(fs, &fp->f_di, file_block); 311 312 if (file_block != fp->f_buf_blkno) { 313 rc = block_map(f, file_block, &disk_block); 314 if (rc) 315 return (rc); 316 317 if (fp->f_buf == (char *)0) 318 fp->f_buf = malloc(fs->fs_bsize); 319 320 if (disk_block == 0) { 321 bzero(fp->f_buf, block_size); 322 fp->f_buf_size = block_size; 323 } else { 324 twiddle(); 325 rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 326 fsbtodb(fs, disk_block), 327 block_size, fp->f_buf, &fp->f_buf_size); 328 if (rc) 329 return (rc); 330 } 331 332 fp->f_buf_blkno = file_block; 333 } 334 335 /* 336 * Return address of byte in buffer corresponding to 337 * offset, and size of remainder of buffer after that 338 * byte. 339 */ 340 *buf_p = fp->f_buf + off; 341 *size_p = block_size - off; 342 343 /* 344 * But truncate buffer at end of file. 345 */ 346 if (*size_p > fp->f_di.di_size - fp->f_seekp) 347 *size_p = fp->f_di.di_size - fp->f_seekp; 348 349 return (0); 350} 351 352/* 353 * Search a directory for a name and return its 354 * i_number. 355 */ 356static int 357search_directory(name, f, inumber_p) 358 char *name; 359 struct open_file *f; 360 ino_t *inumber_p; /* out */ 361{ 362 register struct file *fp = (struct file *)f->f_fsdata; 363 register struct direct *dp; 364 struct direct *edp; 365 char *buf; 366 size_t buf_size; 367 int namlen, length; 368 int rc; 369 370 length = strlen(name); 371 372 fp->f_seekp = 0; 373 while (fp->f_seekp < fp->f_di.di_size) { 374 rc = buf_read_file(f, &buf, &buf_size); 375 if (rc) 376 return (rc); 377 378 dp = (struct direct *)buf; 379 edp = (struct direct *)(buf + buf_size); 380 while (dp < edp) { 381 if (dp->d_ino == (ino_t)0) 382 goto next; 383#if BYTE_ORDER == LITTLE_ENDIAN 384 if (fp->f_fs->fs_maxsymlinklen <= 0) 385 namlen = dp->d_type; 386 else 387#endif 388 namlen = dp->d_namlen; 389 if (namlen == length && 390 !strcmp(name, dp->d_name)) { 391 /* found entry */ 392 *inumber_p = dp->d_ino; 393 return (0); 394 } 395 next: 396 dp = (struct direct *)((char *)dp + dp->d_reclen); 397 } 398 fp->f_seekp += buf_size; 399 } 400 return (ENOENT); 401} 402 403/* 404 * Open a file. 405 */ 406static int 407ufs_open(upath, f) 408 const char *upath; 409 struct open_file *f; 410{ 411 register char *cp, *ncp; 412 register int c; 413 ino_t inumber, parent_inumber; 414 struct file *fp; 415 struct fs *fs; 416 int rc; 417 size_t buf_size; 418 int nlinks = 0; 419 char namebuf[MAXPATHLEN+1]; 420 char *buf = NULL; 421 char *path = NULL; 422 423 /* allocate file system specific data structure */ 424 fp = malloc(sizeof(struct file)); 425 bzero(fp, sizeof(struct file)); 426 f->f_fsdata = (void *)fp; 427 428 /* allocate space and read super block */ 429 fs = malloc(SBSIZE); 430 fp->f_fs = fs; 431 twiddle(); 432 rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 433 SBLOCK, SBSIZE, (char *)fs, &buf_size); 434 if (rc) 435 goto out; 436 437 if (buf_size != SBSIZE || fs->fs_magic != FS_MAGIC || 438 fs->fs_bsize > MAXBSIZE || fs->fs_bsize < sizeof(struct fs)) { 439 rc = EINVAL; 440 goto out; 441 } 442#ifdef COMPAT_UFS 443 ffs_oldfscompat(fs); 444#endif 445 446 /* 447 * Calculate indirect block levels. 448 */ 449 { 450 register int mult; 451 register int level; 452 453 mult = 1; 454 for (level = 0; level < NIADDR; level++) { 455 mult *= NINDIR(fs); 456 fp->f_nindir[level] = mult; 457 } 458 } 459 460 inumber = ROOTINO; 461 if ((rc = read_inode(inumber, f)) != 0) 462 goto out; 463 464 cp = path = strdup(upath); 465 if (path == NULL) { 466 rc = ENOMEM; 467 goto out; 468 } 469 while (*cp) { 470 471 /* 472 * Remove extra separators 473 */ 474 while (*cp == '/') 475 cp++; 476 if (*cp == '\0') 477 break; 478 479 /* 480 * Check that current node is a directory. 481 */ 482 if ((fp->f_di.di_mode & IFMT) != IFDIR) { 483 rc = ENOTDIR; 484 goto out; 485 } 486 487 /* 488 * Get next component of path name. 489 */ 490 { 491 register int len = 0; 492 493 ncp = cp; 494 while ((c = *cp) != '\0' && c != '/') { 495 if (++len > MAXNAMLEN) { 496 rc = ENOENT; 497 goto out; 498 } 499 cp++; 500 } 501 *cp = '\0'; 502 } 503 504 /* 505 * Look up component in current directory. 506 * Save directory inumber in case we find a 507 * symbolic link. 508 */ 509 parent_inumber = inumber; 510 rc = search_directory(ncp, f, &inumber); 511 *cp = c; 512 if (rc) 513 goto out; 514 515 /* 516 * Open next component. 517 */ 518 if ((rc = read_inode(inumber, f)) != 0) 519 goto out; 520 521 /* 522 * Check for symbolic link. 523 */ 524 if ((fp->f_di.di_mode & IFMT) == IFLNK) { 525 int link_len = fp->f_di.di_size; 526 int len; 527 528 len = strlen(cp); 529 530 if (link_len + len > MAXPATHLEN || 531 ++nlinks > MAXSYMLINKS) { 532 rc = ENOENT; 533 goto out; 534 } 535 536 bcopy(cp, &namebuf[link_len], len + 1); 537 538 if (link_len < fs->fs_maxsymlinklen) { 539 bcopy(fp->f_di.di_shortlink, namebuf, 540 (unsigned) link_len); 541 } else { 542 /* 543 * Read file for symbolic link 544 */ 545 size_t buf_size; 546 daddr_t disk_block; 547 register struct fs *fs = fp->f_fs; 548 549 if (!buf) 550 buf = malloc(fs->fs_bsize); 551 rc = block_map(f, (daddr_t)0, &disk_block); 552 if (rc) 553 goto out; 554 555 twiddle(); 556 rc = (f->f_dev->dv_strategy)(f->f_devdata, 557 F_READ, fsbtodb(fs, disk_block), 558 fs->fs_bsize, buf, &buf_size); 559 if (rc) 560 goto out; 561 562 bcopy((char *)buf, namebuf, (unsigned)link_len); 563 } 564 565 /* 566 * If relative pathname, restart at parent directory. 567 * If absolute pathname, restart at root. 568 */ 569 cp = namebuf; 570 if (*cp != '/') 571 inumber = parent_inumber; 572 else 573 inumber = (ino_t)ROOTINO; 574 575 if ((rc = read_inode(inumber, f)) != 0) 576 goto out; 577 } 578 } 579 580 /* 581 * Found terminal component. 582 */ 583 rc = 0; 584out: 585 if (buf) 586 free(buf); 587 if (path) 588 free(path); 589 if (rc) { 590 if (fp->f_buf) 591 free(fp->f_buf); 592 free(fp->f_fs); 593 free(fp); 594 } 595 return (rc); 596} 597 598static int 599ufs_close(f) 600 struct open_file *f; 601{ 602 register struct file *fp = (struct file *)f->f_fsdata; 603 int level; 604 605 f->f_fsdata = (void *)0; 606 if (fp == (struct file *)0) 607 return (0); 608 609 for (level = 0; level < NIADDR; level++) { 610 if (fp->f_blk[level]) 611 free(fp->f_blk[level]); 612 } 613 if (fp->f_buf) 614 free(fp->f_buf); 615 free(fp->f_fs); 616 free(fp); 617 return (0); 618} 619 620/* 621 * Copy a portion of a file into kernel memory. 622 * Cross block boundaries when necessary. 623 */ 624static int 625ufs_read(f, start, size, resid) 626 struct open_file *f; 627 void *start; 628 size_t size; 629 size_t *resid; /* out */ 630{ 631 register struct file *fp = (struct file *)f->f_fsdata; 632 register size_t csize; 633 char *buf; 634 size_t buf_size; 635 int rc = 0; 636 register char *addr = start; 637 638 while (size != 0) { 639 if (fp->f_seekp >= fp->f_di.di_size) 640 break; 641 642 rc = buf_read_file(f, &buf, &buf_size); 643 if (rc) 644 break; 645 646 csize = size; 647 if (csize > buf_size) 648 csize = buf_size; 649 650 bcopy(buf, addr, csize); 651 652 fp->f_seekp += csize; 653 addr += csize; 654 size -= csize; 655 } 656 if (resid) 657 *resid = size; 658 return (rc); 659} 660 661static off_t 662ufs_seek(f, offset, where) 663 struct open_file *f; 664 off_t offset; 665 int where; 666{ 667 register struct file *fp = (struct file *)f->f_fsdata; 668 669 switch (where) { 670 case SEEK_SET: 671 fp->f_seekp = offset; 672 break; 673 case SEEK_CUR: 674 fp->f_seekp += offset; 675 break; 676 case SEEK_END: 677 fp->f_seekp = fp->f_di.di_size - offset; 678 break; 679 default: 680 return (-1); 681 } 682 return (fp->f_seekp); 683} 684 685static int 686ufs_stat(f, sb) 687 struct open_file *f; 688 struct stat *sb; 689{ 690 register struct file *fp = (struct file *)f->f_fsdata; 691 692 /* only important stuff */ 693 sb->st_mode = fp->f_di.di_mode; 694 sb->st_uid = fp->f_di.di_uid; 695 sb->st_gid = fp->f_di.di_gid; 696 sb->st_size = fp->f_di.di_size; 697 return (0); 698} 699 700static int 701ufs_readdir(struct open_file *f, struct dirent *d) 702{ 703 struct file *fp = (struct file *)f->f_fsdata; 704 struct direct *dp; 705 char *buf; 706 size_t buf_size; 707 int error; 708 709 /* 710 * assume that a directory entry will not be split across blocks 711 */ 712again: 713 if (fp->f_seekp >= fp->f_di.di_size) 714 return (ENOENT); 715 error = buf_read_file(f, &buf, &buf_size); 716 if (error) 717 return (error); 718 dp = (struct direct *)buf; 719 fp->f_seekp += dp->d_reclen; 720 if (dp->d_ino == (ino_t)0) 721 goto again; 722 d->d_type = dp->d_type; 723 strcpy(d->d_name, dp->d_name); 724 return (0); 725} 726 727#ifdef COMPAT_UFS 728/* 729 * Sanity checks for old file systems. 730 * 731 * XXX - goes away some day. 732 */ 733static void 734ffs_oldfscompat(fs) 735 struct fs *fs; 736{ 737 int i; 738 739 fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect); /* XXX */ 740 fs->fs_interleave = max(fs->fs_interleave, 1); /* XXX */ 741 if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 742 fs->fs_nrpos = 8; /* XXX */ 743 if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ 744 quad_t sizepb = fs->fs_bsize; /* XXX */ 745 /* XXX */ 746 fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1; /* XXX */ 747 for (i = 0; i < NIADDR; i++) { /* XXX */ 748 sizepb *= NINDIR(fs); /* XXX */ 749 fs->fs_maxfilesize += sizepb; /* XXX */ 750 } /* XXX */ 751 fs->fs_qbmask = ~fs->fs_bmask; /* XXX */ 752 fs->fs_qfmask = ~fs->fs_fmask; /* XXX */ 753 } /* XXX */ 754} 755#endif 756