138451Smsmith/*	$NetBSD: ufs.c,v 1.20 1998/03/01 07:15:39 ross Exp $	*/
238451Smsmith
338451Smsmith/*-
498542Smckusick * Copyright (c) 2002 Networks Associates Technology, Inc.
598542Smckusick * All rights reserved.
698542Smckusick *
798542Smckusick * This software was developed for the FreeBSD Project by Marshall
898542Smckusick * Kirk McKusick and Network Associates Laboratories, the Security
998542Smckusick * Research Division of Network Associates, Inc. under DARPA/SPAWAR
1098542Smckusick * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS
1198542Smckusick * research program
1298542Smckusick *
1398542Smckusick * Copyright (c) 1982, 1989, 1993
1438451Smsmith *	The Regents of the University of California.  All rights reserved.
1538451Smsmith *
1638451Smsmith * This code is derived from software contributed to Berkeley by
1738451Smsmith * The Mach Operating System project at Carnegie-Mellon University.
1838451Smsmith *
1938451Smsmith * Redistribution and use in source and binary forms, with or without
2038451Smsmith * modification, are permitted provided that the following conditions
2138451Smsmith * are met:
2238451Smsmith * 1. Redistributions of source code must retain the above copyright
2338451Smsmith *    notice, this list of conditions and the following disclaimer.
2438451Smsmith * 2. Redistributions in binary form must reproduce the above copyright
2538451Smsmith *    notice, this list of conditions and the following disclaimer in the
2638451Smsmith *    documentation and/or other materials provided with the distribution.
27344376Skevans * 3. Neither the name of the University nor the names of its contributors
2838451Smsmith *    may be used to endorse or promote products derived from this software
2938451Smsmith *    without specific prior written permission.
3038451Smsmith *
3138451Smsmith * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
3238451Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3338451Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3438451Smsmith * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3538451Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3638451Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3738451Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3838451Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3938451Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
4038451Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
4138451Smsmith * SUCH DAMAGE.
4238451Smsmith *
4338451Smsmith *
4438451Smsmith * Copyright (c) 1990, 1991 Carnegie Mellon University
4538451Smsmith * All Rights Reserved.
4638451Smsmith *
4738451Smsmith * Author: David Golub
4838451Smsmith *
4938451Smsmith * Permission to use, copy, modify and distribute this software and its
5038451Smsmith * documentation is hereby granted, provided that both the copyright
5138451Smsmith * notice and this permission notice appear in all copies of the
5238451Smsmith * software, derivative works or modified versions, and any portions
5338451Smsmith * thereof, and that both notices appear in supporting documentation.
5438451Smsmith *
5538451Smsmith * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
5638451Smsmith * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
5738451Smsmith * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
5838451Smsmith *
5938451Smsmith * Carnegie Mellon requests users of this software to return to
6038451Smsmith *
6138451Smsmith *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
6238451Smsmith *  School of Computer Science
6338451Smsmith *  Carnegie Mellon University
6438451Smsmith *  Pittsburgh PA 15213-3890
6538451Smsmith *
6638451Smsmith * any improvements or extensions that they make and grant Carnegie the
6738451Smsmith * rights to redistribute these changes.
6838451Smsmith */
6938451Smsmith
7084221Sdillon#include <sys/cdefs.h>
7184221Sdillon__FBSDID("$FreeBSD: stable/11/stand/libsa/ufs.c 344376 2019-02-20 19:05:58Z kevans $");
7284221Sdillon
7338451Smsmith/*
7438451Smsmith *	Stand-alone file reading package.
7538451Smsmith */
7638451Smsmith
7738451Smsmith#include <sys/param.h>
7896477Sphk#include <sys/disklabel.h>
7938451Smsmith#include <sys/time.h>
8038451Smsmith#include <ufs/ufs/dinode.h>
8138451Smsmith#include <ufs/ufs/dir.h>
8238451Smsmith#include <ufs/ffs/fs.h>
8338451Smsmith#include "stand.h"
8438451Smsmith#include "string.h"
8538451Smsmith
8639468Smsmithstatic int	ufs_open(const char *path, struct open_file *f);
87332138Skevansstatic int	ufs_write(struct open_file *f, const void *buf, size_t size,
88332138Skevans		size_t *resid);
8938451Smsmithstatic int	ufs_close(struct open_file *f);
9038451Smsmithstatic int	ufs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
9138451Smsmithstatic off_t	ufs_seek(struct open_file *f, off_t offset, int where);
9238451Smsmithstatic int	ufs_stat(struct open_file *f, struct stat *sb);
9359766Sjlemonstatic int	ufs_readdir(struct open_file *f, struct dirent *d);
9438451Smsmith
9538451Smsmithstruct fs_ops ufs_fsops = {
9659766Sjlemon	"ufs",
9759766Sjlemon	ufs_open,
9859766Sjlemon	ufs_close,
9959766Sjlemon	ufs_read,
10087631Sjhb	ufs_write,
10159766Sjlemon	ufs_seek,
10259766Sjlemon	ufs_stat,
10359766Sjlemon	ufs_readdir
10438451Smsmith};
10538451Smsmith
10638451Smsmith/*
10738451Smsmith * In-core open file.
10838451Smsmith */
10938451Smsmithstruct file {
11038451Smsmith	off_t		f_seekp;	/* seek pointer */
11138451Smsmith	struct fs	*f_fs;		/* pointer to super-block */
11298542Smckusick	union dinode {
11398542Smckusick		struct ufs1_dinode di1;
11498542Smckusick		struct ufs2_dinode di2;
11598542Smckusick	}		f_di;		/* copy of on-disk inode */
11638451Smsmith	int		f_nindir[NIADDR];
11738451Smsmith					/* number of blocks mapped by
11838451Smsmith					   indirect block at level i */
11938451Smsmith	char		*f_blk[NIADDR];	/* buffer for indirect block at
12038451Smsmith					   level i */
12138451Smsmith	size_t		f_blksize[NIADDR];
12238451Smsmith					/* size of buffer */
12398542Smckusick	ufs2_daddr_t	f_blkno[NIADDR];/* disk address of block in buffer */
12498542Smckusick	ufs2_daddr_t	f_buf_blkno;	/* block number of data block */
12538451Smsmith	char		*f_buf;		/* buffer for data block */
12638451Smsmith	size_t		f_buf_size;	/* size of data block */
127344288Skevans	int		f_inumber;	/* inumber */
12838451Smsmith};
12998542Smckusick#define DIP(fp, field) \
13098542Smckusick	((fp)->f_fs->fs_magic == FS_UFS1_MAGIC ? \
13198542Smckusick	(fp)->f_di.di1.field : (fp)->f_di.di2.field)
13238451Smsmith
13338451Smsmithstatic int	read_inode(ino_t, struct open_file *);
13498542Smckusickstatic int	block_map(struct open_file *, ufs2_daddr_t, ufs2_daddr_t *);
13538451Smsmithstatic int	buf_read_file(struct open_file *, char **, size_t *);
136332138Skevansstatic int	buf_write_file(struct open_file *, const char *, size_t *);
13738451Smsmithstatic int	search_directory(char *, struct open_file *, ino_t *);
13838451Smsmith
13938451Smsmith/*
14038451Smsmith * Read a new inode into a file structure.
14138451Smsmith */
14238451Smsmithstatic int
14338451Smsmithread_inode(inumber, f)
14438451Smsmith	ino_t inumber;
14538451Smsmith	struct open_file *f;
14638451Smsmith{
14792913Sobrien	struct file *fp = (struct file *)f->f_fsdata;
14892913Sobrien	struct fs *fs = fp->f_fs;
14938451Smsmith	char *buf;
15038451Smsmith	size_t rsize;
15138451Smsmith	int rc;
15238451Smsmith
15339665Smsmith	if (fs == NULL)
15439665Smsmith	    panic("fs == NULL");
15539665Smsmith
15638451Smsmith	/*
15738451Smsmith	 * Read inode and save it.
15838451Smsmith	 */
15939665Smsmith	buf = malloc(fs->fs_bsize);
160276079Sian	twiddle(1);
16138451Smsmith	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
162313355Stsoome		fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize,
16338451Smsmith		buf, &rsize);
16438451Smsmith	if (rc)
16538451Smsmith		goto out;
16638451Smsmith	if (rsize != fs->fs_bsize) {
16738451Smsmith		rc = EIO;
16838451Smsmith		goto out;
16938451Smsmith	}
17038451Smsmith
17198542Smckusick	if (fp->f_fs->fs_magic == FS_UFS1_MAGIC)
17298542Smckusick		fp->f_di.di1 = ((struct ufs1_dinode *)buf)
17398542Smckusick		    [ino_to_fsbo(fs, inumber)];
17498542Smckusick	else
17598542Smckusick		fp->f_di.di2 = ((struct ufs2_dinode *)buf)
17698542Smckusick		    [ino_to_fsbo(fs, inumber)];
17738451Smsmith
17838451Smsmith	/*
17938451Smsmith	 * Clear out the old buffers
18038451Smsmith	 */
18138451Smsmith	{
18292913Sobrien		int level;
18338451Smsmith
18438451Smsmith		for (level = 0; level < NIADDR; level++)
18538451Smsmith			fp->f_blkno[level] = -1;
18638451Smsmith		fp->f_buf_blkno = -1;
18738451Smsmith	}
188134760Siedowse	fp->f_seekp = 0;
189344288Skevans	fp->f_inumber = inumber;
19038451Smsmithout:
19139665Smsmith	free(buf);
19238451Smsmith	return (rc);
19338451Smsmith}
19438451Smsmith
19538451Smsmith/*
19638451Smsmith * Given an offset in a file, find the disk block number that
19738451Smsmith * contains that block.
19838451Smsmith */
19938451Smsmithstatic int
20038451Smsmithblock_map(f, file_block, disk_block_p)
20138451Smsmith	struct open_file *f;
20298542Smckusick	ufs2_daddr_t file_block;
20398542Smckusick	ufs2_daddr_t *disk_block_p;	/* out */
20438451Smsmith{
20592913Sobrien	struct file *fp = (struct file *)f->f_fsdata;
20692913Sobrien	struct fs *fs = fp->f_fs;
20738451Smsmith	int level;
20838451Smsmith	int idx;
20998542Smckusick	ufs2_daddr_t ind_block_num;
21038451Smsmith	int rc;
21138451Smsmith
21238451Smsmith	/*
21338451Smsmith	 * Index structure of an inode:
21438451Smsmith	 *
21538451Smsmith	 * di_db[0..NDADDR-1]	hold block numbers for blocks
21638451Smsmith	 *			0..NDADDR-1
21738451Smsmith	 *
21838451Smsmith	 * di_ib[0]		index block 0 is the single indirect block
21938451Smsmith	 *			holds block numbers for blocks
22038451Smsmith	 *			NDADDR .. NDADDR + NINDIR(fs)-1
22138451Smsmith	 *
22238451Smsmith	 * di_ib[1]		index block 1 is the double indirect block
22338451Smsmith	 *			holds block numbers for INDEX blocks for blocks
22438451Smsmith	 *			NDADDR + NINDIR(fs) ..
22538451Smsmith	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1
22638451Smsmith	 *
22738451Smsmith	 * di_ib[2]		index block 2 is the triple indirect block
22838451Smsmith	 *			holds block numbers for double-indirect
22938451Smsmith	 *			blocks for blocks
23038451Smsmith	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2 ..
23138451Smsmith	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2
23238451Smsmith	 *				+ NINDIR(fs)**3 - 1
23338451Smsmith	 */
23438451Smsmith
23538451Smsmith	if (file_block < NDADDR) {
23638451Smsmith		/* Direct block. */
23798542Smckusick		*disk_block_p = DIP(fp, di_db[file_block]);
23838451Smsmith		return (0);
23938451Smsmith	}
24038451Smsmith
24138451Smsmith	file_block -= NDADDR;
24238451Smsmith
24338451Smsmith	/*
24438451Smsmith	 * nindir[0] = NINDIR
24538451Smsmith	 * nindir[1] = NINDIR**2
24638451Smsmith	 * nindir[2] = NINDIR**3
24738451Smsmith	 *	etc
24838451Smsmith	 */
24938451Smsmith	for (level = 0; level < NIADDR; level++) {
25038451Smsmith		if (file_block < fp->f_nindir[level])
25138451Smsmith			break;
25238451Smsmith		file_block -= fp->f_nindir[level];
25338451Smsmith	}
25438451Smsmith	if (level == NIADDR) {
25538451Smsmith		/* Block number too high */
25638451Smsmith		return (EFBIG);
25738451Smsmith	}
25838451Smsmith
25998542Smckusick	ind_block_num = DIP(fp, di_ib[level]);
26038451Smsmith
26138451Smsmith	for (; level >= 0; level--) {
26238451Smsmith		if (ind_block_num == 0) {
26338451Smsmith			*disk_block_p = 0;	/* missing */
26438451Smsmith			return (0);
26538451Smsmith		}
26638451Smsmith
26738451Smsmith		if (fp->f_blkno[level] != ind_block_num) {
26838451Smsmith			if (fp->f_blk[level] == (char *)0)
26938451Smsmith				fp->f_blk[level] =
27039665Smsmith					malloc(fs->fs_bsize);
271276079Sian			twiddle(1);
27238451Smsmith			rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
273313355Stsoome				fsbtodb(fp->f_fs, ind_block_num),
27438451Smsmith				fs->fs_bsize,
27538451Smsmith				fp->f_blk[level],
27638451Smsmith				&fp->f_blksize[level]);
27738451Smsmith			if (rc)
27838451Smsmith				return (rc);
27938451Smsmith			if (fp->f_blksize[level] != fs->fs_bsize)
28038451Smsmith				return (EIO);
28138451Smsmith			fp->f_blkno[level] = ind_block_num;
28238451Smsmith		}
28338451Smsmith
28438451Smsmith		if (level > 0) {
28538451Smsmith			idx = file_block / fp->f_nindir[level - 1];
28638451Smsmith			file_block %= fp->f_nindir[level - 1];
28738451Smsmith		} else
28838451Smsmith			idx = file_block;
28938451Smsmith
29098542Smckusick		if (fp->f_fs->fs_magic == FS_UFS1_MAGIC)
29198542Smckusick			ind_block_num = ((ufs1_daddr_t *)fp->f_blk[level])[idx];
29298542Smckusick		else
29398542Smckusick			ind_block_num = ((ufs2_daddr_t *)fp->f_blk[level])[idx];
29438451Smsmith	}
29538451Smsmith
29638451Smsmith	*disk_block_p = ind_block_num;
29738451Smsmith
29838451Smsmith	return (0);
29938451Smsmith}
30038451Smsmith
30138451Smsmith/*
30287631Sjhb * Write a portion of a file from an internal buffer.
30387631Sjhb */
30487631Sjhbstatic int
30587631Sjhbbuf_write_file(f, buf_p, size_p)
30687631Sjhb	struct open_file *f;
307332138Skevans	const char *buf_p;
30887631Sjhb	size_t *size_p;		/* out */
30987631Sjhb{
31092913Sobrien	struct file *fp = (struct file *)f->f_fsdata;
31192913Sobrien	struct fs *fs = fp->f_fs;
31287631Sjhb	long off;
31398542Smckusick	ufs_lbn_t file_block;
31498542Smckusick	ufs2_daddr_t disk_block;
31587631Sjhb	size_t block_size;
31687631Sjhb	int rc;
31787631Sjhb
31887631Sjhb	/*
31987631Sjhb	 * Calculate the starting block address and offset.
32087631Sjhb	 */
32187631Sjhb	off = blkoff(fs, fp->f_seekp);
32287631Sjhb	file_block = lblkno(fs, fp->f_seekp);
32398542Smckusick	block_size = sblksize(fs, DIP(fp, di_size), file_block);
32487631Sjhb
32587631Sjhb	rc = block_map(f, file_block, &disk_block);
32687631Sjhb	if (rc)
32787631Sjhb		return (rc);
32887631Sjhb
32987631Sjhb 	if (disk_block == 0)
33098542Smckusick		/* Because we can't allocate space on the drive */
33198542Smckusick		return (EFBIG);
33287631Sjhb
33387631Sjhb	/*
33487631Sjhb	 * Truncate buffer at end of file, and at the end of
33587631Sjhb	 * this block.
33687631Sjhb	 */
33798542Smckusick	if (*size_p > DIP(fp, di_size) - fp->f_seekp)
33898542Smckusick		*size_p = DIP(fp, di_size) - fp->f_seekp;
33987631Sjhb	if (*size_p > block_size - off)
34087631Sjhb		*size_p = block_size - off;
34187631Sjhb
34287631Sjhb	/*
34387631Sjhb	 * If we don't entirely occlude the block and it's not
34487631Sjhb	 * in memory already, read it in first.
34587631Sjhb	 */
34687631Sjhb	if (((off > 0) || (*size_p + off < block_size)) &&
34787631Sjhb	    (file_block != fp->f_buf_blkno)) {
34887631Sjhb
34987631Sjhb		if (fp->f_buf == (char *)0)
35087631Sjhb			fp->f_buf = malloc(fs->fs_bsize);
35187631Sjhb
352276079Sian		twiddle(4);
35387631Sjhb		rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
354313355Stsoome			fsbtodb(fs, disk_block),
35587631Sjhb			block_size, fp->f_buf, &fp->f_buf_size);
35687631Sjhb		if (rc)
35787631Sjhb			return (rc);
35887631Sjhb
35987631Sjhb		fp->f_buf_blkno = file_block;
36087631Sjhb	}
36187631Sjhb
36287631Sjhb	/*
36387631Sjhb	 *	Copy the user data into the cached block.
36487631Sjhb	 */
36598542Smckusick	bcopy(buf_p, fp->f_buf + off, *size_p);
36687631Sjhb
36787631Sjhb	/*
36887631Sjhb	 *	Write the block out to storage.
36987631Sjhb	 */
37087631Sjhb
371276079Sian	twiddle(4);
37287631Sjhb	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_WRITE,
373313355Stsoome		fsbtodb(fs, disk_block),
37487631Sjhb		block_size, fp->f_buf, &fp->f_buf_size);
37587631Sjhb	return (rc);
37687631Sjhb}
37787631Sjhb
37887631Sjhb/*
37938451Smsmith * Read a portion of a file into an internal buffer.  Return
38038451Smsmith * the location in the buffer and the amount in the buffer.
38138451Smsmith */
38238451Smsmithstatic int
38338451Smsmithbuf_read_file(f, buf_p, size_p)
38438451Smsmith	struct open_file *f;
38538451Smsmith	char **buf_p;		/* out */
38638451Smsmith	size_t *size_p;		/* out */
38738451Smsmith{
38892913Sobrien	struct file *fp = (struct file *)f->f_fsdata;
38992913Sobrien	struct fs *fs = fp->f_fs;
39038451Smsmith	long off;
39198542Smckusick	ufs_lbn_t file_block;
39298542Smckusick	ufs2_daddr_t disk_block;
39338451Smsmith	size_t block_size;
39438451Smsmith	int rc;
39538451Smsmith
39638451Smsmith	off = blkoff(fs, fp->f_seekp);
39738451Smsmith	file_block = lblkno(fs, fp->f_seekp);
39898542Smckusick	block_size = sblksize(fs, DIP(fp, di_size), file_block);
39938451Smsmith
40038451Smsmith	if (file_block != fp->f_buf_blkno) {
40187631Sjhb		if (fp->f_buf == (char *)0)
40287631Sjhb			fp->f_buf = malloc(fs->fs_bsize);
40387631Sjhb
40438451Smsmith		rc = block_map(f, file_block, &disk_block);
40538451Smsmith		if (rc)
40638451Smsmith			return (rc);
40738451Smsmith
40838451Smsmith		if (disk_block == 0) {
40938451Smsmith			bzero(fp->f_buf, block_size);
41038451Smsmith			fp->f_buf_size = block_size;
41138451Smsmith		} else {
412276079Sian			twiddle(4);
41338451Smsmith			rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
414313355Stsoome				fsbtodb(fs, disk_block),
41538451Smsmith				block_size, fp->f_buf, &fp->f_buf_size);
41638451Smsmith			if (rc)
41738451Smsmith				return (rc);
41838451Smsmith		}
41938451Smsmith
42038451Smsmith		fp->f_buf_blkno = file_block;
42138451Smsmith	}
42238451Smsmith
42338451Smsmith	/*
42438451Smsmith	 * Return address of byte in buffer corresponding to
42538451Smsmith	 * offset, and size of remainder of buffer after that
42638451Smsmith	 * byte.
42738451Smsmith	 */
42838451Smsmith	*buf_p = fp->f_buf + off;
42938451Smsmith	*size_p = block_size - off;
43038451Smsmith
43138451Smsmith	/*
43238451Smsmith	 * But truncate buffer at end of file.
43338451Smsmith	 */
43498542Smckusick	if (*size_p > DIP(fp, di_size) - fp->f_seekp)
43598542Smckusick		*size_p = DIP(fp, di_size) - fp->f_seekp;
43638451Smsmith
43738451Smsmith	return (0);
43838451Smsmith}
43938451Smsmith
44038451Smsmith/*
44138451Smsmith * Search a directory for a name and return its
44238451Smsmith * i_number.
44338451Smsmith */
44438451Smsmithstatic int
44538451Smsmithsearch_directory(name, f, inumber_p)
44638451Smsmith	char *name;
44738451Smsmith	struct open_file *f;
44838451Smsmith	ino_t *inumber_p;		/* out */
44938451Smsmith{
45092913Sobrien	struct file *fp = (struct file *)f->f_fsdata;
45192913Sobrien	struct direct *dp;
45238451Smsmith	struct direct *edp;
45338451Smsmith	char *buf;
45438451Smsmith	size_t buf_size;
45538451Smsmith	int namlen, length;
45638451Smsmith	int rc;
45738451Smsmith
45838451Smsmith	length = strlen(name);
45938451Smsmith
46038451Smsmith	fp->f_seekp = 0;
46198542Smckusick	while (fp->f_seekp < DIP(fp, di_size)) {
46238451Smsmith		rc = buf_read_file(f, &buf, &buf_size);
46338451Smsmith		if (rc)
46438451Smsmith			return (rc);
46538451Smsmith
46638451Smsmith		dp = (struct direct *)buf;
46738451Smsmith		edp = (struct direct *)(buf + buf_size);
46838451Smsmith		while (dp < edp) {
46938451Smsmith			if (dp->d_ino == (ino_t)0)
47038451Smsmith				goto next;
47138451Smsmith#if BYTE_ORDER == LITTLE_ENDIAN
47238451Smsmith			if (fp->f_fs->fs_maxsymlinklen <= 0)
47338451Smsmith				namlen = dp->d_type;
47438451Smsmith			else
47538451Smsmith#endif
47638451Smsmith				namlen = dp->d_namlen;
47738451Smsmith			if (namlen == length &&
47838451Smsmith			    !strcmp(name, dp->d_name)) {
47938451Smsmith				/* found entry */
48038451Smsmith				*inumber_p = dp->d_ino;
48138451Smsmith				return (0);
48238451Smsmith			}
48338451Smsmith		next:
48438451Smsmith			dp = (struct direct *)((char *)dp + dp->d_reclen);
48538451Smsmith		}
48638451Smsmith		fp->f_seekp += buf_size;
48738451Smsmith	}
48838451Smsmith	return (ENOENT);
48938451Smsmith}
49038451Smsmith
49198542Smckusickstatic int sblock_try[] = SBLOCKSEARCH;
49298542Smckusick
49338451Smsmith/*
49438451Smsmith * Open a file.
49538451Smsmith */
49638451Smsmithstatic int
49739468Smsmithufs_open(upath, f)
49839468Smsmith	const char *upath;
49938451Smsmith	struct open_file *f;
50038451Smsmith{
50192913Sobrien	char *cp, *ncp;
50292913Sobrien	int c;
50338451Smsmith	ino_t inumber, parent_inumber;
50438451Smsmith	struct file *fp;
50538451Smsmith	struct fs *fs;
50698542Smckusick	int i, rc;
50738451Smsmith	size_t buf_size;
50838451Smsmith	int nlinks = 0;
50938451Smsmith	char namebuf[MAXPATHLEN+1];
51038451Smsmith	char *buf = NULL;
51139468Smsmith	char *path = NULL;
51238451Smsmith
51338451Smsmith	/* allocate file system specific data structure */
51438451Smsmith	fp = malloc(sizeof(struct file));
51538451Smsmith	bzero(fp, sizeof(struct file));
51638451Smsmith	f->f_fsdata = (void *)fp;
51738451Smsmith
51838451Smsmith	/* allocate space and read super block */
51998542Smckusick	fs = malloc(SBLOCKSIZE);
52038451Smsmith	fp->f_fs = fs;
521276079Sian	twiddle(1);
52298542Smckusick	/*
52398542Smckusick	 * Try reading the superblock in each of its possible locations.
52498542Smckusick	 */
52598542Smckusick	for (i = 0; sblock_try[i] != -1; i++) {
52698542Smckusick		rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
527313355Stsoome		    sblock_try[i] / DEV_BSIZE, SBLOCKSIZE,
52898542Smckusick		    (char *)fs, &buf_size);
52998542Smckusick		if (rc)
53098542Smckusick			goto out;
53198542Smckusick		if ((fs->fs_magic == FS_UFS1_MAGIC ||
53298542Smckusick		     (fs->fs_magic == FS_UFS2_MAGIC &&
533107555Sjake		      fs->fs_sblockloc == sblock_try[i])) &&
53498542Smckusick		    buf_size == SBLOCKSIZE &&
53598542Smckusick		    fs->fs_bsize <= MAXBSIZE &&
53698542Smckusick		    fs->fs_bsize >= sizeof(struct fs))
53798542Smckusick			break;
53898542Smckusick	}
53998542Smckusick	if (sblock_try[i] == -1) {
54038451Smsmith		rc = EINVAL;
54138451Smsmith		goto out;
54238451Smsmith	}
54338451Smsmith	/*
54438451Smsmith	 * Calculate indirect block levels.
54538451Smsmith	 */
54638451Smsmith	{
54798542Smckusick		ufs2_daddr_t mult;
54892913Sobrien		int level;
54938451Smsmith
55038451Smsmith		mult = 1;
55138451Smsmith		for (level = 0; level < NIADDR; level++) {
55238451Smsmith			mult *= NINDIR(fs);
55338451Smsmith			fp->f_nindir[level] = mult;
55438451Smsmith		}
55538451Smsmith	}
55638451Smsmith
55738451Smsmith	inumber = ROOTINO;
55838451Smsmith	if ((rc = read_inode(inumber, f)) != 0)
55938451Smsmith		goto out;
56038451Smsmith
56139468Smsmith	cp = path = strdup(upath);
56239468Smsmith	if (path == NULL) {
56339468Smsmith	    rc = ENOMEM;
56439468Smsmith	    goto out;
56539468Smsmith	}
56638451Smsmith	while (*cp) {
56738451Smsmith
56838451Smsmith		/*
56938451Smsmith		 * Remove extra separators
57038451Smsmith		 */
57138451Smsmith		while (*cp == '/')
57238451Smsmith			cp++;
57338451Smsmith		if (*cp == '\0')
57438451Smsmith			break;
57538451Smsmith
57638451Smsmith		/*
57738451Smsmith		 * Check that current node is a directory.
57838451Smsmith		 */
57998542Smckusick		if ((DIP(fp, di_mode) & IFMT) != IFDIR) {
58038451Smsmith			rc = ENOTDIR;
58138451Smsmith			goto out;
58238451Smsmith		}
58338451Smsmith
58438451Smsmith		/*
58538451Smsmith		 * Get next component of path name.
58638451Smsmith		 */
58738451Smsmith		{
58892913Sobrien			int len = 0;
58938451Smsmith
59038451Smsmith			ncp = cp;
59138451Smsmith			while ((c = *cp) != '\0' && c != '/') {
59238451Smsmith				if (++len > MAXNAMLEN) {
59338451Smsmith					rc = ENOENT;
59438451Smsmith					goto out;
59538451Smsmith				}
59638451Smsmith				cp++;
59738451Smsmith			}
59838451Smsmith			*cp = '\0';
59938451Smsmith		}
60038451Smsmith
60138451Smsmith		/*
60238451Smsmith		 * Look up component in current directory.
60338451Smsmith		 * Save directory inumber in case we find a
60438451Smsmith		 * symbolic link.
60538451Smsmith		 */
60638451Smsmith		parent_inumber = inumber;
60738451Smsmith		rc = search_directory(ncp, f, &inumber);
60838451Smsmith		*cp = c;
60938451Smsmith		if (rc)
61038451Smsmith			goto out;
61138451Smsmith
61238451Smsmith		/*
61338451Smsmith		 * Open next component.
61438451Smsmith		 */
61538451Smsmith		if ((rc = read_inode(inumber, f)) != 0)
61638451Smsmith			goto out;
61738451Smsmith
61838451Smsmith		/*
61938451Smsmith		 * Check for symbolic link.
62038451Smsmith		 */
62198542Smckusick		if ((DIP(fp, di_mode) & IFMT) == IFLNK) {
62298542Smckusick			int link_len = DIP(fp, di_size);
62338451Smsmith			int len;
62438451Smsmith
62538451Smsmith			len = strlen(cp);
62638451Smsmith
62738451Smsmith			if (link_len + len > MAXPATHLEN ||
62838451Smsmith			    ++nlinks > MAXSYMLINKS) {
62938451Smsmith				rc = ENOENT;
63038451Smsmith				goto out;
63138451Smsmith			}
63238451Smsmith
63338451Smsmith			bcopy(cp, &namebuf[link_len], len + 1);
63438451Smsmith
63538451Smsmith			if (link_len < fs->fs_maxsymlinklen) {
63698542Smckusick				if (fp->f_fs->fs_magic == FS_UFS1_MAGIC)
63798542Smckusick					cp = (caddr_t)(fp->f_di.di1.di_db);
63898542Smckusick				else
63998542Smckusick					cp = (caddr_t)(fp->f_di.di2.di_db);
64098542Smckusick				bcopy(cp, namebuf, (unsigned) link_len);
64138451Smsmith			} else {
64238451Smsmith				/*
64338451Smsmith				 * Read file for symbolic link
64438451Smsmith				 */
64538451Smsmith				size_t buf_size;
64698542Smckusick				ufs2_daddr_t disk_block;
64792913Sobrien				struct fs *fs = fp->f_fs;
64838451Smsmith
64938451Smsmith				if (!buf)
65039665Smsmith					buf = malloc(fs->fs_bsize);
65198542Smckusick				rc = block_map(f, (ufs2_daddr_t)0, &disk_block);
65238451Smsmith				if (rc)
65338451Smsmith					goto out;
65438451Smsmith
655276079Sian				twiddle(1);
65638451Smsmith				rc = (f->f_dev->dv_strategy)(f->f_devdata,
657313355Stsoome					F_READ, fsbtodb(fs, disk_block),
65838451Smsmith					fs->fs_bsize, buf, &buf_size);
65938451Smsmith				if (rc)
66038451Smsmith					goto out;
66138451Smsmith
66238451Smsmith				bcopy((char *)buf, namebuf, (unsigned)link_len);
66338451Smsmith			}
66438451Smsmith
66538451Smsmith			/*
66638451Smsmith			 * If relative pathname, restart at parent directory.
66738451Smsmith			 * If absolute pathname, restart at root.
66838451Smsmith			 */
66938451Smsmith			cp = namebuf;
67038451Smsmith			if (*cp != '/')
67138451Smsmith				inumber = parent_inumber;
67238451Smsmith			else
67338451Smsmith				inumber = (ino_t)ROOTINO;
67438451Smsmith
67538451Smsmith			if ((rc = read_inode(inumber, f)) != 0)
67638451Smsmith				goto out;
67738451Smsmith		}
67838451Smsmith	}
67938451Smsmith
68038451Smsmith	/*
68138451Smsmith	 * Found terminal component.
68238451Smsmith	 */
68338451Smsmith	rc = 0;
684134760Siedowse	fp->f_seekp = 0;
68538451Smsmithout:
68638451Smsmith	if (buf)
68739665Smsmith		free(buf);
68839468Smsmith	if (path)
68939468Smsmith		free(path);
69038451Smsmith	if (rc) {
69138451Smsmith		if (fp->f_buf)
69239665Smsmith			free(fp->f_buf);
69338451Smsmith		free(fp->f_fs);
69438451Smsmith		free(fp);
69538451Smsmith	}
69638451Smsmith	return (rc);
69738451Smsmith}
69838451Smsmith
69938451Smsmithstatic int
70038451Smsmithufs_close(f)
70138451Smsmith	struct open_file *f;
70238451Smsmith{
70392913Sobrien	struct file *fp = (struct file *)f->f_fsdata;
70438451Smsmith	int level;
70538451Smsmith
70638451Smsmith	f->f_fsdata = (void *)0;
70738451Smsmith	if (fp == (struct file *)0)
70838451Smsmith		return (0);
70938451Smsmith
71038451Smsmith	for (level = 0; level < NIADDR; level++) {
71138451Smsmith		if (fp->f_blk[level])
71239665Smsmith			free(fp->f_blk[level]);
71338451Smsmith	}
71438451Smsmith	if (fp->f_buf)
71539665Smsmith		free(fp->f_buf);
71639665Smsmith	free(fp->f_fs);
71738451Smsmith	free(fp);
71838451Smsmith	return (0);
71938451Smsmith}
72038451Smsmith
72138451Smsmith/*
72238451Smsmith * Copy a portion of a file into kernel memory.
72338451Smsmith * Cross block boundaries when necessary.
72438451Smsmith */
72538451Smsmithstatic int
72638451Smsmithufs_read(f, start, size, resid)
72738451Smsmith	struct open_file *f;
72838451Smsmith	void *start;
72938451Smsmith	size_t size;
73038451Smsmith	size_t *resid;	/* out */
73138451Smsmith{
73292913Sobrien	struct file *fp = (struct file *)f->f_fsdata;
73392913Sobrien	size_t csize;
73438451Smsmith	char *buf;
73538451Smsmith	size_t buf_size;
73638451Smsmith	int rc = 0;
73792913Sobrien	char *addr = start;
73838451Smsmith
73938451Smsmith	while (size != 0) {
74098542Smckusick		if (fp->f_seekp >= DIP(fp, di_size))
74138451Smsmith			break;
74238451Smsmith
74338451Smsmith		rc = buf_read_file(f, &buf, &buf_size);
74438451Smsmith		if (rc)
74538451Smsmith			break;
74638451Smsmith
74738451Smsmith		csize = size;
74838451Smsmith		if (csize > buf_size)
74938451Smsmith			csize = buf_size;
75038451Smsmith
75138451Smsmith		bcopy(buf, addr, csize);
75238451Smsmith
75338451Smsmith		fp->f_seekp += csize;
75438451Smsmith		addr += csize;
75538451Smsmith		size -= csize;
75638451Smsmith	}
75738451Smsmith	if (resid)
75838451Smsmith		*resid = size;
75938451Smsmith	return (rc);
76038451Smsmith}
76138451Smsmith
76287631Sjhb/*
76387631Sjhb * Write to a portion of an already allocated file.
76487631Sjhb * Cross block boundaries when necessary. Can not
76587631Sjhb * extend the file.
76687631Sjhb */
76787631Sjhbstatic int
76887631Sjhbufs_write(f, start, size, resid)
76987631Sjhb	struct open_file *f;
770332138Skevans	const void *start;
77187631Sjhb	size_t size;
77287631Sjhb	size_t *resid;	/* out */
77387631Sjhb{
77492913Sobrien	struct file *fp = (struct file *)f->f_fsdata;
77587631Sjhb	size_t csize;
77687631Sjhb	int rc = 0;
777332138Skevans	const char *addr = start;
77887631Sjhb
77987631Sjhb	csize = size;
78087631Sjhb	while ((size != 0) && (csize != 0)) {
78198542Smckusick		if (fp->f_seekp >= DIP(fp, di_size))
78287631Sjhb			break;
78387631Sjhb
78487631Sjhb		if (csize >= 512) csize = 512; /* XXX */
78587631Sjhb
78687631Sjhb		rc = buf_write_file(f, addr, &csize);
78787631Sjhb		if (rc)
78887631Sjhb			break;
78987631Sjhb
79087631Sjhb		fp->f_seekp += csize;
79187631Sjhb		addr += csize;
79287631Sjhb		size -= csize;
79387631Sjhb	}
79487631Sjhb	if (resid)
79587631Sjhb		*resid = size;
79687631Sjhb	return (rc);
79787631Sjhb}
79887631Sjhb
79938451Smsmithstatic off_t
80038451Smsmithufs_seek(f, offset, where)
80138451Smsmith	struct open_file *f;
80238451Smsmith	off_t offset;
80338451Smsmith	int where;
80438451Smsmith{
80592913Sobrien	struct file *fp = (struct file *)f->f_fsdata;
80638451Smsmith
80738451Smsmith	switch (where) {
80838451Smsmith	case SEEK_SET:
80938451Smsmith		fp->f_seekp = offset;
81038451Smsmith		break;
81138451Smsmith	case SEEK_CUR:
81238451Smsmith		fp->f_seekp += offset;
81338451Smsmith		break;
81438451Smsmith	case SEEK_END:
81598542Smckusick		fp->f_seekp = DIP(fp, di_size) - offset;
81638451Smsmith		break;
81738451Smsmith	default:
818124811Sjhb		errno = EINVAL;
81938451Smsmith		return (-1);
82038451Smsmith	}
82138451Smsmith	return (fp->f_seekp);
82238451Smsmith}
82338451Smsmith
82438451Smsmithstatic int
82538451Smsmithufs_stat(f, sb)
82638451Smsmith	struct open_file *f;
82738451Smsmith	struct stat *sb;
82838451Smsmith{
82992913Sobrien	struct file *fp = (struct file *)f->f_fsdata;
83038451Smsmith
83138451Smsmith	/* only important stuff */
83298542Smckusick	sb->st_mode = DIP(fp, di_mode);
83398542Smckusick	sb->st_uid = DIP(fp, di_uid);
83498542Smckusick	sb->st_gid = DIP(fp, di_gid);
83598542Smckusick	sb->st_size = DIP(fp, di_size);
836344288Skevans	sb->st_mtime = DIP(fp, di_mtime);
837344288Skevans	/*
838344288Skevans	 * The items below are ufs specific!
839344288Skevans	 * Other fs types will need their own solution
840344288Skevans	 * if these fields are needed.
841344288Skevans	 */
842344288Skevans	sb->st_ino = fp->f_inumber;
843344288Skevans	/*
844344288Skevans	 * We need something to differentiate devs.
845344288Skevans	 * fs_id is unique but 64bit, we xor the two
846344288Skevans	 * halves to squeeze it into 32bits.
847344288Skevans	 */
848344288Skevans	sb->st_dev = (dev_t)(fp->f_fs->fs_id[0] ^ fp->f_fs->fs_id[1]);
849344288Skevans
85038451Smsmith	return (0);
85138451Smsmith}
85238451Smsmith
85359766Sjlemonstatic int
85459766Sjlemonufs_readdir(struct open_file *f, struct dirent *d)
85559766Sjlemon{
85659766Sjlemon	struct file *fp = (struct file *)f->f_fsdata;
85759766Sjlemon	struct direct *dp;
85859766Sjlemon	char *buf;
85959766Sjlemon	size_t buf_size;
86059766Sjlemon	int error;
86159766Sjlemon
86259766Sjlemon	/*
86359766Sjlemon	 * assume that a directory entry will not be split across blocks
86459766Sjlemon	 */
86559766Sjlemonagain:
86698542Smckusick	if (fp->f_seekp >= DIP(fp, di_size))
86759766Sjlemon		return (ENOENT);
86859766Sjlemon	error = buf_read_file(f, &buf, &buf_size);
86959766Sjlemon	if (error)
87059766Sjlemon		return (error);
87159766Sjlemon	dp = (struct direct *)buf;
87259766Sjlemon	fp->f_seekp += dp->d_reclen;
87359766Sjlemon	if (dp->d_ino == (ino_t)0)
87459766Sjlemon		goto again;
87559766Sjlemon	d->d_type = dp->d_type;
87659766Sjlemon	strcpy(d->d_name, dp->d_name);
87759766Sjlemon	return (0);
87859766Sjlemon}
879