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