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