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 }