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