xref: /freebsd/stand/libsa/ufs.c (revision 3e15b01d)
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 /*
71ca987d46SWarner Losh  *	Stand-alone file reading package.
72ca987d46SWarner Losh  */
73ca987d46SWarner Losh 
74ca987d46SWarner Losh #include <sys/param.h>
75ca987d46SWarner Losh #include <sys/disklabel.h>
76ca987d46SWarner Losh #include <sys/time.h>
77ca987d46SWarner Losh #include <ufs/ufs/dinode.h>
78ca987d46SWarner Losh #include <ufs/ufs/dir.h>
79ca987d46SWarner Losh #include <ufs/ffs/fs.h>
80ca987d46SWarner Losh #include "stand.h"
81ca987d46SWarner Losh #include "string.h"
82ca987d46SWarner Losh 
83ca987d46SWarner Losh static int	ufs_open(const char *path, struct open_file *f);
842e7e6fbcSConrad Meyer static int	ufs_write(struct open_file *f, const void *buf, size_t size,
852e7e6fbcSConrad Meyer 		size_t *resid);
86ca987d46SWarner Losh static int	ufs_close(struct open_file *f);
87ca987d46SWarner Losh static int	ufs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
88ca987d46SWarner Losh static off_t	ufs_seek(struct open_file *f, off_t offset, int where);
89ca987d46SWarner Losh static int	ufs_stat(struct open_file *f, struct stat *sb);
90ca987d46SWarner Losh static int	ufs_readdir(struct open_file *f, struct dirent *d);
91b4cb3fe0SToomas Soome static int	ufs_mount(const char *dev, const char *path, void **data);
92b4cb3fe0SToomas Soome static int	ufs_unmount(const char *dev, void *data);
93ca987d46SWarner Losh 
94ca987d46SWarner Losh struct fs_ops ufs_fsops = {
95b4cb3fe0SToomas Soome 	.fs_name = "ufs",
96b4cb3fe0SToomas Soome 	.fo_open = ufs_open,
97b4cb3fe0SToomas Soome 	.fo_close = ufs_close,
98b4cb3fe0SToomas Soome 	.fo_read = ufs_read,
99b4cb3fe0SToomas Soome 	.fo_write = ufs_write,
100b4cb3fe0SToomas Soome 	.fo_seek = ufs_seek,
101b4cb3fe0SToomas Soome 	.fo_stat = ufs_stat,
102b4cb3fe0SToomas Soome 	.fo_readdir = ufs_readdir,
103b4cb3fe0SToomas Soome 	.fo_mount = ufs_mount,
104b4cb3fe0SToomas Soome 	.fo_unmount = ufs_unmount
105ca987d46SWarner Losh };
106ca987d46SWarner Losh 
107ca987d46SWarner Losh /*
108ca987d46SWarner Losh  * In-core open file.
109ca987d46SWarner Losh  */
110ca987d46SWarner Losh struct file {
111ca987d46SWarner Losh 	off_t		f_seekp;	/* seek pointer */
112ca987d46SWarner Losh 	struct fs	*f_fs;		/* pointer to super-block */
113ca987d46SWarner Losh 	union dinode {
114ca987d46SWarner Losh 		struct ufs1_dinode di1;
115ca987d46SWarner Losh 		struct ufs2_dinode di2;
116ca987d46SWarner Losh 	}		f_di;		/* copy of on-disk inode */
117ca987d46SWarner Losh 	int		f_nindir[UFS_NIADDR];
118ca987d46SWarner Losh 					/* number of blocks mapped by
119ca987d46SWarner Losh 					   indirect block at level i */
120ca987d46SWarner Losh 	char		*f_blk[UFS_NIADDR];	/* buffer for indirect block at
121ca987d46SWarner Losh 					   level i */
122ca987d46SWarner Losh 	size_t		f_blksize[UFS_NIADDR];
123ca987d46SWarner Losh 					/* size of buffer */
124ca987d46SWarner Losh 	ufs2_daddr_t	f_blkno[UFS_NIADDR];/* disk address of block in buffer */
125ca987d46SWarner Losh 	ufs2_daddr_t	f_buf_blkno;	/* block number of data block */
126ca987d46SWarner Losh 	char		*f_buf;		/* buffer for data block */
127ca987d46SWarner Losh 	size_t		f_buf_size;	/* size of data block */
1285ad42d0fSSimon J. Gerraty 	int		f_inumber;	/* inumber */
129ca987d46SWarner Losh };
130ca987d46SWarner Losh #define DIP(fp, field) \
131ca987d46SWarner Losh 	((fp)->f_fs->fs_magic == FS_UFS1_MAGIC ? \
132ca987d46SWarner Losh 	(fp)->f_di.di1.field : (fp)->f_di.di2.field)
133ca987d46SWarner Losh 
134b4cb3fe0SToomas Soome typedef struct ufs_mnt {
135b4cb3fe0SToomas Soome 	char			*um_dev;
136b4cb3fe0SToomas Soome 	int			um_fd;
137b4cb3fe0SToomas Soome 	STAILQ_ENTRY(ufs_mnt)	um_link;
138b4cb3fe0SToomas Soome } ufs_mnt_t;
139b4cb3fe0SToomas Soome 
140b4cb3fe0SToomas Soome typedef STAILQ_HEAD(ufs_mnt_list, ufs_mnt) ufs_mnt_list_t;
141b4cb3fe0SToomas Soome static ufs_mnt_list_t mnt_list = STAILQ_HEAD_INITIALIZER(mnt_list);
142b4cb3fe0SToomas Soome 
143ca987d46SWarner Losh static int	read_inode(ino_t, struct open_file *);
144ca987d46SWarner Losh static int	block_map(struct open_file *, ufs2_daddr_t, ufs2_daddr_t *);
145ca987d46SWarner Losh static int	buf_read_file(struct open_file *, char **, size_t *);
1462e7e6fbcSConrad Meyer static int	buf_write_file(struct open_file *, const char *, size_t *);
147ca987d46SWarner Losh static int	search_directory(char *, struct open_file *, ino_t *);
148dffce215SKirk McKusick static int	ufs_use_sa_read(void *, off_t, void **, int);
149dffce215SKirk McKusick 
150dffce215SKirk McKusick /* from ffs_subr.c */
1516d645da0SWarner Losh int	ffs_sbget(void *devfd, struct fs **fsp, off_t sblock, int flags,
1526d645da0SWarner Losh 	    char *filltype,
1536d645da0SWarner Losh 	    int (*readfunc)(void *devfd, off_t loc, void **bufp, int size));
154e6886616SKirk McKusick int	ffs_sbsearch(void *, struct fs **, int, char *,
155dffce215SKirk McKusick 	    int (*)(void *, off_t, void **, int));
156ca987d46SWarner Losh 
157ca987d46SWarner Losh /*
158ca987d46SWarner Losh  * Read a new inode into a file structure.
159ca987d46SWarner Losh  */
160ca987d46SWarner Losh static int
read_inode(ino_t inumber,struct open_file * f)161b4cb3fe0SToomas Soome read_inode(ino_t inumber, struct open_file *f)
162ca987d46SWarner Losh {
163ca987d46SWarner Losh 	struct file *fp = (struct file *)f->f_fsdata;
164ca987d46SWarner Losh 	struct fs *fs = fp->f_fs;
165ca987d46SWarner Losh 	char *buf;
166ca987d46SWarner Losh 	size_t rsize;
167ca987d46SWarner Losh 	int rc;
168ca987d46SWarner Losh 
169ca987d46SWarner Losh 	if (fs == NULL)
170ca987d46SWarner Losh 	    panic("fs == NULL");
171ca987d46SWarner Losh 
172ca987d46SWarner Losh 	/*
173ca987d46SWarner Losh 	 * Read inode and save it.
174ca987d46SWarner Losh 	 */
175ca987d46SWarner Losh 	buf = malloc(fs->fs_bsize);
176ca987d46SWarner Losh 	twiddle(1);
177ca987d46SWarner Losh 	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
178ca987d46SWarner Losh 		fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize,
179ca987d46SWarner Losh 		buf, &rsize);
180ca987d46SWarner Losh 	if (rc)
181ca987d46SWarner Losh 		goto out;
182ca987d46SWarner Losh 	if (rsize != fs->fs_bsize) {
183ca987d46SWarner Losh 		rc = EIO;
184ca987d46SWarner Losh 		goto out;
185ca987d46SWarner Losh 	}
186ca987d46SWarner Losh 
187ca987d46SWarner Losh 	if (fp->f_fs->fs_magic == FS_UFS1_MAGIC)
188ca987d46SWarner Losh 		fp->f_di.di1 = ((struct ufs1_dinode *)buf)
189ca987d46SWarner Losh 		    [ino_to_fsbo(fs, inumber)];
190ca987d46SWarner Losh 	else
191ca987d46SWarner Losh 		fp->f_di.di2 = ((struct ufs2_dinode *)buf)
192ca987d46SWarner Losh 		    [ino_to_fsbo(fs, inumber)];
193ca987d46SWarner Losh 
194ca987d46SWarner Losh 	/*
195ca987d46SWarner Losh 	 * Clear out the old buffers
196ca987d46SWarner Losh 	 */
197ca987d46SWarner Losh 	{
198ca987d46SWarner Losh 		int level;
199ca987d46SWarner Losh 
200ca987d46SWarner Losh 		for (level = 0; level < UFS_NIADDR; level++)
201ca987d46SWarner Losh 			fp->f_blkno[level] = -1;
202ca987d46SWarner Losh 		fp->f_buf_blkno = -1;
203ca987d46SWarner Losh 	}
204ca987d46SWarner Losh 	fp->f_seekp = 0;
2055ad42d0fSSimon J. Gerraty 	fp->f_inumber = inumber;
206ca987d46SWarner Losh out:
207ca987d46SWarner Losh 	free(buf);
208ca987d46SWarner Losh 	return (rc);
209ca987d46SWarner Losh }
210ca987d46SWarner Losh 
211ca987d46SWarner Losh /*
212ca987d46SWarner Losh  * Given an offset in a file, find the disk block number that
213ca987d46SWarner Losh  * contains that block.
214ca987d46SWarner Losh  */
215ca987d46SWarner Losh static int
block_map(struct open_file * f,ufs2_daddr_t file_block,ufs2_daddr_t * disk_block_p)216b4cb3fe0SToomas Soome block_map(struct open_file *f, ufs2_daddr_t file_block,
217b4cb3fe0SToomas Soome     ufs2_daddr_t *disk_block_p)
218ca987d46SWarner Losh {
219ca987d46SWarner Losh 	struct file *fp = (struct file *)f->f_fsdata;
220ca987d46SWarner Losh 	struct fs *fs = fp->f_fs;
221ca987d46SWarner Losh 	int level;
222ca987d46SWarner Losh 	int idx;
223ca987d46SWarner Losh 	ufs2_daddr_t ind_block_num;
224ca987d46SWarner Losh 	int rc;
225ca987d46SWarner Losh 
226ca987d46SWarner Losh 	/*
227ca987d46SWarner Losh 	 * Index structure of an inode:
228ca987d46SWarner Losh 	 *
229ca987d46SWarner Losh 	 * di_db[0..UFS_NDADDR-1] hold block numbers for blocks
230ca987d46SWarner Losh 	 *			0..UFS_NDADDR-1
231ca987d46SWarner Losh 	 *
232ca987d46SWarner Losh 	 * di_ib[0]		index block 0 is the single indirect block
233ca987d46SWarner Losh 	 *			holds block numbers for blocks
234ca987d46SWarner Losh 	 *			UFS_NDADDR .. UFS_NDADDR + NINDIR(fs)-1
235ca987d46SWarner Losh 	 *
236ca987d46SWarner Losh 	 * di_ib[1]		index block 1 is the double indirect block
237ca987d46SWarner Losh 	 *			holds block numbers for INDEX blocks for blocks
238ca987d46SWarner Losh 	 *			UFS_NDADDR + NINDIR(fs) ..
239ca987d46SWarner Losh 	 *			UFS_NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1
240ca987d46SWarner Losh 	 *
241ca987d46SWarner Losh 	 * di_ib[2]		index block 2 is the triple indirect block
242ca987d46SWarner Losh 	 *			holds block numbers for double-indirect
243ca987d46SWarner Losh 	 *			blocks for blocks
244ca987d46SWarner Losh 	 *			UFS_NDADDR + NINDIR(fs) + NINDIR(fs)**2 ..
245ca987d46SWarner Losh 	 *			UFS_NDADDR + NINDIR(fs) + NINDIR(fs)**2
246ca987d46SWarner Losh 	 *				+ NINDIR(fs)**3 - 1
247ca987d46SWarner Losh 	 */
248ca987d46SWarner Losh 
249ca987d46SWarner Losh 	if (file_block < UFS_NDADDR) {
250ca987d46SWarner Losh 		/* Direct block. */
251ca987d46SWarner Losh 		*disk_block_p = DIP(fp, di_db[file_block]);
252ca987d46SWarner Losh 		return (0);
253ca987d46SWarner Losh 	}
254ca987d46SWarner Losh 
255ca987d46SWarner Losh 	file_block -= UFS_NDADDR;
256ca987d46SWarner Losh 
257ca987d46SWarner Losh 	/*
258ca987d46SWarner Losh 	 * nindir[0] = NINDIR
259ca987d46SWarner Losh 	 * nindir[1] = NINDIR**2
260ca987d46SWarner Losh 	 * nindir[2] = NINDIR**3
261ca987d46SWarner Losh 	 *	etc
262ca987d46SWarner Losh 	 */
263ca987d46SWarner Losh 	for (level = 0; level < UFS_NIADDR; level++) {
264ca987d46SWarner Losh 		if (file_block < fp->f_nindir[level])
265ca987d46SWarner Losh 			break;
266ca987d46SWarner Losh 		file_block -= fp->f_nindir[level];
267ca987d46SWarner Losh 	}
268ca987d46SWarner Losh 	if (level == UFS_NIADDR) {
269ca987d46SWarner Losh 		/* Block number too high */
270ca987d46SWarner Losh 		return (EFBIG);
271ca987d46SWarner Losh 	}
272ca987d46SWarner Losh 
273ca987d46SWarner Losh 	ind_block_num = DIP(fp, di_ib[level]);
274ca987d46SWarner Losh 
275ca987d46SWarner Losh 	for (; level >= 0; level--) {
276ca987d46SWarner Losh 		if (ind_block_num == 0) {
277ca987d46SWarner Losh 			*disk_block_p = 0;	/* missing */
278ca987d46SWarner Losh 			return (0);
279ca987d46SWarner Losh 		}
280ca987d46SWarner Losh 
281ca987d46SWarner Losh 		if (fp->f_blkno[level] != ind_block_num) {
282ca987d46SWarner Losh 			if (fp->f_blk[level] == (char *)0)
283ca987d46SWarner Losh 				fp->f_blk[level] =
284ca987d46SWarner Losh 					malloc(fs->fs_bsize);
285ca987d46SWarner Losh 			twiddle(1);
286ca987d46SWarner Losh 			rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
287ca987d46SWarner Losh 				fsbtodb(fp->f_fs, ind_block_num),
288ca987d46SWarner Losh 				fs->fs_bsize,
289ca987d46SWarner Losh 				fp->f_blk[level],
290ca987d46SWarner Losh 				&fp->f_blksize[level]);
291ca987d46SWarner Losh 			if (rc)
292ca987d46SWarner Losh 				return (rc);
293ca987d46SWarner Losh 			if (fp->f_blksize[level] != fs->fs_bsize)
294ca987d46SWarner Losh 				return (EIO);
295ca987d46SWarner Losh 			fp->f_blkno[level] = ind_block_num;
296ca987d46SWarner Losh 		}
297ca987d46SWarner Losh 
298ca987d46SWarner Losh 		if (level > 0) {
299ca987d46SWarner Losh 			idx = file_block / fp->f_nindir[level - 1];
300ca987d46SWarner Losh 			file_block %= fp->f_nindir[level - 1];
301ca987d46SWarner Losh 		} else
302ca987d46SWarner Losh 			idx = file_block;
303ca987d46SWarner Losh 
304ca987d46SWarner Losh 		if (fp->f_fs->fs_magic == FS_UFS1_MAGIC)
305ca987d46SWarner Losh 			ind_block_num = ((ufs1_daddr_t *)fp->f_blk[level])[idx];
306ca987d46SWarner Losh 		else
307ca987d46SWarner Losh 			ind_block_num = ((ufs2_daddr_t *)fp->f_blk[level])[idx];
308ca987d46SWarner Losh 	}
309ca987d46SWarner Losh 
310ca987d46SWarner Losh 	*disk_block_p = ind_block_num;
311ca987d46SWarner Losh 
312ca987d46SWarner Losh 	return (0);
313ca987d46SWarner Losh }
314ca987d46SWarner Losh 
315ca987d46SWarner Losh /*
316ca987d46SWarner Losh  * Write a portion of a file from an internal buffer.
317ca987d46SWarner Losh  */
318ca987d46SWarner Losh static int
buf_write_file(struct open_file * f,const char * buf_p,size_t * size_p)319b4cb3fe0SToomas Soome buf_write_file(struct open_file *f, const char *buf_p, size_t *size_p)
320ca987d46SWarner Losh {
321ca987d46SWarner Losh 	struct file *fp = (struct file *)f->f_fsdata;
322ca987d46SWarner Losh 	struct fs *fs = fp->f_fs;
323ca987d46SWarner Losh 	long off;
324ca987d46SWarner Losh 	ufs_lbn_t file_block;
325ca987d46SWarner Losh 	ufs2_daddr_t disk_block;
326ca987d46SWarner Losh 	size_t block_size;
327ca987d46SWarner Losh 	int rc;
328ca987d46SWarner Losh 
329ca987d46SWarner Losh 	/*
330ca987d46SWarner Losh 	 * Calculate the starting block address and offset.
331ca987d46SWarner Losh 	 */
332ca987d46SWarner Losh 	off = blkoff(fs, fp->f_seekp);
333ca987d46SWarner Losh 	file_block = lblkno(fs, fp->f_seekp);
334ca987d46SWarner Losh 	block_size = sblksize(fs, DIP(fp, di_size), file_block);
335ca987d46SWarner Losh 
336ca987d46SWarner Losh 	rc = block_map(f, file_block, &disk_block);
337ca987d46SWarner Losh 	if (rc)
338ca987d46SWarner Losh 		return (rc);
339ca987d46SWarner Losh 
340ca987d46SWarner Losh  	if (disk_block == 0)
341ca987d46SWarner Losh 		/* Because we can't allocate space on the drive */
342ca987d46SWarner Losh 		return (EFBIG);
343ca987d46SWarner Losh 
344ca987d46SWarner Losh 	/*
345ca987d46SWarner Losh 	 * Truncate buffer at end of file, and at the end of
346ca987d46SWarner Losh 	 * this block.
347ca987d46SWarner Losh 	 */
348ca987d46SWarner Losh 	if (*size_p > DIP(fp, di_size) - fp->f_seekp)
349ca987d46SWarner Losh 		*size_p = DIP(fp, di_size) - fp->f_seekp;
350ca987d46SWarner Losh 	if (*size_p > block_size - off)
351ca987d46SWarner Losh 		*size_p = block_size - off;
352ca987d46SWarner Losh 
353ca987d46SWarner Losh 	/*
354ca987d46SWarner Losh 	 * If we don't entirely occlude the block and it's not
355ca987d46SWarner Losh 	 * in memory already, read it in first.
356ca987d46SWarner Losh 	 */
357ca987d46SWarner Losh 	if (((off > 0) || (*size_p + off < block_size)) &&
358ca987d46SWarner Losh 	    (file_block != fp->f_buf_blkno)) {
359ca987d46SWarner Losh 
360ca987d46SWarner Losh 		if (fp->f_buf == (char *)0)
361ca987d46SWarner Losh 			fp->f_buf = malloc(fs->fs_bsize);
362ca987d46SWarner Losh 
363ca987d46SWarner Losh 		twiddle(4);
364ca987d46SWarner Losh 		rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
365ca987d46SWarner Losh 			fsbtodb(fs, disk_block),
366ca987d46SWarner Losh 			block_size, fp->f_buf, &fp->f_buf_size);
367ca987d46SWarner Losh 		if (rc)
368ca987d46SWarner Losh 			return (rc);
369ca987d46SWarner Losh 
370ca987d46SWarner Losh 		fp->f_buf_blkno = file_block;
371ca987d46SWarner Losh 	}
372ca987d46SWarner Losh 
373ca987d46SWarner Losh 	/*
374ca987d46SWarner Losh 	 *	Copy the user data into the cached block.
375ca987d46SWarner Losh 	 */
376ca987d46SWarner Losh 	bcopy(buf_p, fp->f_buf + off, *size_p);
377ca987d46SWarner Losh 
378ca987d46SWarner Losh 	/*
379ca987d46SWarner Losh 	 *	Write the block out to storage.
380ca987d46SWarner Losh 	 */
381ca987d46SWarner Losh 
382ca987d46SWarner Losh 	twiddle(4);
383ca987d46SWarner Losh 	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_WRITE,
384ca987d46SWarner Losh 		fsbtodb(fs, disk_block),
385ca987d46SWarner Losh 		block_size, fp->f_buf, &fp->f_buf_size);
386ca987d46SWarner Losh 	return (rc);
387ca987d46SWarner Losh }
388ca987d46SWarner Losh 
389ca987d46SWarner Losh /*
390ca987d46SWarner Losh  * Read a portion of a file into an internal buffer.  Return
391ca987d46SWarner Losh  * the location in the buffer and the amount in the buffer.
392ca987d46SWarner Losh  */
393ca987d46SWarner Losh static int
buf_read_file(struct open_file * f,char ** buf_p,size_t * size_p)394b4cb3fe0SToomas Soome buf_read_file(struct open_file *f, char **buf_p, size_t *size_p)
395ca987d46SWarner Losh {
396ca987d46SWarner Losh 	struct file *fp = (struct file *)f->f_fsdata;
397ca987d46SWarner Losh 	struct fs *fs = fp->f_fs;
398ca987d46SWarner Losh 	long off;
399ca987d46SWarner Losh 	ufs_lbn_t file_block;
400ca987d46SWarner Losh 	ufs2_daddr_t disk_block;
401ca987d46SWarner Losh 	size_t block_size;
402ca987d46SWarner Losh 	int rc;
403ca987d46SWarner Losh 
404ca987d46SWarner Losh 	off = blkoff(fs, fp->f_seekp);
405ca987d46SWarner Losh 	file_block = lblkno(fs, fp->f_seekp);
406ca987d46SWarner Losh 	block_size = sblksize(fs, DIP(fp, di_size), file_block);
407ca987d46SWarner Losh 
408ca987d46SWarner Losh 	if (file_block != fp->f_buf_blkno) {
40968160fbdSAlfonso 		if (fp->f_buf == NULL)
410ca987d46SWarner Losh 			fp->f_buf = malloc(fs->fs_bsize);
411ca987d46SWarner Losh 
412ca987d46SWarner Losh 		rc = block_map(f, file_block, &disk_block);
413ca987d46SWarner Losh 		if (rc)
414ca987d46SWarner Losh 			return (rc);
415ca987d46SWarner Losh 
416ca987d46SWarner Losh 		if (disk_block == 0) {
417ca987d46SWarner Losh 			bzero(fp->f_buf, block_size);
418ca987d46SWarner Losh 			fp->f_buf_size = block_size;
419ca987d46SWarner Losh 		} else {
420ca987d46SWarner Losh 			twiddle(4);
421ca987d46SWarner Losh 			rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
422ca987d46SWarner Losh 				fsbtodb(fs, disk_block),
423ca987d46SWarner Losh 				block_size, fp->f_buf, &fp->f_buf_size);
424ca987d46SWarner Losh 			if (rc)
425ca987d46SWarner Losh 				return (rc);
426ca987d46SWarner Losh 		}
427ca987d46SWarner Losh 
428ca987d46SWarner Losh 		fp->f_buf_blkno = file_block;
429ca987d46SWarner Losh 	}
430ca987d46SWarner Losh 
431ca987d46SWarner Losh 	/*
432ca987d46SWarner Losh 	 * Return address of byte in buffer corresponding to
433ca987d46SWarner Losh 	 * offset, and size of remainder of buffer after that
434ca987d46SWarner Losh 	 * byte.
435ca987d46SWarner Losh 	 */
436ca987d46SWarner Losh 	*buf_p = fp->f_buf + off;
437ca987d46SWarner Losh 	*size_p = block_size - off;
438ca987d46SWarner Losh 
439ca987d46SWarner Losh 	/*
440ca987d46SWarner Losh 	 * But truncate buffer at end of file.
441ca987d46SWarner Losh 	 */
442ca987d46SWarner Losh 	if (*size_p > DIP(fp, di_size) - fp->f_seekp)
443ca987d46SWarner Losh 		*size_p = DIP(fp, di_size) - fp->f_seekp;
444ca987d46SWarner Losh 
445ca987d46SWarner Losh 	return (0);
446ca987d46SWarner Losh }
447ca987d46SWarner Losh 
448ca987d46SWarner Losh /*
449ca987d46SWarner Losh  * Search a directory for a name and return its
450ca987d46SWarner Losh  * i_number.
451ca987d46SWarner Losh  */
452ca987d46SWarner Losh static int
search_directory(char * name,struct open_file * f,ino_t * inumber_p)453b4cb3fe0SToomas Soome search_directory(char *name, struct open_file *f, ino_t *inumber_p)
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
ufs_open(const char * upath,struct open_file * f)500b4cb3fe0SToomas Soome ufs_open(const char *upath, struct open_file *f)
501ca987d46SWarner Losh {
502ca987d46SWarner Losh 	char *cp, *ncp;
503ca987d46SWarner Losh 	int c;
504ca987d46SWarner Losh 	ino_t inumber, parent_inumber;
505ca987d46SWarner Losh 	struct file *fp;
506ca987d46SWarner Losh 	struct fs *fs;
5076d423eb2SWarner Losh 	int rc;
508ca987d46SWarner Losh 	int nlinks = 0;
509ca987d46SWarner Losh 	char namebuf[MAXPATHLEN+1];
510ca987d46SWarner Losh 	char *buf = NULL;
511ca987d46SWarner Losh 	char *path = NULL;
512b4cb3fe0SToomas Soome 	const char *dev;
513b4cb3fe0SToomas Soome 	ufs_mnt_t *mnt;
514ca987d46SWarner Losh 
515ca987d46SWarner Losh 	/* allocate file system specific data structure */
516b4cb3fe0SToomas Soome 	errno = 0;
517b4cb3fe0SToomas Soome 	fp = calloc(1, sizeof(struct file));
518b4cb3fe0SToomas Soome 	if (fp == NULL)
519b4cb3fe0SToomas Soome 		return (errno);
520ca987d46SWarner Losh 	f->f_fsdata = (void *)fp;
521ca987d46SWarner Losh 
5220b3a4a58SWarner Losh 	dev = devformat((struct devdesc *)f->f_devdata);
523b4cb3fe0SToomas Soome 	/* Is this device mounted? */
524b4cb3fe0SToomas Soome 	STAILQ_FOREACH(mnt, &mnt_list, um_link) {
525b4cb3fe0SToomas Soome 		if (strcmp(dev, mnt->um_dev) == 0)
526b4cb3fe0SToomas Soome 			break;
527b4cb3fe0SToomas Soome 	}
528b4cb3fe0SToomas Soome 
529b4cb3fe0SToomas Soome 	if (mnt == NULL) {
530dffce215SKirk McKusick 		/* read super block */
531ca987d46SWarner Losh 		twiddle(1);
5326d645da0SWarner Losh 		if ((rc = ffs_sbget(f, &fs, UFS_STDSB, UFS_NOHASHFAIL, "stand",
5336d645da0SWarner Losh 		    ufs_use_sa_read)) != 0) {
534ca987d46SWarner Losh 			goto out;
535b4cb3fe0SToomas Soome 		}
536b4cb3fe0SToomas Soome 	} else {
537b4cb3fe0SToomas Soome 		struct open_file *sbf;
538b4cb3fe0SToomas Soome 		struct file *sfp;
539b4cb3fe0SToomas Soome 
540b4cb3fe0SToomas Soome 		/* get superblock from mounted file system */
541b4cb3fe0SToomas Soome 		sbf = fd2open_file(mnt->um_fd);
542b4cb3fe0SToomas Soome 		sfp = sbf->f_fsdata;
543b4cb3fe0SToomas Soome 		fs = sfp->f_fs;
544b4cb3fe0SToomas Soome 	}
545dffce215SKirk McKusick 	fp->f_fs = fs;
546b4cb3fe0SToomas Soome 
547ca987d46SWarner Losh 	/*
548ca987d46SWarner Losh 	 * Calculate indirect block levels.
549ca987d46SWarner Losh 	 */
550ca987d46SWarner Losh 	{
551ca987d46SWarner Losh 		ufs2_daddr_t mult;
552ca987d46SWarner Losh 		int level;
553ca987d46SWarner Losh 
554ca987d46SWarner Losh 		mult = 1;
555ca987d46SWarner Losh 		for (level = 0; level < UFS_NIADDR; level++) {
556ca987d46SWarner Losh 			mult *= NINDIR(fs);
557ca987d46SWarner Losh 			fp->f_nindir[level] = mult;
558ca987d46SWarner Losh 		}
559ca987d46SWarner Losh 	}
560ca987d46SWarner Losh 
561ca987d46SWarner Losh 	inumber = UFS_ROOTINO;
562ca987d46SWarner Losh 	if ((rc = read_inode(inumber, f)) != 0)
563ca987d46SWarner Losh 		goto out;
564ca987d46SWarner Losh 
565ca987d46SWarner Losh 	cp = path = strdup(upath);
566ca987d46SWarner Losh 	if (path == NULL) {
567ca987d46SWarner Losh 	    rc = ENOMEM;
568ca987d46SWarner Losh 	    goto out;
569ca987d46SWarner Losh 	}
570ca987d46SWarner Losh 	while (*cp) {
571ca987d46SWarner Losh 
572ca987d46SWarner Losh 		/*
573ca987d46SWarner Losh 		 * Remove extra separators
574ca987d46SWarner Losh 		 */
575ca987d46SWarner Losh 		while (*cp == '/')
576ca987d46SWarner Losh 			cp++;
577ca987d46SWarner Losh 		if (*cp == '\0')
578ca987d46SWarner Losh 			break;
579ca987d46SWarner Losh 
580ca987d46SWarner Losh 		/*
581ca987d46SWarner Losh 		 * Check that current node is a directory.
582ca987d46SWarner Losh 		 */
583d8ba45e2SEd Maste 		if ((DIP(fp, di_mode) & IFMT) != IFDIR) {
584ca987d46SWarner Losh 			rc = ENOTDIR;
585ca987d46SWarner Losh 			goto out;
586ca987d46SWarner Losh 		}
587ca987d46SWarner Losh 
588ca987d46SWarner Losh 		/*
589ca987d46SWarner Losh 		 * Get next component of path name.
590ca987d46SWarner Losh 		 */
591ca987d46SWarner Losh 		{
592ca987d46SWarner Losh 			int len = 0;
593ca987d46SWarner Losh 
594ca987d46SWarner Losh 			ncp = cp;
595ca987d46SWarner Losh 			while ((c = *cp) != '\0' && c != '/') {
596ca987d46SWarner Losh 				if (++len > UFS_MAXNAMLEN) {
597ca987d46SWarner Losh 					rc = ENOENT;
598ca987d46SWarner Losh 					goto out;
599ca987d46SWarner Losh 				}
600ca987d46SWarner Losh 				cp++;
601ca987d46SWarner Losh 			}
602ca987d46SWarner Losh 			*cp = '\0';
603ca987d46SWarner Losh 		}
604ca987d46SWarner Losh 
605ca987d46SWarner Losh 		/*
606ca987d46SWarner Losh 		 * Look up component in current directory.
607ca987d46SWarner Losh 		 * Save directory inumber in case we find a
608ca987d46SWarner Losh 		 * symbolic link.
609ca987d46SWarner Losh 		 */
610ca987d46SWarner Losh 		parent_inumber = inumber;
611ca987d46SWarner Losh 		rc = search_directory(ncp, f, &inumber);
612ca987d46SWarner Losh 		*cp = c;
613ca987d46SWarner Losh 		if (rc)
614ca987d46SWarner Losh 			goto out;
615ca987d46SWarner Losh 
616ca987d46SWarner Losh 		/*
617ca987d46SWarner Losh 		 * Open next component.
618ca987d46SWarner Losh 		 */
619ca987d46SWarner Losh 		if ((rc = read_inode(inumber, f)) != 0)
620ca987d46SWarner Losh 			goto out;
621ca987d46SWarner Losh 
622ca987d46SWarner Losh 		/*
623ca987d46SWarner Losh 		 * Check for symbolic link.
624ca987d46SWarner Losh 		 */
625d8ba45e2SEd Maste 		if ((DIP(fp, di_mode) & IFMT) == IFLNK) {
626ca987d46SWarner Losh 			int link_len = DIP(fp, di_size);
627ca987d46SWarner Losh 			int len;
628ca987d46SWarner Losh 
629ca987d46SWarner Losh 			len = strlen(cp);
630ca987d46SWarner Losh 
631ca987d46SWarner Losh 			if (link_len + len > MAXPATHLEN ||
632ca987d46SWarner Losh 			    ++nlinks > MAXSYMLINKS) {
633ca987d46SWarner Losh 				rc = ENOENT;
634ca987d46SWarner Losh 				goto out;
635ca987d46SWarner Losh 			}
636ca987d46SWarner Losh 
637ca987d46SWarner Losh 			bcopy(cp, &namebuf[link_len], len + 1);
638ca987d46SWarner Losh 
639ca987d46SWarner Losh 			if (link_len < fs->fs_maxsymlinklen) {
6405b13fa79SJessica Clarke 				bcopy(DIP(fp, di_shortlink), namebuf,
6415b13fa79SJessica Clarke 				    (unsigned) link_len);
642ca987d46SWarner Losh 			} else {
643ca987d46SWarner Losh 				/*
644ca987d46SWarner Losh 				 * Read file for symbolic link
645ca987d46SWarner Losh 				 */
646ca987d46SWarner Losh 				size_t buf_size;
647ca987d46SWarner Losh 				ufs2_daddr_t disk_block;
648ca987d46SWarner Losh 				struct fs *fs = fp->f_fs;
649ca987d46SWarner Losh 
650ca987d46SWarner Losh 				if (!buf)
651ca987d46SWarner Losh 					buf = malloc(fs->fs_bsize);
652ca987d46SWarner Losh 				rc = block_map(f, (ufs2_daddr_t)0, &disk_block);
653ca987d46SWarner Losh 				if (rc)
654ca987d46SWarner Losh 					goto out;
655ca987d46SWarner Losh 
656ca987d46SWarner Losh 				twiddle(1);
657ca987d46SWarner Losh 				rc = (f->f_dev->dv_strategy)(f->f_devdata,
658ca987d46SWarner Losh 					F_READ, fsbtodb(fs, disk_block),
659ca987d46SWarner Losh 					fs->fs_bsize, buf, &buf_size);
660ca987d46SWarner Losh 				if (rc)
661ca987d46SWarner Losh 					goto out;
662ca987d46SWarner Losh 
663ca987d46SWarner Losh 				bcopy((char *)buf, namebuf, (unsigned)link_len);
664ca987d46SWarner Losh 			}
665ca987d46SWarner Losh 
666ca987d46SWarner Losh 			/*
667ca987d46SWarner Losh 			 * If relative pathname, restart at parent directory.
668ca987d46SWarner Losh 			 * If absolute pathname, restart at root.
669ca987d46SWarner Losh 			 */
670ca987d46SWarner Losh 			cp = namebuf;
671ca987d46SWarner Losh 			if (*cp != '/')
672ca987d46SWarner Losh 				inumber = parent_inumber;
673ca987d46SWarner Losh 			else
674ca987d46SWarner Losh 				inumber = (ino_t)UFS_ROOTINO;
675ca987d46SWarner Losh 
676ca987d46SWarner Losh 			if ((rc = read_inode(inumber, f)) != 0)
677ca987d46SWarner Losh 				goto out;
678ca987d46SWarner Losh 		}
679ca987d46SWarner Losh 	}
680ca987d46SWarner Losh 
681ca987d46SWarner Losh 	/*
682ca987d46SWarner Losh 	 * Found terminal component.
683ca987d46SWarner Losh 	 */
684ca987d46SWarner Losh 	rc = 0;
685ca987d46SWarner Losh 	fp->f_seekp = 0;
686ca987d46SWarner Losh out:
687ca987d46SWarner Losh 	free(buf);
688ca987d46SWarner Losh 	free(path);
689ca987d46SWarner Losh 	if (rc) {
690ca987d46SWarner Losh 		free(fp->f_buf);
691b4cb3fe0SToomas Soome 
692b4cb3fe0SToomas Soome 		if (mnt == NULL && fp->f_fs != NULL) {
69334816cb9SKirk McKusick 			free(fp->f_fs->fs_csp);
69434816cb9SKirk McKusick 			free(fp->f_fs->fs_si);
695ca987d46SWarner Losh 			free(fp->f_fs);
69634816cb9SKirk McKusick 		}
697ca987d46SWarner Losh 		free(fp);
698ca987d46SWarner Losh 	}
699ca987d46SWarner Losh 	return (rc);
700ca987d46SWarner Losh }
701ca987d46SWarner Losh 
702dffce215SKirk McKusick /*
703dffce215SKirk McKusick  * A read function for use by standalone-layer routines.
704dffce215SKirk McKusick  */
705dffce215SKirk McKusick static int
ufs_use_sa_read(void * devfd,off_t loc,void ** bufp,int size)706dffce215SKirk McKusick ufs_use_sa_read(void *devfd, off_t loc, void **bufp, int size)
707dffce215SKirk McKusick {
708dffce215SKirk McKusick 	struct open_file *f;
709dffce215SKirk McKusick 	size_t buf_size;
710dffce215SKirk McKusick 	int error;
711dffce215SKirk McKusick 
712dffce215SKirk McKusick 	f = (struct open_file *)devfd;
713dffce215SKirk McKusick 	if ((*bufp = malloc(size)) == NULL)
714dffce215SKirk McKusick 		return (ENOSPC);
715dffce215SKirk McKusick 	error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, loc / DEV_BSIZE,
716dffce215SKirk McKusick 	    size, *bufp, &buf_size);
717dffce215SKirk McKusick 	if (error != 0)
718dffce215SKirk McKusick 		return (error);
719dffce215SKirk McKusick 	if (buf_size != size)
720dffce215SKirk McKusick 		return (EIO);
721dffce215SKirk McKusick 	return (0);
722dffce215SKirk McKusick }
723dffce215SKirk McKusick 
724ca987d46SWarner Losh static int
ufs_close(struct open_file * f)725b4cb3fe0SToomas Soome ufs_close(struct open_file *f)
726ca987d46SWarner Losh {
727b4cb3fe0SToomas Soome 	ufs_mnt_t *mnt;
728ca987d46SWarner Losh 	struct file *fp = (struct file *)f->f_fsdata;
729ca987d46SWarner Losh 	int level;
730b4cb3fe0SToomas Soome 	char *dev;
731ca987d46SWarner Losh 
732b4cb3fe0SToomas Soome 	f->f_fsdata = NULL;
733b4cb3fe0SToomas Soome 	if (fp == NULL)
734ca987d46SWarner Losh 		return (0);
735ca987d46SWarner Losh 
736ca987d46SWarner Losh 	for (level = 0; level < UFS_NIADDR; level++) {
737ca987d46SWarner Losh 		free(fp->f_blk[level]);
738ca987d46SWarner Losh 	}
739ca987d46SWarner Losh 	free(fp->f_buf);
740b4cb3fe0SToomas Soome 
7410b3a4a58SWarner Losh 	dev = devformat((struct devdesc *)f->f_devdata);
742b4cb3fe0SToomas Soome 	STAILQ_FOREACH(mnt, &mnt_list, um_link) {
743b4cb3fe0SToomas Soome 		if (strcmp(dev, mnt->um_dev) == 0)
744b4cb3fe0SToomas Soome 			break;
745b4cb3fe0SToomas Soome 	}
746b4cb3fe0SToomas Soome 
747b4cb3fe0SToomas Soome 	if (mnt == NULL && fp->f_fs != NULL) {
74834816cb9SKirk McKusick 		free(fp->f_fs->fs_csp);
74934816cb9SKirk McKusick 		free(fp->f_fs->fs_si);
750ca987d46SWarner Losh 		free(fp->f_fs);
75134816cb9SKirk McKusick 	}
752b4cb3fe0SToomas Soome 
753ca987d46SWarner Losh 	free(fp);
754ca987d46SWarner Losh 	return (0);
755ca987d46SWarner Losh }
756ca987d46SWarner Losh 
757ca987d46SWarner Losh /*
758ca987d46SWarner Losh  * Copy a portion of a file into kernel memory.
759ca987d46SWarner Losh  * Cross block boundaries when necessary.
760ca987d46SWarner Losh  */
761ca987d46SWarner Losh static int
ufs_read(struct open_file * f,void * start,size_t size,size_t * resid)762b4cb3fe0SToomas Soome ufs_read(struct open_file *f, void *start, size_t size, size_t *resid)
763ca987d46SWarner Losh {
764ca987d46SWarner Losh 	struct file *fp = (struct file *)f->f_fsdata;
765ca987d46SWarner Losh 	size_t csize;
766ca987d46SWarner Losh 	char *buf;
767ca987d46SWarner Losh 	size_t buf_size;
768ca987d46SWarner Losh 	int rc = 0;
769ca987d46SWarner Losh 	char *addr = start;
770ca987d46SWarner Losh 
771ca987d46SWarner Losh 	while (size != 0) {
772ca987d46SWarner Losh 		if (fp->f_seekp >= DIP(fp, di_size))
773ca987d46SWarner Losh 			break;
774ca987d46SWarner Losh 
775ca987d46SWarner Losh 		rc = buf_read_file(f, &buf, &buf_size);
776ca987d46SWarner Losh 		if (rc)
777ca987d46SWarner Losh 			break;
778ca987d46SWarner Losh 
779ca987d46SWarner Losh 		csize = size;
780ca987d46SWarner Losh 		if (csize > buf_size)
781ca987d46SWarner Losh 			csize = buf_size;
782ca987d46SWarner Losh 
783ca987d46SWarner Losh 		bcopy(buf, addr, csize);
784ca987d46SWarner Losh 
785ca987d46SWarner Losh 		fp->f_seekp += csize;
786ca987d46SWarner Losh 		addr += csize;
787ca987d46SWarner Losh 		size -= csize;
788ca987d46SWarner Losh 	}
789ca987d46SWarner Losh 	if (resid)
790ca987d46SWarner Losh 		*resid = size;
791ca987d46SWarner Losh 	return (rc);
792ca987d46SWarner Losh }
793ca987d46SWarner Losh 
794ca987d46SWarner Losh /*
795ca987d46SWarner Losh  * Write to a portion of an already allocated file.
796ca987d46SWarner Losh  * Cross block boundaries when necessary. Can not
797ca987d46SWarner Losh  * extend the file.
798ca987d46SWarner Losh  */
799ca987d46SWarner Losh static int
ufs_write(struct open_file * f,const void * start,size_t size,size_t * resid)800b4cb3fe0SToomas Soome ufs_write(struct open_file *f, const void *start, size_t size, size_t *resid)
801ca987d46SWarner Losh {
802ca987d46SWarner Losh 	struct file *fp = (struct file *)f->f_fsdata;
803ca987d46SWarner Losh 	size_t csize;
804ca987d46SWarner Losh 	int rc = 0;
8052e7e6fbcSConrad Meyer 	const char *addr = start;
806ca987d46SWarner Losh 
807ca987d46SWarner Losh 	csize = size;
808ca987d46SWarner Losh 	while ((size != 0) && (csize != 0)) {
809ca987d46SWarner Losh 		if (fp->f_seekp >= DIP(fp, di_size))
810ca987d46SWarner Losh 			break;
811ca987d46SWarner Losh 
812ca987d46SWarner Losh 		if (csize >= 512) csize = 512; /* XXX */
813ca987d46SWarner Losh 
814ca987d46SWarner Losh 		rc = buf_write_file(f, addr, &csize);
815ca987d46SWarner Losh 		if (rc)
816ca987d46SWarner Losh 			break;
817ca987d46SWarner Losh 
818ca987d46SWarner Losh 		fp->f_seekp += csize;
819ca987d46SWarner Losh 		addr += csize;
820ca987d46SWarner Losh 		size -= csize;
821ca987d46SWarner Losh 	}
822ca987d46SWarner Losh 	if (resid)
823ca987d46SWarner Losh 		*resid = size;
824ca987d46SWarner Losh 	return (rc);
825ca987d46SWarner Losh }
826ca987d46SWarner Losh 
827ca987d46SWarner Losh static off_t
ufs_seek(struct open_file * f,off_t offset,int where)828b4cb3fe0SToomas Soome ufs_seek(struct open_file *f, off_t offset, int where)
829ca987d46SWarner Losh {
830ca987d46SWarner Losh 	struct file *fp = (struct file *)f->f_fsdata;
831ca987d46SWarner Losh 
832ca987d46SWarner Losh 	switch (where) {
833ca987d46SWarner Losh 	case SEEK_SET:
834ca987d46SWarner Losh 		fp->f_seekp = offset;
835ca987d46SWarner Losh 		break;
836ca987d46SWarner Losh 	case SEEK_CUR:
837ca987d46SWarner Losh 		fp->f_seekp += offset;
838ca987d46SWarner Losh 		break;
839ca987d46SWarner Losh 	case SEEK_END:
840ca987d46SWarner Losh 		fp->f_seekp = DIP(fp, di_size) - offset;
841ca987d46SWarner Losh 		break;
842ca987d46SWarner Losh 	default:
843ca987d46SWarner Losh 		errno = EINVAL;
844ca987d46SWarner Losh 		return (-1);
845ca987d46SWarner Losh 	}
846ca987d46SWarner Losh 	return (fp->f_seekp);
847ca987d46SWarner Losh }
848ca987d46SWarner Losh 
849ca987d46SWarner Losh static int
ufs_stat(struct open_file * f,struct stat * sb)850b4cb3fe0SToomas Soome ufs_stat(struct open_file *f, struct stat *sb)
851ca987d46SWarner Losh {
852ca987d46SWarner Losh 	struct file *fp = (struct file *)f->f_fsdata;
853ca987d46SWarner Losh 
854ca987d46SWarner Losh 	/* only important stuff */
855ca987d46SWarner Losh 	sb->st_mode = DIP(fp, di_mode);
856ca987d46SWarner Losh 	sb->st_uid = DIP(fp, di_uid);
857ca987d46SWarner Losh 	sb->st_gid = DIP(fp, di_gid);
858ca987d46SWarner Losh 	sb->st_size = DIP(fp, di_size);
8595ad42d0fSSimon J. Gerraty 	sb->st_mtime = DIP(fp, di_mtime);
8605ad42d0fSSimon J. Gerraty 	/*
8615ad42d0fSSimon J. Gerraty 	 * The items below are ufs specific!
8625ad42d0fSSimon J. Gerraty 	 * Other fs types will need their own solution
8635ad42d0fSSimon J. Gerraty 	 * if these fields are needed.
8645ad42d0fSSimon J. Gerraty 	 */
8655ad42d0fSSimon J. Gerraty 	sb->st_ino = fp->f_inumber;
8665ad42d0fSSimon J. Gerraty 	/*
8675ad42d0fSSimon J. Gerraty 	 * We need something to differentiate devs.
8685ad42d0fSSimon J. Gerraty 	 * fs_id is unique but 64bit, we xor the two
8695ad42d0fSSimon J. Gerraty 	 * halves to squeeze it into 32bits.
8705ad42d0fSSimon J. Gerraty 	 */
8715ad42d0fSSimon J. Gerraty 	sb->st_dev = (dev_t)(fp->f_fs->fs_id[0] ^ fp->f_fs->fs_id[1]);
8725ad42d0fSSimon J. Gerraty 
873ca987d46SWarner Losh 	return (0);
874ca987d46SWarner Losh }
875ca987d46SWarner Losh 
876ca987d46SWarner Losh static int
ufs_readdir(struct open_file * f,struct dirent * d)877ca987d46SWarner Losh ufs_readdir(struct open_file *f, struct dirent *d)
878ca987d46SWarner Losh {
879ca987d46SWarner Losh 	struct file *fp = (struct file *)f->f_fsdata;
880ca987d46SWarner Losh 	struct direct *dp;
881ca987d46SWarner Losh 	char *buf;
882ca987d46SWarner Losh 	size_t buf_size;
883ca987d46SWarner Losh 	int error;
884ca987d46SWarner Losh 
885ca987d46SWarner Losh 	/*
886ca987d46SWarner Losh 	 * assume that a directory entry will not be split across blocks
887ca987d46SWarner Losh 	 */
88868160fbdSAlfonso 
88968160fbdSAlfonso 	do {
890ca987d46SWarner Losh 		if (fp->f_seekp >= DIP(fp, di_size))
891ca987d46SWarner Losh 			return (ENOENT);
892ca987d46SWarner Losh 		error = buf_read_file(f, &buf, &buf_size);
893ca987d46SWarner Losh 		if (error)
894ca987d46SWarner Losh 			return (error);
895ca987d46SWarner Losh 		dp = (struct direct *)buf;
896ca987d46SWarner Losh 		fp->f_seekp += dp->d_reclen;
89768160fbdSAlfonso 	} while (dp->d_ino == (ino_t)0);
89868160fbdSAlfonso 
899ca987d46SWarner Losh 	d->d_type = dp->d_type;
900ca987d46SWarner Losh 	strcpy(d->d_name, dp->d_name);
901ca987d46SWarner Losh 	return (0);
902ca987d46SWarner Losh }
903b4cb3fe0SToomas Soome 
904b4cb3fe0SToomas Soome static int
ufs_mount(const char * dev,const char * path,void ** data)905b4cb3fe0SToomas Soome ufs_mount(const char *dev, const char *path, void **data)
906b4cb3fe0SToomas Soome {
907b4cb3fe0SToomas Soome 	char *fs;
908b4cb3fe0SToomas Soome 	ufs_mnt_t *mnt;
909b4cb3fe0SToomas Soome 	struct open_file *f;
910b4cb3fe0SToomas Soome 
911b4cb3fe0SToomas Soome 	errno = 0;
912b4cb3fe0SToomas Soome 	mnt = calloc(1, sizeof(*mnt));
913b4cb3fe0SToomas Soome 	if (mnt == NULL)
914b4cb3fe0SToomas Soome 		return (errno);
915b4cb3fe0SToomas Soome 	mnt->um_fd = -1;
916b4cb3fe0SToomas Soome 	mnt->um_dev = strdup(dev);
917b4cb3fe0SToomas Soome 	if (mnt->um_dev == NULL)
918b4cb3fe0SToomas Soome 		goto done;
919b4cb3fe0SToomas Soome 
920b4cb3fe0SToomas Soome 	if (asprintf(&fs, "%s%s", dev, path) < 0)
921b4cb3fe0SToomas Soome 		goto done;
922b4cb3fe0SToomas Soome 
923b4cb3fe0SToomas Soome 	mnt->um_fd = open(fs, O_RDONLY);
924b4cb3fe0SToomas Soome 	free(fs);
925b4cb3fe0SToomas Soome 	if (mnt->um_fd == -1)
926b4cb3fe0SToomas Soome 		goto done;
927b4cb3fe0SToomas Soome 
928b4cb3fe0SToomas Soome 	/* Is it ufs file system? */
929b4cb3fe0SToomas Soome 	f = fd2open_file(mnt->um_fd);
930b4cb3fe0SToomas Soome 	if (strcmp(f->f_ops->fs_name, "ufs") == 0)
931b4cb3fe0SToomas Soome 		STAILQ_INSERT_TAIL(&mnt_list, mnt, um_link);
932b4cb3fe0SToomas Soome 	else
933b4cb3fe0SToomas Soome 		errno = ENXIO;
934b4cb3fe0SToomas Soome 
935b4cb3fe0SToomas Soome done:
936b4cb3fe0SToomas Soome 	if (errno != 0) {
937b4cb3fe0SToomas Soome 		free(mnt->um_dev);
938b4cb3fe0SToomas Soome 		if (mnt->um_fd >= 0)
939b4cb3fe0SToomas Soome 			close(mnt->um_fd);
940b4cb3fe0SToomas Soome 		free(mnt);
941b4cb3fe0SToomas Soome 	} else {
942b4cb3fe0SToomas Soome 		*data = mnt;
943b4cb3fe0SToomas Soome 	}
944b4cb3fe0SToomas Soome 
945b4cb3fe0SToomas Soome 	return (errno);
946b4cb3fe0SToomas Soome }
947b4cb3fe0SToomas Soome 
948b4cb3fe0SToomas Soome static int
ufs_unmount(const char * dev __unused,void * data)949b4cb3fe0SToomas Soome ufs_unmount(const char *dev __unused, void *data)
950b4cb3fe0SToomas Soome {
951b4cb3fe0SToomas Soome 	ufs_mnt_t *mnt = data;
952b4cb3fe0SToomas Soome 
953b4cb3fe0SToomas Soome 	STAILQ_REMOVE(&mnt_list, mnt, ufs_mnt, um_link);
954b4cb3fe0SToomas Soome 	free(mnt->um_dev);
955b4cb3fe0SToomas Soome 	close(mnt->um_fd);
956b4cb3fe0SToomas Soome 	free(mnt);
957b4cb3fe0SToomas Soome 	return (0);
958b4cb3fe0SToomas Soome }
959