1 /* $OpenBSD: ufs.c,v 1.25 2015/07/17 18:55:00 kspillner 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(ufsino_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 *, ufsino_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(ufsino_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] == NULL) 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 == NULL) 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, ufsino_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 == 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 ufsino_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 u_int64_t link_len = fp->f_di.di_size; 469 size_t 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, link_len); 483 } else { 484 /* 485 * Read file for symbolic link 486 */ 487 size_t buf_size; 488 daddr32_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, (daddr32_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(buf, namebuf, 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 = 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 (void)ufs_close_internal(fp); 531 532 return (rc); 533 } 534 535 int 536 ufs_close(struct open_file *f) 537 { 538 struct file *fp = (struct file *)f->f_fsdata; 539 540 f->f_fsdata = NULL; 541 if (fp == NULL) 542 return (0); 543 544 return (ufs_close_internal(fp)); 545 } 546 547 static int 548 ufs_close_internal(struct file *fp) 549 { 550 int level; 551 552 for (level = 0; level < NIADDR; level++) { 553 if (fp->f_blk[level]) 554 free(fp->f_blk[level], fp->f_fs->fs_bsize); 555 } 556 if (fp->f_buf) 557 free(fp->f_buf, fp->f_fs->fs_bsize); 558 free(fp->f_fs, SBSIZE); 559 free(fp, sizeof(struct file)); 560 return (0); 561 } 562 563 /* 564 * Copy a portion of a file into kernel memory. 565 * Cross block boundaries when necessary. 566 */ 567 int 568 ufs_read(struct open_file *f, void *start, size_t size, size_t *resid) 569 { 570 struct file *fp = (struct file *)f->f_fsdata; 571 char *buf, *addr = start; 572 size_t csize, buf_size; 573 int rc = 0; 574 575 while (size != 0) { 576 if (fp->f_seekp >= fp->f_di.di_size) 577 break; 578 579 rc = buf_read_file(f, &buf, &buf_size); 580 if (rc) 581 break; 582 583 csize = size; 584 if (csize > buf_size) 585 csize = buf_size; 586 587 bcopy(buf, addr, csize); 588 589 fp->f_seekp += csize; 590 addr += csize; 591 size -= csize; 592 } 593 if (resid) 594 *resid = size; 595 return (rc); 596 } 597 598 /* 599 * Not implemented. 600 */ 601 int 602 ufs_write(struct open_file *f, void *start, size_t size, size_t *resid) 603 { 604 605 return (EROFS); 606 } 607 608 off_t 609 ufs_seek(struct open_file *f, off_t offset, int where) 610 { 611 struct file *fp = (struct file *)f->f_fsdata; 612 613 switch (where) { 614 case SEEK_SET: 615 fp->f_seekp = offset; 616 break; 617 case SEEK_CUR: 618 fp->f_seekp += offset; 619 break; 620 case SEEK_END: 621 fp->f_seekp = fp->f_di.di_size - offset; 622 break; 623 default: 624 return (-1); 625 } 626 return (fp->f_seekp); 627 } 628 629 int 630 ufs_stat(struct open_file *f, struct stat *sb) 631 { 632 struct file *fp = (struct file *)f->f_fsdata; 633 634 /* only important stuff */ 635 sb->st_mode = fp->f_di.di_mode; 636 sb->st_uid = fp->f_di.di_uid; 637 sb->st_gid = fp->f_di.di_gid; 638 sb->st_size = fp->f_di.di_size; 639 return (0); 640 } 641 642 #ifndef NO_READDIR 643 int 644 ufs_readdir(struct open_file *f, char *name) 645 { 646 struct file *fp = (struct file *)f->f_fsdata; 647 struct direct *dp, *edp; 648 size_t buf_size; 649 int rc, namlen; 650 char *buf; 651 652 if (name == NULL) 653 fp->f_seekp = 0; 654 else { 655 /* end of dir */ 656 if (fp->f_seekp >= fp->f_di.di_size) { 657 *name = '\0'; 658 return -1; 659 } 660 661 do { 662 if ((rc = buf_read_file(f, &buf, &buf_size)) != 0) 663 return rc; 664 665 dp = (struct direct *)buf; 666 edp = (struct direct *)(buf + buf_size); 667 while (dp < edp && dp->d_ino == 0) 668 dp = (struct direct *)((char *)dp + dp->d_reclen); 669 fp->f_seekp += buf_size - 670 ((u_int8_t *)edp - (u_int8_t *)dp); 671 } while (dp >= edp); 672 673 #if BYTE_ORDER == LITTLE_ENDIAN 674 if (fp->f_fs->fs_maxsymlinklen <= 0) 675 namlen = dp->d_type; 676 else 677 #endif 678 namlen = dp->d_namlen; 679 strncpy(name, dp->d_name, namlen + 1); 680 681 fp->f_seekp += dp->d_reclen; 682 } 683 684 return 0; 685 } 686 #endif 687 688 #ifdef COMPAT_UFS 689 /* 690 * Sanity checks for old file systems. 691 * 692 * XXX - goes away some day. 693 */ 694 static void 695 ffs_oldfscompat(struct fs *fs) 696 { 697 int i; 698 699 fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect); /* XXX */ 700 fs->fs_interleave = max(fs->fs_interleave, 1); /* XXX */ 701 if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 702 fs->fs_nrpos = 8; /* XXX */ 703 if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ 704 quad_t sizepb = fs->fs_bsize; /* XXX */ 705 /* XXX */ 706 fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1; /* XXX */ 707 for (i = 0; i < NIADDR; i++) { /* XXX */ 708 sizepb *= NINDIR(fs); /* XXX */ 709 fs->fs_maxfilesize += sizepb; /* XXX */ 710 } /* XXX */ 711 fs->fs_qbmask = ~fs->fs_bmask; /* XXX */ 712 fs->fs_qfmask = ~fs->fs_fmask; /* XXX */ 713 } /* XXX */ 714 } 715 #endif 716