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