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