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