xref: /titanic_51/usr/src/boot/lib/libstand/ufs.c (revision 976852c7c99379de5f63105094194b9024a54029)
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 __FBSDID("$FreeBSD$");
724a5d661aSToomas Soome 
734a5d661aSToomas Soome /*
744a5d661aSToomas Soome  *	Stand-alone file reading package.
754a5d661aSToomas Soome  */
764a5d661aSToomas Soome 
774a5d661aSToomas Soome #include <sys/param.h>
784a5d661aSToomas Soome #include <sys/disklabel.h>
794a5d661aSToomas Soome #include <sys/time.h>
804a5d661aSToomas Soome #include <ufs/ufs/dinode.h>
814a5d661aSToomas Soome #include <ufs/ufs/dir.h>
824a5d661aSToomas Soome #include <ufs/ffs/fs.h>
834a5d661aSToomas Soome #include "stand.h"
844a5d661aSToomas Soome #include "string.h"
854a5d661aSToomas Soome 
864a5d661aSToomas Soome static int	ufs_open(const char *path, struct open_file *f);
874a5d661aSToomas Soome static int	ufs_write(struct open_file *f, void *buf, size_t size, size_t *resid);
884a5d661aSToomas Soome static int	ufs_close(struct open_file *f);
894a5d661aSToomas Soome static int	ufs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
904a5d661aSToomas Soome static off_t	ufs_seek(struct open_file *f, off_t offset, int where);
914a5d661aSToomas Soome static int	ufs_stat(struct open_file *f, struct stat *sb);
924a5d661aSToomas Soome static int	ufs_readdir(struct open_file *f, struct dirent *d);
934a5d661aSToomas Soome 
944a5d661aSToomas Soome struct fs_ops ufs_fsops = {
954a5d661aSToomas Soome 	"ufs",
964a5d661aSToomas Soome 	ufs_open,
974a5d661aSToomas Soome 	ufs_close,
984a5d661aSToomas Soome 	ufs_read,
994a5d661aSToomas Soome 	ufs_write,
1004a5d661aSToomas Soome 	ufs_seek,
1014a5d661aSToomas Soome 	ufs_stat,
1024a5d661aSToomas Soome 	ufs_readdir
1034a5d661aSToomas Soome };
1044a5d661aSToomas Soome 
1054a5d661aSToomas Soome /*
1064a5d661aSToomas Soome  * In-core open file.
1074a5d661aSToomas Soome  */
1084a5d661aSToomas Soome struct file {
1094a5d661aSToomas Soome 	off_t		f_seekp;	/* seek pointer */
1104a5d661aSToomas Soome 	struct fs	*f_fs;		/* pointer to super-block */
1114a5d661aSToomas Soome 	union dinode {
1124a5d661aSToomas Soome 		struct ufs1_dinode di1;
1134a5d661aSToomas Soome 		struct ufs2_dinode di2;
1144a5d661aSToomas Soome 	}		f_di;		/* copy of on-disk inode */
1154a5d661aSToomas Soome 	int		f_nindir[NIADDR];
1164a5d661aSToomas Soome 					/* number of blocks mapped by
1174a5d661aSToomas Soome 					   indirect block at level i */
1184a5d661aSToomas Soome 	char		*f_blk[NIADDR];	/* buffer for indirect block at
1194a5d661aSToomas Soome 					   level i */
1204a5d661aSToomas Soome 	size_t		f_blksize[NIADDR];
1214a5d661aSToomas Soome 					/* size of buffer */
1224a5d661aSToomas Soome 	ufs2_daddr_t	f_blkno[NIADDR];/* disk address of block in buffer */
1234a5d661aSToomas Soome 	ufs2_daddr_t	f_buf_blkno;	/* block number of data block */
1244a5d661aSToomas Soome 	char		*f_buf;		/* buffer for data block */
1254a5d661aSToomas Soome 	size_t		f_buf_size;	/* size of data block */
1264a5d661aSToomas Soome };
1274a5d661aSToomas Soome #define DIP(fp, field) \
1284a5d661aSToomas Soome 	((fp)->f_fs->fs_magic == FS_UFS1_MAGIC ? \
1294a5d661aSToomas Soome 	(fp)->f_di.di1.field : (fp)->f_di.di2.field)
1304a5d661aSToomas Soome 
1314a5d661aSToomas Soome static int	read_inode(ino_t, struct open_file *);
1324a5d661aSToomas Soome static int	block_map(struct open_file *, ufs2_daddr_t, ufs2_daddr_t *);
1334a5d661aSToomas Soome static int	buf_read_file(struct open_file *, char **, size_t *);
1344a5d661aSToomas Soome static int	buf_write_file(struct open_file *, char *, size_t *);
1354a5d661aSToomas Soome static int	search_directory(char *, struct open_file *, ino_t *);
1364a5d661aSToomas Soome 
1374a5d661aSToomas Soome /*
1384a5d661aSToomas Soome  * Read a new inode into a file structure.
1394a5d661aSToomas Soome  */
1404a5d661aSToomas Soome static int
1414a5d661aSToomas Soome read_inode(inumber, f)
1424a5d661aSToomas Soome 	ino_t inumber;
1434a5d661aSToomas Soome 	struct open_file *f;
1444a5d661aSToomas Soome {
1454a5d661aSToomas Soome 	struct file *fp = (struct file *)f->f_fsdata;
1464a5d661aSToomas Soome 	struct fs *fs = fp->f_fs;
1474a5d661aSToomas Soome 	char *buf;
1484a5d661aSToomas Soome 	size_t rsize;
1494a5d661aSToomas Soome 	int rc;
1504a5d661aSToomas Soome 
1514a5d661aSToomas Soome 	if (fs == NULL)
1524a5d661aSToomas Soome 	    panic("fs == NULL");
1534a5d661aSToomas Soome 
1544a5d661aSToomas Soome 	/*
1554a5d661aSToomas Soome 	 * Read inode and save it.
1564a5d661aSToomas Soome 	 */
1574a5d661aSToomas Soome 	buf = malloc(fs->fs_bsize);
1584a5d661aSToomas Soome 	twiddle(1);
1594a5d661aSToomas Soome 	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
160*976852c7SToomas Soome 		fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize,
1614a5d661aSToomas Soome 		buf, &rsize);
1624a5d661aSToomas Soome 	if (rc)
1634a5d661aSToomas Soome 		goto out;
1644a5d661aSToomas Soome 	if (rsize != fs->fs_bsize) {
1654a5d661aSToomas Soome 		rc = EIO;
1664a5d661aSToomas Soome 		goto out;
1674a5d661aSToomas Soome 	}
1684a5d661aSToomas Soome 
1694a5d661aSToomas Soome 	if (fp->f_fs->fs_magic == FS_UFS1_MAGIC)
1704a5d661aSToomas Soome 		fp->f_di.di1 = ((struct ufs1_dinode *)buf)
1714a5d661aSToomas Soome 		    [ino_to_fsbo(fs, inumber)];
1724a5d661aSToomas Soome 	else
1734a5d661aSToomas Soome 		fp->f_di.di2 = ((struct ufs2_dinode *)buf)
1744a5d661aSToomas Soome 		    [ino_to_fsbo(fs, inumber)];
1754a5d661aSToomas Soome 
1764a5d661aSToomas Soome 	/*
1774a5d661aSToomas Soome 	 * Clear out the old buffers
1784a5d661aSToomas Soome 	 */
1794a5d661aSToomas Soome 	{
1804a5d661aSToomas Soome 		int level;
1814a5d661aSToomas Soome 
1824a5d661aSToomas Soome 		for (level = 0; level < NIADDR; level++)
1834a5d661aSToomas Soome 			fp->f_blkno[level] = -1;
1844a5d661aSToomas Soome 		fp->f_buf_blkno = -1;
1854a5d661aSToomas Soome 	}
1864a5d661aSToomas Soome 	fp->f_seekp = 0;
1874a5d661aSToomas Soome out:
1884a5d661aSToomas Soome 	free(buf);
1894a5d661aSToomas Soome 	return (rc);
1904a5d661aSToomas Soome }
1914a5d661aSToomas Soome 
1924a5d661aSToomas Soome /*
1934a5d661aSToomas Soome  * Given an offset in a file, find the disk block number that
1944a5d661aSToomas Soome  * contains that block.
1954a5d661aSToomas Soome  */
1964a5d661aSToomas Soome static int
1974a5d661aSToomas Soome block_map(f, file_block, disk_block_p)
1984a5d661aSToomas Soome 	struct open_file *f;
1994a5d661aSToomas Soome 	ufs2_daddr_t file_block;
2004a5d661aSToomas Soome 	ufs2_daddr_t *disk_block_p;	/* out */
2014a5d661aSToomas Soome {
2024a5d661aSToomas Soome 	struct file *fp = (struct file *)f->f_fsdata;
2034a5d661aSToomas Soome 	struct fs *fs = fp->f_fs;
2044a5d661aSToomas Soome 	int level;
2054a5d661aSToomas Soome 	int idx;
2064a5d661aSToomas Soome 	ufs2_daddr_t ind_block_num;
2074a5d661aSToomas Soome 	int rc;
2084a5d661aSToomas Soome 
2094a5d661aSToomas Soome 	/*
2104a5d661aSToomas Soome 	 * Index structure of an inode:
2114a5d661aSToomas Soome 	 *
2124a5d661aSToomas Soome 	 * di_db[0..NDADDR-1]	hold block numbers for blocks
2134a5d661aSToomas Soome 	 *			0..NDADDR-1
2144a5d661aSToomas Soome 	 *
2154a5d661aSToomas Soome 	 * di_ib[0]		index block 0 is the single indirect block
2164a5d661aSToomas Soome 	 *			holds block numbers for blocks
2174a5d661aSToomas Soome 	 *			NDADDR .. NDADDR + NINDIR(fs)-1
2184a5d661aSToomas Soome 	 *
2194a5d661aSToomas Soome 	 * di_ib[1]		index block 1 is the double indirect block
2204a5d661aSToomas Soome 	 *			holds block numbers for INDEX blocks for blocks
2214a5d661aSToomas Soome 	 *			NDADDR + NINDIR(fs) ..
2224a5d661aSToomas Soome 	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1
2234a5d661aSToomas Soome 	 *
2244a5d661aSToomas Soome 	 * di_ib[2]		index block 2 is the triple indirect block
2254a5d661aSToomas Soome 	 *			holds block numbers for double-indirect
2264a5d661aSToomas Soome 	 *			blocks for blocks
2274a5d661aSToomas Soome 	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2 ..
2284a5d661aSToomas Soome 	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2
2294a5d661aSToomas Soome 	 *				+ NINDIR(fs)**3 - 1
2304a5d661aSToomas Soome 	 */
2314a5d661aSToomas Soome 
2324a5d661aSToomas Soome 	if (file_block < NDADDR) {
2334a5d661aSToomas Soome 		/* Direct block. */
2344a5d661aSToomas Soome 		*disk_block_p = DIP(fp, di_db[file_block]);
2354a5d661aSToomas Soome 		return (0);
2364a5d661aSToomas Soome 	}
2374a5d661aSToomas Soome 
2384a5d661aSToomas Soome 	file_block -= NDADDR;
2394a5d661aSToomas Soome 
2404a5d661aSToomas Soome 	/*
2414a5d661aSToomas Soome 	 * nindir[0] = NINDIR
2424a5d661aSToomas Soome 	 * nindir[1] = NINDIR**2
2434a5d661aSToomas Soome 	 * nindir[2] = NINDIR**3
2444a5d661aSToomas Soome 	 *	etc
2454a5d661aSToomas Soome 	 */
2464a5d661aSToomas Soome 	for (level = 0; level < NIADDR; level++) {
2474a5d661aSToomas Soome 		if (file_block < fp->f_nindir[level])
2484a5d661aSToomas Soome 			break;
2494a5d661aSToomas Soome 		file_block -= fp->f_nindir[level];
2504a5d661aSToomas Soome 	}
2514a5d661aSToomas Soome 	if (level == NIADDR) {
2524a5d661aSToomas Soome 		/* Block number too high */
2534a5d661aSToomas Soome 		return (EFBIG);
2544a5d661aSToomas Soome 	}
2554a5d661aSToomas Soome 
2564a5d661aSToomas Soome 	ind_block_num = DIP(fp, di_ib[level]);
2574a5d661aSToomas Soome 
2584a5d661aSToomas Soome 	for (; level >= 0; level--) {
2594a5d661aSToomas Soome 		if (ind_block_num == 0) {
2604a5d661aSToomas Soome 			*disk_block_p = 0;	/* missing */
2614a5d661aSToomas Soome 			return (0);
2624a5d661aSToomas Soome 		}
2634a5d661aSToomas Soome 
2644a5d661aSToomas Soome 		if (fp->f_blkno[level] != ind_block_num) {
2654a5d661aSToomas Soome 			if (fp->f_blk[level] == (char *)0)
2664a5d661aSToomas Soome 				fp->f_blk[level] =
2674a5d661aSToomas Soome 					malloc(fs->fs_bsize);
2684a5d661aSToomas Soome 			twiddle(1);
2694a5d661aSToomas Soome 			rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
270*976852c7SToomas Soome 				fsbtodb(fp->f_fs, ind_block_num),
2714a5d661aSToomas Soome 				fs->fs_bsize,
2724a5d661aSToomas Soome 				fp->f_blk[level],
2734a5d661aSToomas Soome 				&fp->f_blksize[level]);
2744a5d661aSToomas Soome 			if (rc)
2754a5d661aSToomas Soome 				return (rc);
2764a5d661aSToomas Soome 			if (fp->f_blksize[level] != fs->fs_bsize)
2774a5d661aSToomas Soome 				return (EIO);
2784a5d661aSToomas Soome 			fp->f_blkno[level] = ind_block_num;
2794a5d661aSToomas Soome 		}
2804a5d661aSToomas Soome 
2814a5d661aSToomas Soome 		if (level > 0) {
2824a5d661aSToomas Soome 			idx = file_block / fp->f_nindir[level - 1];
2834a5d661aSToomas Soome 			file_block %= fp->f_nindir[level - 1];
2844a5d661aSToomas Soome 		} else
2854a5d661aSToomas Soome 			idx = file_block;
2864a5d661aSToomas Soome 
2874a5d661aSToomas Soome 		if (fp->f_fs->fs_magic == FS_UFS1_MAGIC)
2884a5d661aSToomas Soome 			ind_block_num = ((ufs1_daddr_t *)fp->f_blk[level])[idx];
2894a5d661aSToomas Soome 		else
2904a5d661aSToomas Soome 			ind_block_num = ((ufs2_daddr_t *)fp->f_blk[level])[idx];
2914a5d661aSToomas Soome 	}
2924a5d661aSToomas Soome 
2934a5d661aSToomas Soome 	*disk_block_p = ind_block_num;
2944a5d661aSToomas Soome 
2954a5d661aSToomas Soome 	return (0);
2964a5d661aSToomas Soome }
2974a5d661aSToomas Soome 
2984a5d661aSToomas Soome /*
2994a5d661aSToomas Soome  * Write a portion of a file from an internal buffer.
3004a5d661aSToomas Soome  */
3014a5d661aSToomas Soome static int
3024a5d661aSToomas Soome buf_write_file(f, buf_p, size_p)
3034a5d661aSToomas Soome 	struct open_file *f;
3044a5d661aSToomas Soome 	char *buf_p;
3054a5d661aSToomas Soome 	size_t *size_p;		/* out */
3064a5d661aSToomas Soome {
3074a5d661aSToomas Soome 	struct file *fp = (struct file *)f->f_fsdata;
3084a5d661aSToomas Soome 	struct fs *fs = fp->f_fs;
3094a5d661aSToomas Soome 	long off;
3104a5d661aSToomas Soome 	ufs_lbn_t file_block;
3114a5d661aSToomas Soome 	ufs2_daddr_t disk_block;
3124a5d661aSToomas Soome 	size_t block_size;
3134a5d661aSToomas Soome 	int rc;
3144a5d661aSToomas Soome 
3154a5d661aSToomas Soome 	/*
3164a5d661aSToomas Soome 	 * Calculate the starting block address and offset.
3174a5d661aSToomas Soome 	 */
3184a5d661aSToomas Soome 	off = blkoff(fs, fp->f_seekp);
3194a5d661aSToomas Soome 	file_block = lblkno(fs, fp->f_seekp);
3204a5d661aSToomas Soome 	block_size = sblksize(fs, DIP(fp, di_size), file_block);
3214a5d661aSToomas Soome 
3224a5d661aSToomas Soome 	rc = block_map(f, file_block, &disk_block);
3234a5d661aSToomas Soome 	if (rc)
3244a5d661aSToomas Soome 		return (rc);
3254a5d661aSToomas Soome 
3264a5d661aSToomas Soome  	if (disk_block == 0)
3274a5d661aSToomas Soome 		/* Because we can't allocate space on the drive */
3284a5d661aSToomas Soome 		return (EFBIG);
3294a5d661aSToomas Soome 
3304a5d661aSToomas Soome 	/*
3314a5d661aSToomas Soome 	 * Truncate buffer at end of file, and at the end of
3324a5d661aSToomas Soome 	 * this block.
3334a5d661aSToomas Soome 	 */
3344a5d661aSToomas Soome 	if (*size_p > DIP(fp, di_size) - fp->f_seekp)
3354a5d661aSToomas Soome 		*size_p = DIP(fp, di_size) - fp->f_seekp;
3364a5d661aSToomas Soome 	if (*size_p > block_size - off)
3374a5d661aSToomas Soome 		*size_p = block_size - off;
3384a5d661aSToomas Soome 
3394a5d661aSToomas Soome 	/*
3404a5d661aSToomas Soome 	 * If we don't entirely occlude the block and it's not
3414a5d661aSToomas Soome 	 * in memory already, read it in first.
3424a5d661aSToomas Soome 	 */
3434a5d661aSToomas Soome 	if (((off > 0) || (*size_p + off < block_size)) &&
3444a5d661aSToomas Soome 	    (file_block != fp->f_buf_blkno)) {
3454a5d661aSToomas Soome 
3464a5d661aSToomas Soome 		if (fp->f_buf == (char *)0)
3474a5d661aSToomas Soome 			fp->f_buf = malloc(fs->fs_bsize);
3484a5d661aSToomas Soome 
3494a5d661aSToomas Soome 		twiddle(8);
3504a5d661aSToomas Soome 		rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
351*976852c7SToomas Soome 			fsbtodb(fs, disk_block),
3524a5d661aSToomas Soome 			block_size, fp->f_buf, &fp->f_buf_size);
3534a5d661aSToomas Soome 		if (rc)
3544a5d661aSToomas Soome 			return (rc);
3554a5d661aSToomas Soome 
3564a5d661aSToomas Soome 		fp->f_buf_blkno = file_block;
3574a5d661aSToomas Soome 	}
3584a5d661aSToomas Soome 
3594a5d661aSToomas Soome 	/*
3604a5d661aSToomas Soome 	 *	Copy the user data into the cached block.
3614a5d661aSToomas Soome 	 */
3624a5d661aSToomas Soome 	bcopy(buf_p, fp->f_buf + off, *size_p);
3634a5d661aSToomas Soome 
3644a5d661aSToomas Soome 	/*
3654a5d661aSToomas Soome 	 *	Write the block out to storage.
3664a5d661aSToomas Soome 	 */
3674a5d661aSToomas Soome 
3684a5d661aSToomas Soome 	twiddle(4);
3694a5d661aSToomas Soome 	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_WRITE,
370*976852c7SToomas Soome 		fsbtodb(fs, disk_block),
3714a5d661aSToomas Soome 		block_size, fp->f_buf, &fp->f_buf_size);
3724a5d661aSToomas Soome 	return (rc);
3734a5d661aSToomas Soome }
3744a5d661aSToomas Soome 
3754a5d661aSToomas Soome /*
3764a5d661aSToomas Soome  * Read a portion of a file into an internal buffer.  Return
3774a5d661aSToomas Soome  * the location in the buffer and the amount in the buffer.
3784a5d661aSToomas Soome  */
3794a5d661aSToomas Soome static int
3804a5d661aSToomas Soome buf_read_file(f, buf_p, size_p)
3814a5d661aSToomas Soome 	struct open_file *f;
3824a5d661aSToomas Soome 	char **buf_p;		/* out */
3834a5d661aSToomas Soome 	size_t *size_p;		/* out */
3844a5d661aSToomas Soome {
3854a5d661aSToomas Soome 	struct file *fp = (struct file *)f->f_fsdata;
3864a5d661aSToomas Soome 	struct fs *fs = fp->f_fs;
3874a5d661aSToomas Soome 	long off;
3884a5d661aSToomas Soome 	ufs_lbn_t file_block;
3894a5d661aSToomas Soome 	ufs2_daddr_t disk_block;
3904a5d661aSToomas Soome 	size_t block_size;
3914a5d661aSToomas Soome 	int rc;
3924a5d661aSToomas Soome 
3934a5d661aSToomas Soome 	off = blkoff(fs, fp->f_seekp);
3944a5d661aSToomas Soome 	file_block = lblkno(fs, fp->f_seekp);
3954a5d661aSToomas Soome 	block_size = sblksize(fs, DIP(fp, di_size), file_block);
3964a5d661aSToomas Soome 
3974a5d661aSToomas Soome 	if (file_block != fp->f_buf_blkno) {
3984a5d661aSToomas Soome 		if (fp->f_buf == (char *)0)
3994a5d661aSToomas Soome 			fp->f_buf = malloc(fs->fs_bsize);
4004a5d661aSToomas Soome 
4014a5d661aSToomas Soome 		rc = block_map(f, file_block, &disk_block);
4024a5d661aSToomas Soome 		if (rc)
4034a5d661aSToomas Soome 			return (rc);
4044a5d661aSToomas Soome 
4054a5d661aSToomas Soome 		if (disk_block == 0) {
4064a5d661aSToomas Soome 			bzero(fp->f_buf, block_size);
4074a5d661aSToomas Soome 			fp->f_buf_size = block_size;
4084a5d661aSToomas Soome 		} else {
4094a5d661aSToomas Soome 			twiddle(4);
4104a5d661aSToomas Soome 			rc = (f->f_dev->dv_strategy)(f->f_devdata,
411*976852c7SToomas Soome 				F_READ, fsbtodb(fs, disk_block),
4124a5d661aSToomas Soome 				block_size, fp->f_buf, &fp->f_buf_size);
4134a5d661aSToomas Soome 			if (rc)
4144a5d661aSToomas Soome 				return (rc);
4154a5d661aSToomas Soome 		}
4164a5d661aSToomas Soome 
4174a5d661aSToomas Soome 		fp->f_buf_blkno = file_block;
4184a5d661aSToomas Soome 	}
4194a5d661aSToomas Soome 
4204a5d661aSToomas Soome 	/*
4214a5d661aSToomas Soome 	 * Return address of byte in buffer corresponding to
4224a5d661aSToomas Soome 	 * offset, and size of remainder of buffer after that
4234a5d661aSToomas Soome 	 * byte.
4244a5d661aSToomas Soome 	 */
4254a5d661aSToomas Soome 	*buf_p = fp->f_buf + off;
4264a5d661aSToomas Soome 	*size_p = block_size - off;
4274a5d661aSToomas Soome 
4284a5d661aSToomas Soome 	/*
4294a5d661aSToomas Soome 	 * But truncate buffer at end of file.
4304a5d661aSToomas Soome 	 */
4314a5d661aSToomas Soome 	if (*size_p > DIP(fp, di_size) - fp->f_seekp)
4324a5d661aSToomas Soome 		*size_p = DIP(fp, di_size) - fp->f_seekp;
4334a5d661aSToomas Soome 
4344a5d661aSToomas Soome 	return (0);
4354a5d661aSToomas Soome }
4364a5d661aSToomas Soome 
4374a5d661aSToomas Soome /*
4384a5d661aSToomas Soome  * Search a directory for a name and return its
4394a5d661aSToomas Soome  * i_number.
4404a5d661aSToomas Soome  */
4414a5d661aSToomas Soome static int
4424a5d661aSToomas Soome search_directory(name, f, inumber_p)
4434a5d661aSToomas Soome 	char *name;
4444a5d661aSToomas Soome 	struct open_file *f;
4454a5d661aSToomas Soome 	ino_t *inumber_p;		/* out */
4464a5d661aSToomas Soome {
4474a5d661aSToomas Soome 	struct file *fp = (struct file *)f->f_fsdata;
4484a5d661aSToomas Soome 	struct direct *dp;
4494a5d661aSToomas Soome 	struct direct *edp;
4504a5d661aSToomas Soome 	char *buf;
4514a5d661aSToomas Soome 	size_t buf_size;
4524a5d661aSToomas Soome 	int namlen, length;
4534a5d661aSToomas Soome 	int rc;
4544a5d661aSToomas Soome 
4554a5d661aSToomas Soome 	length = strlen(name);
4564a5d661aSToomas Soome 
4574a5d661aSToomas Soome 	fp->f_seekp = 0;
4584a5d661aSToomas Soome 	while (fp->f_seekp < DIP(fp, di_size)) {
4594a5d661aSToomas Soome 		rc = buf_read_file(f, &buf, &buf_size);
4604a5d661aSToomas Soome 		if (rc)
4614a5d661aSToomas Soome 			return (rc);
4624a5d661aSToomas Soome 
4634a5d661aSToomas Soome 		dp = (struct direct *)buf;
4644a5d661aSToomas Soome 		edp = (struct direct *)(buf + buf_size);
4654a5d661aSToomas Soome 		while (dp < edp) {
4664a5d661aSToomas Soome 			if (dp->d_ino == (ino_t)0)
4674a5d661aSToomas Soome 				goto next;
4684a5d661aSToomas Soome 			namlen = dp->d_namlen;
4694a5d661aSToomas Soome 			if (namlen == length &&
4704a5d661aSToomas Soome 			    !strcmp(name, dp->d_name)) {
4714a5d661aSToomas Soome 				/* found entry */
4724a5d661aSToomas Soome 				*inumber_p = dp->d_ino;
4734a5d661aSToomas Soome 				return (0);
4744a5d661aSToomas Soome 			}
4754a5d661aSToomas Soome 		next:
4764a5d661aSToomas Soome 			dp = (struct direct *)((char *)dp + dp->d_reclen);
4774a5d661aSToomas Soome 		}
4784a5d661aSToomas Soome 		fp->f_seekp += buf_size;
4794a5d661aSToomas Soome 	}
4804a5d661aSToomas Soome 	return (ENOENT);
4814a5d661aSToomas Soome }
4824a5d661aSToomas Soome 
4834a5d661aSToomas Soome static int sblock_try[] = SBLOCKSEARCH;
4844a5d661aSToomas Soome 
4854a5d661aSToomas Soome /*
4864a5d661aSToomas Soome  * Open a file.
4874a5d661aSToomas Soome  */
4884a5d661aSToomas Soome static int
4894a5d661aSToomas Soome ufs_open(upath, f)
4904a5d661aSToomas Soome 	const char *upath;
4914a5d661aSToomas Soome 	struct open_file *f;
4924a5d661aSToomas Soome {
4934a5d661aSToomas Soome 	char *cp, *ncp;
4944a5d661aSToomas Soome 	int c;
4954a5d661aSToomas Soome 	ino_t inumber, parent_inumber;
4964a5d661aSToomas Soome 	struct file *fp;
4974a5d661aSToomas Soome 	struct fs *fs;
4984a5d661aSToomas Soome 	int i, rc;
4994a5d661aSToomas Soome 	size_t buf_size;
5004a5d661aSToomas Soome 	int nlinks = 0;
5014a5d661aSToomas Soome 	char namebuf[MAXPATHLEN+1];
5024a5d661aSToomas Soome 	char *buf = NULL;
5034a5d661aSToomas Soome 	char *path = NULL;
5044a5d661aSToomas Soome 
5054a5d661aSToomas Soome 	/* allocate file system specific data structure */
5064a5d661aSToomas Soome 	fp = malloc(sizeof(struct file));
5074a5d661aSToomas Soome 	bzero(fp, sizeof(struct file));
5084a5d661aSToomas Soome 	f->f_fsdata = (void *)fp;
5094a5d661aSToomas Soome 
5104a5d661aSToomas Soome 	/* allocate space and read super block */
5114a5d661aSToomas Soome 	fs = malloc(SBLOCKSIZE);
5124a5d661aSToomas Soome 	fp->f_fs = fs;
5134a5d661aSToomas Soome 	twiddle(1);
5144a5d661aSToomas Soome 	/*
5154a5d661aSToomas Soome 	 * Try reading the superblock in each of its possible locations.
5164a5d661aSToomas Soome 	 */
5174a5d661aSToomas Soome 	for (i = 0; sblock_try[i] != -1; i++) {
5184a5d661aSToomas Soome 		rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
519*976852c7SToomas Soome 		    sblock_try[i] / DEV_BSIZE, SBLOCKSIZE,
5204a5d661aSToomas Soome 		    (char *)fs, &buf_size);
5214a5d661aSToomas Soome 		if (rc)
5224a5d661aSToomas Soome 			goto out;
5234a5d661aSToomas Soome 		if ((fs->fs_magic == FS_UFS1_MAGIC ||
5244a5d661aSToomas Soome 		     (fs->fs_magic == FS_UFS2_MAGIC &&
5254a5d661aSToomas Soome 		      fs->fs_sblockloc == sblock_try[i])) &&
5264a5d661aSToomas Soome 		    buf_size == SBLOCKSIZE &&
5274a5d661aSToomas Soome 		    fs->fs_bsize <= MAXBSIZE &&
5284a5d661aSToomas Soome 		    fs->fs_bsize >= sizeof(struct fs))
5294a5d661aSToomas Soome 			break;
5304a5d661aSToomas Soome 	}
5314a5d661aSToomas Soome 	if (sblock_try[i] == -1) {
5324a5d661aSToomas Soome 		rc = EINVAL;
5334a5d661aSToomas Soome 		goto out;
5344a5d661aSToomas Soome 	}
5354a5d661aSToomas Soome 	/*
5364a5d661aSToomas Soome 	 * Calculate indirect block levels.
5374a5d661aSToomas Soome 	 */
5384a5d661aSToomas Soome 	{
5394a5d661aSToomas Soome 		ufs2_daddr_t mult;
5404a5d661aSToomas Soome 		int level;
5414a5d661aSToomas Soome 
5424a5d661aSToomas Soome 		mult = 1;
5434a5d661aSToomas Soome 		for (level = 0; level < NIADDR; level++) {
5444a5d661aSToomas Soome 			mult *= NINDIR(fs);
5454a5d661aSToomas Soome 			fp->f_nindir[level] = mult;
5464a5d661aSToomas Soome 		}
5474a5d661aSToomas Soome 	}
5484a5d661aSToomas Soome 
5494a5d661aSToomas Soome 	inumber = ROOTINO;
5504a5d661aSToomas Soome 	if ((rc = read_inode(inumber, f)) != 0)
5514a5d661aSToomas Soome 		goto out;
5524a5d661aSToomas Soome 
5534a5d661aSToomas Soome 	cp = path = strdup(upath);
5544a5d661aSToomas Soome 	if (path == NULL) {
5554a5d661aSToomas Soome 	    rc = ENOMEM;
5564a5d661aSToomas Soome 	    goto out;
5574a5d661aSToomas Soome 	}
5584a5d661aSToomas Soome 	while (*cp) {
5594a5d661aSToomas Soome 
5604a5d661aSToomas Soome 		/*
5614a5d661aSToomas Soome 		 * Remove extra separators
5624a5d661aSToomas Soome 		 */
5634a5d661aSToomas Soome 		while (*cp == '/')
5644a5d661aSToomas Soome 			cp++;
5654a5d661aSToomas Soome 		if (*cp == '\0')
5664a5d661aSToomas Soome 			break;
5674a5d661aSToomas Soome 
5684a5d661aSToomas Soome 		/*
5694a5d661aSToomas Soome 		 * Check that current node is a directory.
5704a5d661aSToomas Soome 		 */
5714a5d661aSToomas Soome 		if ((DIP(fp, di_mode) & IFMT) != IFDIR) {
5724a5d661aSToomas Soome 			rc = ENOTDIR;
5734a5d661aSToomas Soome 			goto out;
5744a5d661aSToomas Soome 		}
5754a5d661aSToomas Soome 
5764a5d661aSToomas Soome 		/*
5774a5d661aSToomas Soome 		 * Get next component of path name.
5784a5d661aSToomas Soome 		 */
5794a5d661aSToomas Soome 		{
5804a5d661aSToomas Soome 			int len = 0;
5814a5d661aSToomas Soome 
5824a5d661aSToomas Soome 			ncp = cp;
5834a5d661aSToomas Soome 			while ((c = *cp) != '\0' && c != '/') {
5844a5d661aSToomas Soome 				if (++len > MAXNAMLEN) {
5854a5d661aSToomas Soome 					rc = ENOENT;
5864a5d661aSToomas Soome 					goto out;
5874a5d661aSToomas Soome 				}
5884a5d661aSToomas Soome 				cp++;
5894a5d661aSToomas Soome 			}
5904a5d661aSToomas Soome 			*cp = '\0';
5914a5d661aSToomas Soome 		}
5924a5d661aSToomas Soome 
5934a5d661aSToomas Soome 		/*
5944a5d661aSToomas Soome 		 * Look up component in current directory.
5954a5d661aSToomas Soome 		 * Save directory inumber in case we find a
5964a5d661aSToomas Soome 		 * symbolic link.
5974a5d661aSToomas Soome 		 */
5984a5d661aSToomas Soome 		parent_inumber = inumber;
5994a5d661aSToomas Soome 		rc = search_directory(ncp, f, &inumber);
6004a5d661aSToomas Soome 		*cp = c;
6014a5d661aSToomas Soome 		if (rc)
6024a5d661aSToomas Soome 			goto out;
6034a5d661aSToomas Soome 
6044a5d661aSToomas Soome 		/*
6054a5d661aSToomas Soome 		 * Open next component.
6064a5d661aSToomas Soome 		 */
6074a5d661aSToomas Soome 		if ((rc = read_inode(inumber, f)) != 0)
6084a5d661aSToomas Soome 			goto out;
6094a5d661aSToomas Soome 
6104a5d661aSToomas Soome 		/*
6114a5d661aSToomas Soome 		 * Check for symbolic link.
6124a5d661aSToomas Soome 		 */
6134a5d661aSToomas Soome 		if ((DIP(fp, di_mode) & IFMT) == IFLNK) {
6144a5d661aSToomas Soome 			int link_len = DIP(fp, di_size);
6154a5d661aSToomas Soome 			int len;
6164a5d661aSToomas Soome 
6174a5d661aSToomas Soome 			len = strlen(cp);
6184a5d661aSToomas Soome 
6194a5d661aSToomas Soome 			if (link_len + len > MAXPATHLEN ||
6204a5d661aSToomas Soome 			    ++nlinks > MAXSYMLINKS) {
6214a5d661aSToomas Soome 				rc = ENOENT;
6224a5d661aSToomas Soome 				goto out;
6234a5d661aSToomas Soome 			}
6244a5d661aSToomas Soome 
6254a5d661aSToomas Soome 			bcopy(cp, &namebuf[link_len], len + 1);
6264a5d661aSToomas Soome 
6274a5d661aSToomas Soome 			if (link_len < fs->fs_maxsymlinklen) {
6284a5d661aSToomas Soome 				if (fp->f_fs->fs_magic == FS_UFS1_MAGIC)
6294a5d661aSToomas Soome 					cp = (caddr_t)(fp->f_di.di1.di_db);
6304a5d661aSToomas Soome 				else
6314a5d661aSToomas Soome 					cp = (caddr_t)(fp->f_di.di2.di_db);
6324a5d661aSToomas Soome 				bcopy(cp, namebuf, (unsigned) link_len);
6334a5d661aSToomas Soome 			} else {
6344a5d661aSToomas Soome 				/*
6354a5d661aSToomas Soome 				 * Read file for symbolic link
6364a5d661aSToomas Soome 				 */
6374a5d661aSToomas Soome 				size_t buf_size;
6384a5d661aSToomas Soome 				ufs2_daddr_t disk_block;
6394a5d661aSToomas Soome 				struct fs *fs = fp->f_fs;
6404a5d661aSToomas Soome 
6414a5d661aSToomas Soome 				if (!buf)
6424a5d661aSToomas Soome 					buf = malloc(fs->fs_bsize);
6434a5d661aSToomas Soome 				rc = block_map(f, (ufs2_daddr_t)0, &disk_block);
6444a5d661aSToomas Soome 				if (rc)
6454a5d661aSToomas Soome 					goto out;
6464a5d661aSToomas Soome 
6474a5d661aSToomas Soome 				twiddle(1);
6484a5d661aSToomas Soome 				rc = (f->f_dev->dv_strategy)(f->f_devdata,
649*976852c7SToomas Soome 					F_READ, fsbtodb(fs, disk_block),
6504a5d661aSToomas Soome 					fs->fs_bsize, buf, &buf_size);
6514a5d661aSToomas Soome 				if (rc)
6524a5d661aSToomas Soome 					goto out;
6534a5d661aSToomas Soome 
6544a5d661aSToomas Soome 				bcopy((char *)buf, namebuf, (unsigned)link_len);
6554a5d661aSToomas Soome 			}
6564a5d661aSToomas Soome 
6574a5d661aSToomas Soome 			/*
6584a5d661aSToomas Soome 			 * If relative pathname, restart at parent directory.
6594a5d661aSToomas Soome 			 * If absolute pathname, restart at root.
6604a5d661aSToomas Soome 			 */
6614a5d661aSToomas Soome 			cp = namebuf;
6624a5d661aSToomas Soome 			if (*cp != '/')
6634a5d661aSToomas Soome 				inumber = parent_inumber;
6644a5d661aSToomas Soome 			else
6654a5d661aSToomas Soome 				inumber = (ino_t)ROOTINO;
6664a5d661aSToomas Soome 
6674a5d661aSToomas Soome 			if ((rc = read_inode(inumber, f)) != 0)
6684a5d661aSToomas Soome 				goto out;
6694a5d661aSToomas Soome 		}
6704a5d661aSToomas Soome 	}
6714a5d661aSToomas Soome 
6724a5d661aSToomas Soome 	/*
6734a5d661aSToomas Soome 	 * Found terminal component.
6744a5d661aSToomas Soome 	 */
6754a5d661aSToomas Soome 	rc = 0;
6764a5d661aSToomas Soome 	fp->f_seekp = 0;
6774a5d661aSToomas Soome out:
6784a5d661aSToomas Soome 	if (buf)
6794a5d661aSToomas Soome 		free(buf);
6804a5d661aSToomas Soome 	if (path)
6814a5d661aSToomas Soome 		free(path);
6824a5d661aSToomas Soome 	if (rc) {
6834a5d661aSToomas Soome 		if (fp->f_buf)
6844a5d661aSToomas Soome 			free(fp->f_buf);
6854a5d661aSToomas Soome 		free(fp->f_fs);
6864a5d661aSToomas Soome 		free(fp);
6874a5d661aSToomas Soome 	}
6884a5d661aSToomas Soome 	return (rc);
6894a5d661aSToomas Soome }
6904a5d661aSToomas Soome 
6914a5d661aSToomas Soome static int
6924a5d661aSToomas Soome ufs_close(f)
6934a5d661aSToomas Soome 	struct open_file *f;
6944a5d661aSToomas Soome {
6954a5d661aSToomas Soome 	struct file *fp = (struct file *)f->f_fsdata;
6964a5d661aSToomas Soome 	int level;
6974a5d661aSToomas Soome 
6984a5d661aSToomas Soome 	f->f_fsdata = (void *)0;
6994a5d661aSToomas Soome 	if (fp == (struct file *)0)
7004a5d661aSToomas Soome 		return (0);
7014a5d661aSToomas Soome 
7024a5d661aSToomas Soome 	for (level = 0; level < NIADDR; level++) {
7034a5d661aSToomas Soome 		if (fp->f_blk[level])
7044a5d661aSToomas Soome 			free(fp->f_blk[level]);
7054a5d661aSToomas Soome 	}
7064a5d661aSToomas Soome 	if (fp->f_buf)
7074a5d661aSToomas Soome 		free(fp->f_buf);
7084a5d661aSToomas Soome 	free(fp->f_fs);
7094a5d661aSToomas Soome 	free(fp);
7104a5d661aSToomas Soome 	return (0);
7114a5d661aSToomas Soome }
7124a5d661aSToomas Soome 
7134a5d661aSToomas Soome /*
7144a5d661aSToomas Soome  * Copy a portion of a file into kernel memory.
7154a5d661aSToomas Soome  * Cross block boundaries when necessary.
7164a5d661aSToomas Soome  */
7174a5d661aSToomas Soome static int
7184a5d661aSToomas Soome ufs_read(f, start, size, resid)
7194a5d661aSToomas Soome 	struct open_file *f;
7204a5d661aSToomas Soome 	void *start;
7214a5d661aSToomas Soome 	size_t size;
7224a5d661aSToomas Soome 	size_t *resid;	/* out */
7234a5d661aSToomas Soome {
7244a5d661aSToomas Soome 	struct file *fp = (struct file *)f->f_fsdata;
7254a5d661aSToomas Soome 	size_t csize;
7264a5d661aSToomas Soome 	char *buf;
7274a5d661aSToomas Soome 	size_t buf_size;
7284a5d661aSToomas Soome 	int rc = 0;
7294a5d661aSToomas Soome 	char *addr = start;
7304a5d661aSToomas Soome 
7314a5d661aSToomas Soome 	while (size != 0) {
7324a5d661aSToomas Soome 		if (fp->f_seekp >= DIP(fp, di_size))
7334a5d661aSToomas Soome 			break;
7344a5d661aSToomas Soome 
7354a5d661aSToomas Soome 		rc = buf_read_file(f, &buf, &buf_size);
7364a5d661aSToomas Soome 		if (rc)
7374a5d661aSToomas Soome 			break;
7384a5d661aSToomas Soome 
7394a5d661aSToomas Soome 		csize = size;
7404a5d661aSToomas Soome 		if (csize > buf_size)
7414a5d661aSToomas Soome 			csize = buf_size;
7424a5d661aSToomas Soome 
7434a5d661aSToomas Soome 		bcopy(buf, addr, csize);
7444a5d661aSToomas Soome 
7454a5d661aSToomas Soome 		fp->f_seekp += csize;
7464a5d661aSToomas Soome 		addr += csize;
7474a5d661aSToomas Soome 		size -= csize;
7484a5d661aSToomas Soome 	}
7494a5d661aSToomas Soome 	if (resid)
7504a5d661aSToomas Soome 		*resid = size;
7514a5d661aSToomas Soome 	return (rc);
7524a5d661aSToomas Soome }
7534a5d661aSToomas Soome 
7544a5d661aSToomas Soome /*
7554a5d661aSToomas Soome  * Write to a portion of an already allocated file.
7564a5d661aSToomas Soome  * Cross block boundaries when necessary. Can not
7574a5d661aSToomas Soome  * extend the file.
7584a5d661aSToomas Soome  */
7594a5d661aSToomas Soome static int
7604a5d661aSToomas Soome ufs_write(f, start, size, resid)
7614a5d661aSToomas Soome 	struct open_file *f;
7624a5d661aSToomas Soome 	void *start;
7634a5d661aSToomas Soome 	size_t size;
7644a5d661aSToomas Soome 	size_t *resid;	/* out */
7654a5d661aSToomas Soome {
7664a5d661aSToomas Soome 	struct file *fp = (struct file *)f->f_fsdata;
7674a5d661aSToomas Soome 	size_t csize;
7684a5d661aSToomas Soome 	int rc = 0;
7694a5d661aSToomas Soome 	char *addr = start;
7704a5d661aSToomas Soome 
7714a5d661aSToomas Soome 	csize = size;
7724a5d661aSToomas Soome 	while ((size != 0) && (csize != 0)) {
7734a5d661aSToomas Soome 		if (fp->f_seekp >= DIP(fp, di_size))
7744a5d661aSToomas Soome 			break;
7754a5d661aSToomas Soome 
7764a5d661aSToomas Soome 		if (csize >= 512) csize = 512; /* XXX */
7774a5d661aSToomas Soome 
7784a5d661aSToomas Soome 		rc = buf_write_file(f, addr, &csize);
7794a5d661aSToomas Soome 		if (rc)
7804a5d661aSToomas Soome 			break;
7814a5d661aSToomas Soome 
7824a5d661aSToomas Soome 		fp->f_seekp += csize;
7834a5d661aSToomas Soome 		addr += csize;
7844a5d661aSToomas Soome 		size -= csize;
7854a5d661aSToomas Soome 	}
7864a5d661aSToomas Soome 	if (resid)
7874a5d661aSToomas Soome 		*resid = size;
7884a5d661aSToomas Soome 	return (rc);
7894a5d661aSToomas Soome }
7904a5d661aSToomas Soome 
7914a5d661aSToomas Soome static off_t
7924a5d661aSToomas Soome ufs_seek(f, offset, where)
7934a5d661aSToomas Soome 	struct open_file *f;
7944a5d661aSToomas Soome 	off_t offset;
7954a5d661aSToomas Soome 	int where;
7964a5d661aSToomas Soome {
7974a5d661aSToomas Soome 	struct file *fp = (struct file *)f->f_fsdata;
7984a5d661aSToomas Soome 
7994a5d661aSToomas Soome 	switch (where) {
8004a5d661aSToomas Soome 	case SEEK_SET:
8014a5d661aSToomas Soome 		fp->f_seekp = offset;
8024a5d661aSToomas Soome 		break;
8034a5d661aSToomas Soome 	case SEEK_CUR:
8044a5d661aSToomas Soome 		fp->f_seekp += offset;
8054a5d661aSToomas Soome 		break;
8064a5d661aSToomas Soome 	case SEEK_END:
8074a5d661aSToomas Soome 		fp->f_seekp = DIP(fp, di_size) - offset;
8084a5d661aSToomas Soome 		break;
8094a5d661aSToomas Soome 	default:
8104a5d661aSToomas Soome 		errno = EINVAL;
8114a5d661aSToomas Soome 		return (-1);
8124a5d661aSToomas Soome 	}
8134a5d661aSToomas Soome 	return (fp->f_seekp);
8144a5d661aSToomas Soome }
8154a5d661aSToomas Soome 
8164a5d661aSToomas Soome static int
8174a5d661aSToomas Soome ufs_stat(f, sb)
8184a5d661aSToomas Soome 	struct open_file *f;
8194a5d661aSToomas Soome 	struct stat *sb;
8204a5d661aSToomas Soome {
8214a5d661aSToomas Soome 	struct file *fp = (struct file *)f->f_fsdata;
8224a5d661aSToomas Soome 
8234a5d661aSToomas Soome 	/* only important stuff */
8244a5d661aSToomas Soome 	sb->st_mode = DIP(fp, di_mode);
8254a5d661aSToomas Soome 	sb->st_uid = DIP(fp, di_uid);
8264a5d661aSToomas Soome 	sb->st_gid = DIP(fp, di_gid);
8274a5d661aSToomas Soome 	sb->st_size = DIP(fp, di_size);
8284a5d661aSToomas Soome 	return (0);
8294a5d661aSToomas Soome }
8304a5d661aSToomas Soome 
8314a5d661aSToomas Soome static int
8324a5d661aSToomas Soome ufs_readdir(struct open_file *f, struct dirent *d)
8334a5d661aSToomas Soome {
8344a5d661aSToomas Soome 	struct file *fp = (struct file *)f->f_fsdata;
8354a5d661aSToomas Soome 	struct direct *dp;
8364a5d661aSToomas Soome 	char *buf;
8374a5d661aSToomas Soome 	size_t buf_size;
8384a5d661aSToomas Soome 	int error;
8394a5d661aSToomas Soome 
8404a5d661aSToomas Soome 	/*
8414a5d661aSToomas Soome 	 * assume that a directory entry will not be split across blocks
8424a5d661aSToomas Soome 	 */
8434a5d661aSToomas Soome again:
8444a5d661aSToomas Soome 	if (fp->f_seekp >= DIP(fp, di_size))
8454a5d661aSToomas Soome 		return (ENOENT);
8464a5d661aSToomas Soome 	error = buf_read_file(f, &buf, &buf_size);
8474a5d661aSToomas Soome 	if (error)
8484a5d661aSToomas Soome 		return (error);
8494a5d661aSToomas Soome 	dp = (struct direct *)buf;
8504a5d661aSToomas Soome 	fp->f_seekp += dp->d_reclen;
8514a5d661aSToomas Soome 	if (dp->d_ino == (ino_t)0)
8524a5d661aSToomas Soome 		goto again;
8534a5d661aSToomas Soome 
8544a5d661aSToomas Soome 	d->d_type = 0;		/* illumos ufs does not have type in direct */
8554a5d661aSToomas Soome 	strcpy(d->d_name, dp->d_name);
8564a5d661aSToomas Soome 	return (0);
8574a5d661aSToomas Soome }
858