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.
2738451Smsmith * 4. 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$");
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);
8787631Sjhbstatic int	ufs_write(struct open_file *f, void *buf, size_t size, size_t *resid);
8838451Smsmithstatic int	ufs_close(struct open_file *f);
8938451Smsmithstatic int	ufs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
9038451Smsmithstatic off_t	ufs_seek(struct open_file *f, off_t offset, int where);
9138451Smsmithstatic int	ufs_stat(struct open_file *f, struct stat *sb);
9259766Sjlemonstatic int	ufs_readdir(struct open_file *f, struct dirent *d);
9338451Smsmith
9438451Smsmithstruct fs_ops ufs_fsops = {
9559766Sjlemon	"ufs",
9659766Sjlemon	ufs_open,
9759766Sjlemon	ufs_close,
9859766Sjlemon	ufs_read,
9987631Sjhb	ufs_write,
10059766Sjlemon	ufs_seek,
10159766Sjlemon	ufs_stat,
10259766Sjlemon	ufs_readdir
10338451Smsmith};
10438451Smsmith
10538451Smsmith/*
10638451Smsmith * In-core open file.
10738451Smsmith */
10838451Smsmithstruct file {
10938451Smsmith	off_t		f_seekp;	/* seek pointer */
11038451Smsmith	struct fs	*f_fs;		/* pointer to super-block */
11198542Smckusick	union dinode {
11298542Smckusick		struct ufs1_dinode di1;
11398542Smckusick		struct ufs2_dinode di2;
11498542Smckusick	}		f_di;		/* copy of on-disk inode */
11538451Smsmith	int		f_nindir[NIADDR];
11638451Smsmith					/* number of blocks mapped by
11738451Smsmith					   indirect block at level i */
11838451Smsmith	char		*f_blk[NIADDR];	/* buffer for indirect block at
11938451Smsmith					   level i */
12038451Smsmith	size_t		f_blksize[NIADDR];
12138451Smsmith					/* size of buffer */
12298542Smckusick	ufs2_daddr_t	f_blkno[NIADDR];/* disk address of block in buffer */
12398542Smckusick	ufs2_daddr_t	f_buf_blkno;	/* block number of data block */
12438451Smsmith	char		*f_buf;		/* buffer for data block */
12538451Smsmith	size_t		f_buf_size;	/* size of data block */
12638451Smsmith};
12798542Smckusick#define DIP(fp, field) \
12898542Smckusick	((fp)->f_fs->fs_magic == FS_UFS1_MAGIC ? \
12998542Smckusick	(fp)->f_di.di1.field : (fp)->f_di.di2.field)
13038451Smsmith
13138451Smsmithstatic int	read_inode(ino_t, struct open_file *);
13298542Smckusickstatic int	block_map(struct open_file *, ufs2_daddr_t, ufs2_daddr_t *);
13338451Smsmithstatic int	buf_read_file(struct open_file *, char **, size_t *);
13487631Sjhbstatic int	buf_write_file(struct open_file *, char *, size_t *);
13538451Smsmithstatic int	search_directory(char *, struct open_file *, ino_t *);
13638451Smsmith
13738451Smsmith/*
13838451Smsmith * Read a new inode into a file structure.
13938451Smsmith */
14038451Smsmithstatic int
14138451Smsmithread_inode(inumber, f)
14238451Smsmith	ino_t inumber;
14338451Smsmith	struct open_file *f;
14438451Smsmith{
14592913Sobrien	struct file *fp = (struct file *)f->f_fsdata;
14692913Sobrien	struct fs *fs = fp->f_fs;
14738451Smsmith	char *buf;
14838451Smsmith	size_t rsize;
14938451Smsmith	int rc;
15038451Smsmith
15139665Smsmith	if (fs == NULL)
15239665Smsmith	    panic("fs == NULL");
15339665Smsmith
15438451Smsmith	/*
15538451Smsmith	 * Read inode and save it.
15638451Smsmith	 */
15739665Smsmith	buf = malloc(fs->fs_bsize);
15838451Smsmith	twiddle();
15938451Smsmith	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
16038451Smsmith		fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize,
16138451Smsmith		buf, &rsize);
16238451Smsmith	if (rc)
16338451Smsmith		goto out;
16438451Smsmith	if (rsize != fs->fs_bsize) {
16538451Smsmith		rc = EIO;
16638451Smsmith		goto out;
16738451Smsmith	}
16838451Smsmith
16998542Smckusick	if (fp->f_fs->fs_magic == FS_UFS1_MAGIC)
17098542Smckusick		fp->f_di.di1 = ((struct ufs1_dinode *)buf)
17198542Smckusick		    [ino_to_fsbo(fs, inumber)];
17298542Smckusick	else
17398542Smckusick		fp->f_di.di2 = ((struct ufs2_dinode *)buf)
17498542Smckusick		    [ino_to_fsbo(fs, inumber)];
17538451Smsmith
17638451Smsmith	/*
17738451Smsmith	 * Clear out the old buffers
17838451Smsmith	 */
17938451Smsmith	{
18092913Sobrien		int level;
18138451Smsmith
18238451Smsmith		for (level = 0; level < NIADDR; level++)
18338451Smsmith			fp->f_blkno[level] = -1;
18438451Smsmith		fp->f_buf_blkno = -1;
18538451Smsmith	}
186134760Siedowse	fp->f_seekp = 0;
18738451Smsmithout:
18839665Smsmith	free(buf);
18938451Smsmith	return (rc);
19038451Smsmith}
19138451Smsmith
19238451Smsmith/*
19338451Smsmith * Given an offset in a file, find the disk block number that
19438451Smsmith * contains that block.
19538451Smsmith */
19638451Smsmithstatic int
19738451Smsmithblock_map(f, file_block, disk_block_p)
19838451Smsmith	struct open_file *f;
19998542Smckusick	ufs2_daddr_t file_block;
20098542Smckusick	ufs2_daddr_t *disk_block_p;	/* out */
20138451Smsmith{
20292913Sobrien	struct file *fp = (struct file *)f->f_fsdata;
20392913Sobrien	struct fs *fs = fp->f_fs;
20438451Smsmith	int level;
20538451Smsmith	int idx;
20698542Smckusick	ufs2_daddr_t ind_block_num;
20738451Smsmith	int rc;
20838451Smsmith
20938451Smsmith	/*
21038451Smsmith	 * Index structure of an inode:
21138451Smsmith	 *
21238451Smsmith	 * di_db[0..NDADDR-1]	hold block numbers for blocks
21338451Smsmith	 *			0..NDADDR-1
21438451Smsmith	 *
21538451Smsmith	 * di_ib[0]		index block 0 is the single indirect block
21638451Smsmith	 *			holds block numbers for blocks
21738451Smsmith	 *			NDADDR .. NDADDR + NINDIR(fs)-1
21838451Smsmith	 *
21938451Smsmith	 * di_ib[1]		index block 1 is the double indirect block
22038451Smsmith	 *			holds block numbers for INDEX blocks for blocks
22138451Smsmith	 *			NDADDR + NINDIR(fs) ..
22238451Smsmith	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1
22338451Smsmith	 *
22438451Smsmith	 * di_ib[2]		index block 2 is the triple indirect block
22538451Smsmith	 *			holds block numbers for double-indirect
22638451Smsmith	 *			blocks for blocks
22738451Smsmith	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2 ..
22838451Smsmith	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2
22938451Smsmith	 *				+ NINDIR(fs)**3 - 1
23038451Smsmith	 */
23138451Smsmith
23238451Smsmith	if (file_block < NDADDR) {
23338451Smsmith		/* Direct block. */
23498542Smckusick		*disk_block_p = DIP(fp, di_db[file_block]);
23538451Smsmith		return (0);
23638451Smsmith	}
23738451Smsmith
23838451Smsmith	file_block -= NDADDR;
23938451Smsmith
24038451Smsmith	/*
24138451Smsmith	 * nindir[0] = NINDIR
24238451Smsmith	 * nindir[1] = NINDIR**2
24338451Smsmith	 * nindir[2] = NINDIR**3
24438451Smsmith	 *	etc
24538451Smsmith	 */
24638451Smsmith	for (level = 0; level < NIADDR; level++) {
24738451Smsmith		if (file_block < fp->f_nindir[level])
24838451Smsmith			break;
24938451Smsmith		file_block -= fp->f_nindir[level];
25038451Smsmith	}
25138451Smsmith	if (level == NIADDR) {
25238451Smsmith		/* Block number too high */
25338451Smsmith		return (EFBIG);
25438451Smsmith	}
25538451Smsmith
25698542Smckusick	ind_block_num = DIP(fp, di_ib[level]);
25738451Smsmith
25838451Smsmith	for (; level >= 0; level--) {
25938451Smsmith		if (ind_block_num == 0) {
26038451Smsmith			*disk_block_p = 0;	/* missing */
26138451Smsmith			return (0);
26238451Smsmith		}
26338451Smsmith
26438451Smsmith		if (fp->f_blkno[level] != ind_block_num) {
26538451Smsmith			if (fp->f_blk[level] == (char *)0)
26638451Smsmith				fp->f_blk[level] =
26739665Smsmith					malloc(fs->fs_bsize);
26838451Smsmith			twiddle();
26938451Smsmith			rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
27038451Smsmith				fsbtodb(fp->f_fs, ind_block_num),
27138451Smsmith				fs->fs_bsize,
27238451Smsmith				fp->f_blk[level],
27338451Smsmith				&fp->f_blksize[level]);
27438451Smsmith			if (rc)
27538451Smsmith				return (rc);
27638451Smsmith			if (fp->f_blksize[level] != fs->fs_bsize)
27738451Smsmith				return (EIO);
27838451Smsmith			fp->f_blkno[level] = ind_block_num;
27938451Smsmith		}
28038451Smsmith
28138451Smsmith		if (level > 0) {
28238451Smsmith			idx = file_block / fp->f_nindir[level - 1];
28338451Smsmith			file_block %= fp->f_nindir[level - 1];
28438451Smsmith		} else
28538451Smsmith			idx = file_block;
28638451Smsmith
28798542Smckusick		if (fp->f_fs->fs_magic == FS_UFS1_MAGIC)
28898542Smckusick			ind_block_num = ((ufs1_daddr_t *)fp->f_blk[level])[idx];
28998542Smckusick		else
29098542Smckusick			ind_block_num = ((ufs2_daddr_t *)fp->f_blk[level])[idx];
29138451Smsmith	}
29238451Smsmith
29338451Smsmith	*disk_block_p = ind_block_num;
29438451Smsmith
29538451Smsmith	return (0);
29638451Smsmith}
29738451Smsmith
29838451Smsmith/*
29987631Sjhb * Write a portion of a file from an internal buffer.
30087631Sjhb */
30187631Sjhbstatic int
30287631Sjhbbuf_write_file(f, buf_p, size_p)
30387631Sjhb	struct open_file *f;
30487631Sjhb	char *buf_p;
30587631Sjhb	size_t *size_p;		/* out */
30687631Sjhb{
30792913Sobrien	struct file *fp = (struct file *)f->f_fsdata;
30892913Sobrien	struct fs *fs = fp->f_fs;
30987631Sjhb	long off;
31098542Smckusick	ufs_lbn_t file_block;
31198542Smckusick	ufs2_daddr_t disk_block;
31287631Sjhb	size_t block_size;
31387631Sjhb	int rc;
31487631Sjhb
31587631Sjhb	/*
31687631Sjhb	 * Calculate the starting block address and offset.
31787631Sjhb	 */
31887631Sjhb	off = blkoff(fs, fp->f_seekp);
31987631Sjhb	file_block = lblkno(fs, fp->f_seekp);
32098542Smckusick	block_size = sblksize(fs, DIP(fp, di_size), file_block);
32187631Sjhb
32287631Sjhb	rc = block_map(f, file_block, &disk_block);
32387631Sjhb	if (rc)
32487631Sjhb		return (rc);
32587631Sjhb
32687631Sjhb 	if (disk_block == 0)
32798542Smckusick		/* Because we can't allocate space on the drive */
32898542Smckusick		return (EFBIG);
32987631Sjhb
33087631Sjhb	/*
33187631Sjhb	 * Truncate buffer at end of file, and at the end of
33287631Sjhb	 * this block.
33387631Sjhb	 */
33498542Smckusick	if (*size_p > DIP(fp, di_size) - fp->f_seekp)
33598542Smckusick		*size_p = DIP(fp, di_size) - fp->f_seekp;
33687631Sjhb	if (*size_p > block_size - off)
33787631Sjhb		*size_p = block_size - off;
33887631Sjhb
33987631Sjhb	/*
34087631Sjhb	 * If we don't entirely occlude the block and it's not
34187631Sjhb	 * in memory already, read it in first.
34287631Sjhb	 */
34387631Sjhb	if (((off > 0) || (*size_p + off < block_size)) &&
34487631Sjhb	    (file_block != fp->f_buf_blkno)) {
34587631Sjhb
34687631Sjhb		if (fp->f_buf == (char *)0)
34787631Sjhb			fp->f_buf = malloc(fs->fs_bsize);
34887631Sjhb
34987631Sjhb		twiddle();
35087631Sjhb		rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
35187631Sjhb			fsbtodb(fs, disk_block),
35287631Sjhb			block_size, fp->f_buf, &fp->f_buf_size);
35387631Sjhb		if (rc)
35487631Sjhb			return (rc);
35587631Sjhb
35687631Sjhb		fp->f_buf_blkno = file_block;
35787631Sjhb	}
35887631Sjhb
35987631Sjhb	/*
36087631Sjhb	 *	Copy the user data into the cached block.
36187631Sjhb	 */
36298542Smckusick	bcopy(buf_p, fp->f_buf + off, *size_p);
36387631Sjhb
36487631Sjhb	/*
36587631Sjhb	 *	Write the block out to storage.
36687631Sjhb	 */
36787631Sjhb
36887631Sjhb	twiddle();
36987631Sjhb	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_WRITE,
37087631Sjhb		fsbtodb(fs, disk_block),
37187631Sjhb		block_size, fp->f_buf, &fp->f_buf_size);
37287631Sjhb	return (rc);
37387631Sjhb}
37487631Sjhb
37587631Sjhb/*
37638451Smsmith * Read a portion of a file into an internal buffer.  Return
37738451Smsmith * the location in the buffer and the amount in the buffer.
37838451Smsmith */
37938451Smsmithstatic int
38038451Smsmithbuf_read_file(f, buf_p, size_p)
38138451Smsmith	struct open_file *f;
38238451Smsmith	char **buf_p;		/* out */
38338451Smsmith	size_t *size_p;		/* out */
38438451Smsmith{
38592913Sobrien	struct file *fp = (struct file *)f->f_fsdata;
38692913Sobrien	struct fs *fs = fp->f_fs;
38738451Smsmith	long off;
38898542Smckusick	ufs_lbn_t file_block;
38998542Smckusick	ufs2_daddr_t disk_block;
39038451Smsmith	size_t block_size;
39138451Smsmith	int rc;
39238451Smsmith
39338451Smsmith	off = blkoff(fs, fp->f_seekp);
39438451Smsmith	file_block = lblkno(fs, fp->f_seekp);
39598542Smckusick	block_size = sblksize(fs, DIP(fp, di_size), file_block);
39638451Smsmith
39738451Smsmith	if (file_block != fp->f_buf_blkno) {
39887631Sjhb		if (fp->f_buf == (char *)0)
39987631Sjhb			fp->f_buf = malloc(fs->fs_bsize);
40087631Sjhb
40138451Smsmith		rc = block_map(f, file_block, &disk_block);
40238451Smsmith		if (rc)
40338451Smsmith			return (rc);
40438451Smsmith
40538451Smsmith		if (disk_block == 0) {
40638451Smsmith			bzero(fp->f_buf, block_size);
40738451Smsmith			fp->f_buf_size = block_size;
40838451Smsmith		} else {
40938451Smsmith			twiddle();
41038451Smsmith			rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
41138451Smsmith				fsbtodb(fs, disk_block),
41238451Smsmith				block_size, fp->f_buf, &fp->f_buf_size);
41338451Smsmith			if (rc)
41438451Smsmith				return (rc);
41538451Smsmith		}
41638451Smsmith
41738451Smsmith		fp->f_buf_blkno = file_block;
41838451Smsmith	}
41938451Smsmith
42038451Smsmith	/*
42138451Smsmith	 * Return address of byte in buffer corresponding to
42238451Smsmith	 * offset, and size of remainder of buffer after that
42338451Smsmith	 * byte.
42438451Smsmith	 */
42538451Smsmith	*buf_p = fp->f_buf + off;
42638451Smsmith	*size_p = block_size - off;
42738451Smsmith
42838451Smsmith	/*
42938451Smsmith	 * But truncate buffer at end of file.
43038451Smsmith	 */
43198542Smckusick	if (*size_p > DIP(fp, di_size) - fp->f_seekp)
43298542Smckusick		*size_p = DIP(fp, di_size) - fp->f_seekp;
43338451Smsmith
43438451Smsmith	return (0);
43538451Smsmith}
43638451Smsmith
43738451Smsmith/*
43838451Smsmith * Search a directory for a name and return its
43938451Smsmith * i_number.
44038451Smsmith */
44138451Smsmithstatic int
44238451Smsmithsearch_directory(name, f, inumber_p)
44338451Smsmith	char *name;
44438451Smsmith	struct open_file *f;
44538451Smsmith	ino_t *inumber_p;		/* out */
44638451Smsmith{
44792913Sobrien	struct file *fp = (struct file *)f->f_fsdata;
44892913Sobrien	struct direct *dp;
44938451Smsmith	struct direct *edp;
45038451Smsmith	char *buf;
45138451Smsmith	size_t buf_size;
45238451Smsmith	int namlen, length;
45338451Smsmith	int rc;
45438451Smsmith
45538451Smsmith	length = strlen(name);
45638451Smsmith
45738451Smsmith	fp->f_seekp = 0;
45898542Smckusick	while (fp->f_seekp < DIP(fp, di_size)) {
45938451Smsmith		rc = buf_read_file(f, &buf, &buf_size);
46038451Smsmith		if (rc)
46138451Smsmith			return (rc);
46238451Smsmith
46338451Smsmith		dp = (struct direct *)buf;
46438451Smsmith		edp = (struct direct *)(buf + buf_size);
46538451Smsmith		while (dp < edp) {
46638451Smsmith			if (dp->d_ino == (ino_t)0)
46738451Smsmith				goto next;
46838451Smsmith#if BYTE_ORDER == LITTLE_ENDIAN
46938451Smsmith			if (fp->f_fs->fs_maxsymlinklen <= 0)
47038451Smsmith				namlen = dp->d_type;
47138451Smsmith			else
47238451Smsmith#endif
47338451Smsmith				namlen = dp->d_namlen;
47438451Smsmith			if (namlen == length &&
47538451Smsmith			    !strcmp(name, dp->d_name)) {
47638451Smsmith				/* found entry */
47738451Smsmith				*inumber_p = dp->d_ino;
47838451Smsmith				return (0);
47938451Smsmith			}
48038451Smsmith		next:
48138451Smsmith			dp = (struct direct *)((char *)dp + dp->d_reclen);
48238451Smsmith		}
48338451Smsmith		fp->f_seekp += buf_size;
48438451Smsmith	}
48538451Smsmith	return (ENOENT);
48638451Smsmith}
48738451Smsmith
48898542Smckusickstatic int sblock_try[] = SBLOCKSEARCH;
48998542Smckusick
49038451Smsmith/*
49138451Smsmith * Open a file.
49238451Smsmith */
49338451Smsmithstatic int
49439468Smsmithufs_open(upath, f)
49539468Smsmith	const char *upath;
49638451Smsmith	struct open_file *f;
49738451Smsmith{
49892913Sobrien	char *cp, *ncp;
49992913Sobrien	int c;
50038451Smsmith	ino_t inumber, parent_inumber;
50138451Smsmith	struct file *fp;
50238451Smsmith	struct fs *fs;
50398542Smckusick	int i, rc;
50438451Smsmith	size_t buf_size;
50538451Smsmith	int nlinks = 0;
50638451Smsmith	char namebuf[MAXPATHLEN+1];
50738451Smsmith	char *buf = NULL;
50839468Smsmith	char *path = NULL;
50938451Smsmith
51038451Smsmith	/* allocate file system specific data structure */
51138451Smsmith	fp = malloc(sizeof(struct file));
51238451Smsmith	bzero(fp, sizeof(struct file));
51338451Smsmith	f->f_fsdata = (void *)fp;
51438451Smsmith
51538451Smsmith	/* allocate space and read super block */
51698542Smckusick	fs = malloc(SBLOCKSIZE);
51738451Smsmith	fp->f_fs = fs;
51838451Smsmith	twiddle();
51998542Smckusick	/*
52098542Smckusick	 * Try reading the superblock in each of its possible locations.
52198542Smckusick	 */
52298542Smckusick	for (i = 0; sblock_try[i] != -1; i++) {
52398542Smckusick		rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
52498542Smckusick		    sblock_try[i] / DEV_BSIZE, SBLOCKSIZE,
52598542Smckusick		    (char *)fs, &buf_size);
52698542Smckusick		if (rc)
52798542Smckusick			goto out;
52898542Smckusick		if ((fs->fs_magic == FS_UFS1_MAGIC ||
52998542Smckusick		     (fs->fs_magic == FS_UFS2_MAGIC &&
530107555Sjake		      fs->fs_sblockloc == sblock_try[i])) &&
53198542Smckusick		    buf_size == SBLOCKSIZE &&
53298542Smckusick		    fs->fs_bsize <= MAXBSIZE &&
53398542Smckusick		    fs->fs_bsize >= sizeof(struct fs))
53498542Smckusick			break;
53598542Smckusick	}
53698542Smckusick	if (sblock_try[i] == -1) {
53738451Smsmith		rc = EINVAL;
53838451Smsmith		goto out;
53938451Smsmith	}
54038451Smsmith	/*
54138451Smsmith	 * Calculate indirect block levels.
54238451Smsmith	 */
54338451Smsmith	{
54498542Smckusick		ufs2_daddr_t mult;
54592913Sobrien		int level;
54638451Smsmith
54738451Smsmith		mult = 1;
54838451Smsmith		for (level = 0; level < NIADDR; level++) {
54938451Smsmith			mult *= NINDIR(fs);
55038451Smsmith			fp->f_nindir[level] = mult;
55138451Smsmith		}
55238451Smsmith	}
55338451Smsmith
55438451Smsmith	inumber = ROOTINO;
55538451Smsmith	if ((rc = read_inode(inumber, f)) != 0)
55638451Smsmith		goto out;
55738451Smsmith
55839468Smsmith	cp = path = strdup(upath);
55939468Smsmith	if (path == NULL) {
56039468Smsmith	    rc = ENOMEM;
56139468Smsmith	    goto out;
56239468Smsmith	}
56338451Smsmith	while (*cp) {
56438451Smsmith
56538451Smsmith		/*
56638451Smsmith		 * Remove extra separators
56738451Smsmith		 */
56838451Smsmith		while (*cp == '/')
56938451Smsmith			cp++;
57038451Smsmith		if (*cp == '\0')
57138451Smsmith			break;
57238451Smsmith
57338451Smsmith		/*
57438451Smsmith		 * Check that current node is a directory.
57538451Smsmith		 */
57698542Smckusick		if ((DIP(fp, di_mode) & IFMT) != IFDIR) {
57738451Smsmith			rc = ENOTDIR;
57838451Smsmith			goto out;
57938451Smsmith		}
58038451Smsmith
58138451Smsmith		/*
58238451Smsmith		 * Get next component of path name.
58338451Smsmith		 */
58438451Smsmith		{
58592913Sobrien			int len = 0;
58638451Smsmith
58738451Smsmith			ncp = cp;
58838451Smsmith			while ((c = *cp) != '\0' && c != '/') {
58938451Smsmith				if (++len > MAXNAMLEN) {
59038451Smsmith					rc = ENOENT;
59138451Smsmith					goto out;
59238451Smsmith				}
59338451Smsmith				cp++;
59438451Smsmith			}
59538451Smsmith			*cp = '\0';
59638451Smsmith		}
59738451Smsmith
59838451Smsmith		/*
59938451Smsmith		 * Look up component in current directory.
60038451Smsmith		 * Save directory inumber in case we find a
60138451Smsmith		 * symbolic link.
60238451Smsmith		 */
60338451Smsmith		parent_inumber = inumber;
60438451Smsmith		rc = search_directory(ncp, f, &inumber);
60538451Smsmith		*cp = c;
60638451Smsmith		if (rc)
60738451Smsmith			goto out;
60838451Smsmith
60938451Smsmith		/*
61038451Smsmith		 * Open next component.
61138451Smsmith		 */
61238451Smsmith		if ((rc = read_inode(inumber, f)) != 0)
61338451Smsmith			goto out;
61438451Smsmith
61538451Smsmith		/*
61638451Smsmith		 * Check for symbolic link.
61738451Smsmith		 */
61898542Smckusick		if ((DIP(fp, di_mode) & IFMT) == IFLNK) {
61998542Smckusick			int link_len = DIP(fp, di_size);
62038451Smsmith			int len;
62138451Smsmith
62238451Smsmith			len = strlen(cp);
62338451Smsmith
62438451Smsmith			if (link_len + len > MAXPATHLEN ||
62538451Smsmith			    ++nlinks > MAXSYMLINKS) {
62638451Smsmith				rc = ENOENT;
62738451Smsmith				goto out;
62838451Smsmith			}
62938451Smsmith
63038451Smsmith			bcopy(cp, &namebuf[link_len], len + 1);
63138451Smsmith
63238451Smsmith			if (link_len < fs->fs_maxsymlinklen) {
63398542Smckusick				if (fp->f_fs->fs_magic == FS_UFS1_MAGIC)
63498542Smckusick					cp = (caddr_t)(fp->f_di.di1.di_db);
63598542Smckusick				else
63698542Smckusick					cp = (caddr_t)(fp->f_di.di2.di_db);
63798542Smckusick				bcopy(cp, namebuf, (unsigned) link_len);
63838451Smsmith			} else {
63938451Smsmith				/*
64038451Smsmith				 * Read file for symbolic link
64138451Smsmith				 */
64238451Smsmith				size_t buf_size;
64398542Smckusick				ufs2_daddr_t disk_block;
64492913Sobrien				struct fs *fs = fp->f_fs;
64538451Smsmith
64638451Smsmith				if (!buf)
64739665Smsmith					buf = malloc(fs->fs_bsize);
64898542Smckusick				rc = block_map(f, (ufs2_daddr_t)0, &disk_block);
64938451Smsmith				if (rc)
65038451Smsmith					goto out;
65138451Smsmith
65238451Smsmith				twiddle();
65338451Smsmith				rc = (f->f_dev->dv_strategy)(f->f_devdata,
65438451Smsmith					F_READ, fsbtodb(fs, disk_block),
65538451Smsmith					fs->fs_bsize, buf, &buf_size);
65638451Smsmith				if (rc)
65738451Smsmith					goto out;
65838451Smsmith
65938451Smsmith				bcopy((char *)buf, namebuf, (unsigned)link_len);
66038451Smsmith			}
66138451Smsmith
66238451Smsmith			/*
66338451Smsmith			 * If relative pathname, restart at parent directory.
66438451Smsmith			 * If absolute pathname, restart at root.
66538451Smsmith			 */
66638451Smsmith			cp = namebuf;
66738451Smsmith			if (*cp != '/')
66838451Smsmith				inumber = parent_inumber;
66938451Smsmith			else
67038451Smsmith				inumber = (ino_t)ROOTINO;
67138451Smsmith
67238451Smsmith			if ((rc = read_inode(inumber, f)) != 0)
67338451Smsmith				goto out;
67438451Smsmith		}
67538451Smsmith	}
67638451Smsmith
67738451Smsmith	/*
67838451Smsmith	 * Found terminal component.
67938451Smsmith	 */
68038451Smsmith	rc = 0;
681134760Siedowse	fp->f_seekp = 0;
68238451Smsmithout:
68338451Smsmith	if (buf)
68439665Smsmith		free(buf);
68539468Smsmith	if (path)
68639468Smsmith		free(path);
68738451Smsmith	if (rc) {
68838451Smsmith		if (fp->f_buf)
68939665Smsmith			free(fp->f_buf);
69038451Smsmith		free(fp->f_fs);
69138451Smsmith		free(fp);
69238451Smsmith	}
69338451Smsmith	return (rc);
69438451Smsmith}
69538451Smsmith
69638451Smsmithstatic int
69738451Smsmithufs_close(f)
69838451Smsmith	struct open_file *f;
69938451Smsmith{
70092913Sobrien	struct file *fp = (struct file *)f->f_fsdata;
70138451Smsmith	int level;
70238451Smsmith
70338451Smsmith	f->f_fsdata = (void *)0;
70438451Smsmith	if (fp == (struct file *)0)
70538451Smsmith		return (0);
70638451Smsmith
70738451Smsmith	for (level = 0; level < NIADDR; level++) {
70838451Smsmith		if (fp->f_blk[level])
70939665Smsmith			free(fp->f_blk[level]);
71038451Smsmith	}
71138451Smsmith	if (fp->f_buf)
71239665Smsmith		free(fp->f_buf);
71339665Smsmith	free(fp->f_fs);
71438451Smsmith	free(fp);
71538451Smsmith	return (0);
71638451Smsmith}
71738451Smsmith
71838451Smsmith/*
71938451Smsmith * Copy a portion of a file into kernel memory.
72038451Smsmith * Cross block boundaries when necessary.
72138451Smsmith */
72238451Smsmithstatic int
72338451Smsmithufs_read(f, start, size, resid)
72438451Smsmith	struct open_file *f;
72538451Smsmith	void *start;
72638451Smsmith	size_t size;
72738451Smsmith	size_t *resid;	/* out */
72838451Smsmith{
72992913Sobrien	struct file *fp = (struct file *)f->f_fsdata;
73092913Sobrien	size_t csize;
73138451Smsmith	char *buf;
73238451Smsmith	size_t buf_size;
73338451Smsmith	int rc = 0;
73492913Sobrien	char *addr = start;
73538451Smsmith
73638451Smsmith	while (size != 0) {
73798542Smckusick		if (fp->f_seekp >= DIP(fp, di_size))
73838451Smsmith			break;
73938451Smsmith
74038451Smsmith		rc = buf_read_file(f, &buf, &buf_size);
74138451Smsmith		if (rc)
74238451Smsmith			break;
74338451Smsmith
74438451Smsmith		csize = size;
74538451Smsmith		if (csize > buf_size)
74638451Smsmith			csize = buf_size;
74738451Smsmith
74838451Smsmith		bcopy(buf, addr, csize);
74938451Smsmith
75038451Smsmith		fp->f_seekp += csize;
75138451Smsmith		addr += csize;
75238451Smsmith		size -= csize;
75338451Smsmith	}
75438451Smsmith	if (resid)
75538451Smsmith		*resid = size;
75638451Smsmith	return (rc);
75738451Smsmith}
75838451Smsmith
75987631Sjhb/*
76087631Sjhb * Write to a portion of an already allocated file.
76187631Sjhb * Cross block boundaries when necessary. Can not
76287631Sjhb * extend the file.
76387631Sjhb */
76487631Sjhbstatic int
76587631Sjhbufs_write(f, start, size, resid)
76687631Sjhb	struct open_file *f;
76787631Sjhb	void *start;
76887631Sjhb	size_t size;
76987631Sjhb	size_t *resid;	/* out */
77087631Sjhb{
77192913Sobrien	struct file *fp = (struct file *)f->f_fsdata;
77287631Sjhb	size_t csize;
77387631Sjhb	int rc = 0;
77492913Sobrien	char *addr = start;
77587631Sjhb
77687631Sjhb	csize = size;
77787631Sjhb	while ((size != 0) && (csize != 0)) {
77898542Smckusick		if (fp->f_seekp >= DIP(fp, di_size))
77987631Sjhb			break;
78087631Sjhb
78187631Sjhb		if (csize >= 512) csize = 512; /* XXX */
78287631Sjhb
78387631Sjhb		rc = buf_write_file(f, addr, &csize);
78487631Sjhb		if (rc)
78587631Sjhb			break;
78687631Sjhb
78787631Sjhb		fp->f_seekp += csize;
78887631Sjhb		addr += csize;
78987631Sjhb		size -= csize;
79087631Sjhb	}
79187631Sjhb	if (resid)
79287631Sjhb		*resid = size;
79387631Sjhb	return (rc);
79487631Sjhb}
79587631Sjhb
79638451Smsmithstatic off_t
79738451Smsmithufs_seek(f, offset, where)
79838451Smsmith	struct open_file *f;
79938451Smsmith	off_t offset;
80038451Smsmith	int where;
80138451Smsmith{
80292913Sobrien	struct file *fp = (struct file *)f->f_fsdata;
80338451Smsmith
80438451Smsmith	switch (where) {
80538451Smsmith	case SEEK_SET:
80638451Smsmith		fp->f_seekp = offset;
80738451Smsmith		break;
80838451Smsmith	case SEEK_CUR:
80938451Smsmith		fp->f_seekp += offset;
81038451Smsmith		break;
81138451Smsmith	case SEEK_END:
81298542Smckusick		fp->f_seekp = DIP(fp, di_size) - offset;
81338451Smsmith		break;
81438451Smsmith	default:
815124811Sjhb		errno = EINVAL;
81638451Smsmith		return (-1);
81738451Smsmith	}
81838451Smsmith	return (fp->f_seekp);
81938451Smsmith}
82038451Smsmith
82138451Smsmithstatic int
82238451Smsmithufs_stat(f, sb)
82338451Smsmith	struct open_file *f;
82438451Smsmith	struct stat *sb;
82538451Smsmith{
82692913Sobrien	struct file *fp = (struct file *)f->f_fsdata;
82738451Smsmith
82838451Smsmith	/* only important stuff */
82998542Smckusick	sb->st_mode = DIP(fp, di_mode);
83098542Smckusick	sb->st_uid = DIP(fp, di_uid);
83198542Smckusick	sb->st_gid = DIP(fp, di_gid);
83298542Smckusick	sb->st_size = DIP(fp, di_size);
83338451Smsmith	return (0);
83438451Smsmith}
83538451Smsmith
83659766Sjlemonstatic int
83759766Sjlemonufs_readdir(struct open_file *f, struct dirent *d)
83859766Sjlemon{
83959766Sjlemon	struct file *fp = (struct file *)f->f_fsdata;
84059766Sjlemon	struct direct *dp;
84159766Sjlemon	char *buf;
84259766Sjlemon	size_t buf_size;
84359766Sjlemon	int error;
84459766Sjlemon
84559766Sjlemon	/*
84659766Sjlemon	 * assume that a directory entry will not be split across blocks
84759766Sjlemon	 */
84859766Sjlemonagain:
84998542Smckusick	if (fp->f_seekp >= DIP(fp, di_size))
85059766Sjlemon		return (ENOENT);
85159766Sjlemon	error = buf_read_file(f, &buf, &buf_size);
85259766Sjlemon	if (error)
85359766Sjlemon		return (error);
85459766Sjlemon	dp = (struct direct *)buf;
85559766Sjlemon	fp->f_seekp += dp->d_reclen;
85659766Sjlemon	if (dp->d_ino == (ino_t)0)
85759766Sjlemon		goto again;
85859766Sjlemon	d->d_type = dp->d_type;
85959766Sjlemon	strcpy(d->d_name, dp->d_name);
86059766Sjlemon	return (0);
86159766Sjlemon}
862