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