xref: /csrg-svn/sys/stand/ufs.c (revision 64985)
163280Smckusick /*-
263370Sbostic  * Copyright (c) 1993
363370Sbostic  *	The Regents of the University of California.  All rights reserved.
463280Smckusick  *
563280Smckusick  * This code is derived from software contributed to Berkeley by
663280Smckusick  * The Mach Operating System project at Carnegie-Mellon University.
763280Smckusick  *
863280Smckusick  * %sccs.include.redist.c%
963280Smckusick  *
10*64985Smckusick  *	@(#)ufs.c	8.2 (Berkeley) 11/30/93
1163280Smckusick  *
1263280Smckusick  *
1363280Smckusick  * Copyright (c) 1990, 1991 Carnegie Mellon University
1463280Smckusick  * All Rights Reserved.
1563280Smckusick  *
1663280Smckusick  * Author: David Golub
1763280Smckusick  *
1863280Smckusick  * Permission to use, copy, modify and distribute this software and its
1963280Smckusick  * documentation is hereby granted, provided that both the copyright
2063280Smckusick  * notice and this permission notice appear in all copies of the
2163280Smckusick  * software, derivative works or modified versions, and any portions
2263280Smckusick  * thereof, and that both notices appear in supporting documentation.
2363280Smckusick  *
2463280Smckusick  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
2563280Smckusick  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
2663280Smckusick  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
2763280Smckusick  *
2863280Smckusick  * Carnegie Mellon requests users of this software to return to
2963280Smckusick  *
3063280Smckusick  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
3163280Smckusick  *  School of Computer Science
3263280Smckusick  *  Carnegie Mellon University
3363280Smckusick  *  Pittsburgh PA 15213-3890
3463280Smckusick  *
3563280Smckusick  * any improvements or extensions that they make and grant Carnegie the
3663280Smckusick  * rights to redistribute these changes.
3763280Smckusick  */
3863280Smckusick 
3963280Smckusick /*
4063280Smckusick  *	Stand-alone file reading package.
4163280Smckusick  */
4263280Smckusick 
4363280Smckusick #include <sys/param.h>
4463280Smckusick #include <sys/time.h>
4563280Smckusick #include <ufs/ffs/fs.h>
4663280Smckusick #include <ufs/ufs/dinode.h>
4763280Smckusick #include <ufs/ufs/dir.h>
4863280Smckusick #include <stand/stand.h>
4963280Smckusick 
5063280Smckusick /*
5163280Smckusick  * In-core open file.
5263280Smckusick  */
5363280Smckusick struct file {
5463280Smckusick 	off_t		f_seekp;	/* seek pointer */
5563280Smckusick 	struct fs	*f_fs;		/* pointer to super-block */
5663280Smckusick 	struct dinode	f_di;		/* copy of on-disk inode */
5763280Smckusick 	int		f_nindir[NIADDR];
5863280Smckusick 					/* number of blocks mapped by
5963280Smckusick 					   indirect block at level i */
6063280Smckusick 	char		*f_blk[NIADDR];	/* buffer for indirect block at
6163280Smckusick 					   level i */
62*64985Smckusick 	u_int		f_blksize[NIADDR];
6363280Smckusick 					/* size of buffer */
6463280Smckusick 	daddr_t		f_blkno[NIADDR];/* disk address of block in buffer */
6563280Smckusick 	char		*f_buf;		/* buffer for data block */
6663280Smckusick 	u_int		f_buf_size;	/* size of data block */
6763280Smckusick 	daddr_t		f_buf_blkno;	/* block number of data block */
6863280Smckusick };
6963280Smckusick 
7063280Smckusick /*
7163280Smckusick  * Read a new inode into a file structure.
7263280Smckusick  */
7363280Smckusick static int
read_inode(inumber,f)7463280Smckusick read_inode(inumber, f)
7563280Smckusick 	ino_t inumber;
7663280Smckusick 	struct open_file *f;
7763280Smckusick {
7863280Smckusick 	register struct file *fp = (struct file *)f->f_fsdata;
7963280Smckusick 	register struct fs *fs = fp->f_fs;
8063280Smckusick 	char *buf;
8163280Smckusick 	u_int rsize;
8263280Smckusick 	int rc;
8363280Smckusick 
8463280Smckusick 	/*
8563280Smckusick 	 * Read inode and save it.
8663280Smckusick 	 */
8763280Smckusick 	buf = alloc(fs->fs_bsize);
8863280Smckusick 	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
89*64985Smckusick 		fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize,
90*64985Smckusick 		buf, &rsize);
9163280Smckusick 	if (rc)
9263280Smckusick 		goto out;
9363280Smckusick 	if (rsize != fs->fs_bsize) {
9463280Smckusick 		rc = EIO;
9563280Smckusick 		goto out;
9663280Smckusick 	}
9763280Smckusick 
9863280Smckusick 	{
9963280Smckusick 		register struct dinode *dp;
10063280Smckusick 
10163280Smckusick 		dp = (struct dinode *)buf;
102*64985Smckusick 		fp->f_di = dp[ino_to_fsbo(fs, inumber)];
10363280Smckusick 	}
10463280Smckusick 
10563280Smckusick 	/*
10663280Smckusick 	 * Clear out the old buffers
10763280Smckusick 	 */
10863280Smckusick 	{
10963280Smckusick 		register int level;
11063280Smckusick 
11163280Smckusick 		for (level = 0; level < NIADDR; level++)
11263280Smckusick 			fp->f_blkno[level] = -1;
11363280Smckusick 		fp->f_buf_blkno = -1;
11463280Smckusick 	}
11563280Smckusick out:
11663280Smckusick 	free(buf, fs->fs_bsize);
11763280Smckusick 	return (0);
11863280Smckusick }
11963280Smckusick 
12063280Smckusick /*
12163280Smckusick  * Given an offset in a file, find the disk block number that
12263280Smckusick  * contains that block.
12363280Smckusick  */
12463280Smckusick static int
block_map(f,file_block,disk_block_p)12563280Smckusick block_map(f, file_block, disk_block_p)
12663280Smckusick 	struct open_file *f;
12763280Smckusick 	daddr_t file_block;
12863280Smckusick 	daddr_t *disk_block_p;	/* out */
12963280Smckusick {
13063280Smckusick 	register struct file *fp = (struct file *)f->f_fsdata;
13163280Smckusick 	register struct fs *fs = fp->f_fs;
13263280Smckusick 	int level;
13363280Smckusick 	int idx;
13463280Smckusick 	daddr_t ind_block_num;
13563280Smckusick 	daddr_t *ind_p;
13663280Smckusick 	int rc;
13763280Smckusick 
13863280Smckusick 	/*
13963280Smckusick 	 * Index structure of an inode:
14063280Smckusick 	 *
14163280Smckusick 	 * di_db[0..NDADDR-1]	hold block numbers for blocks
14263280Smckusick 	 *			0..NDADDR-1
14363280Smckusick 	 *
14463280Smckusick 	 * di_ib[0]		index block 0 is the single indirect block
14563280Smckusick 	 *			holds block numbers for blocks
14663280Smckusick 	 *			NDADDR .. NDADDR + NINDIR(fs)-1
14763280Smckusick 	 *
14863280Smckusick 	 * di_ib[1]		index block 1 is the double indirect block
14963280Smckusick 	 *			holds block numbers for INDEX blocks for blocks
15063280Smckusick 	 *			NDADDR + NINDIR(fs) ..
15163280Smckusick 	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1
15263280Smckusick 	 *
15363280Smckusick 	 * di_ib[2]		index block 2 is the triple indirect block
15463280Smckusick 	 *			holds block numbers for double-indirect
15563280Smckusick 	 *			blocks for blocks
15663280Smckusick 	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2 ..
15763280Smckusick 	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2
15863280Smckusick 	 *				+ NINDIR(fs)**3 - 1
15963280Smckusick 	 */
16063280Smckusick 
16163280Smckusick 	if (file_block < NDADDR) {
16263280Smckusick 		/* Direct block. */
16363280Smckusick 		*disk_block_p = fp->f_di.di_db[file_block];
16463280Smckusick 		return (0);
16563280Smckusick 	}
16663280Smckusick 
16763280Smckusick 	file_block -= NDADDR;
16863280Smckusick 
16963280Smckusick 	/*
17063280Smckusick 	 * nindir[0] = NINDIR
17163280Smckusick 	 * nindir[1] = NINDIR**2
17263280Smckusick 	 * nindir[2] = NINDIR**3
17363280Smckusick 	 *	etc
17463280Smckusick 	 */
17563280Smckusick 	for (level = 0; level < NIADDR; level++) {
17663280Smckusick 		if (file_block < fp->f_nindir[level])
17763280Smckusick 			break;
17863280Smckusick 		file_block -= fp->f_nindir[level];
17963280Smckusick 	}
18063280Smckusick 	if (level == NIADDR) {
18163280Smckusick 		/* Block number too high */
18263280Smckusick 		return (EFBIG);
18363280Smckusick 	}
18463280Smckusick 
18563280Smckusick 	ind_block_num = fp->f_di.di_ib[level];
18663280Smckusick 
18763280Smckusick 	for (; level >= 0; level--) {
18863280Smckusick 		if (ind_block_num == 0) {
18963280Smckusick 			*disk_block_p = 0;	/* missing */
19063280Smckusick 			return (0);
19163280Smckusick 		}
19263280Smckusick 
19363280Smckusick 		if (fp->f_blkno[level] != ind_block_num) {
19463280Smckusick 			if (fp->f_blk[level] == (char *)0)
19563280Smckusick 				fp->f_blk[level] =
19663280Smckusick 					alloc(fs->fs_bsize);
19763280Smckusick 			rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
19863280Smckusick 				fsbtodb(fp->f_fs, ind_block_num),
19963280Smckusick 				fs->fs_bsize,
20063280Smckusick 				fp->f_blk[level],
20163280Smckusick 				&fp->f_blksize[level]);
20263280Smckusick 			if (rc)
20363280Smckusick 				return (rc);
20463280Smckusick 			if (fp->f_blksize[level] != fs->fs_bsize)
20563280Smckusick 				return (EIO);
20663280Smckusick 			fp->f_blkno[level] = ind_block_num;
20763280Smckusick 		}
20863280Smckusick 
20963280Smckusick 		ind_p = (daddr_t *)fp->f_blk[level];
21063280Smckusick 
21163280Smckusick 		if (level > 0) {
21263280Smckusick 			idx = file_block / fp->f_nindir[level - 1];
21363280Smckusick 			file_block %= fp->f_nindir[level - 1];
21463280Smckusick 		} else
21563280Smckusick 			idx = file_block;
21663280Smckusick 
21763280Smckusick 		ind_block_num = ind_p[idx];
21863280Smckusick 	}
21963280Smckusick 
22063280Smckusick 	*disk_block_p = ind_block_num;
22163280Smckusick 
22263280Smckusick 	return (0);
22363280Smckusick }
22463280Smckusick 
22563280Smckusick /*
22663280Smckusick  * Read a portion of a file into an internal buffer.  Return
22763280Smckusick  * the location in the buffer and the amount in the buffer.
22863280Smckusick  */
22963280Smckusick static int
buf_read_file(f,buf_p,size_p)23063280Smckusick buf_read_file(f, buf_p, size_p)
23163280Smckusick 	struct open_file *f;
23263280Smckusick 	char **buf_p;		/* out */
23363280Smckusick 	u_int *size_p;		/* out */
23463280Smckusick {
23563280Smckusick 	register struct file *fp = (struct file *)f->f_fsdata;
23663280Smckusick 	register struct fs *fs = fp->f_fs;
23763280Smckusick 	long off;
23863280Smckusick 	register daddr_t file_block;
23963280Smckusick 	daddr_t	disk_block;
24063280Smckusick 	long block_size;
24163280Smckusick 	int rc;
24263280Smckusick 
24363280Smckusick 	off = blkoff(fs, fp->f_seekp);
24463280Smckusick 	file_block = lblkno(fs, fp->f_seekp);
24563280Smckusick 	block_size = dblksize(fs, &fp->f_di, file_block);
24663280Smckusick 
24763280Smckusick 	if (file_block != fp->f_buf_blkno) {
24863280Smckusick 		rc = block_map(f, file_block, &disk_block);
24963280Smckusick 		if (rc)
25063280Smckusick 			return (rc);
25163280Smckusick 
25263280Smckusick 		if (fp->f_buf == (char *)0)
25363280Smckusick 			fp->f_buf = alloc(fs->fs_bsize);
25463280Smckusick 
25563280Smckusick 		if (disk_block == 0) {
25663280Smckusick 			bzero(fp->f_buf, block_size);
25763280Smckusick 			fp->f_buf_size = block_size;
25863280Smckusick 		} else {
25963280Smckusick 			rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
26063280Smckusick 				fsbtodb(fs, disk_block),
26163280Smckusick 				block_size, fp->f_buf, &fp->f_buf_size);
26263280Smckusick 			if (rc)
26363280Smckusick 				return (rc);
26463280Smckusick 		}
26563280Smckusick 
26663280Smckusick 		fp->f_buf_blkno = file_block;
26763280Smckusick 	}
26863280Smckusick 
26963280Smckusick 	/*
27063280Smckusick 	 * Return address of byte in buffer corresponding to
27163280Smckusick 	 * offset, and size of remainder of buffer after that
27263280Smckusick 	 * byte.
27363280Smckusick 	 */
27463280Smckusick 	*buf_p = fp->f_buf + off;
27563280Smckusick 	*size_p = block_size - off;
27663280Smckusick 
27763280Smckusick 	/*
27863280Smckusick 	 * But truncate buffer at end of file.
27963280Smckusick 	 */
28063280Smckusick 	if (*size_p > fp->f_di.di_size - fp->f_seekp)
28163280Smckusick 		*size_p = fp->f_di.di_size - fp->f_seekp;
28263280Smckusick 
28363280Smckusick 	return (0);
28463280Smckusick }
28563280Smckusick 
28663280Smckusick /*
28763280Smckusick  * Search a directory for a name and return its
28863280Smckusick  * i_number.
28963280Smckusick  */
29063280Smckusick static int
search_directory(name,f,inumber_p)29163280Smckusick search_directory(name, f, inumber_p)
29263280Smckusick 	char *name;
29363280Smckusick 	struct open_file *f;
29463280Smckusick 	ino_t *inumber_p;		/* out */
29563280Smckusick {
29663280Smckusick 	register struct file *fp = (struct file *)f->f_fsdata;
29763280Smckusick 	register struct direct *dp;
29863280Smckusick 	struct direct *edp;
29963280Smckusick 	char *buf;
30063280Smckusick 	u_int buf_size;
30163280Smckusick 	int namlen, length;
30263280Smckusick 	int rc;
30363280Smckusick 
30463280Smckusick 	length = strlen(name);
30563280Smckusick 
30663280Smckusick 	fp->f_seekp = 0;
30763280Smckusick 	while (fp->f_seekp < fp->f_di.di_size) {
30863280Smckusick 		rc = buf_read_file(f, &buf, &buf_size);
30963280Smckusick 		if (rc)
31063280Smckusick 			return (rc);
31163280Smckusick 
31263280Smckusick 		dp = (struct direct *)buf;
31363280Smckusick 		edp = (struct direct *)(buf + buf_size);
31463280Smckusick 		while (dp < edp) {
31563280Smckusick 			if (dp->d_ino == (ino_t)0)
31663280Smckusick 				goto next;
31763280Smckusick #if BYTE_ORDER == LITTLE_ENDIAN
31863280Smckusick 			if (fp->f_fs->fs_maxsymlinklen <= 0)
31963280Smckusick 				namlen = dp->d_type;
32063280Smckusick 			else
32163280Smckusick #endif
32263280Smckusick 				namlen = dp->d_namlen;
32363280Smckusick 			if (namlen == length &&
32463280Smckusick 			    !strcmp(name, dp->d_name)) {
32563280Smckusick 				/* found entry */
32663280Smckusick 				*inumber_p = dp->d_ino;
32763280Smckusick 				return (0);
32863280Smckusick 			}
32963280Smckusick 		next:
33063280Smckusick 			dp = (struct direct *)((char *)dp + dp->d_reclen);
33163280Smckusick 		}
33263280Smckusick 		fp->f_seekp += buf_size;
33363280Smckusick 	}
33463280Smckusick 	return (ENOENT);
33563280Smckusick }
33663280Smckusick 
33763280Smckusick /*
33863280Smckusick  * Open a file.
33963280Smckusick  */
34063280Smckusick int
ufs_open(path,f)34163280Smckusick ufs_open(path, f)
34263280Smckusick 	char *path;
34363280Smckusick 	struct open_file *f;
34463280Smckusick {
34563280Smckusick 	register char *cp, *ncp;
34663280Smckusick 	register int c;
34763280Smckusick 	ino_t inumber, parent_inumber;
34863280Smckusick 	int nlinks = 0;
34963280Smckusick 	struct file *fp;
35063280Smckusick 	struct fs *fs;
35163280Smckusick 	int rc;
35263280Smckusick 	u_int buf_size;
35363280Smckusick #if 0
35463280Smckusick 	char namebuf[MAXPATHLEN+1];
35563280Smckusick #endif
35663280Smckusick 
35763280Smckusick 	/* allocate file system specific data structure */
35863280Smckusick 	fp = alloc(sizeof(struct file));
35963280Smckusick 	bzero(fp, sizeof(struct file));
36063280Smckusick 	f->f_fsdata = (void *)fp;
36163280Smckusick 
36263280Smckusick 	/* allocate space and read super block */
36363280Smckusick 	fs = alloc(SBSIZE);
36463280Smckusick 	fp->f_fs = fs;
36563280Smckusick 	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
36663280Smckusick 		SBLOCK, SBSIZE, (char *)fs, &buf_size);
36763280Smckusick 	if (rc)
36863280Smckusick 		goto out;
36963280Smckusick 
37063280Smckusick 	if (buf_size != SBSIZE || fs->fs_magic != FS_MAGIC ||
37163280Smckusick 	    fs->fs_bsize > MAXBSIZE || fs->fs_bsize < sizeof(struct fs)) {
37263280Smckusick 		rc = EINVAL;
37363280Smckusick 		goto out;
37463280Smckusick 	}
37563280Smckusick 
37663280Smckusick 	/*
37763280Smckusick 	 * Calculate indirect block levels.
37863280Smckusick 	 */
37963280Smckusick 	{
38063280Smckusick 		register int mult;
38163280Smckusick 		register int level;
38263280Smckusick 
38363280Smckusick 		mult = 1;
38463280Smckusick 		for (level = 0; level < NIADDR; level++) {
38563280Smckusick 			mult *= NINDIR(fs);
38663280Smckusick 			fp->f_nindir[level] = mult;
38763280Smckusick 		}
38863280Smckusick 	}
38963280Smckusick 
39063280Smckusick 	inumber = ROOTINO;
39163280Smckusick 	if ((rc = read_inode(inumber, f)) != 0)
39263280Smckusick 		goto out;
39363280Smckusick 
39463280Smckusick 	cp = path;
39563280Smckusick 	while (*cp) {
39663280Smckusick 
39763280Smckusick 		/*
39863280Smckusick 		 * Remove extra separators
39963280Smckusick 		 */
40063280Smckusick 		while (*cp == '/')
40163280Smckusick 			cp++;
40263280Smckusick 		if (*cp == '\0')
40363280Smckusick 			break;
40463280Smckusick 
40563280Smckusick 		/*
40663280Smckusick 		 * Check that current node is a directory.
40763280Smckusick 		 */
40863280Smckusick 		if ((fp->f_di.di_mode & IFMT) != IFDIR) {
40963280Smckusick 			rc = ENOTDIR;
41063280Smckusick 			goto out;
41163280Smckusick 		}
41263280Smckusick 
41363280Smckusick 		/*
41463280Smckusick 		 * Get next component of path name.
41563280Smckusick 		 */
41663280Smckusick 		{
41763280Smckusick 			register int len = 0;
41863280Smckusick 
41963280Smckusick 			ncp = cp;
42063280Smckusick 			while ((c = *cp) != '\0' && c != '/') {
42163280Smckusick 				if (++len > MAXNAMLEN) {
42263280Smckusick 					rc = ENOENT;
42363280Smckusick 					goto out;
42463280Smckusick 				}
42563280Smckusick 				cp++;
42663280Smckusick 			}
42763280Smckusick 			*cp = '\0';
42863280Smckusick 		}
42963280Smckusick 
43063280Smckusick 		/*
43163280Smckusick 		 * Look up component in current directory.
43263280Smckusick 		 * Save directory inumber in case we find a
43363280Smckusick 		 * symbolic link.
43463280Smckusick 		 */
43563280Smckusick 		parent_inumber = inumber;
43663280Smckusick 		rc = search_directory(ncp, f, &inumber);
43763280Smckusick 		*cp = c;
43863280Smckusick 		if (rc)
43963280Smckusick 			goto out;
44063280Smckusick 
44163280Smckusick 		/*
44263280Smckusick 		 * Open next component.
44363280Smckusick 		 */
44463280Smckusick 		if ((rc = read_inode(inumber, f)) != 0)
44563280Smckusick 			goto out;
44663280Smckusick 
44763280Smckusick #if 0
44863280Smckusick 		/*
44963280Smckusick 		 * Check for symbolic link.
45063280Smckusick 		 */
45163280Smckusick 		if ((fp->i_mode & IFMT) == IFLNK) {
45263280Smckusick 			int link_len = fp->f_di.di_size;
45363280Smckusick 			int len;
45463280Smckusick 
45563280Smckusick 			len = strlen(cp) + 1;
45663280Smckusick 
45763280Smckusick 			if (fp->f_di.di_size >= MAXPATHLEN - 1 ||
45863280Smckusick 			    ++nlinks > MAXSYMLINKS) {
45963280Smckusick 				rc = ENOENT;
46063280Smckusick 				goto out;
46163280Smckusick 			}
46263280Smckusick 
46363280Smckusick 			strcpy(&namebuf[link_len], cp);
46463280Smckusick 
46563280Smckusick 			if ((fp->i_flags & IC_FASTLINK) != 0) {
46663280Smckusick 				bcopy(fp->i_symlink, namebuf, (unsigned) link_len);
46763280Smckusick 			} else {
46863280Smckusick 				/*
46963280Smckusick 				 * Read file for symbolic link
47063280Smckusick 				 */
47163280Smckusick 				char *buf;
47263280Smckusick 				u_int buf_size;
47363280Smckusick 				daddr_t	disk_block;
47463280Smckusick 				register struct fs *fs = fp->f_fs;
47563280Smckusick 
47663280Smckusick 				(void) block_map(f, (daddr_t)0, &disk_block);
47763280Smckusick 				rc = device_read(&fp->f_dev,
47863280Smckusick 						 fsbtodb(fs, disk_block),
47963280Smckusick 						 blksize(fs, fp, 0),
48063280Smckusick 						 &buf, &buf_size);
48163280Smckusick 				if (rc)
48263280Smckusick 					goto out;
48363280Smckusick 
48463280Smckusick 				bcopy((char *)buf, namebuf, (unsigned)link_len);
48563280Smckusick 				free(buf, buf_size);
48663280Smckusick 			}
48763280Smckusick 
48863280Smckusick 			/*
48963280Smckusick 			 * If relative pathname, restart at parent directory.
49063280Smckusick 			 * If absolute pathname, restart at root.
49163280Smckusick 			 */
49263280Smckusick 			cp = namebuf;
49363280Smckusick 			if (*cp != '/')
49463280Smckusick 				inumber = parent_inumber;
49563280Smckusick 			else
49663280Smckusick 				inumber = (ino_t)ROOTINO;
49763280Smckusick 
49863280Smckusick 			if ((rc = read_inode(inumber, fp)) != 0)
49963280Smckusick 				goto out;
50063280Smckusick 		}
50163280Smckusick #endif
50263280Smckusick 	}
50363280Smckusick 
50463280Smckusick 	/*
50563280Smckusick 	 * Found terminal component.
50663280Smckusick 	 */
50763280Smckusick 	rc = 0;
50863280Smckusick out:
50963280Smckusick 	if (rc)
51063280Smckusick 		free(fp, sizeof(struct file));
51163280Smckusick 	return (rc);
51263280Smckusick }
51363280Smckusick 
51463280Smckusick int
ufs_close(f)51563280Smckusick ufs_close(f)
51663280Smckusick 	struct open_file *f;
51763280Smckusick {
51863280Smckusick 	register struct file *fp = (struct file *)f->f_fsdata;
51963280Smckusick 	int level;
52063280Smckusick 
52163280Smckusick 	f->f_fsdata = (void *)0;
52263280Smckusick 	if (fp == (struct file *)0)
52363280Smckusick 		return (0);
52463280Smckusick 
52563280Smckusick 	for (level = 0; level < NIADDR; level++) {
52663280Smckusick 		if (fp->f_blk[level])
52763280Smckusick 			free(fp->f_blk[level], fp->f_fs->fs_bsize);
52863280Smckusick 	}
52963280Smckusick 	if (fp->f_buf)
53063280Smckusick 		free(fp->f_buf, fp->f_fs->fs_bsize);
53163280Smckusick 	free(fp->f_fs, SBSIZE);
53263280Smckusick 	free(fp, sizeof(struct file));
53363280Smckusick 	return (0);
53463280Smckusick }
53563280Smckusick 
53663280Smckusick /*
53763280Smckusick  * Copy a portion of a file into kernel memory.
53863280Smckusick  * Cross block boundaries when necessary.
53963280Smckusick  */
54063280Smckusick int
ufs_read(f,start,size,resid)54163280Smckusick ufs_read(f, start, size, resid)
54263280Smckusick 	struct open_file *f;
54363280Smckusick 	char *start;
54463280Smckusick 	u_int size;
54563280Smckusick 	u_int *resid;	/* out */
54663280Smckusick {
54763280Smckusick 	register struct file *fp = (struct file *)f->f_fsdata;
54863280Smckusick 	register u_int csize;
54963280Smckusick 	char *buf;
55063280Smckusick 	u_int buf_size;
55163280Smckusick 	int rc = 0;
55263280Smckusick 
55363280Smckusick 	while (size != 0) {
55463280Smckusick 		if (fp->f_seekp >= fp->f_di.di_size)
55563280Smckusick 			break;
55663280Smckusick 
55763280Smckusick 		rc = buf_read_file(f, &buf, &buf_size);
55863280Smckusick 		if (rc)
55963280Smckusick 			break;
56063280Smckusick 
56163280Smckusick 		csize = size;
56263280Smckusick 		if (csize > buf_size)
56363280Smckusick 			csize = buf_size;
56463280Smckusick 
56563280Smckusick 		bcopy(buf, start, csize);
56663280Smckusick 
56763280Smckusick 		fp->f_seekp += csize;
56863280Smckusick 		start += csize;
56963280Smckusick 		size -= csize;
57063280Smckusick 	}
57163280Smckusick 	if (resid)
57263280Smckusick 		*resid = size;
57363280Smckusick 	return (rc);
57463280Smckusick }
57563280Smckusick 
57663280Smckusick /*
57763280Smckusick  * Not implemented.
57863280Smckusick  */
57963280Smckusick int
ufs_write(f,start,size,resid)58063280Smckusick ufs_write(f, start, size, resid)
58163280Smckusick 	struct open_file *f;
58263280Smckusick 	char *start;
58363280Smckusick 	u_int size;
58463280Smckusick 	u_int *resid;	/* out */
58563280Smckusick {
58663280Smckusick 
58763280Smckusick 	return (EROFS);
58863280Smckusick }
58963280Smckusick 
59063280Smckusick off_t
ufs_seek(f,offset,where)59163280Smckusick ufs_seek(f, offset, where)
59263280Smckusick 	struct open_file *f;
59363280Smckusick 	off_t offset;
59463280Smckusick 	int where;
59563280Smckusick {
59663280Smckusick 	register struct file *fp = (struct file *)f->f_fsdata;
59763280Smckusick 
59863280Smckusick 	switch (where) {
59963280Smckusick 	case SEEK_SET:
60063280Smckusick 		fp->f_seekp = offset;
60163280Smckusick 		break;
60263280Smckusick 	case SEEK_CUR:
60363280Smckusick 		fp->f_seekp += offset;
60463280Smckusick 		break;
60563280Smckusick 	case SEEK_END:
60663280Smckusick 		fp->f_seekp = fp->f_di.di_size - offset;
60763280Smckusick 		break;
60863280Smckusick 	default:
60963280Smckusick 		return (-1);
61063280Smckusick 	}
61163280Smckusick 	return (fp->f_seekp);
61263280Smckusick }
61363280Smckusick 
61463280Smckusick int
ufs_stat(f,sb)61563280Smckusick ufs_stat(f, sb)
61663280Smckusick 	struct open_file *f;
61763280Smckusick 	struct stat *sb;
61863280Smckusick {
61963280Smckusick 	register struct file *fp = (struct file *)f->f_fsdata;
62063280Smckusick 
62163280Smckusick 	/* only important stuff */
62263280Smckusick 	sb->st_mode = fp->f_di.di_mode;
62363280Smckusick 	sb->st_uid = fp->f_di.di_uid;
62463280Smckusick 	sb->st_gid = fp->f_di.di_gid;
62563280Smckusick 	sb->st_size = fp->f_di.di_size;
62663280Smckusick 	return (0);
62763280Smckusick }
628