ufs.c revision 332138
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 * 4. 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: stable/11/stand/libsa/ufs.c 332138 2018-04-06 19:21:36Z kevans $"); 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 86static int ufs_open(const char *path, struct open_file *f); 87static int ufs_write(struct open_file *f, const void *buf, size_t size, 88 size_t *resid); 89static int ufs_close(struct open_file *f); 90static int ufs_read(struct open_file *f, void *buf, size_t size, size_t *resid); 91static off_t ufs_seek(struct open_file *f, off_t offset, int where); 92static int ufs_stat(struct open_file *f, struct stat *sb); 93static int ufs_readdir(struct open_file *f, struct dirent *d); 94 95struct fs_ops ufs_fsops = { 96 "ufs", 97 ufs_open, 98 ufs_close, 99 ufs_read, 100 ufs_write, 101 ufs_seek, 102 ufs_stat, 103 ufs_readdir 104}; 105 106/* 107 * In-core open file. 108 */ 109struct file { 110 off_t f_seekp; /* seek pointer */ 111 struct fs *f_fs; /* pointer to super-block */ 112 union dinode { 113 struct ufs1_dinode di1; 114 struct ufs2_dinode di2; 115 } f_di; /* copy of on-disk inode */ 116 int f_nindir[NIADDR]; 117 /* number of blocks mapped by 118 indirect block at level i */ 119 char *f_blk[NIADDR]; /* buffer for indirect block at 120 level i */ 121 size_t f_blksize[NIADDR]; 122 /* size of buffer */ 123 ufs2_daddr_t f_blkno[NIADDR];/* disk address of block in buffer */ 124 ufs2_daddr_t f_buf_blkno; /* block number of data block */ 125 char *f_buf; /* buffer for data block */ 126 size_t f_buf_size; /* size of data block */ 127}; 128#define DIP(fp, field) \ 129 ((fp)->f_fs->fs_magic == FS_UFS1_MAGIC ? \ 130 (fp)->f_di.di1.field : (fp)->f_di.di2.field) 131 132static int read_inode(ino_t, struct open_file *); 133static int block_map(struct open_file *, ufs2_daddr_t, ufs2_daddr_t *); 134static int buf_read_file(struct open_file *, char **, size_t *); 135static int buf_write_file(struct open_file *, const char *, size_t *); 136static int search_directory(char *, struct open_file *, ino_t *); 137 138/* 139 * Read a new inode into a file structure. 140 */ 141static int 142read_inode(inumber, f) 143 ino_t inumber; 144 struct open_file *f; 145{ 146 struct file *fp = (struct file *)f->f_fsdata; 147 struct fs *fs = fp->f_fs; 148 char *buf; 149 size_t rsize; 150 int rc; 151 152 if (fs == NULL) 153 panic("fs == NULL"); 154 155 /* 156 * Read inode and save it. 157 */ 158 buf = malloc(fs->fs_bsize); 159 twiddle(1); 160 rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 161 fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize, 162 buf, &rsize); 163 if (rc) 164 goto out; 165 if (rsize != fs->fs_bsize) { 166 rc = EIO; 167 goto out; 168 } 169 170 if (fp->f_fs->fs_magic == FS_UFS1_MAGIC) 171 fp->f_di.di1 = ((struct ufs1_dinode *)buf) 172 [ino_to_fsbo(fs, inumber)]; 173 else 174 fp->f_di.di2 = ((struct ufs2_dinode *)buf) 175 [ino_to_fsbo(fs, inumber)]; 176 177 /* 178 * Clear out the old buffers 179 */ 180 { 181 int level; 182 183 for (level = 0; level < NIADDR; level++) 184 fp->f_blkno[level] = -1; 185 fp->f_buf_blkno = -1; 186 } 187 fp->f_seekp = 0; 188out: 189 free(buf); 190 return (rc); 191} 192 193/* 194 * Given an offset in a file, find the disk block number that 195 * contains that block. 196 */ 197static int 198block_map(f, file_block, disk_block_p) 199 struct open_file *f; 200 ufs2_daddr_t file_block; 201 ufs2_daddr_t *disk_block_p; /* out */ 202{ 203 struct file *fp = (struct file *)f->f_fsdata; 204 struct fs *fs = fp->f_fs; 205 int level; 206 int idx; 207 ufs2_daddr_t ind_block_num; 208 int 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 = DIP(fp, 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 = DIP(fp, 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] == (char *)0) 267 fp->f_blk[level] = 268 malloc(fs->fs_bsize); 269 twiddle(1); 270 rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 271 fsbtodb(fp->f_fs, ind_block_num), 272 fs->fs_bsize, 273 fp->f_blk[level], 274 &fp->f_blksize[level]); 275 if (rc) 276 return (rc); 277 if (fp->f_blksize[level] != fs->fs_bsize) 278 return (EIO); 279 fp->f_blkno[level] = ind_block_num; 280 } 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 if (fp->f_fs->fs_magic == FS_UFS1_MAGIC) 289 ind_block_num = ((ufs1_daddr_t *)fp->f_blk[level])[idx]; 290 else 291 ind_block_num = ((ufs2_daddr_t *)fp->f_blk[level])[idx]; 292 } 293 294 *disk_block_p = ind_block_num; 295 296 return (0); 297} 298 299/* 300 * Write a portion of a file from an internal buffer. 301 */ 302static int 303buf_write_file(f, buf_p, size_p) 304 struct open_file *f; 305 const char *buf_p; 306 size_t *size_p; /* out */ 307{ 308 struct file *fp = (struct file *)f->f_fsdata; 309 struct fs *fs = fp->f_fs; 310 long off; 311 ufs_lbn_t file_block; 312 ufs2_daddr_t disk_block; 313 size_t block_size; 314 int rc; 315 316 /* 317 * Calculate the starting block address and offset. 318 */ 319 off = blkoff(fs, fp->f_seekp); 320 file_block = lblkno(fs, fp->f_seekp); 321 block_size = sblksize(fs, DIP(fp, di_size), file_block); 322 323 rc = block_map(f, file_block, &disk_block); 324 if (rc) 325 return (rc); 326 327 if (disk_block == 0) 328 /* Because we can't allocate space on the drive */ 329 return (EFBIG); 330 331 /* 332 * Truncate buffer at end of file, and at the end of 333 * this block. 334 */ 335 if (*size_p > DIP(fp, di_size) - fp->f_seekp) 336 *size_p = DIP(fp, di_size) - fp->f_seekp; 337 if (*size_p > block_size - off) 338 *size_p = block_size - off; 339 340 /* 341 * If we don't entirely occlude the block and it's not 342 * in memory already, read it in first. 343 */ 344 if (((off > 0) || (*size_p + off < block_size)) && 345 (file_block != fp->f_buf_blkno)) { 346 347 if (fp->f_buf == (char *)0) 348 fp->f_buf = malloc(fs->fs_bsize); 349 350 twiddle(4); 351 rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 352 fsbtodb(fs, disk_block), 353 block_size, fp->f_buf, &fp->f_buf_size); 354 if (rc) 355 return (rc); 356 357 fp->f_buf_blkno = file_block; 358 } 359 360 /* 361 * Copy the user data into the cached block. 362 */ 363 bcopy(buf_p, fp->f_buf + off, *size_p); 364 365 /* 366 * Write the block out to storage. 367 */ 368 369 twiddle(4); 370 rc = (f->f_dev->dv_strategy)(f->f_devdata, F_WRITE, 371 fsbtodb(fs, disk_block), 372 block_size, fp->f_buf, &fp->f_buf_size); 373 return (rc); 374} 375 376/* 377 * Read a portion of a file into an internal buffer. Return 378 * the location in the buffer and the amount in the buffer. 379 */ 380static int 381buf_read_file(f, buf_p, size_p) 382 struct open_file *f; 383 char **buf_p; /* out */ 384 size_t *size_p; /* out */ 385{ 386 struct file *fp = (struct file *)f->f_fsdata; 387 struct fs *fs = fp->f_fs; 388 long off; 389 ufs_lbn_t file_block; 390 ufs2_daddr_t disk_block; 391 size_t block_size; 392 int rc; 393 394 off = blkoff(fs, fp->f_seekp); 395 file_block = lblkno(fs, fp->f_seekp); 396 block_size = sblksize(fs, DIP(fp, di_size), file_block); 397 398 if (file_block != fp->f_buf_blkno) { 399 if (fp->f_buf == (char *)0) 400 fp->f_buf = malloc(fs->fs_bsize); 401 402 rc = block_map(f, file_block, &disk_block); 403 if (rc) 404 return (rc); 405 406 if (disk_block == 0) { 407 bzero(fp->f_buf, block_size); 408 fp->f_buf_size = block_size; 409 } else { 410 twiddle(4); 411 rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 412 fsbtodb(fs, disk_block), 413 block_size, fp->f_buf, &fp->f_buf_size); 414 if (rc) 415 return (rc); 416 } 417 418 fp->f_buf_blkno = file_block; 419 } 420 421 /* 422 * Return address of byte in buffer corresponding to 423 * offset, and size of remainder of buffer after that 424 * byte. 425 */ 426 *buf_p = fp->f_buf + off; 427 *size_p = block_size - off; 428 429 /* 430 * But truncate buffer at end of file. 431 */ 432 if (*size_p > DIP(fp, di_size) - fp->f_seekp) 433 *size_p = DIP(fp, di_size) - fp->f_seekp; 434 435 return (0); 436} 437 438/* 439 * Search a directory for a name and return its 440 * i_number. 441 */ 442static int 443search_directory(name, f, inumber_p) 444 char *name; 445 struct open_file *f; 446 ino_t *inumber_p; /* out */ 447{ 448 struct file *fp = (struct file *)f->f_fsdata; 449 struct direct *dp; 450 struct direct *edp; 451 char *buf; 452 size_t buf_size; 453 int namlen, length; 454 int rc; 455 456 length = strlen(name); 457 458 fp->f_seekp = 0; 459 while (fp->f_seekp < DIP(fp, di_size)) { 460 rc = buf_read_file(f, &buf, &buf_size); 461 if (rc) 462 return (rc); 463 464 dp = (struct direct *)buf; 465 edp = (struct direct *)(buf + buf_size); 466 while (dp < edp) { 467 if (dp->d_ino == (ino_t)0) 468 goto next; 469#if BYTE_ORDER == LITTLE_ENDIAN 470 if (fp->f_fs->fs_maxsymlinklen <= 0) 471 namlen = dp->d_type; 472 else 473#endif 474 namlen = dp->d_namlen; 475 if (namlen == length && 476 !strcmp(name, dp->d_name)) { 477 /* found entry */ 478 *inumber_p = dp->d_ino; 479 return (0); 480 } 481 next: 482 dp = (struct direct *)((char *)dp + dp->d_reclen); 483 } 484 fp->f_seekp += buf_size; 485 } 486 return (ENOENT); 487} 488 489static int sblock_try[] = SBLOCKSEARCH; 490 491/* 492 * Open a file. 493 */ 494static int 495ufs_open(upath, f) 496 const char *upath; 497 struct open_file *f; 498{ 499 char *cp, *ncp; 500 int c; 501 ino_t inumber, parent_inumber; 502 struct file *fp; 503 struct fs *fs; 504 int i, rc; 505 size_t buf_size; 506 int nlinks = 0; 507 char namebuf[MAXPATHLEN+1]; 508 char *buf = NULL; 509 char *path = NULL; 510 511 /* allocate file system specific data structure */ 512 fp = malloc(sizeof(struct file)); 513 bzero(fp, sizeof(struct file)); 514 f->f_fsdata = (void *)fp; 515 516 /* allocate space and read super block */ 517 fs = malloc(SBLOCKSIZE); 518 fp->f_fs = fs; 519 twiddle(1); 520 /* 521 * Try reading the superblock in each of its possible locations. 522 */ 523 for (i = 0; sblock_try[i] != -1; i++) { 524 rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 525 sblock_try[i] / DEV_BSIZE, SBLOCKSIZE, 526 (char *)fs, &buf_size); 527 if (rc) 528 goto out; 529 if ((fs->fs_magic == FS_UFS1_MAGIC || 530 (fs->fs_magic == FS_UFS2_MAGIC && 531 fs->fs_sblockloc == sblock_try[i])) && 532 buf_size == SBLOCKSIZE && 533 fs->fs_bsize <= MAXBSIZE && 534 fs->fs_bsize >= sizeof(struct fs)) 535 break; 536 } 537 if (sblock_try[i] == -1) { 538 rc = EINVAL; 539 goto out; 540 } 541 /* 542 * Calculate indirect block levels. 543 */ 544 { 545 ufs2_daddr_t mult; 546 int level; 547 548 mult = 1; 549 for (level = 0; level < NIADDR; level++) { 550 mult *= NINDIR(fs); 551 fp->f_nindir[level] = mult; 552 } 553 } 554 555 inumber = ROOTINO; 556 if ((rc = read_inode(inumber, f)) != 0) 557 goto out; 558 559 cp = path = strdup(upath); 560 if (path == NULL) { 561 rc = ENOMEM; 562 goto out; 563 } 564 while (*cp) { 565 566 /* 567 * Remove extra separators 568 */ 569 while (*cp == '/') 570 cp++; 571 if (*cp == '\0') 572 break; 573 574 /* 575 * Check that current node is a directory. 576 */ 577 if ((DIP(fp, di_mode) & IFMT) != IFDIR) { 578 rc = ENOTDIR; 579 goto out; 580 } 581 582 /* 583 * Get next component of path name. 584 */ 585 { 586 int len = 0; 587 588 ncp = cp; 589 while ((c = *cp) != '\0' && c != '/') { 590 if (++len > MAXNAMLEN) { 591 rc = ENOENT; 592 goto out; 593 } 594 cp++; 595 } 596 *cp = '\0'; 597 } 598 599 /* 600 * Look up component in current directory. 601 * Save directory inumber in case we find a 602 * symbolic link. 603 */ 604 parent_inumber = inumber; 605 rc = search_directory(ncp, f, &inumber); 606 *cp = c; 607 if (rc) 608 goto out; 609 610 /* 611 * Open next component. 612 */ 613 if ((rc = read_inode(inumber, f)) != 0) 614 goto out; 615 616 /* 617 * Check for symbolic link. 618 */ 619 if ((DIP(fp, di_mode) & IFMT) == IFLNK) { 620 int link_len = DIP(fp, di_size); 621 int len; 622 623 len = strlen(cp); 624 625 if (link_len + len > MAXPATHLEN || 626 ++nlinks > MAXSYMLINKS) { 627 rc = ENOENT; 628 goto out; 629 } 630 631 bcopy(cp, &namebuf[link_len], len + 1); 632 633 if (link_len < fs->fs_maxsymlinklen) { 634 if (fp->f_fs->fs_magic == FS_UFS1_MAGIC) 635 cp = (caddr_t)(fp->f_di.di1.di_db); 636 else 637 cp = (caddr_t)(fp->f_di.di2.di_db); 638 bcopy(cp, namebuf, (unsigned) link_len); 639 } else { 640 /* 641 * Read file for symbolic link 642 */ 643 size_t buf_size; 644 ufs2_daddr_t disk_block; 645 struct fs *fs = fp->f_fs; 646 647 if (!buf) 648 buf = malloc(fs->fs_bsize); 649 rc = block_map(f, (ufs2_daddr_t)0, &disk_block); 650 if (rc) 651 goto out; 652 653 twiddle(1); 654 rc = (f->f_dev->dv_strategy)(f->f_devdata, 655 F_READ, fsbtodb(fs, disk_block), 656 fs->fs_bsize, buf, &buf_size); 657 if (rc) 658 goto out; 659 660 bcopy((char *)buf, namebuf, (unsigned)link_len); 661 } 662 663 /* 664 * If relative pathname, restart at parent directory. 665 * If absolute pathname, restart at root. 666 */ 667 cp = namebuf; 668 if (*cp != '/') 669 inumber = parent_inumber; 670 else 671 inumber = (ino_t)ROOTINO; 672 673 if ((rc = read_inode(inumber, f)) != 0) 674 goto out; 675 } 676 } 677 678 /* 679 * Found terminal component. 680 */ 681 rc = 0; 682 fp->f_seekp = 0; 683out: 684 if (buf) 685 free(buf); 686 if (path) 687 free(path); 688 if (rc) { 689 if (fp->f_buf) 690 free(fp->f_buf); 691 free(fp->f_fs); 692 free(fp); 693 } 694 return (rc); 695} 696 697static int 698ufs_close(f) 699 struct open_file *f; 700{ 701 struct file *fp = (struct file *)f->f_fsdata; 702 int level; 703 704 f->f_fsdata = (void *)0; 705 if (fp == (struct file *)0) 706 return (0); 707 708 for (level = 0; level < NIADDR; level++) { 709 if (fp->f_blk[level]) 710 free(fp->f_blk[level]); 711 } 712 if (fp->f_buf) 713 free(fp->f_buf); 714 free(fp->f_fs); 715 free(fp); 716 return (0); 717} 718 719/* 720 * Copy a portion of a file into kernel memory. 721 * Cross block boundaries when necessary. 722 */ 723static int 724ufs_read(f, start, size, resid) 725 struct open_file *f; 726 void *start; 727 size_t size; 728 size_t *resid; /* out */ 729{ 730 struct file *fp = (struct file *)f->f_fsdata; 731 size_t csize; 732 char *buf; 733 size_t buf_size; 734 int rc = 0; 735 char *addr = start; 736 737 while (size != 0) { 738 if (fp->f_seekp >= DIP(fp, di_size)) 739 break; 740 741 rc = buf_read_file(f, &buf, &buf_size); 742 if (rc) 743 break; 744 745 csize = size; 746 if (csize > buf_size) 747 csize = buf_size; 748 749 bcopy(buf, addr, csize); 750 751 fp->f_seekp += csize; 752 addr += csize; 753 size -= csize; 754 } 755 if (resid) 756 *resid = size; 757 return (rc); 758} 759 760/* 761 * Write to a portion of an already allocated file. 762 * Cross block boundaries when necessary. Can not 763 * extend the file. 764 */ 765static int 766ufs_write(f, start, size, resid) 767 struct open_file *f; 768 const void *start; 769 size_t size; 770 size_t *resid; /* out */ 771{ 772 struct file *fp = (struct file *)f->f_fsdata; 773 size_t csize; 774 int rc = 0; 775 const char *addr = start; 776 777 csize = size; 778 while ((size != 0) && (csize != 0)) { 779 if (fp->f_seekp >= DIP(fp, di_size)) 780 break; 781 782 if (csize >= 512) csize = 512; /* XXX */ 783 784 rc = buf_write_file(f, addr, &csize); 785 if (rc) 786 break; 787 788 fp->f_seekp += csize; 789 addr += csize; 790 size -= csize; 791 } 792 if (resid) 793 *resid = size; 794 return (rc); 795} 796 797static off_t 798ufs_seek(f, offset, where) 799 struct open_file *f; 800 off_t offset; 801 int where; 802{ 803 struct file *fp = (struct file *)f->f_fsdata; 804 805 switch (where) { 806 case SEEK_SET: 807 fp->f_seekp = offset; 808 break; 809 case SEEK_CUR: 810 fp->f_seekp += offset; 811 break; 812 case SEEK_END: 813 fp->f_seekp = DIP(fp, di_size) - offset; 814 break; 815 default: 816 errno = EINVAL; 817 return (-1); 818 } 819 return (fp->f_seekp); 820} 821 822static int 823ufs_stat(f, sb) 824 struct open_file *f; 825 struct stat *sb; 826{ 827 struct file *fp = (struct file *)f->f_fsdata; 828 829 /* only important stuff */ 830 sb->st_mode = DIP(fp, di_mode); 831 sb->st_uid = DIP(fp, di_uid); 832 sb->st_gid = DIP(fp, di_gid); 833 sb->st_size = DIP(fp, di_size); 834 return (0); 835} 836 837static int 838ufs_readdir(struct open_file *f, struct dirent *d) 839{ 840 struct file *fp = (struct file *)f->f_fsdata; 841 struct direct *dp; 842 char *buf; 843 size_t buf_size; 844 int error; 845 846 /* 847 * assume that a directory entry will not be split across blocks 848 */ 849again: 850 if (fp->f_seekp >= DIP(fp, di_size)) 851 return (ENOENT); 852 error = buf_read_file(f, &buf, &buf_size); 853 if (error) 854 return (error); 855 dp = (struct direct *)buf; 856 fp->f_seekp += dp->d_reclen; 857 if (dp->d_ino == (ino_t)0) 858 goto again; 859 d->d_type = dp->d_type; 860 strcpy(d->d_name, dp->d_name); 861 return (0); 862} 863