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