xref: /titanic_51/usr/src/boot/lib/libstand/ufs.c (revision e48f27a0bf5ac8d6bcd05e2d0554b4aab53b1059)
14a5d661aSToomas Soome /*	$NetBSD: ufs.c,v 1.20 1998/03/01 07:15:39 ross Exp $	*/
24a5d661aSToomas Soome 
34a5d661aSToomas Soome /*-
44a5d661aSToomas Soome  * Copyright (c) 2002 Networks Associates Technology, Inc.
54a5d661aSToomas Soome  * All rights reserved.
64a5d661aSToomas Soome  *
74a5d661aSToomas Soome  * This software was developed for the FreeBSD Project by Marshall
84a5d661aSToomas Soome  * Kirk McKusick and Network Associates Laboratories, the Security
94a5d661aSToomas Soome  * Research Division of Network Associates, Inc. under DARPA/SPAWAR
104a5d661aSToomas Soome  * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS
114a5d661aSToomas Soome  * research program
124a5d661aSToomas Soome  *
134a5d661aSToomas Soome  * Copyright (c) 1982, 1989, 1993
144a5d661aSToomas Soome  *	The Regents of the University of California.  All rights reserved.
154a5d661aSToomas Soome  *
164a5d661aSToomas Soome  * This code is derived from software contributed to Berkeley by
174a5d661aSToomas Soome  * The Mach Operating System project at Carnegie-Mellon University.
184a5d661aSToomas Soome  *
194a5d661aSToomas Soome  * Redistribution and use in source and binary forms, with or without
204a5d661aSToomas Soome  * modification, are permitted provided that the following conditions
214a5d661aSToomas Soome  * are met:
224a5d661aSToomas Soome  * 1. Redistributions of source code must retain the above copyright
234a5d661aSToomas Soome  *    notice, this list of conditions and the following disclaimer.
244a5d661aSToomas Soome  * 2. Redistributions in binary form must reproduce the above copyright
254a5d661aSToomas Soome  *    notice, this list of conditions and the following disclaimer in the
264a5d661aSToomas Soome  *    documentation and/or other materials provided with the distribution.
274a5d661aSToomas Soome  * 3. Neither the name of the University nor the names of its contributors
284a5d661aSToomas Soome  *    may be used to endorse or promote products derived from this software
294a5d661aSToomas Soome  *    without specific prior written permission.
304a5d661aSToomas Soome  *
314a5d661aSToomas Soome  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
324a5d661aSToomas Soome  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
334a5d661aSToomas Soome  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
344a5d661aSToomas Soome  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
354a5d661aSToomas Soome  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
364a5d661aSToomas Soome  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
374a5d661aSToomas Soome  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
384a5d661aSToomas Soome  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
394a5d661aSToomas Soome  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
404a5d661aSToomas Soome  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
414a5d661aSToomas Soome  * SUCH DAMAGE.
424a5d661aSToomas Soome  *
434a5d661aSToomas Soome  *
444a5d661aSToomas Soome  * Copyright (c) 1990, 1991 Carnegie Mellon University
454a5d661aSToomas Soome  * All Rights Reserved.
464a5d661aSToomas Soome  *
474a5d661aSToomas Soome  * Author: David Golub
484a5d661aSToomas Soome  *
494a5d661aSToomas Soome  * Permission to use, copy, modify and distribute this software and its
504a5d661aSToomas Soome  * documentation is hereby granted, provided that both the copyright
514a5d661aSToomas Soome  * notice and this permission notice appear in all copies of the
524a5d661aSToomas Soome  * software, derivative works or modified versions, and any portions
534a5d661aSToomas Soome  * thereof, and that both notices appear in supporting documentation.
544a5d661aSToomas Soome  *
554a5d661aSToomas Soome  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
564a5d661aSToomas Soome  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
574a5d661aSToomas Soome  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
584a5d661aSToomas Soome  *
594a5d661aSToomas Soome  * Carnegie Mellon requests users of this software to return to
604a5d661aSToomas Soome  *
614a5d661aSToomas Soome  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
624a5d661aSToomas Soome  *  School of Computer Science
634a5d661aSToomas Soome  *  Carnegie Mellon University
644a5d661aSToomas Soome  *  Pittsburgh PA 15213-3890
654a5d661aSToomas Soome  *
664a5d661aSToomas Soome  * any improvements or extensions that they make and grant Carnegie the
674a5d661aSToomas Soome  * rights to redistribute these changes.
684a5d661aSToomas Soome  */
694a5d661aSToomas Soome 
704a5d661aSToomas Soome #include <sys/cdefs.h>
714a5d661aSToomas Soome 
724a5d661aSToomas Soome /*
734a5d661aSToomas Soome  *	Stand-alone file reading package.
744a5d661aSToomas Soome  */
754a5d661aSToomas Soome 
764a5d661aSToomas Soome #include <sys/param.h>
774a5d661aSToomas Soome #include <sys/disklabel.h>
784a5d661aSToomas Soome #include <sys/time.h>
794a5d661aSToomas Soome #include <ufs/ufs/dinode.h>
804a5d661aSToomas Soome #include <ufs/ufs/dir.h>
814a5d661aSToomas Soome #include <ufs/ffs/fs.h>
824a5d661aSToomas Soome #include "stand.h"
834a5d661aSToomas Soome #include "string.h"
844a5d661aSToomas Soome 
854a5d661aSToomas Soome static int	ufs_open(const char *path, struct open_file *f);
864a5d661aSToomas Soome static int	ufs_write(struct open_file *f, void *buf, size_t size, size_t *resid);
874a5d661aSToomas Soome static int	ufs_close(struct open_file *f);
884a5d661aSToomas Soome static int	ufs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
894a5d661aSToomas Soome static off_t	ufs_seek(struct open_file *f, off_t offset, int where);
904a5d661aSToomas Soome static int	ufs_stat(struct open_file *f, struct stat *sb);
914a5d661aSToomas Soome static int	ufs_readdir(struct open_file *f, struct dirent *d);
924a5d661aSToomas Soome 
934a5d661aSToomas Soome struct fs_ops ufs_fsops = {
944a5d661aSToomas Soome 	"ufs",
954a5d661aSToomas Soome 	ufs_open,
964a5d661aSToomas Soome 	ufs_close,
974a5d661aSToomas Soome 	ufs_read,
984a5d661aSToomas Soome 	ufs_write,
994a5d661aSToomas Soome 	ufs_seek,
1004a5d661aSToomas Soome 	ufs_stat,
1014a5d661aSToomas Soome 	ufs_readdir
1024a5d661aSToomas Soome };
1034a5d661aSToomas Soome 
1044a5d661aSToomas Soome /*
1054a5d661aSToomas Soome  * In-core open file.
1064a5d661aSToomas Soome  */
1074a5d661aSToomas Soome struct file {
1084a5d661aSToomas Soome 	off_t		f_seekp;	/* seek pointer */
1094a5d661aSToomas Soome 	struct fs	*f_fs;		/* pointer to super-block */
1104a5d661aSToomas Soome 	union dinode {
1114a5d661aSToomas Soome 		struct ufs1_dinode di1;
1124a5d661aSToomas Soome 		struct ufs2_dinode di2;
1134a5d661aSToomas Soome 	}		f_di;		/* copy of on-disk inode */
1144a5d661aSToomas Soome 	int		f_nindir[NIADDR];
1154a5d661aSToomas Soome 					/* number of blocks mapped by
1164a5d661aSToomas Soome 					   indirect block at level i */
1174a5d661aSToomas Soome 	char		*f_blk[NIADDR];	/* buffer for indirect block at
1184a5d661aSToomas Soome 					   level i */
1194a5d661aSToomas Soome 	size_t		f_blksize[NIADDR];
1204a5d661aSToomas Soome 					/* size of buffer */
1214a5d661aSToomas Soome 	ufs2_daddr_t	f_blkno[NIADDR];/* disk address of block in buffer */
1224a5d661aSToomas Soome 	ufs2_daddr_t	f_buf_blkno;	/* block number of data block */
1234a5d661aSToomas Soome 	char		*f_buf;		/* buffer for data block */
1244a5d661aSToomas Soome 	size_t		f_buf_size;	/* size of data block */
1254a5d661aSToomas Soome };
1264a5d661aSToomas Soome #define DIP(fp, field) \
1274a5d661aSToomas Soome 	((fp)->f_fs->fs_magic == FS_UFS1_MAGIC ? \
1284a5d661aSToomas Soome 	(fp)->f_di.di1.field : (fp)->f_di.di2.field)
1294a5d661aSToomas Soome 
1304a5d661aSToomas Soome static int	read_inode(ino_t, struct open_file *);
1314a5d661aSToomas Soome static int	block_map(struct open_file *, ufs2_daddr_t, ufs2_daddr_t *);
1324a5d661aSToomas Soome static int	buf_read_file(struct open_file *, char **, size_t *);
1334a5d661aSToomas Soome static int	buf_write_file(struct open_file *, char *, size_t *);
1344a5d661aSToomas Soome static int	search_directory(char *, struct open_file *, ino_t *);
1354a5d661aSToomas Soome 
1364a5d661aSToomas Soome /*
1374a5d661aSToomas Soome  * Read a new inode into a file structure.
1384a5d661aSToomas Soome  */
1394a5d661aSToomas Soome static int
1404a5d661aSToomas Soome read_inode(inumber, f)
1414a5d661aSToomas Soome 	ino_t inumber;
1424a5d661aSToomas Soome 	struct open_file *f;
1434a5d661aSToomas Soome {
1444a5d661aSToomas Soome 	struct file *fp = (struct file *)f->f_fsdata;
1454a5d661aSToomas Soome 	struct fs *fs = fp->f_fs;
1464a5d661aSToomas Soome 	char *buf;
1474a5d661aSToomas Soome 	size_t rsize;
1484a5d661aSToomas Soome 	int rc;
1494a5d661aSToomas Soome 
1504a5d661aSToomas Soome 	if (fs == NULL)
1514a5d661aSToomas Soome 	    panic("fs == NULL");
1524a5d661aSToomas Soome 
1534a5d661aSToomas Soome 	/*
1544a5d661aSToomas Soome 	 * Read inode and save it.
1554a5d661aSToomas Soome 	 */
1564a5d661aSToomas Soome 	buf = malloc(fs->fs_bsize);
1574a5d661aSToomas Soome 	twiddle(1);
1584a5d661aSToomas Soome 	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
159976852c7SToomas Soome 		fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize,
1604a5d661aSToomas Soome 		buf, &rsize);
1614a5d661aSToomas Soome 	if (rc)
1624a5d661aSToomas Soome 		goto out;
1634a5d661aSToomas Soome 	if (rsize != fs->fs_bsize) {
1644a5d661aSToomas Soome 		rc = EIO;
1654a5d661aSToomas Soome 		goto out;
1664a5d661aSToomas Soome 	}
1674a5d661aSToomas Soome 
1684a5d661aSToomas Soome 	if (fp->f_fs->fs_magic == FS_UFS1_MAGIC)
1694a5d661aSToomas Soome 		fp->f_di.di1 = ((struct ufs1_dinode *)buf)
1704a5d661aSToomas Soome 		    [ino_to_fsbo(fs, inumber)];
1714a5d661aSToomas Soome 	else
1724a5d661aSToomas Soome 		fp->f_di.di2 = ((struct ufs2_dinode *)buf)
1734a5d661aSToomas Soome 		    [ino_to_fsbo(fs, inumber)];
1744a5d661aSToomas Soome 
1754a5d661aSToomas Soome 	/*
1764a5d661aSToomas Soome 	 * Clear out the old buffers
1774a5d661aSToomas Soome 	 */
1784a5d661aSToomas Soome 	{
1794a5d661aSToomas Soome 		int level;
1804a5d661aSToomas Soome 
1814a5d661aSToomas Soome 		for (level = 0; level < NIADDR; level++)
1824a5d661aSToomas Soome 			fp->f_blkno[level] = -1;
1834a5d661aSToomas Soome 		fp->f_buf_blkno = -1;
1844a5d661aSToomas Soome 	}
1854a5d661aSToomas Soome 	fp->f_seekp = 0;
1864a5d661aSToomas Soome out:
1874a5d661aSToomas Soome 	free(buf);
1884a5d661aSToomas Soome 	return (rc);
1894a5d661aSToomas Soome }
1904a5d661aSToomas Soome 
1914a5d661aSToomas Soome /*
1924a5d661aSToomas Soome  * Given an offset in a file, find the disk block number that
1934a5d661aSToomas Soome  * contains that block.
1944a5d661aSToomas Soome  */
1954a5d661aSToomas Soome static int
1964a5d661aSToomas Soome block_map(f, file_block, disk_block_p)
1974a5d661aSToomas Soome 	struct open_file *f;
1984a5d661aSToomas Soome 	ufs2_daddr_t file_block;
1994a5d661aSToomas Soome 	ufs2_daddr_t *disk_block_p;	/* out */
2004a5d661aSToomas Soome {
2014a5d661aSToomas Soome 	struct file *fp = (struct file *)f->f_fsdata;
2024a5d661aSToomas Soome 	struct fs *fs = fp->f_fs;
2034a5d661aSToomas Soome 	int level;
2044a5d661aSToomas Soome 	int idx;
2054a5d661aSToomas Soome 	ufs2_daddr_t ind_block_num;
2064a5d661aSToomas Soome 	int rc;
2074a5d661aSToomas Soome 
2084a5d661aSToomas Soome 	/*
2094a5d661aSToomas Soome 	 * Index structure of an inode:
2104a5d661aSToomas Soome 	 *
2114a5d661aSToomas Soome 	 * di_db[0..NDADDR-1]	hold block numbers for blocks
2124a5d661aSToomas Soome 	 *			0..NDADDR-1
2134a5d661aSToomas Soome 	 *
2144a5d661aSToomas Soome 	 * di_ib[0]		index block 0 is the single indirect block
2154a5d661aSToomas Soome 	 *			holds block numbers for blocks
2164a5d661aSToomas Soome 	 *			NDADDR .. NDADDR + NINDIR(fs)-1
2174a5d661aSToomas Soome 	 *
2184a5d661aSToomas Soome 	 * di_ib[1]		index block 1 is the double indirect block
2194a5d661aSToomas Soome 	 *			holds block numbers for INDEX blocks for blocks
2204a5d661aSToomas Soome 	 *			NDADDR + NINDIR(fs) ..
2214a5d661aSToomas Soome 	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1
2224a5d661aSToomas Soome 	 *
2234a5d661aSToomas Soome 	 * di_ib[2]		index block 2 is the triple indirect block
2244a5d661aSToomas Soome 	 *			holds block numbers for double-indirect
2254a5d661aSToomas Soome 	 *			blocks for blocks
2264a5d661aSToomas Soome 	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2 ..
2274a5d661aSToomas Soome 	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2
2284a5d661aSToomas Soome 	 *				+ NINDIR(fs)**3 - 1
2294a5d661aSToomas Soome 	 */
2304a5d661aSToomas Soome 
2314a5d661aSToomas Soome 	if (file_block < NDADDR) {
2324a5d661aSToomas Soome 		/* Direct block. */
2334a5d661aSToomas Soome 		*disk_block_p = DIP(fp, di_db[file_block]);
2344a5d661aSToomas Soome 		return (0);
2354a5d661aSToomas Soome 	}
2364a5d661aSToomas Soome 
2374a5d661aSToomas Soome 	file_block -= NDADDR;
2384a5d661aSToomas Soome 
2394a5d661aSToomas Soome 	/*
2404a5d661aSToomas Soome 	 * nindir[0] = NINDIR
2414a5d661aSToomas Soome 	 * nindir[1] = NINDIR**2
2424a5d661aSToomas Soome 	 * nindir[2] = NINDIR**3
2434a5d661aSToomas Soome 	 *	etc
2444a5d661aSToomas Soome 	 */
2454a5d661aSToomas Soome 	for (level = 0; level < NIADDR; level++) {
2464a5d661aSToomas Soome 		if (file_block < fp->f_nindir[level])
2474a5d661aSToomas Soome 			break;
2484a5d661aSToomas Soome 		file_block -= fp->f_nindir[level];
2494a5d661aSToomas Soome 	}
2504a5d661aSToomas Soome 	if (level == NIADDR) {
2514a5d661aSToomas Soome 		/* Block number too high */
2524a5d661aSToomas Soome 		return (EFBIG);
2534a5d661aSToomas Soome 	}
2544a5d661aSToomas Soome 
2554a5d661aSToomas Soome 	ind_block_num = DIP(fp, di_ib[level]);
2564a5d661aSToomas Soome 
2574a5d661aSToomas Soome 	for (; level >= 0; level--) {
2584a5d661aSToomas Soome 		if (ind_block_num == 0) {
2594a5d661aSToomas Soome 			*disk_block_p = 0;	/* missing */
2604a5d661aSToomas Soome 			return (0);
2614a5d661aSToomas Soome 		}
2624a5d661aSToomas Soome 
2634a5d661aSToomas Soome 		if (fp->f_blkno[level] != ind_block_num) {
2644a5d661aSToomas Soome 			if (fp->f_blk[level] == (char *)0)
2654a5d661aSToomas Soome 				fp->f_blk[level] =
2664a5d661aSToomas Soome 					malloc(fs->fs_bsize);
2674a5d661aSToomas Soome 			twiddle(1);
2684a5d661aSToomas Soome 			rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
269976852c7SToomas Soome 				fsbtodb(fp->f_fs, ind_block_num),
2704a5d661aSToomas Soome 				fs->fs_bsize,
2714a5d661aSToomas Soome 				fp->f_blk[level],
2724a5d661aSToomas Soome 				&fp->f_blksize[level]);
2734a5d661aSToomas Soome 			if (rc)
2744a5d661aSToomas Soome 				return (rc);
2754a5d661aSToomas Soome 			if (fp->f_blksize[level] != fs->fs_bsize)
2764a5d661aSToomas Soome 				return (EIO);
2774a5d661aSToomas Soome 			fp->f_blkno[level] = ind_block_num;
2784a5d661aSToomas Soome 		}
2794a5d661aSToomas Soome 
2804a5d661aSToomas Soome 		if (level > 0) {
2814a5d661aSToomas Soome 			idx = file_block / fp->f_nindir[level - 1];
2824a5d661aSToomas Soome 			file_block %= fp->f_nindir[level - 1];
2834a5d661aSToomas Soome 		} else
2844a5d661aSToomas Soome 			idx = file_block;
2854a5d661aSToomas Soome 
2864a5d661aSToomas Soome 		if (fp->f_fs->fs_magic == FS_UFS1_MAGIC)
2874a5d661aSToomas Soome 			ind_block_num = ((ufs1_daddr_t *)fp->f_blk[level])[idx];
2884a5d661aSToomas Soome 		else
2894a5d661aSToomas Soome 			ind_block_num = ((ufs2_daddr_t *)fp->f_blk[level])[idx];
2904a5d661aSToomas Soome 	}
2914a5d661aSToomas Soome 
2924a5d661aSToomas Soome 	*disk_block_p = ind_block_num;
2934a5d661aSToomas Soome 
2944a5d661aSToomas Soome 	return (0);
2954a5d661aSToomas Soome }
2964a5d661aSToomas Soome 
2974a5d661aSToomas Soome /*
2984a5d661aSToomas Soome  * Write a portion of a file from an internal buffer.
2994a5d661aSToomas Soome  */
3004a5d661aSToomas Soome static int
3014a5d661aSToomas Soome buf_write_file(f, buf_p, size_p)
3024a5d661aSToomas Soome 	struct open_file *f;
3034a5d661aSToomas Soome 	char *buf_p;
3044a5d661aSToomas Soome 	size_t *size_p;		/* out */
3054a5d661aSToomas Soome {
3064a5d661aSToomas Soome 	struct file *fp = (struct file *)f->f_fsdata;
3074a5d661aSToomas Soome 	struct fs *fs = fp->f_fs;
3084a5d661aSToomas Soome 	long off;
3094a5d661aSToomas Soome 	ufs_lbn_t file_block;
3104a5d661aSToomas Soome 	ufs2_daddr_t disk_block;
3114a5d661aSToomas Soome 	size_t block_size;
3124a5d661aSToomas Soome 	int rc;
3134a5d661aSToomas Soome 
3144a5d661aSToomas Soome 	/*
3154a5d661aSToomas Soome 	 * Calculate the starting block address and offset.
3164a5d661aSToomas Soome 	 */
3174a5d661aSToomas Soome 	off = blkoff(fs, fp->f_seekp);
3184a5d661aSToomas Soome 	file_block = lblkno(fs, fp->f_seekp);
3194a5d661aSToomas Soome 	block_size = sblksize(fs, DIP(fp, di_size), file_block);
3204a5d661aSToomas Soome 
3214a5d661aSToomas Soome 	rc = block_map(f, file_block, &disk_block);
3224a5d661aSToomas Soome 	if (rc)
3234a5d661aSToomas Soome 		return (rc);
3244a5d661aSToomas Soome 
3254a5d661aSToomas Soome  	if (disk_block == 0)
3264a5d661aSToomas Soome 		/* Because we can't allocate space on the drive */
3274a5d661aSToomas Soome 		return (EFBIG);
3284a5d661aSToomas Soome 
3294a5d661aSToomas Soome 	/*
3304a5d661aSToomas Soome 	 * Truncate buffer at end of file, and at the end of
3314a5d661aSToomas Soome 	 * this block.
3324a5d661aSToomas Soome 	 */
3334a5d661aSToomas Soome 	if (*size_p > DIP(fp, di_size) - fp->f_seekp)
3344a5d661aSToomas Soome 		*size_p = DIP(fp, di_size) - fp->f_seekp;
3354a5d661aSToomas Soome 	if (*size_p > block_size - off)
3364a5d661aSToomas Soome 		*size_p = block_size - off;
3374a5d661aSToomas Soome 
3384a5d661aSToomas Soome 	/*
3394a5d661aSToomas Soome 	 * If we don't entirely occlude the block and it's not
3404a5d661aSToomas Soome 	 * in memory already, read it in first.
3414a5d661aSToomas Soome 	 */
3424a5d661aSToomas Soome 	if (((off > 0) || (*size_p + off < block_size)) &&
3434a5d661aSToomas Soome 	    (file_block != fp->f_buf_blkno)) {
3444a5d661aSToomas Soome 
3454a5d661aSToomas Soome 		if (fp->f_buf == (char *)0)
3464a5d661aSToomas Soome 			fp->f_buf = malloc(fs->fs_bsize);
3474a5d661aSToomas Soome 
3484a5d661aSToomas Soome 		twiddle(8);
3494a5d661aSToomas Soome 		rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
350976852c7SToomas Soome 			fsbtodb(fs, disk_block),
3514a5d661aSToomas Soome 			block_size, fp->f_buf, &fp->f_buf_size);
3524a5d661aSToomas Soome 		if (rc)
3534a5d661aSToomas Soome 			return (rc);
3544a5d661aSToomas Soome 
3554a5d661aSToomas Soome 		fp->f_buf_blkno = file_block;
3564a5d661aSToomas Soome 	}
3574a5d661aSToomas Soome 
3584a5d661aSToomas Soome 	/*
3594a5d661aSToomas Soome 	 *	Copy the user data into the cached block.
3604a5d661aSToomas Soome 	 */
3614a5d661aSToomas Soome 	bcopy(buf_p, fp->f_buf + off, *size_p);
3624a5d661aSToomas Soome 
3634a5d661aSToomas Soome 	/*
3644a5d661aSToomas Soome 	 *	Write the block out to storage.
3654a5d661aSToomas Soome 	 */
3664a5d661aSToomas Soome 
3674a5d661aSToomas Soome 	twiddle(4);
3684a5d661aSToomas Soome 	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_WRITE,
369976852c7SToomas Soome 		fsbtodb(fs, disk_block),
3704a5d661aSToomas Soome 		block_size, fp->f_buf, &fp->f_buf_size);
3714a5d661aSToomas Soome 	return (rc);
3724a5d661aSToomas Soome }
3734a5d661aSToomas Soome 
3744a5d661aSToomas Soome /*
3754a5d661aSToomas Soome  * Read a portion of a file into an internal buffer.  Return
3764a5d661aSToomas Soome  * the location in the buffer and the amount in the buffer.
3774a5d661aSToomas Soome  */
3784a5d661aSToomas Soome static int
3794a5d661aSToomas Soome buf_read_file(f, buf_p, size_p)
3804a5d661aSToomas Soome 	struct open_file *f;
3814a5d661aSToomas Soome 	char **buf_p;		/* out */
3824a5d661aSToomas Soome 	size_t *size_p;		/* out */
3834a5d661aSToomas Soome {
3844a5d661aSToomas Soome 	struct file *fp = (struct file *)f->f_fsdata;
3854a5d661aSToomas Soome 	struct fs *fs = fp->f_fs;
3864a5d661aSToomas Soome 	long off;
3874a5d661aSToomas Soome 	ufs_lbn_t file_block;
3884a5d661aSToomas Soome 	ufs2_daddr_t disk_block;
3894a5d661aSToomas Soome 	size_t block_size;
3904a5d661aSToomas Soome 	int rc;
3914a5d661aSToomas Soome 
3924a5d661aSToomas Soome 	off = blkoff(fs, fp->f_seekp);
3934a5d661aSToomas Soome 	file_block = lblkno(fs, fp->f_seekp);
3944a5d661aSToomas Soome 	block_size = sblksize(fs, DIP(fp, di_size), file_block);
3954a5d661aSToomas Soome 
3964a5d661aSToomas Soome 	if (file_block != fp->f_buf_blkno) {
3974a5d661aSToomas Soome 		if (fp->f_buf == (char *)0)
3984a5d661aSToomas Soome 			fp->f_buf = malloc(fs->fs_bsize);
3994a5d661aSToomas Soome 
4004a5d661aSToomas Soome 		rc = block_map(f, file_block, &disk_block);
4014a5d661aSToomas Soome 		if (rc)
4024a5d661aSToomas Soome 			return (rc);
4034a5d661aSToomas Soome 
4044a5d661aSToomas Soome 		if (disk_block == 0) {
4054a5d661aSToomas Soome 			bzero(fp->f_buf, block_size);
4064a5d661aSToomas Soome 			fp->f_buf_size = block_size;
4074a5d661aSToomas Soome 		} else {
4084a5d661aSToomas Soome 			twiddle(4);
4094a5d661aSToomas Soome 			rc = (f->f_dev->dv_strategy)(f->f_devdata,
410976852c7SToomas Soome 				F_READ, fsbtodb(fs, disk_block),
4114a5d661aSToomas Soome 				block_size, fp->f_buf, &fp->f_buf_size);
4124a5d661aSToomas Soome 			if (rc)
4134a5d661aSToomas Soome 				return (rc);
4144a5d661aSToomas Soome 		}
4154a5d661aSToomas Soome 
4164a5d661aSToomas Soome 		fp->f_buf_blkno = file_block;
4174a5d661aSToomas Soome 	}
4184a5d661aSToomas Soome 
4194a5d661aSToomas Soome 	/*
4204a5d661aSToomas Soome 	 * Return address of byte in buffer corresponding to
4214a5d661aSToomas Soome 	 * offset, and size of remainder of buffer after that
4224a5d661aSToomas Soome 	 * byte.
4234a5d661aSToomas Soome 	 */
4244a5d661aSToomas Soome 	*buf_p = fp->f_buf + off;
4254a5d661aSToomas Soome 	*size_p = block_size - off;
4264a5d661aSToomas Soome 
4274a5d661aSToomas Soome 	/*
4284a5d661aSToomas Soome 	 * But truncate buffer at end of file.
4294a5d661aSToomas Soome 	 */
4304a5d661aSToomas Soome 	if (*size_p > DIP(fp, di_size) - fp->f_seekp)
4314a5d661aSToomas Soome 		*size_p = DIP(fp, di_size) - fp->f_seekp;
4324a5d661aSToomas Soome 
4334a5d661aSToomas Soome 	return (0);
4344a5d661aSToomas Soome }
4354a5d661aSToomas Soome 
4364a5d661aSToomas Soome /*
4374a5d661aSToomas Soome  * Search a directory for a name and return its
4384a5d661aSToomas Soome  * i_number.
4394a5d661aSToomas Soome  */
4404a5d661aSToomas Soome static int
4414a5d661aSToomas Soome search_directory(name, f, inumber_p)
4424a5d661aSToomas Soome 	char *name;
4434a5d661aSToomas Soome 	struct open_file *f;
4444a5d661aSToomas Soome 	ino_t *inumber_p;		/* out */
4454a5d661aSToomas Soome {
4464a5d661aSToomas Soome 	struct file *fp = (struct file *)f->f_fsdata;
4474a5d661aSToomas Soome 	struct direct *dp;
4484a5d661aSToomas Soome 	struct direct *edp;
4494a5d661aSToomas Soome 	char *buf;
4504a5d661aSToomas Soome 	size_t buf_size;
4514a5d661aSToomas Soome 	int namlen, length;
4524a5d661aSToomas Soome 	int rc;
4534a5d661aSToomas Soome 
4544a5d661aSToomas Soome 	length = strlen(name);
4554a5d661aSToomas Soome 
4564a5d661aSToomas Soome 	fp->f_seekp = 0;
4574a5d661aSToomas Soome 	while (fp->f_seekp < DIP(fp, di_size)) {
4584a5d661aSToomas Soome 		rc = buf_read_file(f, &buf, &buf_size);
4594a5d661aSToomas Soome 		if (rc)
4604a5d661aSToomas Soome 			return (rc);
4614a5d661aSToomas Soome 
4624a5d661aSToomas Soome 		dp = (struct direct *)buf;
4634a5d661aSToomas Soome 		edp = (struct direct *)(buf + buf_size);
4644a5d661aSToomas Soome 		while (dp < edp) {
4654a5d661aSToomas Soome 			if (dp->d_ino == (ino_t)0)
4664a5d661aSToomas Soome 				goto next;
4674a5d661aSToomas Soome 			namlen = dp->d_namlen;
4684a5d661aSToomas Soome 			if (namlen == length &&
4694a5d661aSToomas Soome 			    !strcmp(name, dp->d_name)) {
4704a5d661aSToomas Soome 				/* found entry */
4714a5d661aSToomas Soome 				*inumber_p = dp->d_ino;
4724a5d661aSToomas Soome 				return (0);
4734a5d661aSToomas Soome 			}
4744a5d661aSToomas Soome 		next:
4754a5d661aSToomas Soome 			dp = (struct direct *)((char *)dp + dp->d_reclen);
4764a5d661aSToomas Soome 		}
4774a5d661aSToomas Soome 		fp->f_seekp += buf_size;
4784a5d661aSToomas Soome 	}
4794a5d661aSToomas Soome 	return (ENOENT);
4804a5d661aSToomas Soome }
4814a5d661aSToomas Soome 
4824a5d661aSToomas Soome static int sblock_try[] = SBLOCKSEARCH;
4834a5d661aSToomas Soome 
4844a5d661aSToomas Soome /*
4854a5d661aSToomas Soome  * Open a file.
4864a5d661aSToomas Soome  */
4874a5d661aSToomas Soome static int
4884a5d661aSToomas Soome ufs_open(upath, f)
4894a5d661aSToomas Soome 	const char *upath;
4904a5d661aSToomas Soome 	struct open_file *f;
4914a5d661aSToomas Soome {
4924a5d661aSToomas Soome 	char *cp, *ncp;
4934a5d661aSToomas Soome 	int c;
4944a5d661aSToomas Soome 	ino_t inumber, parent_inumber;
4954a5d661aSToomas Soome 	struct file *fp;
4964a5d661aSToomas Soome 	struct fs *fs;
4974a5d661aSToomas Soome 	int i, rc;
4984a5d661aSToomas Soome 	size_t buf_size;
4994a5d661aSToomas Soome 	int nlinks = 0;
5004a5d661aSToomas Soome 	char namebuf[MAXPATHLEN+1];
5014a5d661aSToomas Soome 	char *buf = NULL;
5024a5d661aSToomas Soome 	char *path = NULL;
5034a5d661aSToomas Soome 
5044a5d661aSToomas Soome 	/* allocate file system specific data structure */
5054a5d661aSToomas Soome 	fp = malloc(sizeof(struct file));
5064a5d661aSToomas Soome 	bzero(fp, sizeof(struct file));
5074a5d661aSToomas Soome 	f->f_fsdata = (void *)fp;
5084a5d661aSToomas Soome 
5094a5d661aSToomas Soome 	/* allocate space and read super block */
5104a5d661aSToomas Soome 	fs = malloc(SBLOCKSIZE);
5114a5d661aSToomas Soome 	fp->f_fs = fs;
5124a5d661aSToomas Soome 	twiddle(1);
5134a5d661aSToomas Soome 	/*
5144a5d661aSToomas Soome 	 * Try reading the superblock in each of its possible locations.
5154a5d661aSToomas Soome 	 */
5164a5d661aSToomas Soome 	for (i = 0; sblock_try[i] != -1; i++) {
5174a5d661aSToomas Soome 		rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
518976852c7SToomas Soome 		    sblock_try[i] / DEV_BSIZE, SBLOCKSIZE,
5194a5d661aSToomas Soome 		    (char *)fs, &buf_size);
5204a5d661aSToomas Soome 		if (rc)
5214a5d661aSToomas Soome 			goto out;
5224a5d661aSToomas Soome 		if ((fs->fs_magic == FS_UFS1_MAGIC ||
5234a5d661aSToomas Soome 		     (fs->fs_magic == FS_UFS2_MAGIC &&
5244a5d661aSToomas Soome 		      fs->fs_sblockloc == sblock_try[i])) &&
5254a5d661aSToomas Soome 		    buf_size == SBLOCKSIZE &&
5264a5d661aSToomas Soome 		    fs->fs_bsize <= MAXBSIZE &&
5274a5d661aSToomas Soome 		    fs->fs_bsize >= sizeof(struct fs))
5284a5d661aSToomas Soome 			break;
5294a5d661aSToomas Soome 	}
5304a5d661aSToomas Soome 	if (sblock_try[i] == -1) {
5314a5d661aSToomas Soome 		rc = EINVAL;
5324a5d661aSToomas Soome 		goto out;
5334a5d661aSToomas Soome 	}
5344a5d661aSToomas Soome 	/*
5354a5d661aSToomas Soome 	 * Calculate indirect block levels.
5364a5d661aSToomas Soome 	 */
5374a5d661aSToomas Soome 	{
5384a5d661aSToomas Soome 		ufs2_daddr_t mult;
5394a5d661aSToomas Soome 		int level;
5404a5d661aSToomas Soome 
5414a5d661aSToomas Soome 		mult = 1;
5424a5d661aSToomas Soome 		for (level = 0; level < NIADDR; level++) {
5434a5d661aSToomas Soome 			mult *= NINDIR(fs);
5444a5d661aSToomas Soome 			fp->f_nindir[level] = mult;
5454a5d661aSToomas Soome 		}
5464a5d661aSToomas Soome 	}
5474a5d661aSToomas Soome 
5484a5d661aSToomas Soome 	inumber = ROOTINO;
5494a5d661aSToomas Soome 	if ((rc = read_inode(inumber, f)) != 0)
5504a5d661aSToomas Soome 		goto out;
5514a5d661aSToomas Soome 
5524a5d661aSToomas Soome 	cp = path = strdup(upath);
5534a5d661aSToomas Soome 	if (path == NULL) {
5544a5d661aSToomas Soome 	    rc = ENOMEM;
5554a5d661aSToomas Soome 	    goto out;
5564a5d661aSToomas Soome 	}
5574a5d661aSToomas Soome 	while (*cp) {
5584a5d661aSToomas Soome 
5594a5d661aSToomas Soome 		/*
5604a5d661aSToomas Soome 		 * Remove extra separators
5614a5d661aSToomas Soome 		 */
5624a5d661aSToomas Soome 		while (*cp == '/')
5634a5d661aSToomas Soome 			cp++;
5644a5d661aSToomas Soome 		if (*cp == '\0')
5654a5d661aSToomas Soome 			break;
5664a5d661aSToomas Soome 
5674a5d661aSToomas Soome 		/*
5684a5d661aSToomas Soome 		 * Check that current node is a directory.
5694a5d661aSToomas Soome 		 */
5704a5d661aSToomas Soome 		if ((DIP(fp, di_mode) & IFMT) != IFDIR) {
5714a5d661aSToomas Soome 			rc = ENOTDIR;
5724a5d661aSToomas Soome 			goto out;
5734a5d661aSToomas Soome 		}
5744a5d661aSToomas Soome 
5754a5d661aSToomas Soome 		/*
5764a5d661aSToomas Soome 		 * Get next component of path name.
5774a5d661aSToomas Soome 		 */
5784a5d661aSToomas Soome 		{
5794a5d661aSToomas Soome 			int len = 0;
5804a5d661aSToomas Soome 
5814a5d661aSToomas Soome 			ncp = cp;
5824a5d661aSToomas Soome 			while ((c = *cp) != '\0' && c != '/') {
583*e48f27a0SToomas Soome 				if (++len > UFS_MAXNAMLEN) {
5844a5d661aSToomas Soome 					rc = ENOENT;
5854a5d661aSToomas Soome 					goto out;
5864a5d661aSToomas Soome 				}
5874a5d661aSToomas Soome 				cp++;
5884a5d661aSToomas Soome 			}
5894a5d661aSToomas Soome 			*cp = '\0';
5904a5d661aSToomas Soome 		}
5914a5d661aSToomas Soome 
5924a5d661aSToomas Soome 		/*
5934a5d661aSToomas Soome 		 * Look up component in current directory.
5944a5d661aSToomas Soome 		 * Save directory inumber in case we find a
5954a5d661aSToomas Soome 		 * symbolic link.
5964a5d661aSToomas Soome 		 */
5974a5d661aSToomas Soome 		parent_inumber = inumber;
5984a5d661aSToomas Soome 		rc = search_directory(ncp, f, &inumber);
5994a5d661aSToomas Soome 		*cp = c;
6004a5d661aSToomas Soome 		if (rc)
6014a5d661aSToomas Soome 			goto out;
6024a5d661aSToomas Soome 
6034a5d661aSToomas Soome 		/*
6044a5d661aSToomas Soome 		 * Open next component.
6054a5d661aSToomas Soome 		 */
6064a5d661aSToomas Soome 		if ((rc = read_inode(inumber, f)) != 0)
6074a5d661aSToomas Soome 			goto out;
6084a5d661aSToomas Soome 
6094a5d661aSToomas Soome 		/*
6104a5d661aSToomas Soome 		 * Check for symbolic link.
6114a5d661aSToomas Soome 		 */
6124a5d661aSToomas Soome 		if ((DIP(fp, di_mode) & IFMT) == IFLNK) {
6134a5d661aSToomas Soome 			int link_len = DIP(fp, di_size);
6144a5d661aSToomas Soome 			int len;
6154a5d661aSToomas Soome 
6164a5d661aSToomas Soome 			len = strlen(cp);
6174a5d661aSToomas Soome 
6184a5d661aSToomas Soome 			if (link_len + len > MAXPATHLEN ||
6194a5d661aSToomas Soome 			    ++nlinks > MAXSYMLINKS) {
6204a5d661aSToomas Soome 				rc = ENOENT;
6214a5d661aSToomas Soome 				goto out;
6224a5d661aSToomas Soome 			}
6234a5d661aSToomas Soome 
6244a5d661aSToomas Soome 			bcopy(cp, &namebuf[link_len], len + 1);
6254a5d661aSToomas Soome 
6264a5d661aSToomas Soome 			if (link_len < fs->fs_maxsymlinklen) {
6274a5d661aSToomas Soome 				if (fp->f_fs->fs_magic == FS_UFS1_MAGIC)
6284a5d661aSToomas Soome 					cp = (caddr_t)(fp->f_di.di1.di_db);
6294a5d661aSToomas Soome 				else
6304a5d661aSToomas Soome 					cp = (caddr_t)(fp->f_di.di2.di_db);
6314a5d661aSToomas Soome 				bcopy(cp, namebuf, (unsigned) link_len);
6324a5d661aSToomas Soome 			} else {
6334a5d661aSToomas Soome 				/*
6344a5d661aSToomas Soome 				 * Read file for symbolic link
6354a5d661aSToomas Soome 				 */
6364a5d661aSToomas Soome 				size_t buf_size;
6374a5d661aSToomas Soome 				ufs2_daddr_t disk_block;
6384a5d661aSToomas Soome 				struct fs *fs = fp->f_fs;
6394a5d661aSToomas Soome 
6404a5d661aSToomas Soome 				if (!buf)
6414a5d661aSToomas Soome 					buf = malloc(fs->fs_bsize);
6424a5d661aSToomas Soome 				rc = block_map(f, (ufs2_daddr_t)0, &disk_block);
6434a5d661aSToomas Soome 				if (rc)
6444a5d661aSToomas Soome 					goto out;
6454a5d661aSToomas Soome 
6464a5d661aSToomas Soome 				twiddle(1);
6474a5d661aSToomas Soome 				rc = (f->f_dev->dv_strategy)(f->f_devdata,
648976852c7SToomas Soome 					F_READ, fsbtodb(fs, disk_block),
6494a5d661aSToomas Soome 					fs->fs_bsize, buf, &buf_size);
6504a5d661aSToomas Soome 				if (rc)
6514a5d661aSToomas Soome 					goto out;
6524a5d661aSToomas Soome 
6534a5d661aSToomas Soome 				bcopy((char *)buf, namebuf, (unsigned)link_len);
6544a5d661aSToomas Soome 			}
6554a5d661aSToomas Soome 
6564a5d661aSToomas Soome 			/*
6574a5d661aSToomas Soome 			 * If relative pathname, restart at parent directory.
6584a5d661aSToomas Soome 			 * If absolute pathname, restart at root.
6594a5d661aSToomas Soome 			 */
6604a5d661aSToomas Soome 			cp = namebuf;
6614a5d661aSToomas Soome 			if (*cp != '/')
6624a5d661aSToomas Soome 				inumber = parent_inumber;
6634a5d661aSToomas Soome 			else
6644a5d661aSToomas Soome 				inumber = (ino_t)ROOTINO;
6654a5d661aSToomas Soome 
6664a5d661aSToomas Soome 			if ((rc = read_inode(inumber, f)) != 0)
6674a5d661aSToomas Soome 				goto out;
6684a5d661aSToomas Soome 		}
6694a5d661aSToomas Soome 	}
6704a5d661aSToomas Soome 
6714a5d661aSToomas Soome 	/*
6724a5d661aSToomas Soome 	 * Found terminal component.
6734a5d661aSToomas Soome 	 */
6744a5d661aSToomas Soome 	rc = 0;
6754a5d661aSToomas Soome 	fp->f_seekp = 0;
6764a5d661aSToomas Soome out:
6774a5d661aSToomas Soome 	if (buf)
6784a5d661aSToomas Soome 		free(buf);
6794a5d661aSToomas Soome 	if (path)
6804a5d661aSToomas Soome 		free(path);
6814a5d661aSToomas Soome 	if (rc) {
6824a5d661aSToomas Soome 		if (fp->f_buf)
6834a5d661aSToomas Soome 			free(fp->f_buf);
6844a5d661aSToomas Soome 		free(fp->f_fs);
6854a5d661aSToomas Soome 		free(fp);
6864a5d661aSToomas Soome 	}
6874a5d661aSToomas Soome 	return (rc);
6884a5d661aSToomas Soome }
6894a5d661aSToomas Soome 
6904a5d661aSToomas Soome static int
6914a5d661aSToomas Soome ufs_close(f)
6924a5d661aSToomas Soome 	struct open_file *f;
6934a5d661aSToomas Soome {
6944a5d661aSToomas Soome 	struct file *fp = (struct file *)f->f_fsdata;
6954a5d661aSToomas Soome 	int level;
6964a5d661aSToomas Soome 
6974a5d661aSToomas Soome 	f->f_fsdata = (void *)0;
6984a5d661aSToomas Soome 	if (fp == (struct file *)0)
6994a5d661aSToomas Soome 		return (0);
7004a5d661aSToomas Soome 
7014a5d661aSToomas Soome 	for (level = 0; level < NIADDR; level++) {
7024a5d661aSToomas Soome 		if (fp->f_blk[level])
7034a5d661aSToomas Soome 			free(fp->f_blk[level]);
7044a5d661aSToomas Soome 	}
7054a5d661aSToomas Soome 	if (fp->f_buf)
7064a5d661aSToomas Soome 		free(fp->f_buf);
7074a5d661aSToomas Soome 	free(fp->f_fs);
7084a5d661aSToomas Soome 	free(fp);
7094a5d661aSToomas Soome 	return (0);
7104a5d661aSToomas Soome }
7114a5d661aSToomas Soome 
7124a5d661aSToomas Soome /*
7134a5d661aSToomas Soome  * Copy a portion of a file into kernel memory.
7144a5d661aSToomas Soome  * Cross block boundaries when necessary.
7154a5d661aSToomas Soome  */
7164a5d661aSToomas Soome static int
7174a5d661aSToomas Soome ufs_read(f, start, size, resid)
7184a5d661aSToomas Soome 	struct open_file *f;
7194a5d661aSToomas Soome 	void *start;
7204a5d661aSToomas Soome 	size_t size;
7214a5d661aSToomas Soome 	size_t *resid;	/* out */
7224a5d661aSToomas Soome {
7234a5d661aSToomas Soome 	struct file *fp = (struct file *)f->f_fsdata;
7244a5d661aSToomas Soome 	size_t csize;
7254a5d661aSToomas Soome 	char *buf;
7264a5d661aSToomas Soome 	size_t buf_size;
7274a5d661aSToomas Soome 	int rc = 0;
7284a5d661aSToomas Soome 	char *addr = start;
7294a5d661aSToomas Soome 
7304a5d661aSToomas Soome 	while (size != 0) {
7314a5d661aSToomas Soome 		if (fp->f_seekp >= DIP(fp, di_size))
7324a5d661aSToomas Soome 			break;
7334a5d661aSToomas Soome 
7344a5d661aSToomas Soome 		rc = buf_read_file(f, &buf, &buf_size);
7354a5d661aSToomas Soome 		if (rc)
7364a5d661aSToomas Soome 			break;
7374a5d661aSToomas Soome 
7384a5d661aSToomas Soome 		csize = size;
7394a5d661aSToomas Soome 		if (csize > buf_size)
7404a5d661aSToomas Soome 			csize = buf_size;
7414a5d661aSToomas Soome 
7424a5d661aSToomas Soome 		bcopy(buf, addr, csize);
7434a5d661aSToomas Soome 
7444a5d661aSToomas Soome 		fp->f_seekp += csize;
7454a5d661aSToomas Soome 		addr += csize;
7464a5d661aSToomas Soome 		size -= csize;
7474a5d661aSToomas Soome 	}
7484a5d661aSToomas Soome 	if (resid)
7494a5d661aSToomas Soome 		*resid = size;
7504a5d661aSToomas Soome 	return (rc);
7514a5d661aSToomas Soome }
7524a5d661aSToomas Soome 
7534a5d661aSToomas Soome /*
7544a5d661aSToomas Soome  * Write to a portion of an already allocated file.
7554a5d661aSToomas Soome  * Cross block boundaries when necessary. Can not
7564a5d661aSToomas Soome  * extend the file.
7574a5d661aSToomas Soome  */
7584a5d661aSToomas Soome static int
7594a5d661aSToomas Soome ufs_write(f, start, size, resid)
7604a5d661aSToomas Soome 	struct open_file *f;
7614a5d661aSToomas Soome 	void *start;
7624a5d661aSToomas Soome 	size_t size;
7634a5d661aSToomas Soome 	size_t *resid;	/* out */
7644a5d661aSToomas Soome {
7654a5d661aSToomas Soome 	struct file *fp = (struct file *)f->f_fsdata;
7664a5d661aSToomas Soome 	size_t csize;
7674a5d661aSToomas Soome 	int rc = 0;
7684a5d661aSToomas Soome 	char *addr = start;
7694a5d661aSToomas Soome 
7704a5d661aSToomas Soome 	csize = size;
7714a5d661aSToomas Soome 	while ((size != 0) && (csize != 0)) {
7724a5d661aSToomas Soome 		if (fp->f_seekp >= DIP(fp, di_size))
7734a5d661aSToomas Soome 			break;
7744a5d661aSToomas Soome 
7754a5d661aSToomas Soome 		if (csize >= 512) csize = 512; /* XXX */
7764a5d661aSToomas Soome 
7774a5d661aSToomas Soome 		rc = buf_write_file(f, addr, &csize);
7784a5d661aSToomas Soome 		if (rc)
7794a5d661aSToomas Soome 			break;
7804a5d661aSToomas Soome 
7814a5d661aSToomas Soome 		fp->f_seekp += csize;
7824a5d661aSToomas Soome 		addr += csize;
7834a5d661aSToomas Soome 		size -= csize;
7844a5d661aSToomas Soome 	}
7854a5d661aSToomas Soome 	if (resid)
7864a5d661aSToomas Soome 		*resid = size;
7874a5d661aSToomas Soome 	return (rc);
7884a5d661aSToomas Soome }
7894a5d661aSToomas Soome 
7904a5d661aSToomas Soome static off_t
7914a5d661aSToomas Soome ufs_seek(f, offset, where)
7924a5d661aSToomas Soome 	struct open_file *f;
7934a5d661aSToomas Soome 	off_t offset;
7944a5d661aSToomas Soome 	int where;
7954a5d661aSToomas Soome {
7964a5d661aSToomas Soome 	struct file *fp = (struct file *)f->f_fsdata;
7974a5d661aSToomas Soome 
7984a5d661aSToomas Soome 	switch (where) {
7994a5d661aSToomas Soome 	case SEEK_SET:
8004a5d661aSToomas Soome 		fp->f_seekp = offset;
8014a5d661aSToomas Soome 		break;
8024a5d661aSToomas Soome 	case SEEK_CUR:
8034a5d661aSToomas Soome 		fp->f_seekp += offset;
8044a5d661aSToomas Soome 		break;
8054a5d661aSToomas Soome 	case SEEK_END:
8064a5d661aSToomas Soome 		fp->f_seekp = DIP(fp, di_size) - offset;
8074a5d661aSToomas Soome 		break;
8084a5d661aSToomas Soome 	default:
8094a5d661aSToomas Soome 		errno = EINVAL;
8104a5d661aSToomas Soome 		return (-1);
8114a5d661aSToomas Soome 	}
8124a5d661aSToomas Soome 	return (fp->f_seekp);
8134a5d661aSToomas Soome }
8144a5d661aSToomas Soome 
8154a5d661aSToomas Soome static int
8164a5d661aSToomas Soome ufs_stat(f, sb)
8174a5d661aSToomas Soome 	struct open_file *f;
8184a5d661aSToomas Soome 	struct stat *sb;
8194a5d661aSToomas Soome {
8204a5d661aSToomas Soome 	struct file *fp = (struct file *)f->f_fsdata;
8214a5d661aSToomas Soome 
8224a5d661aSToomas Soome 	/* only important stuff */
8234a5d661aSToomas Soome 	sb->st_mode = DIP(fp, di_mode);
8244a5d661aSToomas Soome 	sb->st_uid = DIP(fp, di_uid);
8254a5d661aSToomas Soome 	sb->st_gid = DIP(fp, di_gid);
8264a5d661aSToomas Soome 	sb->st_size = DIP(fp, di_size);
8274a5d661aSToomas Soome 	return (0);
8284a5d661aSToomas Soome }
8294a5d661aSToomas Soome 
8304a5d661aSToomas Soome static int
8314a5d661aSToomas Soome ufs_readdir(struct open_file *f, struct dirent *d)
8324a5d661aSToomas Soome {
8334a5d661aSToomas Soome 	struct file *fp = (struct file *)f->f_fsdata;
8344a5d661aSToomas Soome 	struct direct *dp;
8354a5d661aSToomas Soome 	char *buf;
8364a5d661aSToomas Soome 	size_t buf_size;
8374a5d661aSToomas Soome 	int error;
8384a5d661aSToomas Soome 
8394a5d661aSToomas Soome 	/*
8404a5d661aSToomas Soome 	 * assume that a directory entry will not be split across blocks
8414a5d661aSToomas Soome 	 */
8424a5d661aSToomas Soome again:
8434a5d661aSToomas Soome 	if (fp->f_seekp >= DIP(fp, di_size))
8444a5d661aSToomas Soome 		return (ENOENT);
8454a5d661aSToomas Soome 	error = buf_read_file(f, &buf, &buf_size);
8464a5d661aSToomas Soome 	if (error)
8474a5d661aSToomas Soome 		return (error);
8484a5d661aSToomas Soome 	dp = (struct direct *)buf;
8494a5d661aSToomas Soome 	fp->f_seekp += dp->d_reclen;
8504a5d661aSToomas Soome 	if (dp->d_ino == (ino_t)0)
8514a5d661aSToomas Soome 		goto again;
8524a5d661aSToomas Soome 
8534a5d661aSToomas Soome 	d->d_type = 0;		/* illumos ufs does not have type in direct */
8544a5d661aSToomas Soome 	strcpy(d->d_name, dp->d_name);
8554a5d661aSToomas Soome 	return (0);
8564a5d661aSToomas Soome }
857