ufs.c revision 92913
1275970Scy/* $NetBSD: ufs.c,v 1.20 1998/03/01 07:15:39 ross Exp $ */ 2275970Scy 3275970Scy/*- 4275970Scy * Copyright (c) 1993 5275970Scy * The Regents of the University of California. All rights reserved. 6275970Scy * 7275970Scy * This code is derived from software contributed to Berkeley by 8275970Scy * The Mach Operating System project at Carnegie-Mellon University. 9275970Scy * 10275970Scy * Redistribution and use in source and binary forms, with or without 11275970Scy * modification, are permitted provided that the following conditions 12275970Scy * are met: 13275970Scy * 1. Redistributions of source code must retain the above copyright 14275970Scy * notice, this list of conditions and the following disclaimer. 15275970Scy * 2. Redistributions in binary form must reproduce the above copyright 16275970Scy * notice, this list of conditions and the following disclaimer in the 17275970Scy * documentation and/or other materials provided with the distribution. 18275970Scy * 3. All advertising materials mentioning features or use of this software 19275970Scy * must display the following acknowledgement: 20275970Scy * This product includes software developed by the University of 21275970Scy * California, Berkeley and its contributors. 22275970Scy * 4. Neither the name of the University nor the names of its contributors 23275970Scy * may be used to endorse or promote products derived from this software 24275970Scy * without specific prior written permission. 25275970Scy * 26275970Scy * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27275970Scy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28275970Scy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29275970Scy * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30275970Scy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31275970Scy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32275970Scy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33275970Scy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34275970Scy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35275970Scy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36275970Scy * SUCH DAMAGE. 37275970Scy * 38275970Scy * 39275970Scy * Copyright (c) 1990, 1991 Carnegie Mellon University 40275970Scy * All Rights Reserved. 41275970Scy * 42275970Scy * Author: David Golub 43275970Scy * 44275970Scy * Permission to use, copy, modify and distribute this software and its 45275970Scy * documentation is hereby granted, provided that both the copyright 46275970Scy * notice and this permission notice appear in all copies of the 47275970Scy * software, derivative works or modified versions, and any portions 48275970Scy * thereof, and that both notices appear in supporting documentation. 49275970Scy * 50275970Scy * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 51275970Scy * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 52275970Scy * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 53275970Scy * 54275970Scy * Carnegie Mellon requests users of this software to return to 55275970Scy * 56275970Scy * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 57275970Scy * School of Computer Science 58275970Scy * Carnegie Mellon University 59275970Scy * Pittsburgh PA 15213-3890 60275970Scy * 61275970Scy * any improvements or extensions that they make and grant Carnegie the 62275970Scy * rights to redistribute these changes. 63275970Scy */ 64275970Scy 65275970Scy#include <sys/cdefs.h> 66275970Scy__FBSDID("$FreeBSD: head/lib/libstand/ufs.c 92913 2002-03-21 23:39:28Z obrien $"); 67275970Scy 68275970Scy/* 69275970Scy * Stand-alone file reading package. 70275970Scy */ 71275970Scy 72275970Scy#include <sys/param.h> 73275970Scy#include <sys/time.h> 74275970Scy#include <ufs/ufs/dinode.h> 75275970Scy#include <ufs/ufs/dir.h> 76275970Scy#include <ufs/ffs/fs.h> 77275970Scy#include "stand.h" 78275970Scy#include "string.h" 79275970Scy 80275970Scy#ifdef __alpha__ 81275970Scy#define COMPAT_UFS /* DUX has old format file systems */ 82275970Scy#endif 83275970Scy 84275970Scystatic int ufs_open(const char *path, struct open_file *f); 85275970Scystatic int ufs_write(struct open_file *f, void *buf, size_t size, size_t *resid); 86275970Scystatic int ufs_close(struct open_file *f); 87275970Scystatic int ufs_read(struct open_file *f, void *buf, size_t size, size_t *resid); 88275970Scystatic off_t ufs_seek(struct open_file *f, off_t offset, int where); 89275970Scystatic int ufs_stat(struct open_file *f, struct stat *sb); 90275970Scystatic int ufs_readdir(struct open_file *f, struct dirent *d); 91275970Scy 92275970Scystruct fs_ops ufs_fsops = { 93275970Scy "ufs", 94275970Scy ufs_open, 95275970Scy ufs_close, 96275970Scy ufs_read, 97275970Scy ufs_write, 98275970Scy ufs_seek, 99275970Scy ufs_stat, 100275970Scy ufs_readdir 101275970Scy}; 102275970Scy 103275970Scy/* 104275970Scy * In-core open file. 105275970Scy */ 106struct file { 107 off_t f_seekp; /* seek pointer */ 108 struct fs *f_fs; /* pointer to super-block */ 109 struct dinode f_di; /* copy of on-disk inode */ 110 int f_nindir[NIADDR]; 111 /* number of blocks mapped by 112 indirect block at level i */ 113 char *f_blk[NIADDR]; /* buffer for indirect block at 114 level i */ 115 size_t f_blksize[NIADDR]; 116 /* size of buffer */ 117 daddr_t f_blkno[NIADDR];/* disk address of block in buffer */ 118 char *f_buf; /* buffer for data block */ 119 size_t f_buf_size; /* size of data block */ 120 daddr_t f_buf_blkno; /* block number of data block */ 121}; 122 123static int read_inode(ino_t, struct open_file *); 124static int block_map(struct open_file *, daddr_t, daddr_t *); 125static int buf_read_file(struct open_file *, char **, size_t *); 126static int buf_write_file(struct open_file *, char *, size_t *); 127static int search_directory(char *, struct open_file *, ino_t *); 128#ifdef COMPAT_UFS 129static void ffs_oldfscompat(struct fs *); 130#endif 131 132/* 133 * Read a new inode into a file structure. 134 */ 135static int 136read_inode(inumber, f) 137 ino_t inumber; 138 struct open_file *f; 139{ 140 struct file *fp = (struct file *)f->f_fsdata; 141 struct fs *fs = fp->f_fs; 142 char *buf; 143 size_t rsize; 144 int rc; 145 146 if (fs == NULL) 147 panic("fs == NULL"); 148 149 /* 150 * Read inode and save it. 151 */ 152 buf = malloc(fs->fs_bsize); 153 twiddle(); 154 rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 155 fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize, 156 buf, &rsize); 157 if (rc) 158 goto out; 159 if (rsize != fs->fs_bsize) { 160 rc = EIO; 161 goto out; 162 } 163 164 { 165 struct dinode *dp; 166 167 dp = (struct dinode *)buf; 168 fp->f_di = dp[ino_to_fsbo(fs, inumber)]; 169 } 170 171 /* 172 * Clear out the old buffers 173 */ 174 { 175 int level; 176 177 for (level = 0; level < NIADDR; level++) 178 fp->f_blkno[level] = -1; 179 fp->f_buf_blkno = -1; 180 } 181out: 182 free(buf); 183 return (rc); 184} 185 186/* 187 * Given an offset in a file, find the disk block number that 188 * contains that block. 189 */ 190static int 191block_map(f, file_block, disk_block_p) 192 struct open_file *f; 193 daddr_t file_block; 194 daddr_t *disk_block_p; /* out */ 195{ 196 struct file *fp = (struct file *)f->f_fsdata; 197 struct fs *fs = fp->f_fs; 198 int level; 199 int idx; 200 daddr_t ind_block_num; 201 daddr_t *ind_p; 202 int rc; 203 204 /* 205 * Index structure of an inode: 206 * 207 * di_db[0..NDADDR-1] hold block numbers for blocks 208 * 0..NDADDR-1 209 * 210 * di_ib[0] index block 0 is the single indirect block 211 * holds block numbers for blocks 212 * NDADDR .. NDADDR + NINDIR(fs)-1 213 * 214 * di_ib[1] index block 1 is the double indirect block 215 * holds block numbers for INDEX blocks for blocks 216 * NDADDR + NINDIR(fs) .. 217 * NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1 218 * 219 * di_ib[2] index block 2 is the triple indirect block 220 * holds block numbers for double-indirect 221 * blocks for blocks 222 * NDADDR + NINDIR(fs) + NINDIR(fs)**2 .. 223 * NDADDR + NINDIR(fs) + NINDIR(fs)**2 224 * + NINDIR(fs)**3 - 1 225 */ 226 227 if (file_block < NDADDR) { 228 /* Direct block. */ 229 *disk_block_p = fp->f_di.di_db[file_block]; 230 return (0); 231 } 232 233 file_block -= NDADDR; 234 235 /* 236 * nindir[0] = NINDIR 237 * nindir[1] = NINDIR**2 238 * nindir[2] = NINDIR**3 239 * etc 240 */ 241 for (level = 0; level < NIADDR; level++) { 242 if (file_block < fp->f_nindir[level]) 243 break; 244 file_block -= fp->f_nindir[level]; 245 } 246 if (level == NIADDR) { 247 /* Block number too high */ 248 return (EFBIG); 249 } 250 251 ind_block_num = fp->f_di.di_ib[level]; 252 253 for (; level >= 0; level--) { 254 if (ind_block_num == 0) { 255 *disk_block_p = 0; /* missing */ 256 return (0); 257 } 258 259 if (fp->f_blkno[level] != ind_block_num) { 260 if (fp->f_blk[level] == (char *)0) 261 fp->f_blk[level] = 262 malloc(fs->fs_bsize); 263 twiddle(); 264 rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 265 fsbtodb(fp->f_fs, ind_block_num), 266 fs->fs_bsize, 267 fp->f_blk[level], 268 &fp->f_blksize[level]); 269 if (rc) 270 return (rc); 271 if (fp->f_blksize[level] != fs->fs_bsize) 272 return (EIO); 273 fp->f_blkno[level] = ind_block_num; 274 } 275 276 ind_p = (daddr_t *)fp->f_blk[level]; 277 278 if (level > 0) { 279 idx = file_block / fp->f_nindir[level - 1]; 280 file_block %= fp->f_nindir[level - 1]; 281 } else 282 idx = file_block; 283 284 ind_block_num = ind_p[idx]; 285 } 286 287 *disk_block_p = ind_block_num; 288 289 return (0); 290} 291 292/* 293 * Write a portion of a file from an internal buffer. 294 */ 295static int 296buf_write_file(f, buf_p, size_p) 297 struct open_file *f; 298 char *buf_p; 299 size_t *size_p; /* out */ 300{ 301 struct file *fp = (struct file *)f->f_fsdata; 302 struct fs *fs = fp->f_fs; 303 long off; 304 daddr_t file_block; 305 daddr_t disk_block; 306 size_t block_size; 307 int rc; 308 309 /* 310 * Calculate the starting block address and offset. 311 */ 312 off = blkoff(fs, fp->f_seekp); 313 file_block = lblkno(fs, fp->f_seekp); 314 block_size = dblksize(fs, &fp->f_di, file_block); 315 316 rc = block_map(f, file_block, &disk_block); 317 if (rc) 318 return (rc); 319 320 if (disk_block == 0) 321 return (EFBIG); /* Because we can't allocate space on the drive */ 322 323 /* 324 * Truncate buffer at end of file, and at the end of 325 * this block. 326 */ 327 if (*size_p > fp->f_di.di_size - fp->f_seekp) 328 *size_p = fp->f_di.di_size - fp->f_seekp; 329 if (*size_p > block_size - off) 330 *size_p = block_size - off; 331 332 /* 333 * If we don't entirely occlude the block and it's not 334 * in memory already, read it in first. 335 */ 336 if (((off > 0) || (*size_p + off < block_size)) && 337 (file_block != fp->f_buf_blkno)) { 338 339 if (fp->f_buf == (char *)0) 340 fp->f_buf = malloc(fs->fs_bsize); 341 342 twiddle(); 343 rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 344 fsbtodb(fs, disk_block), 345 block_size, fp->f_buf, &fp->f_buf_size); 346 if (rc) 347 return (rc); 348 349 fp->f_buf_blkno = file_block; 350 } 351 352 /* 353 * Copy the user data into the cached block. 354 */ 355 bcopy(buf_p,fp->f_buf + off,*size_p); 356 357 /* 358 * Write the block out to storage. 359 */ 360 361 twiddle(); 362 rc = (f->f_dev->dv_strategy)(f->f_devdata, F_WRITE, 363 fsbtodb(fs, disk_block), 364 block_size, fp->f_buf, &fp->f_buf_size); 365 return (rc); 366} 367 368/* 369 * Read a portion of a file into an internal buffer. Return 370 * the location in the buffer and the amount in the buffer. 371 */ 372static int 373buf_read_file(f, buf_p, size_p) 374 struct open_file *f; 375 char **buf_p; /* out */ 376 size_t *size_p; /* out */ 377{ 378 struct file *fp = (struct file *)f->f_fsdata; 379 struct fs *fs = fp->f_fs; 380 long off; 381 daddr_t file_block; 382 daddr_t disk_block; 383 size_t block_size; 384 int rc; 385 386 off = blkoff(fs, fp->f_seekp); 387 file_block = lblkno(fs, fp->f_seekp); 388 block_size = dblksize(fs, &fp->f_di, file_block); 389 390 if (file_block != fp->f_buf_blkno) { 391 if (fp->f_buf == (char *)0) 392 fp->f_buf = malloc(fs->fs_bsize); 393 394 rc = block_map(f, file_block, &disk_block); 395 if (rc) 396 return (rc); 397 398 if (disk_block == 0) { 399 bzero(fp->f_buf, block_size); 400 fp->f_buf_size = block_size; 401 } else { 402 twiddle(); 403 rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 404 fsbtodb(fs, disk_block), 405 block_size, fp->f_buf, &fp->f_buf_size); 406 if (rc) 407 return (rc); 408 } 409 410 fp->f_buf_blkno = file_block; 411 } 412 413 /* 414 * Return address of byte in buffer corresponding to 415 * offset, and size of remainder of buffer after that 416 * byte. 417 */ 418 *buf_p = fp->f_buf + off; 419 *size_p = block_size - off; 420 421 /* 422 * But truncate buffer at end of file. 423 */ 424 if (*size_p > fp->f_di.di_size - fp->f_seekp) 425 *size_p = fp->f_di.di_size - fp->f_seekp; 426 427 return (0); 428} 429 430/* 431 * Search a directory for a name and return its 432 * i_number. 433 */ 434static int 435search_directory(name, f, inumber_p) 436 char *name; 437 struct open_file *f; 438 ino_t *inumber_p; /* out */ 439{ 440 struct file *fp = (struct file *)f->f_fsdata; 441 struct direct *dp; 442 struct direct *edp; 443 char *buf; 444 size_t buf_size; 445 int namlen, length; 446 int rc; 447 448 length = strlen(name); 449 450 fp->f_seekp = 0; 451 while (fp->f_seekp < fp->f_di.di_size) { 452 rc = buf_read_file(f, &buf, &buf_size); 453 if (rc) 454 return (rc); 455 456 dp = (struct direct *)buf; 457 edp = (struct direct *)(buf + buf_size); 458 while (dp < edp) { 459 if (dp->d_ino == (ino_t)0) 460 goto next; 461#if BYTE_ORDER == LITTLE_ENDIAN 462 if (fp->f_fs->fs_maxsymlinklen <= 0) 463 namlen = dp->d_type; 464 else 465#endif 466 namlen = dp->d_namlen; 467 if (namlen == length && 468 !strcmp(name, dp->d_name)) { 469 /* found entry */ 470 *inumber_p = dp->d_ino; 471 return (0); 472 } 473 next: 474 dp = (struct direct *)((char *)dp + dp->d_reclen); 475 } 476 fp->f_seekp += buf_size; 477 } 478 return (ENOENT); 479} 480 481/* 482 * Open a file. 483 */ 484static int 485ufs_open(upath, f) 486 const char *upath; 487 struct open_file *f; 488{ 489 char *cp, *ncp; 490 int c; 491 ino_t inumber, parent_inumber; 492 struct file *fp; 493 struct fs *fs; 494 int rc; 495 size_t buf_size; 496 int nlinks = 0; 497 char namebuf[MAXPATHLEN+1]; 498 char *buf = NULL; 499 char *path = NULL; 500 501 /* allocate file system specific data structure */ 502 fp = malloc(sizeof(struct file)); 503 bzero(fp, sizeof(struct file)); 504 f->f_fsdata = (void *)fp; 505 506 /* allocate space and read super block */ 507 fs = malloc(SBSIZE); 508 fp->f_fs = fs; 509 twiddle(); 510 rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 511 SBLOCK, SBSIZE, (char *)fs, &buf_size); 512 if (rc) 513 goto out; 514 515 if (buf_size != SBSIZE || fs->fs_magic != FS_MAGIC || 516 fs->fs_bsize > MAXBSIZE || fs->fs_bsize < sizeof(struct fs)) { 517 rc = EINVAL; 518 goto out; 519 } 520#ifdef COMPAT_UFS 521 ffs_oldfscompat(fs); 522#endif 523 524 /* 525 * Calculate indirect block levels. 526 */ 527 { 528 int mult; 529 int level; 530 531 mult = 1; 532 for (level = 0; level < NIADDR; level++) { 533 mult *= NINDIR(fs); 534 fp->f_nindir[level] = mult; 535 } 536 } 537 538 inumber = ROOTINO; 539 if ((rc = read_inode(inumber, f)) != 0) 540 goto out; 541 542 cp = path = strdup(upath); 543 if (path == NULL) { 544 rc = ENOMEM; 545 goto out; 546 } 547 while (*cp) { 548 549 /* 550 * Remove extra separators 551 */ 552 while (*cp == '/') 553 cp++; 554 if (*cp == '\0') 555 break; 556 557 /* 558 * Check that current node is a directory. 559 */ 560 if ((fp->f_di.di_mode & IFMT) != IFDIR) { 561 rc = ENOTDIR; 562 goto out; 563 } 564 565 /* 566 * Get next component of path name. 567 */ 568 { 569 int len = 0; 570 571 ncp = cp; 572 while ((c = *cp) != '\0' && c != '/') { 573 if (++len > MAXNAMLEN) { 574 rc = ENOENT; 575 goto out; 576 } 577 cp++; 578 } 579 *cp = '\0'; 580 } 581 582 /* 583 * Look up component in current directory. 584 * Save directory inumber in case we find a 585 * symbolic link. 586 */ 587 parent_inumber = inumber; 588 rc = search_directory(ncp, f, &inumber); 589 *cp = c; 590 if (rc) 591 goto out; 592 593 /* 594 * Open next component. 595 */ 596 if ((rc = read_inode(inumber, f)) != 0) 597 goto out; 598 599 /* 600 * Check for symbolic link. 601 */ 602 if ((fp->f_di.di_mode & IFMT) == IFLNK) { 603 int link_len = fp->f_di.di_size; 604 int len; 605 606 len = strlen(cp); 607 608 if (link_len + len > MAXPATHLEN || 609 ++nlinks > MAXSYMLINKS) { 610 rc = ENOENT; 611 goto out; 612 } 613 614 bcopy(cp, &namebuf[link_len], len + 1); 615 616 if (link_len < fs->fs_maxsymlinklen) { 617 bcopy(fp->f_di.di_shortlink, namebuf, 618 (unsigned) link_len); 619 } else { 620 /* 621 * Read file for symbolic link 622 */ 623 size_t buf_size; 624 daddr_t disk_block; 625 struct fs *fs = fp->f_fs; 626 627 if (!buf) 628 buf = malloc(fs->fs_bsize); 629 rc = block_map(f, (daddr_t)0, &disk_block); 630 if (rc) 631 goto out; 632 633 twiddle(); 634 rc = (f->f_dev->dv_strategy)(f->f_devdata, 635 F_READ, fsbtodb(fs, disk_block), 636 fs->fs_bsize, buf, &buf_size); 637 if (rc) 638 goto out; 639 640 bcopy((char *)buf, namebuf, (unsigned)link_len); 641 } 642 643 /* 644 * If relative pathname, restart at parent directory. 645 * If absolute pathname, restart at root. 646 */ 647 cp = namebuf; 648 if (*cp != '/') 649 inumber = parent_inumber; 650 else 651 inumber = (ino_t)ROOTINO; 652 653 if ((rc = read_inode(inumber, f)) != 0) 654 goto out; 655 } 656 } 657 658 /* 659 * Found terminal component. 660 */ 661 rc = 0; 662out: 663 if (buf) 664 free(buf); 665 if (path) 666 free(path); 667 if (rc) { 668 if (fp->f_buf) 669 free(fp->f_buf); 670 free(fp->f_fs); 671 free(fp); 672 } 673 return (rc); 674} 675 676static int 677ufs_close(f) 678 struct open_file *f; 679{ 680 struct file *fp = (struct file *)f->f_fsdata; 681 int level; 682 683 f->f_fsdata = (void *)0; 684 if (fp == (struct file *)0) 685 return (0); 686 687 for (level = 0; level < NIADDR; level++) { 688 if (fp->f_blk[level]) 689 free(fp->f_blk[level]); 690 } 691 if (fp->f_buf) 692 free(fp->f_buf); 693 free(fp->f_fs); 694 free(fp); 695 return (0); 696} 697 698/* 699 * Copy a portion of a file into kernel memory. 700 * Cross block boundaries when necessary. 701 */ 702static int 703ufs_read(f, start, size, resid) 704 struct open_file *f; 705 void *start; 706 size_t size; 707 size_t *resid; /* out */ 708{ 709 struct file *fp = (struct file *)f->f_fsdata; 710 size_t csize; 711 char *buf; 712 size_t buf_size; 713 int rc = 0; 714 char *addr = start; 715 716 while (size != 0) { 717 if (fp->f_seekp >= fp->f_di.di_size) 718 break; 719 720 rc = buf_read_file(f, &buf, &buf_size); 721 if (rc) 722 break; 723 724 csize = size; 725 if (csize > buf_size) 726 csize = buf_size; 727 728 bcopy(buf, addr, csize); 729 730 fp->f_seekp += csize; 731 addr += csize; 732 size -= csize; 733 } 734 if (resid) 735 *resid = size; 736 return (rc); 737} 738 739/* 740 * Write to a portion of an already allocated file. 741 * Cross block boundaries when necessary. Can not 742 * extend the file. 743 */ 744static int 745ufs_write(f, start, size, resid) 746 struct open_file *f; 747 void *start; 748 size_t size; 749 size_t *resid; /* out */ 750{ 751 struct file *fp = (struct file *)f->f_fsdata; 752 size_t csize; 753 int rc = 0; 754 char *addr = start; 755 756 csize = size; 757 while ((size != 0) && (csize != 0)) { 758 if (fp->f_seekp >= fp->f_di.di_size) 759 break; 760 761 if (csize >= 512) csize = 512; /* XXX */ 762 763 rc = buf_write_file(f, addr, &csize); 764 if (rc) 765 break; 766 767 fp->f_seekp += csize; 768 addr += csize; 769 size -= csize; 770 } 771 if (resid) 772 *resid = size; 773 return (rc); 774} 775 776static off_t 777ufs_seek(f, offset, where) 778 struct open_file *f; 779 off_t offset; 780 int where; 781{ 782 struct file *fp = (struct file *)f->f_fsdata; 783 784 switch (where) { 785 case SEEK_SET: 786 fp->f_seekp = offset; 787 break; 788 case SEEK_CUR: 789 fp->f_seekp += offset; 790 break; 791 case SEEK_END: 792 fp->f_seekp = fp->f_di.di_size - offset; 793 break; 794 default: 795 return (-1); 796 } 797 return (fp->f_seekp); 798} 799 800static int 801ufs_stat(f, sb) 802 struct open_file *f; 803 struct stat *sb; 804{ 805 struct file *fp = (struct file *)f->f_fsdata; 806 807 /* only important stuff */ 808 sb->st_mode = fp->f_di.di_mode; 809 sb->st_uid = fp->f_di.di_uid; 810 sb->st_gid = fp->f_di.di_gid; 811 sb->st_size = fp->f_di.di_size; 812 return (0); 813} 814 815static int 816ufs_readdir(struct open_file *f, struct dirent *d) 817{ 818 struct file *fp = (struct file *)f->f_fsdata; 819 struct direct *dp; 820 char *buf; 821 size_t buf_size; 822 int error; 823 824 /* 825 * assume that a directory entry will not be split across blocks 826 */ 827again: 828 if (fp->f_seekp >= fp->f_di.di_size) 829 return (ENOENT); 830 error = buf_read_file(f, &buf, &buf_size); 831 if (error) 832 return (error); 833 dp = (struct direct *)buf; 834 fp->f_seekp += dp->d_reclen; 835 if (dp->d_ino == (ino_t)0) 836 goto again; 837 d->d_type = dp->d_type; 838 strcpy(d->d_name, dp->d_name); 839 return (0); 840} 841 842#ifdef COMPAT_UFS 843/* 844 * Sanity checks for old file systems. 845 * 846 * XXX - goes away some day. 847 */ 848static void 849ffs_oldfscompat(fs) 850 struct fs *fs; 851{ 852 int i; 853 854 fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect); /* XXX */ 855 fs->fs_interleave = max(fs->fs_interleave, 1); /* XXX */ 856 if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 857 fs->fs_nrpos = 8; /* XXX */ 858 if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ 859 quad_t sizepb = fs->fs_bsize; /* XXX */ 860 /* XXX */ 861 fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1; /* XXX */ 862 for (i = 0; i < NIADDR; i++) { /* XXX */ 863 sizepb *= NINDIR(fs); /* XXX */ 864 fs->fs_maxfilesize += sizepb; /* XXX */ 865 } /* XXX */ 866 fs->fs_qbmask = ~fs->fs_bmask; /* XXX */ 867 fs->fs_qfmask = ~fs->fs_fmask; /* XXX */ 868 } /* XXX */ 869} 870#endif 871