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