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