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 i, rc; 510 size_t buf_size; 511 int nlinks = 0; 512 char namebuf[MAXPATHLEN+1]; 513 char *buf = NULL; 514 char *path = NULL; 515 516 /* allocate file system specific data structure */ 517 fp = malloc(sizeof(struct file)); 518 bzero(fp, sizeof(struct file)); 519 f->f_fsdata = (void *)fp; 520 521 /* read super block */ 522 twiddle(1); 523 if ((rc = ffs_sbget(f, &fs, -1, "stand", ufs_use_sa_read)) != 0) 524 goto out; 525 fp->f_fs = fs; 526 /* 527 * Calculate indirect block levels. 528 */ 529 { 530 ufs2_daddr_t mult; 531 int level; 532 533 mult = 1; 534 for (level = 0; level < UFS_NIADDR; level++) { 535 mult *= NINDIR(fs); 536 fp->f_nindir[level] = mult; 537 } 538 } 539 540 inumber = UFS_ROOTINO; 541 if ((rc = read_inode(inumber, f)) != 0) 542 goto out; 543 544 cp = path = strdup(upath); 545 if (path == NULL) { 546 rc = ENOMEM; 547 goto out; 548 } 549 while (*cp) { 550 551 /* 552 * Remove extra separators 553 */ 554 while (*cp == '/') 555 cp++; 556 if (*cp == '\0') 557 break; 558 559 /* 560 * Check that current node is a directory. 561 */ 562 if ((DIP(fp, di_mode) & IFMT) != IFDIR) { 563 rc = ENOTDIR; 564 goto out; 565 } 566 567 /* 568 * Get next component of path name. 569 */ 570 { 571 int len = 0; 572 573 ncp = cp; 574 while ((c = *cp) != '\0' && c != '/') { 575 if (++len > UFS_MAXNAMLEN) { 576 rc = ENOENT; 577 goto out; 578 } 579 cp++; 580 } 581 *cp = '\0'; 582 } 583 584 /* 585 * Look up component in current directory. 586 * Save directory inumber in case we find a 587 * symbolic link. 588 */ 589 parent_inumber = inumber; 590 rc = search_directory(ncp, f, &inumber); 591 *cp = c; 592 if (rc) 593 goto out; 594 595 /* 596 * Open next component. 597 */ 598 if ((rc = read_inode(inumber, f)) != 0) 599 goto out; 600 601 /* 602 * Check for symbolic link. 603 */ 604 if ((DIP(fp, di_mode) & IFMT) == IFLNK) { 605 int link_len = DIP(fp, di_size); 606 int len; 607 608 len = strlen(cp); 609 610 if (link_len + len > MAXPATHLEN || 611 ++nlinks > MAXSYMLINKS) { 612 rc = ENOENT; 613 goto out; 614 } 615 616 bcopy(cp, &namebuf[link_len], len + 1); 617 618 if (link_len < fs->fs_maxsymlinklen) { 619 if (fp->f_fs->fs_magic == FS_UFS1_MAGIC) 620 cp = (caddr_t)(fp->f_di.di1.di_db); 621 else 622 cp = (caddr_t)(fp->f_di.di2.di_db); 623 bcopy(cp, namebuf, (unsigned) link_len); 624 } else { 625 /* 626 * Read file for symbolic link 627 */ 628 size_t buf_size; 629 ufs2_daddr_t disk_block; 630 struct fs *fs = fp->f_fs; 631 632 if (!buf) 633 buf = malloc(fs->fs_bsize); 634 rc = block_map(f, (ufs2_daddr_t)0, &disk_block); 635 if (rc) 636 goto out; 637 638 twiddle(1); 639 rc = (f->f_dev->dv_strategy)(f->f_devdata, 640 F_READ, fsbtodb(fs, disk_block), 641 fs->fs_bsize, buf, &buf_size); 642 if (rc) 643 goto out; 644 645 bcopy((char *)buf, namebuf, (unsigned)link_len); 646 } 647 648 /* 649 * If relative pathname, restart at parent directory. 650 * If absolute pathname, restart at root. 651 */ 652 cp = namebuf; 653 if (*cp != '/') 654 inumber = parent_inumber; 655 else 656 inumber = (ino_t)UFS_ROOTINO; 657 658 if ((rc = read_inode(inumber, f)) != 0) 659 goto out; 660 } 661 } 662 663 /* 664 * Found terminal component. 665 */ 666 rc = 0; 667 fp->f_seekp = 0; 668 out: 669 if (buf) 670 free(buf); 671 if (path) 672 free(path); 673 if (rc) { 674 if (fp->f_buf) 675 free(fp->f_buf); 676 free(fp->f_fs); 677 free(fp); 678 } 679 return (rc); 680 } 681 682 /* 683 * A read function for use by standalone-layer routines. 684 */ 685 static int 686 ufs_use_sa_read(void *devfd, off_t loc, void **bufp, int size) 687 { 688 struct open_file *f; 689 size_t buf_size; 690 int error; 691 692 f = (struct open_file *)devfd; 693 if ((*bufp = malloc(size)) == NULL) 694 return (ENOSPC); 695 error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, loc / DEV_BSIZE, 696 size, *bufp, &buf_size); 697 if (error != 0) 698 return (error); 699 if (buf_size != size) 700 return (EIO); 701 return (0); 702 } 703 704 static int 705 ufs_close(f) 706 struct open_file *f; 707 { 708 struct file *fp = (struct file *)f->f_fsdata; 709 int level; 710 711 f->f_fsdata = (void *)0; 712 if (fp == (struct file *)0) 713 return (0); 714 715 for (level = 0; level < UFS_NIADDR; level++) { 716 if (fp->f_blk[level]) 717 free(fp->f_blk[level]); 718 } 719 if (fp->f_buf) 720 free(fp->f_buf); 721 free(fp->f_fs); 722 free(fp); 723 return (0); 724 } 725 726 /* 727 * Copy a portion of a file into kernel memory. 728 * Cross block boundaries when necessary. 729 */ 730 static int 731 ufs_read(f, start, size, resid) 732 struct open_file *f; 733 void *start; 734 size_t size; 735 size_t *resid; /* out */ 736 { 737 struct file *fp = (struct file *)f->f_fsdata; 738 size_t csize; 739 char *buf; 740 size_t buf_size; 741 int rc = 0; 742 char *addr = start; 743 744 while (size != 0) { 745 if (fp->f_seekp >= DIP(fp, di_size)) 746 break; 747 748 rc = buf_read_file(f, &buf, &buf_size); 749 if (rc) 750 break; 751 752 csize = size; 753 if (csize > buf_size) 754 csize = buf_size; 755 756 bcopy(buf, addr, csize); 757 758 fp->f_seekp += csize; 759 addr += csize; 760 size -= csize; 761 } 762 if (resid) 763 *resid = size; 764 return (rc); 765 } 766 767 /* 768 * Write to a portion of an already allocated file. 769 * Cross block boundaries when necessary. Can not 770 * extend the file. 771 */ 772 static int 773 ufs_write(f, start, size, resid) 774 struct open_file *f; 775 const void *start; 776 size_t size; 777 size_t *resid; /* out */ 778 { 779 struct file *fp = (struct file *)f->f_fsdata; 780 size_t csize; 781 int rc = 0; 782 const char *addr = start; 783 784 csize = size; 785 while ((size != 0) && (csize != 0)) { 786 if (fp->f_seekp >= DIP(fp, di_size)) 787 break; 788 789 if (csize >= 512) csize = 512; /* XXX */ 790 791 rc = buf_write_file(f, addr, &csize); 792 if (rc) 793 break; 794 795 fp->f_seekp += csize; 796 addr += csize; 797 size -= csize; 798 } 799 if (resid) 800 *resid = size; 801 return (rc); 802 } 803 804 static off_t 805 ufs_seek(f, offset, where) 806 struct open_file *f; 807 off_t offset; 808 int where; 809 { 810 struct file *fp = (struct file *)f->f_fsdata; 811 812 switch (where) { 813 case SEEK_SET: 814 fp->f_seekp = offset; 815 break; 816 case SEEK_CUR: 817 fp->f_seekp += offset; 818 break; 819 case SEEK_END: 820 fp->f_seekp = DIP(fp, di_size) - offset; 821 break; 822 default: 823 errno = EINVAL; 824 return (-1); 825 } 826 return (fp->f_seekp); 827 } 828 829 static int 830 ufs_stat(f, sb) 831 struct open_file *f; 832 struct stat *sb; 833 { 834 struct file *fp = (struct file *)f->f_fsdata; 835 836 /* only important stuff */ 837 sb->st_mode = DIP(fp, di_mode); 838 sb->st_uid = DIP(fp, di_uid); 839 sb->st_gid = DIP(fp, di_gid); 840 sb->st_size = DIP(fp, di_size); 841 sb->st_mtime = DIP(fp, di_mtime); 842 /* 843 * The items below are ufs specific! 844 * Other fs types will need their own solution 845 * if these fields are needed. 846 */ 847 sb->st_ino = fp->f_inumber; 848 /* 849 * We need something to differentiate devs. 850 * fs_id is unique but 64bit, we xor the two 851 * halves to squeeze it into 32bits. 852 */ 853 sb->st_dev = (dev_t)(fp->f_fs->fs_id[0] ^ fp->f_fs->fs_id[1]); 854 855 return (0); 856 } 857 858 static int 859 ufs_readdir(struct open_file *f, struct dirent *d) 860 { 861 struct file *fp = (struct file *)f->f_fsdata; 862 struct direct *dp; 863 char *buf; 864 size_t buf_size; 865 int error; 866 867 /* 868 * assume that a directory entry will not be split across blocks 869 */ 870 again: 871 if (fp->f_seekp >= DIP(fp, di_size)) 872 return (ENOENT); 873 error = buf_read_file(f, &buf, &buf_size); 874 if (error) 875 return (error); 876 dp = (struct direct *)buf; 877 fp->f_seekp += dp->d_reclen; 878 if (dp->d_ino == (ino_t)0) 879 goto again; 880 d->d_type = dp->d_type; 881 strcpy(d->d_name, dp->d_name); 882 return (0); 883 } 884