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[NIADDR]; 116 /* number of blocks mapped by 117 indirect block at level i */ 118 char *f_blk[NIADDR]; /* buffer for indirect block at 119 level i */ 120 size_t f_blksize[NIADDR]; 121 /* size of buffer */ 122 ufs2_daddr_t f_blkno[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)), 0, 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 < 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..NDADDR-1] hold block numbers for blocks 213 * 0..NDADDR-1 214 * 215 * di_ib[0] index block 0 is the single indirect block 216 * holds block numbers for blocks 217 * NDADDR .. 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 * NDADDR + NINDIR(fs) .. 222 * 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 * NDADDR + NINDIR(fs) + NINDIR(fs)**2 .. 228 * NDADDR + NINDIR(fs) + NINDIR(fs)**2 229 * + NINDIR(fs)**3 - 1 230 */ 231 232 if (file_block < NDADDR) { 233 /* Direct block. */ 234 *disk_block_p = DIP(fp, di_db[file_block]); 235 return (0); 236 } 237 238 file_block -= 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 < NIADDR; level++) { 247 if (file_block < fp->f_nindir[level]) 248 break; 249 file_block -= fp->f_nindir[level]; 250 } 251 if (level == 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), 0, 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(8); 350 rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 351 fsbtodb(fs, disk_block), 0, 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), 0, 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, 411 F_READ, fsbtodb(fs, disk_block), 0, 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 namlen = dp->d_namlen; 469 if (namlen == length && 470 !strcmp(name, dp->d_name)) { 471 /* found entry */ 472 *inumber_p = dp->d_ino; 473 return (0); 474 } 475 next: 476 dp = (struct direct *)((char *)dp + dp->d_reclen); 477 } 478 fp->f_seekp += buf_size; 479 } 480 return (ENOENT); 481 } 482 483 static int sblock_try[] = SBLOCKSEARCH; 484 485 /* 486 * Open a file. 487 */ 488 static int 489 ufs_open(upath, f) 490 const char *upath; 491 struct open_file *f; 492 { 493 char *cp, *ncp; 494 int c; 495 ino_t inumber, parent_inumber; 496 struct file *fp; 497 struct fs *fs; 498 int i, rc; 499 size_t buf_size; 500 int nlinks = 0; 501 char namebuf[MAXPATHLEN+1]; 502 char *buf = NULL; 503 char *path = NULL; 504 505 /* allocate file system specific data structure */ 506 fp = malloc(sizeof(struct file)); 507 bzero(fp, sizeof(struct file)); 508 f->f_fsdata = (void *)fp; 509 510 /* allocate space and read super block */ 511 fs = malloc(SBLOCKSIZE); 512 fp->f_fs = fs; 513 twiddle(1); 514 /* 515 * Try reading the superblock in each of its possible locations. 516 */ 517 for (i = 0; sblock_try[i] != -1; i++) { 518 rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 519 sblock_try[i] / DEV_BSIZE, 0, SBLOCKSIZE, 520 (char *)fs, &buf_size); 521 if (rc) 522 goto out; 523 if ((fs->fs_magic == FS_UFS1_MAGIC || 524 (fs->fs_magic == FS_UFS2_MAGIC && 525 fs->fs_sblockloc == sblock_try[i])) && 526 buf_size == SBLOCKSIZE && 527 fs->fs_bsize <= MAXBSIZE && 528 fs->fs_bsize >= sizeof(struct fs)) 529 break; 530 } 531 if (sblock_try[i] == -1) { 532 rc = EINVAL; 533 goto out; 534 } 535 /* 536 * Calculate indirect block levels. 537 */ 538 { 539 ufs2_daddr_t mult; 540 int level; 541 542 mult = 1; 543 for (level = 0; level < NIADDR; level++) { 544 mult *= NINDIR(fs); 545 fp->f_nindir[level] = mult; 546 } 547 } 548 549 inumber = ROOTINO; 550 if ((rc = read_inode(inumber, f)) != 0) 551 goto out; 552 553 cp = path = strdup(upath); 554 if (path == NULL) { 555 rc = ENOMEM; 556 goto out; 557 } 558 while (*cp) { 559 560 /* 561 * Remove extra separators 562 */ 563 while (*cp == '/') 564 cp++; 565 if (*cp == '\0') 566 break; 567 568 /* 569 * Check that current node is a directory. 570 */ 571 if ((DIP(fp, di_mode) & IFMT) != IFDIR) { 572 rc = ENOTDIR; 573 goto out; 574 } 575 576 /* 577 * Get next component of path name. 578 */ 579 { 580 int len = 0; 581 582 ncp = cp; 583 while ((c = *cp) != '\0' && c != '/') { 584 if (++len > MAXNAMLEN) { 585 rc = ENOENT; 586 goto out; 587 } 588 cp++; 589 } 590 *cp = '\0'; 591 } 592 593 /* 594 * Look up component in current directory. 595 * Save directory inumber in case we find a 596 * symbolic link. 597 */ 598 parent_inumber = inumber; 599 rc = search_directory(ncp, f, &inumber); 600 *cp = c; 601 if (rc) 602 goto out; 603 604 /* 605 * Open next component. 606 */ 607 if ((rc = read_inode(inumber, f)) != 0) 608 goto out; 609 610 /* 611 * Check for symbolic link. 612 */ 613 if ((DIP(fp, di_mode) & IFMT) == IFLNK) { 614 int link_len = DIP(fp, di_size); 615 int len; 616 617 len = strlen(cp); 618 619 if (link_len + len > MAXPATHLEN || 620 ++nlinks > MAXSYMLINKS) { 621 rc = ENOENT; 622 goto out; 623 } 624 625 bcopy(cp, &namebuf[link_len], len + 1); 626 627 if (link_len < fs->fs_maxsymlinklen) { 628 if (fp->f_fs->fs_magic == FS_UFS1_MAGIC) 629 cp = (caddr_t)(fp->f_di.di1.di_db); 630 else 631 cp = (caddr_t)(fp->f_di.di2.di_db); 632 bcopy(cp, namebuf, (unsigned) link_len); 633 } else { 634 /* 635 * Read file for symbolic link 636 */ 637 size_t buf_size; 638 ufs2_daddr_t disk_block; 639 struct fs *fs = fp->f_fs; 640 641 if (!buf) 642 buf = malloc(fs->fs_bsize); 643 rc = block_map(f, (ufs2_daddr_t)0, &disk_block); 644 if (rc) 645 goto out; 646 647 twiddle(1); 648 rc = (f->f_dev->dv_strategy)(f->f_devdata, 649 F_READ, fsbtodb(fs, disk_block), 0, 650 fs->fs_bsize, buf, &buf_size); 651 if (rc) 652 goto out; 653 654 bcopy((char *)buf, namebuf, (unsigned)link_len); 655 } 656 657 /* 658 * If relative pathname, restart at parent directory. 659 * If absolute pathname, restart at root. 660 */ 661 cp = namebuf; 662 if (*cp != '/') 663 inumber = parent_inumber; 664 else 665 inumber = (ino_t)ROOTINO; 666 667 if ((rc = read_inode(inumber, f)) != 0) 668 goto out; 669 } 670 } 671 672 /* 673 * Found terminal component. 674 */ 675 rc = 0; 676 fp->f_seekp = 0; 677 out: 678 if (buf) 679 free(buf); 680 if (path) 681 free(path); 682 if (rc) { 683 if (fp->f_buf) 684 free(fp->f_buf); 685 free(fp->f_fs); 686 free(fp); 687 } 688 return (rc); 689 } 690 691 static int 692 ufs_close(f) 693 struct open_file *f; 694 { 695 struct file *fp = (struct file *)f->f_fsdata; 696 int level; 697 698 f->f_fsdata = (void *)0; 699 if (fp == (struct file *)0) 700 return (0); 701 702 for (level = 0; level < NIADDR; level++) { 703 if (fp->f_blk[level]) 704 free(fp->f_blk[level]); 705 } 706 if (fp->f_buf) 707 free(fp->f_buf); 708 free(fp->f_fs); 709 free(fp); 710 return (0); 711 } 712 713 /* 714 * Copy a portion of a file into kernel memory. 715 * Cross block boundaries when necessary. 716 */ 717 static int 718 ufs_read(f, start, size, resid) 719 struct open_file *f; 720 void *start; 721 size_t size; 722 size_t *resid; /* out */ 723 { 724 struct file *fp = (struct file *)f->f_fsdata; 725 size_t csize; 726 char *buf; 727 size_t buf_size; 728 int rc = 0; 729 char *addr = start; 730 731 while (size != 0) { 732 if (fp->f_seekp >= DIP(fp, di_size)) 733 break; 734 735 rc = buf_read_file(f, &buf, &buf_size); 736 if (rc) 737 break; 738 739 csize = size; 740 if (csize > buf_size) 741 csize = buf_size; 742 743 bcopy(buf, addr, csize); 744 745 fp->f_seekp += csize; 746 addr += csize; 747 size -= csize; 748 } 749 if (resid) 750 *resid = size; 751 return (rc); 752 } 753 754 /* 755 * Write to a portion of an already allocated file. 756 * Cross block boundaries when necessary. Can not 757 * extend the file. 758 */ 759 static int 760 ufs_write(f, start, size, resid) 761 struct open_file *f; 762 void *start; 763 size_t size; 764 size_t *resid; /* out */ 765 { 766 struct file *fp = (struct file *)f->f_fsdata; 767 size_t csize; 768 int rc = 0; 769 char *addr = start; 770 771 csize = size; 772 while ((size != 0) && (csize != 0)) { 773 if (fp->f_seekp >= DIP(fp, di_size)) 774 break; 775 776 if (csize >= 512) csize = 512; /* XXX */ 777 778 rc = buf_write_file(f, addr, &csize); 779 if (rc) 780 break; 781 782 fp->f_seekp += csize; 783 addr += csize; 784 size -= csize; 785 } 786 if (resid) 787 *resid = size; 788 return (rc); 789 } 790 791 static off_t 792 ufs_seek(f, offset, where) 793 struct open_file *f; 794 off_t offset; 795 int where; 796 { 797 struct file *fp = (struct file *)f->f_fsdata; 798 799 switch (where) { 800 case SEEK_SET: 801 fp->f_seekp = offset; 802 break; 803 case SEEK_CUR: 804 fp->f_seekp += offset; 805 break; 806 case SEEK_END: 807 fp->f_seekp = DIP(fp, di_size) - offset; 808 break; 809 default: 810 errno = EINVAL; 811 return (-1); 812 } 813 return (fp->f_seekp); 814 } 815 816 static int 817 ufs_stat(f, sb) 818 struct open_file *f; 819 struct stat *sb; 820 { 821 struct file *fp = (struct file *)f->f_fsdata; 822 823 /* only important stuff */ 824 sb->st_mode = DIP(fp, di_mode); 825 sb->st_uid = DIP(fp, di_uid); 826 sb->st_gid = DIP(fp, di_gid); 827 sb->st_size = DIP(fp, di_size); 828 return (0); 829 } 830 831 static int 832 ufs_readdir(struct open_file *f, struct dirent *d) 833 { 834 struct file *fp = (struct file *)f->f_fsdata; 835 struct direct *dp; 836 char *buf; 837 size_t buf_size; 838 int error; 839 840 /* 841 * assume that a directory entry will not be split across blocks 842 */ 843 again: 844 if (fp->f_seekp >= DIP(fp, di_size)) 845 return (ENOENT); 846 error = buf_read_file(f, &buf, &buf_size); 847 if (error) 848 return (error); 849 dp = (struct direct *)buf; 850 fp->f_seekp += dp->d_reclen; 851 if (dp->d_ino == (ino_t)0) 852 goto again; 853 854 d->d_type = 0; /* illumos ufs does not have type in direct */ 855 strcpy(d->d_name, dp->d_name); 856 return (0); 857 } 858