xref: /titanic_51/usr/src/boot/lib/libstand/ufs.c (revision 4a5d661a82b942b6538acd26209d959ce98b593a)
1*4a5d661aSToomas Soome /*	$NetBSD: ufs.c,v 1.20 1998/03/01 07:15:39 ross Exp $	*/
2*4a5d661aSToomas Soome 
3*4a5d661aSToomas Soome /*-
4*4a5d661aSToomas Soome  * Copyright (c) 2002 Networks Associates Technology, Inc.
5*4a5d661aSToomas Soome  * All rights reserved.
6*4a5d661aSToomas Soome  *
7*4a5d661aSToomas Soome  * This software was developed for the FreeBSD Project by Marshall
8*4a5d661aSToomas Soome  * Kirk McKusick and Network Associates Laboratories, the Security
9*4a5d661aSToomas Soome  * Research Division of Network Associates, Inc. under DARPA/SPAWAR
10*4a5d661aSToomas Soome  * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS
11*4a5d661aSToomas Soome  * research program
12*4a5d661aSToomas Soome  *
13*4a5d661aSToomas Soome  * Copyright (c) 1982, 1989, 1993
14*4a5d661aSToomas Soome  *	The Regents of the University of California.  All rights reserved.
15*4a5d661aSToomas Soome  *
16*4a5d661aSToomas Soome  * This code is derived from software contributed to Berkeley by
17*4a5d661aSToomas Soome  * The Mach Operating System project at Carnegie-Mellon University.
18*4a5d661aSToomas Soome  *
19*4a5d661aSToomas Soome  * Redistribution and use in source and binary forms, with or without
20*4a5d661aSToomas Soome  * modification, are permitted provided that the following conditions
21*4a5d661aSToomas Soome  * are met:
22*4a5d661aSToomas Soome  * 1. Redistributions of source code must retain the above copyright
23*4a5d661aSToomas Soome  *    notice, this list of conditions and the following disclaimer.
24*4a5d661aSToomas Soome  * 2. Redistributions in binary form must reproduce the above copyright
25*4a5d661aSToomas Soome  *    notice, this list of conditions and the following disclaimer in the
26*4a5d661aSToomas Soome  *    documentation and/or other materials provided with the distribution.
27*4a5d661aSToomas Soome  * 3. Neither the name of the University nor the names of its contributors
28*4a5d661aSToomas Soome  *    may be used to endorse or promote products derived from this software
29*4a5d661aSToomas Soome  *    without specific prior written permission.
30*4a5d661aSToomas Soome  *
31*4a5d661aSToomas Soome  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
32*4a5d661aSToomas Soome  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
33*4a5d661aSToomas Soome  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34*4a5d661aSToomas Soome  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
35*4a5d661aSToomas Soome  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36*4a5d661aSToomas Soome  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37*4a5d661aSToomas Soome  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38*4a5d661aSToomas Soome  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
39*4a5d661aSToomas Soome  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
40*4a5d661aSToomas Soome  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
41*4a5d661aSToomas Soome  * SUCH DAMAGE.
42*4a5d661aSToomas Soome  *
43*4a5d661aSToomas Soome  *
44*4a5d661aSToomas Soome  * Copyright (c) 1990, 1991 Carnegie Mellon University
45*4a5d661aSToomas Soome  * All Rights Reserved.
46*4a5d661aSToomas Soome  *
47*4a5d661aSToomas Soome  * Author: David Golub
48*4a5d661aSToomas Soome  *
49*4a5d661aSToomas Soome  * Permission to use, copy, modify and distribute this software and its
50*4a5d661aSToomas Soome  * documentation is hereby granted, provided that both the copyright
51*4a5d661aSToomas Soome  * notice and this permission notice appear in all copies of the
52*4a5d661aSToomas Soome  * software, derivative works or modified versions, and any portions
53*4a5d661aSToomas Soome  * thereof, and that both notices appear in supporting documentation.
54*4a5d661aSToomas Soome  *
55*4a5d661aSToomas Soome  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
56*4a5d661aSToomas Soome  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
57*4a5d661aSToomas Soome  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
58*4a5d661aSToomas Soome  *
59*4a5d661aSToomas Soome  * Carnegie Mellon requests users of this software to return to
60*4a5d661aSToomas Soome  *
61*4a5d661aSToomas Soome  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
62*4a5d661aSToomas Soome  *  School of Computer Science
63*4a5d661aSToomas Soome  *  Carnegie Mellon University
64*4a5d661aSToomas Soome  *  Pittsburgh PA 15213-3890
65*4a5d661aSToomas Soome  *
66*4a5d661aSToomas Soome  * any improvements or extensions that they make and grant Carnegie the
67*4a5d661aSToomas Soome  * rights to redistribute these changes.
68*4a5d661aSToomas Soome  */
69*4a5d661aSToomas Soome 
70*4a5d661aSToomas Soome #include <sys/cdefs.h>
71*4a5d661aSToomas Soome __FBSDID("$FreeBSD$");
72*4a5d661aSToomas Soome 
73*4a5d661aSToomas Soome /*
74*4a5d661aSToomas Soome  *	Stand-alone file reading package.
75*4a5d661aSToomas Soome  */
76*4a5d661aSToomas Soome 
77*4a5d661aSToomas Soome #include <sys/param.h>
78*4a5d661aSToomas Soome #include <sys/disklabel.h>
79*4a5d661aSToomas Soome #include <sys/time.h>
80*4a5d661aSToomas Soome #include <ufs/ufs/dinode.h>
81*4a5d661aSToomas Soome #include <ufs/ufs/dir.h>
82*4a5d661aSToomas Soome #include <ufs/ffs/fs.h>
83*4a5d661aSToomas Soome #include "stand.h"
84*4a5d661aSToomas Soome #include "string.h"
85*4a5d661aSToomas Soome 
86*4a5d661aSToomas Soome static int	ufs_open(const char *path, struct open_file *f);
87*4a5d661aSToomas Soome static int	ufs_write(struct open_file *f, void *buf, size_t size, size_t *resid);
88*4a5d661aSToomas Soome static int	ufs_close(struct open_file *f);
89*4a5d661aSToomas Soome static int	ufs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
90*4a5d661aSToomas Soome static off_t	ufs_seek(struct open_file *f, off_t offset, int where);
91*4a5d661aSToomas Soome static int	ufs_stat(struct open_file *f, struct stat *sb);
92*4a5d661aSToomas Soome static int	ufs_readdir(struct open_file *f, struct dirent *d);
93*4a5d661aSToomas Soome 
94*4a5d661aSToomas Soome struct fs_ops ufs_fsops = {
95*4a5d661aSToomas Soome 	"ufs",
96*4a5d661aSToomas Soome 	ufs_open,
97*4a5d661aSToomas Soome 	ufs_close,
98*4a5d661aSToomas Soome 	ufs_read,
99*4a5d661aSToomas Soome 	ufs_write,
100*4a5d661aSToomas Soome 	ufs_seek,
101*4a5d661aSToomas Soome 	ufs_stat,
102*4a5d661aSToomas Soome 	ufs_readdir
103*4a5d661aSToomas Soome };
104*4a5d661aSToomas Soome 
105*4a5d661aSToomas Soome /*
106*4a5d661aSToomas Soome  * In-core open file.
107*4a5d661aSToomas Soome  */
108*4a5d661aSToomas Soome struct file {
109*4a5d661aSToomas Soome 	off_t		f_seekp;	/* seek pointer */
110*4a5d661aSToomas Soome 	struct fs	*f_fs;		/* pointer to super-block */
111*4a5d661aSToomas Soome 	union dinode {
112*4a5d661aSToomas Soome 		struct ufs1_dinode di1;
113*4a5d661aSToomas Soome 		struct ufs2_dinode di2;
114*4a5d661aSToomas Soome 	}		f_di;		/* copy of on-disk inode */
115*4a5d661aSToomas Soome 	int		f_nindir[NIADDR];
116*4a5d661aSToomas Soome 					/* number of blocks mapped by
117*4a5d661aSToomas Soome 					   indirect block at level i */
118*4a5d661aSToomas Soome 	char		*f_blk[NIADDR];	/* buffer for indirect block at
119*4a5d661aSToomas Soome 					   level i */
120*4a5d661aSToomas Soome 	size_t		f_blksize[NIADDR];
121*4a5d661aSToomas Soome 					/* size of buffer */
122*4a5d661aSToomas Soome 	ufs2_daddr_t	f_blkno[NIADDR];/* disk address of block in buffer */
123*4a5d661aSToomas Soome 	ufs2_daddr_t	f_buf_blkno;	/* block number of data block */
124*4a5d661aSToomas Soome 	char		*f_buf;		/* buffer for data block */
125*4a5d661aSToomas Soome 	size_t		f_buf_size;	/* size of data block */
126*4a5d661aSToomas Soome };
127*4a5d661aSToomas Soome #define DIP(fp, field) \
128*4a5d661aSToomas Soome 	((fp)->f_fs->fs_magic == FS_UFS1_MAGIC ? \
129*4a5d661aSToomas Soome 	(fp)->f_di.di1.field : (fp)->f_di.di2.field)
130*4a5d661aSToomas Soome 
131*4a5d661aSToomas Soome static int	read_inode(ino_t, struct open_file *);
132*4a5d661aSToomas Soome static int	block_map(struct open_file *, ufs2_daddr_t, ufs2_daddr_t *);
133*4a5d661aSToomas Soome static int	buf_read_file(struct open_file *, char **, size_t *);
134*4a5d661aSToomas Soome static int	buf_write_file(struct open_file *, char *, size_t *);
135*4a5d661aSToomas Soome static int	search_directory(char *, struct open_file *, ino_t *);
136*4a5d661aSToomas Soome 
137*4a5d661aSToomas Soome /*
138*4a5d661aSToomas Soome  * Read a new inode into a file structure.
139*4a5d661aSToomas Soome  */
140*4a5d661aSToomas Soome static int
141*4a5d661aSToomas Soome read_inode(inumber, f)
142*4a5d661aSToomas Soome 	ino_t inumber;
143*4a5d661aSToomas Soome 	struct open_file *f;
144*4a5d661aSToomas Soome {
145*4a5d661aSToomas Soome 	struct file *fp = (struct file *)f->f_fsdata;
146*4a5d661aSToomas Soome 	struct fs *fs = fp->f_fs;
147*4a5d661aSToomas Soome 	char *buf;
148*4a5d661aSToomas Soome 	size_t rsize;
149*4a5d661aSToomas Soome 	int rc;
150*4a5d661aSToomas Soome 
151*4a5d661aSToomas Soome 	if (fs == NULL)
152*4a5d661aSToomas Soome 	    panic("fs == NULL");
153*4a5d661aSToomas Soome 
154*4a5d661aSToomas Soome 	/*
155*4a5d661aSToomas Soome 	 * Read inode and save it.
156*4a5d661aSToomas Soome 	 */
157*4a5d661aSToomas Soome 	buf = malloc(fs->fs_bsize);
158*4a5d661aSToomas Soome 	twiddle(1);
159*4a5d661aSToomas Soome 	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
160*4a5d661aSToomas Soome 		fsbtodb(fs, ino_to_fsba(fs, inumber)), 0, fs->fs_bsize,
161*4a5d661aSToomas Soome 		buf, &rsize);
162*4a5d661aSToomas Soome 	if (rc)
163*4a5d661aSToomas Soome 		goto out;
164*4a5d661aSToomas Soome 	if (rsize != fs->fs_bsize) {
165*4a5d661aSToomas Soome 		rc = EIO;
166*4a5d661aSToomas Soome 		goto out;
167*4a5d661aSToomas Soome 	}
168*4a5d661aSToomas Soome 
169*4a5d661aSToomas Soome 	if (fp->f_fs->fs_magic == FS_UFS1_MAGIC)
170*4a5d661aSToomas Soome 		fp->f_di.di1 = ((struct ufs1_dinode *)buf)
171*4a5d661aSToomas Soome 		    [ino_to_fsbo(fs, inumber)];
172*4a5d661aSToomas Soome 	else
173*4a5d661aSToomas Soome 		fp->f_di.di2 = ((struct ufs2_dinode *)buf)
174*4a5d661aSToomas Soome 		    [ino_to_fsbo(fs, inumber)];
175*4a5d661aSToomas Soome 
176*4a5d661aSToomas Soome 	/*
177*4a5d661aSToomas Soome 	 * Clear out the old buffers
178*4a5d661aSToomas Soome 	 */
179*4a5d661aSToomas Soome 	{
180*4a5d661aSToomas Soome 		int level;
181*4a5d661aSToomas Soome 
182*4a5d661aSToomas Soome 		for (level = 0; level < NIADDR; level++)
183*4a5d661aSToomas Soome 			fp->f_blkno[level] = -1;
184*4a5d661aSToomas Soome 		fp->f_buf_blkno = -1;
185*4a5d661aSToomas Soome 	}
186*4a5d661aSToomas Soome 	fp->f_seekp = 0;
187*4a5d661aSToomas Soome out:
188*4a5d661aSToomas Soome 	free(buf);
189*4a5d661aSToomas Soome 	return (rc);
190*4a5d661aSToomas Soome }
191*4a5d661aSToomas Soome 
192*4a5d661aSToomas Soome /*
193*4a5d661aSToomas Soome  * Given an offset in a file, find the disk block number that
194*4a5d661aSToomas Soome  * contains that block.
195*4a5d661aSToomas Soome  */
196*4a5d661aSToomas Soome static int
197*4a5d661aSToomas Soome block_map(f, file_block, disk_block_p)
198*4a5d661aSToomas Soome 	struct open_file *f;
199*4a5d661aSToomas Soome 	ufs2_daddr_t file_block;
200*4a5d661aSToomas Soome 	ufs2_daddr_t *disk_block_p;	/* out */
201*4a5d661aSToomas Soome {
202*4a5d661aSToomas Soome 	struct file *fp = (struct file *)f->f_fsdata;
203*4a5d661aSToomas Soome 	struct fs *fs = fp->f_fs;
204*4a5d661aSToomas Soome 	int level;
205*4a5d661aSToomas Soome 	int idx;
206*4a5d661aSToomas Soome 	ufs2_daddr_t ind_block_num;
207*4a5d661aSToomas Soome 	int rc;
208*4a5d661aSToomas Soome 
209*4a5d661aSToomas Soome 	/*
210*4a5d661aSToomas Soome 	 * Index structure of an inode:
211*4a5d661aSToomas Soome 	 *
212*4a5d661aSToomas Soome 	 * di_db[0..NDADDR-1]	hold block numbers for blocks
213*4a5d661aSToomas Soome 	 *			0..NDADDR-1
214*4a5d661aSToomas Soome 	 *
215*4a5d661aSToomas Soome 	 * di_ib[0]		index block 0 is the single indirect block
216*4a5d661aSToomas Soome 	 *			holds block numbers for blocks
217*4a5d661aSToomas Soome 	 *			NDADDR .. NDADDR + NINDIR(fs)-1
218*4a5d661aSToomas Soome 	 *
219*4a5d661aSToomas Soome 	 * di_ib[1]		index block 1 is the double indirect block
220*4a5d661aSToomas Soome 	 *			holds block numbers for INDEX blocks for blocks
221*4a5d661aSToomas Soome 	 *			NDADDR + NINDIR(fs) ..
222*4a5d661aSToomas Soome 	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1
223*4a5d661aSToomas Soome 	 *
224*4a5d661aSToomas Soome 	 * di_ib[2]		index block 2 is the triple indirect block
225*4a5d661aSToomas Soome 	 *			holds block numbers for double-indirect
226*4a5d661aSToomas Soome 	 *			blocks for blocks
227*4a5d661aSToomas Soome 	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2 ..
228*4a5d661aSToomas Soome 	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2
229*4a5d661aSToomas Soome 	 *				+ NINDIR(fs)**3 - 1
230*4a5d661aSToomas Soome 	 */
231*4a5d661aSToomas Soome 
232*4a5d661aSToomas Soome 	if (file_block < NDADDR) {
233*4a5d661aSToomas Soome 		/* Direct block. */
234*4a5d661aSToomas Soome 		*disk_block_p = DIP(fp, di_db[file_block]);
235*4a5d661aSToomas Soome 		return (0);
236*4a5d661aSToomas Soome 	}
237*4a5d661aSToomas Soome 
238*4a5d661aSToomas Soome 	file_block -= NDADDR;
239*4a5d661aSToomas Soome 
240*4a5d661aSToomas Soome 	/*
241*4a5d661aSToomas Soome 	 * nindir[0] = NINDIR
242*4a5d661aSToomas Soome 	 * nindir[1] = NINDIR**2
243*4a5d661aSToomas Soome 	 * nindir[2] = NINDIR**3
244*4a5d661aSToomas Soome 	 *	etc
245*4a5d661aSToomas Soome 	 */
246*4a5d661aSToomas Soome 	for (level = 0; level < NIADDR; level++) {
247*4a5d661aSToomas Soome 		if (file_block < fp->f_nindir[level])
248*4a5d661aSToomas Soome 			break;
249*4a5d661aSToomas Soome 		file_block -= fp->f_nindir[level];
250*4a5d661aSToomas Soome 	}
251*4a5d661aSToomas Soome 	if (level == NIADDR) {
252*4a5d661aSToomas Soome 		/* Block number too high */
253*4a5d661aSToomas Soome 		return (EFBIG);
254*4a5d661aSToomas Soome 	}
255*4a5d661aSToomas Soome 
256*4a5d661aSToomas Soome 	ind_block_num = DIP(fp, di_ib[level]);
257*4a5d661aSToomas Soome 
258*4a5d661aSToomas Soome 	for (; level >= 0; level--) {
259*4a5d661aSToomas Soome 		if (ind_block_num == 0) {
260*4a5d661aSToomas Soome 			*disk_block_p = 0;	/* missing */
261*4a5d661aSToomas Soome 			return (0);
262*4a5d661aSToomas Soome 		}
263*4a5d661aSToomas Soome 
264*4a5d661aSToomas Soome 		if (fp->f_blkno[level] != ind_block_num) {
265*4a5d661aSToomas Soome 			if (fp->f_blk[level] == (char *)0)
266*4a5d661aSToomas Soome 				fp->f_blk[level] =
267*4a5d661aSToomas Soome 					malloc(fs->fs_bsize);
268*4a5d661aSToomas Soome 			twiddle(1);
269*4a5d661aSToomas Soome 			rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
270*4a5d661aSToomas Soome 				fsbtodb(fp->f_fs, ind_block_num), 0,
271*4a5d661aSToomas Soome 				fs->fs_bsize,
272*4a5d661aSToomas Soome 				fp->f_blk[level],
273*4a5d661aSToomas Soome 				&fp->f_blksize[level]);
274*4a5d661aSToomas Soome 			if (rc)
275*4a5d661aSToomas Soome 				return (rc);
276*4a5d661aSToomas Soome 			if (fp->f_blksize[level] != fs->fs_bsize)
277*4a5d661aSToomas Soome 				return (EIO);
278*4a5d661aSToomas Soome 			fp->f_blkno[level] = ind_block_num;
279*4a5d661aSToomas Soome 		}
280*4a5d661aSToomas Soome 
281*4a5d661aSToomas Soome 		if (level > 0) {
282*4a5d661aSToomas Soome 			idx = file_block / fp->f_nindir[level - 1];
283*4a5d661aSToomas Soome 			file_block %= fp->f_nindir[level - 1];
284*4a5d661aSToomas Soome 		} else
285*4a5d661aSToomas Soome 			idx = file_block;
286*4a5d661aSToomas Soome 
287*4a5d661aSToomas Soome 		if (fp->f_fs->fs_magic == FS_UFS1_MAGIC)
288*4a5d661aSToomas Soome 			ind_block_num = ((ufs1_daddr_t *)fp->f_blk[level])[idx];
289*4a5d661aSToomas Soome 		else
290*4a5d661aSToomas Soome 			ind_block_num = ((ufs2_daddr_t *)fp->f_blk[level])[idx];
291*4a5d661aSToomas Soome 	}
292*4a5d661aSToomas Soome 
293*4a5d661aSToomas Soome 	*disk_block_p = ind_block_num;
294*4a5d661aSToomas Soome 
295*4a5d661aSToomas Soome 	return (0);
296*4a5d661aSToomas Soome }
297*4a5d661aSToomas Soome 
298*4a5d661aSToomas Soome /*
299*4a5d661aSToomas Soome  * Write a portion of a file from an internal buffer.
300*4a5d661aSToomas Soome  */
301*4a5d661aSToomas Soome static int
302*4a5d661aSToomas Soome buf_write_file(f, buf_p, size_p)
303*4a5d661aSToomas Soome 	struct open_file *f;
304*4a5d661aSToomas Soome 	char *buf_p;
305*4a5d661aSToomas Soome 	size_t *size_p;		/* out */
306*4a5d661aSToomas Soome {
307*4a5d661aSToomas Soome 	struct file *fp = (struct file *)f->f_fsdata;
308*4a5d661aSToomas Soome 	struct fs *fs = fp->f_fs;
309*4a5d661aSToomas Soome 	long off;
310*4a5d661aSToomas Soome 	ufs_lbn_t file_block;
311*4a5d661aSToomas Soome 	ufs2_daddr_t disk_block;
312*4a5d661aSToomas Soome 	size_t block_size;
313*4a5d661aSToomas Soome 	int rc;
314*4a5d661aSToomas Soome 
315*4a5d661aSToomas Soome 	/*
316*4a5d661aSToomas Soome 	 * Calculate the starting block address and offset.
317*4a5d661aSToomas Soome 	 */
318*4a5d661aSToomas Soome 	off = blkoff(fs, fp->f_seekp);
319*4a5d661aSToomas Soome 	file_block = lblkno(fs, fp->f_seekp);
320*4a5d661aSToomas Soome 	block_size = sblksize(fs, DIP(fp, di_size), file_block);
321*4a5d661aSToomas Soome 
322*4a5d661aSToomas Soome 	rc = block_map(f, file_block, &disk_block);
323*4a5d661aSToomas Soome 	if (rc)
324*4a5d661aSToomas Soome 		return (rc);
325*4a5d661aSToomas Soome 
326*4a5d661aSToomas Soome  	if (disk_block == 0)
327*4a5d661aSToomas Soome 		/* Because we can't allocate space on the drive */
328*4a5d661aSToomas Soome 		return (EFBIG);
329*4a5d661aSToomas Soome 
330*4a5d661aSToomas Soome 	/*
331*4a5d661aSToomas Soome 	 * Truncate buffer at end of file, and at the end of
332*4a5d661aSToomas Soome 	 * this block.
333*4a5d661aSToomas Soome 	 */
334*4a5d661aSToomas Soome 	if (*size_p > DIP(fp, di_size) - fp->f_seekp)
335*4a5d661aSToomas Soome 		*size_p = DIP(fp, di_size) - fp->f_seekp;
336*4a5d661aSToomas Soome 	if (*size_p > block_size - off)
337*4a5d661aSToomas Soome 		*size_p = block_size - off;
338*4a5d661aSToomas Soome 
339*4a5d661aSToomas Soome 	/*
340*4a5d661aSToomas Soome 	 * If we don't entirely occlude the block and it's not
341*4a5d661aSToomas Soome 	 * in memory already, read it in first.
342*4a5d661aSToomas Soome 	 */
343*4a5d661aSToomas Soome 	if (((off > 0) || (*size_p + off < block_size)) &&
344*4a5d661aSToomas Soome 	    (file_block != fp->f_buf_blkno)) {
345*4a5d661aSToomas Soome 
346*4a5d661aSToomas Soome 		if (fp->f_buf == (char *)0)
347*4a5d661aSToomas Soome 			fp->f_buf = malloc(fs->fs_bsize);
348*4a5d661aSToomas Soome 
349*4a5d661aSToomas Soome 		twiddle(8);
350*4a5d661aSToomas Soome 		rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
351*4a5d661aSToomas Soome 			fsbtodb(fs, disk_block), 0,
352*4a5d661aSToomas Soome 			block_size, fp->f_buf, &fp->f_buf_size);
353*4a5d661aSToomas Soome 		if (rc)
354*4a5d661aSToomas Soome 			return (rc);
355*4a5d661aSToomas Soome 
356*4a5d661aSToomas Soome 		fp->f_buf_blkno = file_block;
357*4a5d661aSToomas Soome 	}
358*4a5d661aSToomas Soome 
359*4a5d661aSToomas Soome 	/*
360*4a5d661aSToomas Soome 	 *	Copy the user data into the cached block.
361*4a5d661aSToomas Soome 	 */
362*4a5d661aSToomas Soome 	bcopy(buf_p, fp->f_buf + off, *size_p);
363*4a5d661aSToomas Soome 
364*4a5d661aSToomas Soome 	/*
365*4a5d661aSToomas Soome 	 *	Write the block out to storage.
366*4a5d661aSToomas Soome 	 */
367*4a5d661aSToomas Soome 
368*4a5d661aSToomas Soome 	twiddle(4);
369*4a5d661aSToomas Soome 	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_WRITE,
370*4a5d661aSToomas Soome 		fsbtodb(fs, disk_block), 0,
371*4a5d661aSToomas Soome 		block_size, fp->f_buf, &fp->f_buf_size);
372*4a5d661aSToomas Soome 	return (rc);
373*4a5d661aSToomas Soome }
374*4a5d661aSToomas Soome 
375*4a5d661aSToomas Soome /*
376*4a5d661aSToomas Soome  * Read a portion of a file into an internal buffer.  Return
377*4a5d661aSToomas Soome  * the location in the buffer and the amount in the buffer.
378*4a5d661aSToomas Soome  */
379*4a5d661aSToomas Soome static int
380*4a5d661aSToomas Soome buf_read_file(f, buf_p, size_p)
381*4a5d661aSToomas Soome 	struct open_file *f;
382*4a5d661aSToomas Soome 	char **buf_p;		/* out */
383*4a5d661aSToomas Soome 	size_t *size_p;		/* out */
384*4a5d661aSToomas Soome {
385*4a5d661aSToomas Soome 	struct file *fp = (struct file *)f->f_fsdata;
386*4a5d661aSToomas Soome 	struct fs *fs = fp->f_fs;
387*4a5d661aSToomas Soome 	long off;
388*4a5d661aSToomas Soome 	ufs_lbn_t file_block;
389*4a5d661aSToomas Soome 	ufs2_daddr_t disk_block;
390*4a5d661aSToomas Soome 	size_t block_size;
391*4a5d661aSToomas Soome 	int rc;
392*4a5d661aSToomas Soome 
393*4a5d661aSToomas Soome 	off = blkoff(fs, fp->f_seekp);
394*4a5d661aSToomas Soome 	file_block = lblkno(fs, fp->f_seekp);
395*4a5d661aSToomas Soome 	block_size = sblksize(fs, DIP(fp, di_size), file_block);
396*4a5d661aSToomas Soome 
397*4a5d661aSToomas Soome 	if (file_block != fp->f_buf_blkno) {
398*4a5d661aSToomas Soome 		if (fp->f_buf == (char *)0)
399*4a5d661aSToomas Soome 			fp->f_buf = malloc(fs->fs_bsize);
400*4a5d661aSToomas Soome 
401*4a5d661aSToomas Soome 		rc = block_map(f, file_block, &disk_block);
402*4a5d661aSToomas Soome 		if (rc)
403*4a5d661aSToomas Soome 			return (rc);
404*4a5d661aSToomas Soome 
405*4a5d661aSToomas Soome 		if (disk_block == 0) {
406*4a5d661aSToomas Soome 			bzero(fp->f_buf, block_size);
407*4a5d661aSToomas Soome 			fp->f_buf_size = block_size;
408*4a5d661aSToomas Soome 		} else {
409*4a5d661aSToomas Soome 			twiddle(4);
410*4a5d661aSToomas Soome 			rc = (f->f_dev->dv_strategy)(f->f_devdata,
411*4a5d661aSToomas Soome 				F_READ, fsbtodb(fs, disk_block), 0,
412*4a5d661aSToomas Soome 				block_size, fp->f_buf, &fp->f_buf_size);
413*4a5d661aSToomas Soome 			if (rc)
414*4a5d661aSToomas Soome 				return (rc);
415*4a5d661aSToomas Soome 		}
416*4a5d661aSToomas Soome 
417*4a5d661aSToomas Soome 		fp->f_buf_blkno = file_block;
418*4a5d661aSToomas Soome 	}
419*4a5d661aSToomas Soome 
420*4a5d661aSToomas Soome 	/*
421*4a5d661aSToomas Soome 	 * Return address of byte in buffer corresponding to
422*4a5d661aSToomas Soome 	 * offset, and size of remainder of buffer after that
423*4a5d661aSToomas Soome 	 * byte.
424*4a5d661aSToomas Soome 	 */
425*4a5d661aSToomas Soome 	*buf_p = fp->f_buf + off;
426*4a5d661aSToomas Soome 	*size_p = block_size - off;
427*4a5d661aSToomas Soome 
428*4a5d661aSToomas Soome 	/*
429*4a5d661aSToomas Soome 	 * But truncate buffer at end of file.
430*4a5d661aSToomas Soome 	 */
431*4a5d661aSToomas Soome 	if (*size_p > DIP(fp, di_size) - fp->f_seekp)
432*4a5d661aSToomas Soome 		*size_p = DIP(fp, di_size) - fp->f_seekp;
433*4a5d661aSToomas Soome 
434*4a5d661aSToomas Soome 	return (0);
435*4a5d661aSToomas Soome }
436*4a5d661aSToomas Soome 
437*4a5d661aSToomas Soome /*
438*4a5d661aSToomas Soome  * Search a directory for a name and return its
439*4a5d661aSToomas Soome  * i_number.
440*4a5d661aSToomas Soome  */
441*4a5d661aSToomas Soome static int
442*4a5d661aSToomas Soome search_directory(name, f, inumber_p)
443*4a5d661aSToomas Soome 	char *name;
444*4a5d661aSToomas Soome 	struct open_file *f;
445*4a5d661aSToomas Soome 	ino_t *inumber_p;		/* out */
446*4a5d661aSToomas Soome {
447*4a5d661aSToomas Soome 	struct file *fp = (struct file *)f->f_fsdata;
448*4a5d661aSToomas Soome 	struct direct *dp;
449*4a5d661aSToomas Soome 	struct direct *edp;
450*4a5d661aSToomas Soome 	char *buf;
451*4a5d661aSToomas Soome 	size_t buf_size;
452*4a5d661aSToomas Soome 	int namlen, length;
453*4a5d661aSToomas Soome 	int rc;
454*4a5d661aSToomas Soome 
455*4a5d661aSToomas Soome 	length = strlen(name);
456*4a5d661aSToomas Soome 
457*4a5d661aSToomas Soome 	fp->f_seekp = 0;
458*4a5d661aSToomas Soome 	while (fp->f_seekp < DIP(fp, di_size)) {
459*4a5d661aSToomas Soome 		rc = buf_read_file(f, &buf, &buf_size);
460*4a5d661aSToomas Soome 		if (rc)
461*4a5d661aSToomas Soome 			return (rc);
462*4a5d661aSToomas Soome 
463*4a5d661aSToomas Soome 		dp = (struct direct *)buf;
464*4a5d661aSToomas Soome 		edp = (struct direct *)(buf + buf_size);
465*4a5d661aSToomas Soome 		while (dp < edp) {
466*4a5d661aSToomas Soome 			if (dp->d_ino == (ino_t)0)
467*4a5d661aSToomas Soome 				goto next;
468*4a5d661aSToomas Soome 			namlen = dp->d_namlen;
469*4a5d661aSToomas Soome 			if (namlen == length &&
470*4a5d661aSToomas Soome 			    !strcmp(name, dp->d_name)) {
471*4a5d661aSToomas Soome 				/* found entry */
472*4a5d661aSToomas Soome 				*inumber_p = dp->d_ino;
473*4a5d661aSToomas Soome 				return (0);
474*4a5d661aSToomas Soome 			}
475*4a5d661aSToomas Soome 		next:
476*4a5d661aSToomas Soome 			dp = (struct direct *)((char *)dp + dp->d_reclen);
477*4a5d661aSToomas Soome 		}
478*4a5d661aSToomas Soome 		fp->f_seekp += buf_size;
479*4a5d661aSToomas Soome 	}
480*4a5d661aSToomas Soome 	return (ENOENT);
481*4a5d661aSToomas Soome }
482*4a5d661aSToomas Soome 
483*4a5d661aSToomas Soome static int sblock_try[] = SBLOCKSEARCH;
484*4a5d661aSToomas Soome 
485*4a5d661aSToomas Soome /*
486*4a5d661aSToomas Soome  * Open a file.
487*4a5d661aSToomas Soome  */
488*4a5d661aSToomas Soome static int
489*4a5d661aSToomas Soome ufs_open(upath, f)
490*4a5d661aSToomas Soome 	const char *upath;
491*4a5d661aSToomas Soome 	struct open_file *f;
492*4a5d661aSToomas Soome {
493*4a5d661aSToomas Soome 	char *cp, *ncp;
494*4a5d661aSToomas Soome 	int c;
495*4a5d661aSToomas Soome 	ino_t inumber, parent_inumber;
496*4a5d661aSToomas Soome 	struct file *fp;
497*4a5d661aSToomas Soome 	struct fs *fs;
498*4a5d661aSToomas Soome 	int i, rc;
499*4a5d661aSToomas Soome 	size_t buf_size;
500*4a5d661aSToomas Soome 	int nlinks = 0;
501*4a5d661aSToomas Soome 	char namebuf[MAXPATHLEN+1];
502*4a5d661aSToomas Soome 	char *buf = NULL;
503*4a5d661aSToomas Soome 	char *path = NULL;
504*4a5d661aSToomas Soome 
505*4a5d661aSToomas Soome 	/* allocate file system specific data structure */
506*4a5d661aSToomas Soome 	fp = malloc(sizeof(struct file));
507*4a5d661aSToomas Soome 	bzero(fp, sizeof(struct file));
508*4a5d661aSToomas Soome 	f->f_fsdata = (void *)fp;
509*4a5d661aSToomas Soome 
510*4a5d661aSToomas Soome 	/* allocate space and read super block */
511*4a5d661aSToomas Soome 	fs = malloc(SBLOCKSIZE);
512*4a5d661aSToomas Soome 	fp->f_fs = fs;
513*4a5d661aSToomas Soome 	twiddle(1);
514*4a5d661aSToomas Soome 	/*
515*4a5d661aSToomas Soome 	 * Try reading the superblock in each of its possible locations.
516*4a5d661aSToomas Soome 	 */
517*4a5d661aSToomas Soome 	for (i = 0; sblock_try[i] != -1; i++) {
518*4a5d661aSToomas Soome 		rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
519*4a5d661aSToomas Soome 		    sblock_try[i] / DEV_BSIZE, 0, SBLOCKSIZE,
520*4a5d661aSToomas Soome 		    (char *)fs, &buf_size);
521*4a5d661aSToomas Soome 		if (rc)
522*4a5d661aSToomas Soome 			goto out;
523*4a5d661aSToomas Soome 		if ((fs->fs_magic == FS_UFS1_MAGIC ||
524*4a5d661aSToomas Soome 		     (fs->fs_magic == FS_UFS2_MAGIC &&
525*4a5d661aSToomas Soome 		      fs->fs_sblockloc == sblock_try[i])) &&
526*4a5d661aSToomas Soome 		    buf_size == SBLOCKSIZE &&
527*4a5d661aSToomas Soome 		    fs->fs_bsize <= MAXBSIZE &&
528*4a5d661aSToomas Soome 		    fs->fs_bsize >= sizeof(struct fs))
529*4a5d661aSToomas Soome 			break;
530*4a5d661aSToomas Soome 	}
531*4a5d661aSToomas Soome 	if (sblock_try[i] == -1) {
532*4a5d661aSToomas Soome 		rc = EINVAL;
533*4a5d661aSToomas Soome 		goto out;
534*4a5d661aSToomas Soome 	}
535*4a5d661aSToomas Soome 	/*
536*4a5d661aSToomas Soome 	 * Calculate indirect block levels.
537*4a5d661aSToomas Soome 	 */
538*4a5d661aSToomas Soome 	{
539*4a5d661aSToomas Soome 		ufs2_daddr_t mult;
540*4a5d661aSToomas Soome 		int level;
541*4a5d661aSToomas Soome 
542*4a5d661aSToomas Soome 		mult = 1;
543*4a5d661aSToomas Soome 		for (level = 0; level < NIADDR; level++) {
544*4a5d661aSToomas Soome 			mult *= NINDIR(fs);
545*4a5d661aSToomas Soome 			fp->f_nindir[level] = mult;
546*4a5d661aSToomas Soome 		}
547*4a5d661aSToomas Soome 	}
548*4a5d661aSToomas Soome 
549*4a5d661aSToomas Soome 	inumber = ROOTINO;
550*4a5d661aSToomas Soome 	if ((rc = read_inode(inumber, f)) != 0)
551*4a5d661aSToomas Soome 		goto out;
552*4a5d661aSToomas Soome 
553*4a5d661aSToomas Soome 	cp = path = strdup(upath);
554*4a5d661aSToomas Soome 	if (path == NULL) {
555*4a5d661aSToomas Soome 	    rc = ENOMEM;
556*4a5d661aSToomas Soome 	    goto out;
557*4a5d661aSToomas Soome 	}
558*4a5d661aSToomas Soome 	while (*cp) {
559*4a5d661aSToomas Soome 
560*4a5d661aSToomas Soome 		/*
561*4a5d661aSToomas Soome 		 * Remove extra separators
562*4a5d661aSToomas Soome 		 */
563*4a5d661aSToomas Soome 		while (*cp == '/')
564*4a5d661aSToomas Soome 			cp++;
565*4a5d661aSToomas Soome 		if (*cp == '\0')
566*4a5d661aSToomas Soome 			break;
567*4a5d661aSToomas Soome 
568*4a5d661aSToomas Soome 		/*
569*4a5d661aSToomas Soome 		 * Check that current node is a directory.
570*4a5d661aSToomas Soome 		 */
571*4a5d661aSToomas Soome 		if ((DIP(fp, di_mode) & IFMT) != IFDIR) {
572*4a5d661aSToomas Soome 			rc = ENOTDIR;
573*4a5d661aSToomas Soome 			goto out;
574*4a5d661aSToomas Soome 		}
575*4a5d661aSToomas Soome 
576*4a5d661aSToomas Soome 		/*
577*4a5d661aSToomas Soome 		 * Get next component of path name.
578*4a5d661aSToomas Soome 		 */
579*4a5d661aSToomas Soome 		{
580*4a5d661aSToomas Soome 			int len = 0;
581*4a5d661aSToomas Soome 
582*4a5d661aSToomas Soome 			ncp = cp;
583*4a5d661aSToomas Soome 			while ((c = *cp) != '\0' && c != '/') {
584*4a5d661aSToomas Soome 				if (++len > MAXNAMLEN) {
585*4a5d661aSToomas Soome 					rc = ENOENT;
586*4a5d661aSToomas Soome 					goto out;
587*4a5d661aSToomas Soome 				}
588*4a5d661aSToomas Soome 				cp++;
589*4a5d661aSToomas Soome 			}
590*4a5d661aSToomas Soome 			*cp = '\0';
591*4a5d661aSToomas Soome 		}
592*4a5d661aSToomas Soome 
593*4a5d661aSToomas Soome 		/*
594*4a5d661aSToomas Soome 		 * Look up component in current directory.
595*4a5d661aSToomas Soome 		 * Save directory inumber in case we find a
596*4a5d661aSToomas Soome 		 * symbolic link.
597*4a5d661aSToomas Soome 		 */
598*4a5d661aSToomas Soome 		parent_inumber = inumber;
599*4a5d661aSToomas Soome 		rc = search_directory(ncp, f, &inumber);
600*4a5d661aSToomas Soome 		*cp = c;
601*4a5d661aSToomas Soome 		if (rc)
602*4a5d661aSToomas Soome 			goto out;
603*4a5d661aSToomas Soome 
604*4a5d661aSToomas Soome 		/*
605*4a5d661aSToomas Soome 		 * Open next component.
606*4a5d661aSToomas Soome 		 */
607*4a5d661aSToomas Soome 		if ((rc = read_inode(inumber, f)) != 0)
608*4a5d661aSToomas Soome 			goto out;
609*4a5d661aSToomas Soome 
610*4a5d661aSToomas Soome 		/*
611*4a5d661aSToomas Soome 		 * Check for symbolic link.
612*4a5d661aSToomas Soome 		 */
613*4a5d661aSToomas Soome 		if ((DIP(fp, di_mode) & IFMT) == IFLNK) {
614*4a5d661aSToomas Soome 			int link_len = DIP(fp, di_size);
615*4a5d661aSToomas Soome 			int len;
616*4a5d661aSToomas Soome 
617*4a5d661aSToomas Soome 			len = strlen(cp);
618*4a5d661aSToomas Soome 
619*4a5d661aSToomas Soome 			if (link_len + len > MAXPATHLEN ||
620*4a5d661aSToomas Soome 			    ++nlinks > MAXSYMLINKS) {
621*4a5d661aSToomas Soome 				rc = ENOENT;
622*4a5d661aSToomas Soome 				goto out;
623*4a5d661aSToomas Soome 			}
624*4a5d661aSToomas Soome 
625*4a5d661aSToomas Soome 			bcopy(cp, &namebuf[link_len], len + 1);
626*4a5d661aSToomas Soome 
627*4a5d661aSToomas Soome 			if (link_len < fs->fs_maxsymlinklen) {
628*4a5d661aSToomas Soome 				if (fp->f_fs->fs_magic == FS_UFS1_MAGIC)
629*4a5d661aSToomas Soome 					cp = (caddr_t)(fp->f_di.di1.di_db);
630*4a5d661aSToomas Soome 				else
631*4a5d661aSToomas Soome 					cp = (caddr_t)(fp->f_di.di2.di_db);
632*4a5d661aSToomas Soome 				bcopy(cp, namebuf, (unsigned) link_len);
633*4a5d661aSToomas Soome 			} else {
634*4a5d661aSToomas Soome 				/*
635*4a5d661aSToomas Soome 				 * Read file for symbolic link
636*4a5d661aSToomas Soome 				 */
637*4a5d661aSToomas Soome 				size_t buf_size;
638*4a5d661aSToomas Soome 				ufs2_daddr_t disk_block;
639*4a5d661aSToomas Soome 				struct fs *fs = fp->f_fs;
640*4a5d661aSToomas Soome 
641*4a5d661aSToomas Soome 				if (!buf)
642*4a5d661aSToomas Soome 					buf = malloc(fs->fs_bsize);
643*4a5d661aSToomas Soome 				rc = block_map(f, (ufs2_daddr_t)0, &disk_block);
644*4a5d661aSToomas Soome 				if (rc)
645*4a5d661aSToomas Soome 					goto out;
646*4a5d661aSToomas Soome 
647*4a5d661aSToomas Soome 				twiddle(1);
648*4a5d661aSToomas Soome 				rc = (f->f_dev->dv_strategy)(f->f_devdata,
649*4a5d661aSToomas Soome 					F_READ, fsbtodb(fs, disk_block), 0,
650*4a5d661aSToomas Soome 					fs->fs_bsize, buf, &buf_size);
651*4a5d661aSToomas Soome 				if (rc)
652*4a5d661aSToomas Soome 					goto out;
653*4a5d661aSToomas Soome 
654*4a5d661aSToomas Soome 				bcopy((char *)buf, namebuf, (unsigned)link_len);
655*4a5d661aSToomas Soome 			}
656*4a5d661aSToomas Soome 
657*4a5d661aSToomas Soome 			/*
658*4a5d661aSToomas Soome 			 * If relative pathname, restart at parent directory.
659*4a5d661aSToomas Soome 			 * If absolute pathname, restart at root.
660*4a5d661aSToomas Soome 			 */
661*4a5d661aSToomas Soome 			cp = namebuf;
662*4a5d661aSToomas Soome 			if (*cp != '/')
663*4a5d661aSToomas Soome 				inumber = parent_inumber;
664*4a5d661aSToomas Soome 			else
665*4a5d661aSToomas Soome 				inumber = (ino_t)ROOTINO;
666*4a5d661aSToomas Soome 
667*4a5d661aSToomas Soome 			if ((rc = read_inode(inumber, f)) != 0)
668*4a5d661aSToomas Soome 				goto out;
669*4a5d661aSToomas Soome 		}
670*4a5d661aSToomas Soome 	}
671*4a5d661aSToomas Soome 
672*4a5d661aSToomas Soome 	/*
673*4a5d661aSToomas Soome 	 * Found terminal component.
674*4a5d661aSToomas Soome 	 */
675*4a5d661aSToomas Soome 	rc = 0;
676*4a5d661aSToomas Soome 	fp->f_seekp = 0;
677*4a5d661aSToomas Soome out:
678*4a5d661aSToomas Soome 	if (buf)
679*4a5d661aSToomas Soome 		free(buf);
680*4a5d661aSToomas Soome 	if (path)
681*4a5d661aSToomas Soome 		free(path);
682*4a5d661aSToomas Soome 	if (rc) {
683*4a5d661aSToomas Soome 		if (fp->f_buf)
684*4a5d661aSToomas Soome 			free(fp->f_buf);
685*4a5d661aSToomas Soome 		free(fp->f_fs);
686*4a5d661aSToomas Soome 		free(fp);
687*4a5d661aSToomas Soome 	}
688*4a5d661aSToomas Soome 	return (rc);
689*4a5d661aSToomas Soome }
690*4a5d661aSToomas Soome 
691*4a5d661aSToomas Soome static int
692*4a5d661aSToomas Soome ufs_close(f)
693*4a5d661aSToomas Soome 	struct open_file *f;
694*4a5d661aSToomas Soome {
695*4a5d661aSToomas Soome 	struct file *fp = (struct file *)f->f_fsdata;
696*4a5d661aSToomas Soome 	int level;
697*4a5d661aSToomas Soome 
698*4a5d661aSToomas Soome 	f->f_fsdata = (void *)0;
699*4a5d661aSToomas Soome 	if (fp == (struct file *)0)
700*4a5d661aSToomas Soome 		return (0);
701*4a5d661aSToomas Soome 
702*4a5d661aSToomas Soome 	for (level = 0; level < NIADDR; level++) {
703*4a5d661aSToomas Soome 		if (fp->f_blk[level])
704*4a5d661aSToomas Soome 			free(fp->f_blk[level]);
705*4a5d661aSToomas Soome 	}
706*4a5d661aSToomas Soome 	if (fp->f_buf)
707*4a5d661aSToomas Soome 		free(fp->f_buf);
708*4a5d661aSToomas Soome 	free(fp->f_fs);
709*4a5d661aSToomas Soome 	free(fp);
710*4a5d661aSToomas Soome 	return (0);
711*4a5d661aSToomas Soome }
712*4a5d661aSToomas Soome 
713*4a5d661aSToomas Soome /*
714*4a5d661aSToomas Soome  * Copy a portion of a file into kernel memory.
715*4a5d661aSToomas Soome  * Cross block boundaries when necessary.
716*4a5d661aSToomas Soome  */
717*4a5d661aSToomas Soome static int
718*4a5d661aSToomas Soome ufs_read(f, start, size, resid)
719*4a5d661aSToomas Soome 	struct open_file *f;
720*4a5d661aSToomas Soome 	void *start;
721*4a5d661aSToomas Soome 	size_t size;
722*4a5d661aSToomas Soome 	size_t *resid;	/* out */
723*4a5d661aSToomas Soome {
724*4a5d661aSToomas Soome 	struct file *fp = (struct file *)f->f_fsdata;
725*4a5d661aSToomas Soome 	size_t csize;
726*4a5d661aSToomas Soome 	char *buf;
727*4a5d661aSToomas Soome 	size_t buf_size;
728*4a5d661aSToomas Soome 	int rc = 0;
729*4a5d661aSToomas Soome 	char *addr = start;
730*4a5d661aSToomas Soome 
731*4a5d661aSToomas Soome 	while (size != 0) {
732*4a5d661aSToomas Soome 		if (fp->f_seekp >= DIP(fp, di_size))
733*4a5d661aSToomas Soome 			break;
734*4a5d661aSToomas Soome 
735*4a5d661aSToomas Soome 		rc = buf_read_file(f, &buf, &buf_size);
736*4a5d661aSToomas Soome 		if (rc)
737*4a5d661aSToomas Soome 			break;
738*4a5d661aSToomas Soome 
739*4a5d661aSToomas Soome 		csize = size;
740*4a5d661aSToomas Soome 		if (csize > buf_size)
741*4a5d661aSToomas Soome 			csize = buf_size;
742*4a5d661aSToomas Soome 
743*4a5d661aSToomas Soome 		bcopy(buf, addr, csize);
744*4a5d661aSToomas Soome 
745*4a5d661aSToomas Soome 		fp->f_seekp += csize;
746*4a5d661aSToomas Soome 		addr += csize;
747*4a5d661aSToomas Soome 		size -= csize;
748*4a5d661aSToomas Soome 	}
749*4a5d661aSToomas Soome 	if (resid)
750*4a5d661aSToomas Soome 		*resid = size;
751*4a5d661aSToomas Soome 	return (rc);
752*4a5d661aSToomas Soome }
753*4a5d661aSToomas Soome 
754*4a5d661aSToomas Soome /*
755*4a5d661aSToomas Soome  * Write to a portion of an already allocated file.
756*4a5d661aSToomas Soome  * Cross block boundaries when necessary. Can not
757*4a5d661aSToomas Soome  * extend the file.
758*4a5d661aSToomas Soome  */
759*4a5d661aSToomas Soome static int
760*4a5d661aSToomas Soome ufs_write(f, start, size, resid)
761*4a5d661aSToomas Soome 	struct open_file *f;
762*4a5d661aSToomas Soome 	void *start;
763*4a5d661aSToomas Soome 	size_t size;
764*4a5d661aSToomas Soome 	size_t *resid;	/* out */
765*4a5d661aSToomas Soome {
766*4a5d661aSToomas Soome 	struct file *fp = (struct file *)f->f_fsdata;
767*4a5d661aSToomas Soome 	size_t csize;
768*4a5d661aSToomas Soome 	int rc = 0;
769*4a5d661aSToomas Soome 	char *addr = start;
770*4a5d661aSToomas Soome 
771*4a5d661aSToomas Soome 	csize = size;
772*4a5d661aSToomas Soome 	while ((size != 0) && (csize != 0)) {
773*4a5d661aSToomas Soome 		if (fp->f_seekp >= DIP(fp, di_size))
774*4a5d661aSToomas Soome 			break;
775*4a5d661aSToomas Soome 
776*4a5d661aSToomas Soome 		if (csize >= 512) csize = 512; /* XXX */
777*4a5d661aSToomas Soome 
778*4a5d661aSToomas Soome 		rc = buf_write_file(f, addr, &csize);
779*4a5d661aSToomas Soome 		if (rc)
780*4a5d661aSToomas Soome 			break;
781*4a5d661aSToomas Soome 
782*4a5d661aSToomas Soome 		fp->f_seekp += csize;
783*4a5d661aSToomas Soome 		addr += csize;
784*4a5d661aSToomas Soome 		size -= csize;
785*4a5d661aSToomas Soome 	}
786*4a5d661aSToomas Soome 	if (resid)
787*4a5d661aSToomas Soome 		*resid = size;
788*4a5d661aSToomas Soome 	return (rc);
789*4a5d661aSToomas Soome }
790*4a5d661aSToomas Soome 
791*4a5d661aSToomas Soome static off_t
792*4a5d661aSToomas Soome ufs_seek(f, offset, where)
793*4a5d661aSToomas Soome 	struct open_file *f;
794*4a5d661aSToomas Soome 	off_t offset;
795*4a5d661aSToomas Soome 	int where;
796*4a5d661aSToomas Soome {
797*4a5d661aSToomas Soome 	struct file *fp = (struct file *)f->f_fsdata;
798*4a5d661aSToomas Soome 
799*4a5d661aSToomas Soome 	switch (where) {
800*4a5d661aSToomas Soome 	case SEEK_SET:
801*4a5d661aSToomas Soome 		fp->f_seekp = offset;
802*4a5d661aSToomas Soome 		break;
803*4a5d661aSToomas Soome 	case SEEK_CUR:
804*4a5d661aSToomas Soome 		fp->f_seekp += offset;
805*4a5d661aSToomas Soome 		break;
806*4a5d661aSToomas Soome 	case SEEK_END:
807*4a5d661aSToomas Soome 		fp->f_seekp = DIP(fp, di_size) - offset;
808*4a5d661aSToomas Soome 		break;
809*4a5d661aSToomas Soome 	default:
810*4a5d661aSToomas Soome 		errno = EINVAL;
811*4a5d661aSToomas Soome 		return (-1);
812*4a5d661aSToomas Soome 	}
813*4a5d661aSToomas Soome 	return (fp->f_seekp);
814*4a5d661aSToomas Soome }
815*4a5d661aSToomas Soome 
816*4a5d661aSToomas Soome static int
817*4a5d661aSToomas Soome ufs_stat(f, sb)
818*4a5d661aSToomas Soome 	struct open_file *f;
819*4a5d661aSToomas Soome 	struct stat *sb;
820*4a5d661aSToomas Soome {
821*4a5d661aSToomas Soome 	struct file *fp = (struct file *)f->f_fsdata;
822*4a5d661aSToomas Soome 
823*4a5d661aSToomas Soome 	/* only important stuff */
824*4a5d661aSToomas Soome 	sb->st_mode = DIP(fp, di_mode);
825*4a5d661aSToomas Soome 	sb->st_uid = DIP(fp, di_uid);
826*4a5d661aSToomas Soome 	sb->st_gid = DIP(fp, di_gid);
827*4a5d661aSToomas Soome 	sb->st_size = DIP(fp, di_size);
828*4a5d661aSToomas Soome 	return (0);
829*4a5d661aSToomas Soome }
830*4a5d661aSToomas Soome 
831*4a5d661aSToomas Soome static int
832*4a5d661aSToomas Soome ufs_readdir(struct open_file *f, struct dirent *d)
833*4a5d661aSToomas Soome {
834*4a5d661aSToomas Soome 	struct file *fp = (struct file *)f->f_fsdata;
835*4a5d661aSToomas Soome 	struct direct *dp;
836*4a5d661aSToomas Soome 	char *buf;
837*4a5d661aSToomas Soome 	size_t buf_size;
838*4a5d661aSToomas Soome 	int error;
839*4a5d661aSToomas Soome 
840*4a5d661aSToomas Soome 	/*
841*4a5d661aSToomas Soome 	 * assume that a directory entry will not be split across blocks
842*4a5d661aSToomas Soome 	 */
843*4a5d661aSToomas Soome again:
844*4a5d661aSToomas Soome 	if (fp->f_seekp >= DIP(fp, di_size))
845*4a5d661aSToomas Soome 		return (ENOENT);
846*4a5d661aSToomas Soome 	error = buf_read_file(f, &buf, &buf_size);
847*4a5d661aSToomas Soome 	if (error)
848*4a5d661aSToomas Soome 		return (error);
849*4a5d661aSToomas Soome 	dp = (struct direct *)buf;
850*4a5d661aSToomas Soome 	fp->f_seekp += dp->d_reclen;
851*4a5d661aSToomas Soome 	if (dp->d_ino == (ino_t)0)
852*4a5d661aSToomas Soome 		goto again;
853*4a5d661aSToomas Soome 
854*4a5d661aSToomas Soome 	d->d_type = 0;		/* illumos ufs does not have type in direct */
855*4a5d661aSToomas Soome 	strcpy(d->d_name, dp->d_name);
856*4a5d661aSToomas Soome 	return (0);
857*4a5d661aSToomas Soome }
858