1 /* $OpenBSD: ufs.c,v 1.19 2008/01/06 11:17:18 otto Exp $ */ 2 /* $NetBSD: ufs.c,v 1.16 1996/09/30 16:01:22 ws Exp $ */ 3 4 /*- 5 * Copyright (c) 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * The Mach Operating System project at Carnegie-Mellon University. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * 36 * Copyright (c) 1990, 1991 Carnegie Mellon University 37 * All Rights Reserved. 38 * 39 * Author: David Golub 40 * 41 * Permission to use, copy, modify and distribute this software and its 42 * documentation is hereby granted, provided that both the copyright 43 * notice and this permission notice appear in all copies of the 44 * software, derivative works or modified versions, and any portions 45 * thereof, and that both notices appear in supporting documentation. 46 * 47 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 48 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 49 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 50 * 51 * Carnegie Mellon requests users of this software to return to 52 * 53 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 54 * School of Computer Science 55 * Carnegie Mellon University 56 * Pittsburgh PA 15213-3890 57 * 58 * any improvements or extensions that they make and grant Carnegie the 59 * rights to redistribute these changes. 60 */ 61 62 /* 63 * Stand-alone file reading package. 64 */ 65 66 #include <sys/param.h> 67 #include <sys/time.h> 68 #include <sys/stat.h> 69 #include <ufs/ffs/fs.h> 70 #include <ufs/ufs/dinode.h> 71 #include <ufs/ufs/dir.h> 72 #include <lib/libkern/libkern.h> 73 74 #include "stand.h" 75 #include "ufs.h" 76 77 /* 78 * In-core open file. 79 */ 80 struct file { 81 off_t f_seekp; /* seek pointer */ 82 struct fs *f_fs; /* pointer to super-block */ 83 struct ufs1_dinode f_di; /* copy of on-disk inode */ 84 int f_nindir[NIADDR]; 85 /* number of blocks mapped by 86 indirect block at level i */ 87 char *f_blk[NIADDR]; /* buffer for indirect block at 88 level i */ 89 size_t f_blksize[NIADDR]; 90 /* size of buffer */ 91 daddr_t f_blkno[NIADDR];/* disk address of block in buffer */ 92 char *f_buf; /* buffer for data block */ 93 size_t f_buf_size; /* size of data block */ 94 daddr_t f_buf_blkno; /* block number of data block */ 95 }; 96 97 static int read_inode(ino_t, struct open_file *); 98 static int block_map(struct open_file *, daddr_t, daddr_t *); 99 static int buf_read_file(struct open_file *, char **, size_t *); 100 static int search_directory(char *, struct open_file *, ino_t *); 101 #ifdef COMPAT_UFS 102 static void ffs_oldfscompat(struct fs *); 103 #endif 104 105 /* 106 * Read a new inode into a file structure. 107 */ 108 static int 109 read_inode(ino_t inumber, struct open_file *f) 110 { 111 struct file *fp = (struct file *)f->f_fsdata; 112 struct fs *fs = fp->f_fs; 113 char *buf; 114 size_t rsize; 115 int rc; 116 117 /* 118 * Read inode and save it. 119 */ 120 buf = alloc(fs->fs_bsize); 121 twiddle(); 122 rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 123 fsbtodb(fs, (daddr_t)ino_to_fsba(fs, inumber)), fs->fs_bsize, 124 buf, &rsize); 125 if (rc) 126 goto out; 127 if (rsize != (size_t)fs->fs_bsize) { 128 rc = EIO; 129 goto out; 130 } 131 132 { 133 struct ufs1_dinode *dp; 134 135 dp = (struct ufs1_dinode *)buf; 136 fp->f_di = dp[ino_to_fsbo(fs, inumber)]; 137 } 138 139 /* 140 * Clear out the old buffers 141 */ 142 { 143 int level; 144 145 for (level = 0; level < NIADDR; level++) 146 fp->f_blkno[level] = -1; 147 fp->f_buf_blkno = -1; 148 fp->f_seekp = 0; 149 } 150 out: 151 free(buf, fs->fs_bsize); 152 return (rc); 153 } 154 155 /* 156 * Given an offset in a file, find the disk block number that 157 * contains that block. 158 */ 159 static int 160 block_map(struct open_file *f, daddr_t file_block, daddr_t *disk_block_p) 161 { 162 struct file *fp = (struct file *)f->f_fsdata; 163 daddr_t ind_block_num, *ind_p; 164 struct fs *fs = fp->f_fs; 165 int level, idx, rc; 166 167 /* 168 * Index structure of an inode: 169 * 170 * di_db[0..NDADDR-1] hold block numbers for blocks 171 * 0..NDADDR-1 172 * 173 * di_ib[0] index block 0 is the single indirect block 174 * holds block numbers for blocks 175 * NDADDR .. NDADDR + NINDIR(fs)-1 176 * 177 * di_ib[1] index block 1 is the double indirect block 178 * holds block numbers for INDEX blocks for blocks 179 * NDADDR + NINDIR(fs) .. 180 * NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1 181 * 182 * di_ib[2] index block 2 is the triple indirect block 183 * holds block numbers for double-indirect 184 * blocks for blocks 185 * NDADDR + NINDIR(fs) + NINDIR(fs)**2 .. 186 * NDADDR + NINDIR(fs) + NINDIR(fs)**2 187 * + NINDIR(fs)**3 - 1 188 */ 189 190 if (file_block < NDADDR) { 191 /* Direct block. */ 192 *disk_block_p = fp->f_di.di_db[file_block]; 193 return (0); 194 } 195 196 file_block -= NDADDR; 197 198 /* 199 * nindir[0] = NINDIR 200 * nindir[1] = NINDIR**2 201 * nindir[2] = NINDIR**3 202 * etc 203 */ 204 for (level = 0; level < NIADDR; level++) { 205 if (file_block < fp->f_nindir[level]) 206 break; 207 file_block -= fp->f_nindir[level]; 208 } 209 if (level == NIADDR) { 210 /* Block number too high */ 211 return (EFBIG); 212 } 213 214 ind_block_num = fp->f_di.di_ib[level]; 215 216 for (; level >= 0; level--) { 217 if (ind_block_num == 0) { 218 *disk_block_p = 0; /* missing */ 219 return (0); 220 } 221 222 if (fp->f_blkno[level] != ind_block_num) { 223 if (fp->f_blk[level] == (char *)0) 224 fp->f_blk[level] = 225 alloc(fs->fs_bsize); 226 twiddle(); 227 rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 228 fsbtodb(fp->f_fs, ind_block_num), fs->fs_bsize, 229 fp->f_blk[level], &fp->f_blksize[level]); 230 if (rc) 231 return (rc); 232 if (fp->f_blksize[level] != (size_t)fs->fs_bsize) 233 return (EIO); 234 fp->f_blkno[level] = ind_block_num; 235 } 236 237 ind_p = (daddr_t *)fp->f_blk[level]; 238 239 if (level > 0) { 240 idx = file_block / fp->f_nindir[level - 1]; 241 file_block %= fp->f_nindir[level - 1]; 242 } else 243 idx = file_block; 244 245 ind_block_num = ind_p[idx]; 246 } 247 248 *disk_block_p = ind_block_num; 249 return (0); 250 } 251 252 /* 253 * Read a portion of a file into an internal buffer. Return 254 * the location in the buffer and the amount in the buffer. 255 */ 256 static int 257 buf_read_file(struct open_file *f, char **buf_p, size_t *size_p) 258 { 259 struct file *fp = (struct file *)f->f_fsdata; 260 struct fs *fs = fp->f_fs; 261 daddr_t file_block, disk_block; 262 size_t block_size; 263 long off; 264 int rc; 265 266 off = blkoff(fs, fp->f_seekp); 267 file_block = lblkno(fs, fp->f_seekp); 268 block_size = dblksize(fs, &fp->f_di, file_block); 269 270 if (file_block != fp->f_buf_blkno) { 271 rc = block_map(f, file_block, &disk_block); 272 if (rc) 273 return (rc); 274 275 if (fp->f_buf == (char *)0) 276 fp->f_buf = alloc(fs->fs_bsize); 277 278 if (disk_block == 0) { 279 bzero(fp->f_buf, block_size); 280 fp->f_buf_size = block_size; 281 } else { 282 twiddle(); 283 rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 284 fsbtodb(fs, disk_block), 285 block_size, fp->f_buf, &fp->f_buf_size); 286 if (rc) 287 return (rc); 288 } 289 290 fp->f_buf_blkno = file_block; 291 } 292 293 /* 294 * Return address of byte in buffer corresponding to 295 * offset, and size of remainder of buffer after that 296 * byte. 297 */ 298 *buf_p = fp->f_buf + off; 299 *size_p = block_size - off; 300 301 /* 302 * But truncate buffer at end of file. 303 */ 304 if (*size_p > fp->f_di.di_size - fp->f_seekp) 305 *size_p = fp->f_di.di_size - fp->f_seekp; 306 307 return (0); 308 } 309 310 /* 311 * Search a directory for a name and return its 312 * i_number. 313 */ 314 static int 315 search_directory(char *name, struct open_file *f, ino_t *inumber_p) 316 { 317 struct file *fp = (struct file *)f->f_fsdata; 318 int namlen, length, rc; 319 struct direct *dp, *edp; 320 size_t buf_size; 321 char *buf; 322 323 length = strlen(name); 324 325 fp->f_seekp = 0; 326 while (fp->f_seekp < fp->f_di.di_size) { 327 rc = buf_read_file(f, &buf, &buf_size); 328 if (rc) 329 return (rc); 330 331 dp = (struct direct *)buf; 332 edp = (struct direct *)(buf + buf_size); 333 while (dp < edp) { 334 if (dp->d_ino == (ino_t)0) 335 goto next; 336 #if BYTE_ORDER == LITTLE_ENDIAN 337 if (fp->f_fs->fs_maxsymlinklen <= 0) 338 namlen = dp->d_type; 339 else 340 #endif 341 namlen = dp->d_namlen; 342 if (namlen == length && 343 !strcmp(name, dp->d_name)) { 344 /* found entry */ 345 *inumber_p = dp->d_ino; 346 return (0); 347 } 348 next: 349 dp = (struct direct *)((char *)dp + dp->d_reclen); 350 } 351 fp->f_seekp += buf_size; 352 } 353 return (ENOENT); 354 } 355 356 /* 357 * Open a file. 358 */ 359 int 360 ufs_open(char *path, struct open_file *f) 361 { 362 char namebuf[MAXPATHLEN+1], *cp, *ncp, *buf = NULL; 363 ino_t inumber, parent_inumber; 364 int rc, c, nlinks = 0; 365 struct file *fp; 366 size_t buf_size; 367 struct fs *fs; 368 369 /* allocate file system specific data structure */ 370 fp = alloc(sizeof(struct file)); 371 bzero(fp, sizeof(struct file)); 372 f->f_fsdata = (void *)fp; 373 374 /* allocate space and read super block */ 375 fs = alloc(SBSIZE); 376 fp->f_fs = fs; 377 twiddle(); 378 rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 379 SBLOCK, SBSIZE, (char *)fs, &buf_size); 380 if (rc) 381 goto out; 382 383 if (buf_size != SBSIZE || fs->fs_magic != FS_MAGIC || 384 fs->fs_bsize > MAXBSIZE || fs->fs_bsize < sizeof(struct fs)) { 385 rc = EINVAL; 386 goto out; 387 } 388 #ifdef COMPAT_UFS 389 ffs_oldfscompat(fs); 390 #endif 391 392 /* 393 * Calculate indirect block levels. 394 */ 395 { 396 int mult; 397 int level; 398 399 mult = 1; 400 for (level = 0; level < NIADDR; level++) { 401 mult *= NINDIR(fs); 402 fp->f_nindir[level] = mult; 403 } 404 } 405 406 inumber = ROOTINO; 407 if ((rc = read_inode(inumber, f)) != 0) 408 goto out; 409 410 cp = path; 411 while (*cp) { 412 413 /* 414 * Remove extra separators 415 */ 416 while (*cp == '/') 417 cp++; 418 if (*cp == '\0') 419 break; 420 421 /* 422 * Check that current node is a directory. 423 */ 424 if ((fp->f_di.di_mode & IFMT) != IFDIR) { 425 rc = ENOTDIR; 426 goto out; 427 } 428 429 /* 430 * Get next component of path name. 431 */ 432 { 433 int len = 0; 434 435 ncp = cp; 436 while ((c = *cp) != '\0' && c != '/') { 437 if (++len > MAXNAMLEN) { 438 rc = ENOENT; 439 goto out; 440 } 441 cp++; 442 } 443 *cp = '\0'; 444 } 445 446 /* 447 * Look up component in current directory. 448 * Save directory inumber in case we find a 449 * symbolic link. 450 */ 451 parent_inumber = inumber; 452 rc = search_directory(ncp, f, &inumber); 453 *cp = c; 454 if (rc) 455 goto out; 456 457 /* 458 * Open next component. 459 */ 460 if ((rc = read_inode(inumber, f)) != 0) 461 goto out; 462 463 /* 464 * Check for symbolic link. 465 */ 466 if ((fp->f_di.di_mode & IFMT) == IFLNK) { 467 int link_len = fp->f_di.di_size; 468 int len; 469 470 len = strlen(cp); 471 472 if (link_len + len > MAXPATHLEN || 473 ++nlinks > MAXSYMLINKS) { 474 rc = ENOENT; 475 goto out; 476 } 477 478 bcopy(cp, &namebuf[link_len], len + 1); 479 480 if (link_len < fs->fs_maxsymlinklen) { 481 bcopy(fp->f_di.di_shortlink, namebuf, 482 (unsigned) link_len); 483 } else { 484 /* 485 * Read file for symbolic link 486 */ 487 size_t buf_size; 488 daddr_t disk_block; 489 struct fs *fs = fp->f_fs; 490 491 if (!buf) 492 buf = alloc(fs->fs_bsize); 493 rc = block_map(f, (daddr_t)0, &disk_block); 494 if (rc) 495 goto out; 496 497 twiddle(); 498 rc = (f->f_dev->dv_strategy)(f->f_devdata, 499 F_READ, fsbtodb(fs, disk_block), 500 fs->fs_bsize, buf, &buf_size); 501 if (rc) 502 goto out; 503 504 bcopy((char *)buf, namebuf, (unsigned)link_len); 505 } 506 507 /* 508 * If relative pathname, restart at parent directory. 509 * If absolute pathname, restart at root. 510 */ 511 cp = namebuf; 512 if (*cp != '/') 513 inumber = parent_inumber; 514 else 515 inumber = (ino_t)ROOTINO; 516 517 if ((rc = read_inode(inumber, f)) != 0) 518 goto out; 519 } 520 } 521 522 /* 523 * Found terminal component. 524 */ 525 rc = 0; 526 out: 527 if (buf) 528 free(buf, fs->fs_bsize); 529 if (rc) { 530 free(fp->f_fs, SBSIZE); 531 free(fp, sizeof(struct file)); 532 } 533 return (rc); 534 } 535 536 int 537 ufs_close(struct open_file *f) 538 { 539 struct file *fp = (struct file *)f->f_fsdata; 540 int level; 541 542 f->f_fsdata = (void *)0; 543 if (fp == (struct file *)0) 544 return (0); 545 546 for (level = 0; level < NIADDR; level++) { 547 if (fp->f_blk[level]) 548 free(fp->f_blk[level], fp->f_fs->fs_bsize); 549 } 550 if (fp->f_buf) 551 free(fp->f_buf, fp->f_fs->fs_bsize); 552 free(fp->f_fs, SBSIZE); 553 free(fp, sizeof(struct file)); 554 return (0); 555 } 556 557 /* 558 * Copy a portion of a file into kernel memory. 559 * Cross block boundaries when necessary. 560 */ 561 int 562 ufs_read(struct open_file *f, void *start, size_t size, size_t *resid) 563 { 564 struct file *fp = (struct file *)f->f_fsdata; 565 char *buf, *addr = start; 566 size_t csize, buf_size; 567 int rc = 0; 568 569 while (size != 0) { 570 if (fp->f_seekp >= fp->f_di.di_size) 571 break; 572 573 rc = buf_read_file(f, &buf, &buf_size); 574 if (rc) 575 break; 576 577 csize = size; 578 if (csize > buf_size) 579 csize = buf_size; 580 581 bcopy(buf, addr, csize); 582 583 fp->f_seekp += csize; 584 addr += csize; 585 size -= csize; 586 } 587 if (resid) 588 *resid = size; 589 return (rc); 590 } 591 592 /* 593 * Not implemented. 594 */ 595 int 596 ufs_write(struct open_file *f, void *start, size_t size, size_t *resid) 597 { 598 599 return (EROFS); 600 } 601 602 off_t 603 ufs_seek(struct open_file *f, off_t offset, int where) 604 { 605 struct file *fp = (struct file *)f->f_fsdata; 606 607 switch (where) { 608 case SEEK_SET: 609 fp->f_seekp = offset; 610 break; 611 case SEEK_CUR: 612 fp->f_seekp += offset; 613 break; 614 case SEEK_END: 615 fp->f_seekp = fp->f_di.di_size - offset; 616 break; 617 default: 618 return (-1); 619 } 620 return (fp->f_seekp); 621 } 622 623 int 624 ufs_stat(struct open_file *f, struct stat *sb) 625 { 626 struct file *fp = (struct file *)f->f_fsdata; 627 628 /* only important stuff */ 629 sb->st_mode = fp->f_di.di_mode; 630 sb->st_uid = fp->f_di.di_uid; 631 sb->st_gid = fp->f_di.di_gid; 632 sb->st_size = fp->f_di.di_size; 633 return (0); 634 } 635 636 #ifndef NO_READDIR 637 int 638 ufs_readdir(struct open_file *f, char *name) 639 { 640 struct file *fp = (struct file *)f->f_fsdata; 641 struct direct *dp, *edp; 642 size_t buf_size; 643 int rc, namlen; 644 char *buf; 645 646 if (name == NULL) 647 fp->f_seekp = 0; 648 else { 649 /* end of dir */ 650 if (fp->f_seekp >= fp->f_di.di_size) { 651 *name = '\0'; 652 return -1; 653 } 654 655 do { 656 if ((rc = buf_read_file(f, &buf, &buf_size)) != 0) 657 return rc; 658 659 dp = (struct direct *)buf; 660 edp = (struct direct *)(buf + buf_size); 661 while (dp < edp && dp->d_ino == (ino_t)0) 662 dp = (struct direct *)((char *)dp + dp->d_reclen); 663 fp->f_seekp += buf_size - 664 ((u_int8_t *)edp - (u_int8_t *)dp); 665 } while (dp >= edp); 666 667 #if BYTE_ORDER == LITTLE_ENDIAN 668 if (fp->f_fs->fs_maxsymlinklen <= 0) 669 namlen = dp->d_type; 670 else 671 #endif 672 namlen = dp->d_namlen; 673 strncpy(name, dp->d_name, namlen + 1); 674 675 fp->f_seekp += dp->d_reclen; 676 } 677 678 return 0; 679 } 680 #endif 681 682 #ifdef COMPAT_UFS 683 /* 684 * Sanity checks for old file systems. 685 * 686 * XXX - goes away some day. 687 */ 688 static void 689 ffs_oldfscompat(struct fs *fs) 690 { 691 int i; 692 693 fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect); /* XXX */ 694 fs->fs_interleave = max(fs->fs_interleave, 1); /* XXX */ 695 if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 696 fs->fs_nrpos = 8; /* XXX */ 697 if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ 698 quad_t sizepb = fs->fs_bsize; /* XXX */ 699 /* XXX */ 700 fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1; /* XXX */ 701 for (i = 0; i < NIADDR; i++) { /* XXX */ 702 sizepb *= NINDIR(fs); /* XXX */ 703 fs->fs_maxfilesize += sizepb; /* XXX */ 704 } /* XXX */ 705 fs->fs_qbmask = ~fs->fs_bmask; /* XXX */ 706 fs->fs_qfmask = ~fs->fs_fmask; /* XXX */ 707 } /* XXX */ 708 } 709 #endif 710