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