xref: /csrg-svn/sys/stand/ufs.c (revision 63370)
163280Smckusick /*-
2*63370Sbostic  * Copyright (c) 1993
3*63370Sbostic  *	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*63370Sbostic  *	@(#)ufs.c	8.1 (Berkeley) 06/11/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 */
6263280Smckusick 	u_long		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
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,
8963280Smckusick 		fsbtodb(fs, itod(fs, inumber)), fs->fs_bsize, buf, &rsize);
9063280Smckusick 	if (rc)
9163280Smckusick 		goto out;
9263280Smckusick 	if (rsize != fs->fs_bsize) {
9363280Smckusick 		rc = EIO;
9463280Smckusick 		goto out;
9563280Smckusick 	}
9663280Smckusick 
9763280Smckusick 	{
9863280Smckusick 		register struct dinode *dp;
9963280Smckusick 
10063280Smckusick 		dp = (struct dinode *)buf;
10163280Smckusick 		fp->f_di = dp[itoo(fs, inumber)];
10263280Smckusick 	}
10363280Smckusick 
10463280Smckusick 	/*
10563280Smckusick 	 * Clear out the old buffers
10663280Smckusick 	 */
10763280Smckusick 	{
10863280Smckusick 		register int level;
10963280Smckusick 
11063280Smckusick 		for (level = 0; level < NIADDR; level++)
11163280Smckusick 			fp->f_blkno[level] = -1;
11263280Smckusick 		fp->f_buf_blkno = -1;
11363280Smckusick 	}
11463280Smckusick out:
11563280Smckusick 	free(buf, fs->fs_bsize);
11663280Smckusick 	return (0);
11763280Smckusick }
11863280Smckusick 
11963280Smckusick /*
12063280Smckusick  * Given an offset in a file, find the disk block number that
12163280Smckusick  * contains that block.
12263280Smckusick  */
12363280Smckusick static int
12463280Smckusick block_map(f, file_block, disk_block_p)
12563280Smckusick 	struct open_file *f;
12663280Smckusick 	daddr_t file_block;
12763280Smckusick 	daddr_t *disk_block_p;	/* out */
12863280Smckusick {
12963280Smckusick 	register struct file *fp = (struct file *)f->f_fsdata;
13063280Smckusick 	register struct fs *fs = fp->f_fs;
13163280Smckusick 	int level;
13263280Smckusick 	int idx;
13363280Smckusick 	daddr_t ind_block_num;
13463280Smckusick 	daddr_t *ind_p;
13563280Smckusick 	int rc;
13663280Smckusick 
13763280Smckusick 	/*
13863280Smckusick 	 * Index structure of an inode:
13963280Smckusick 	 *
14063280Smckusick 	 * di_db[0..NDADDR-1]	hold block numbers for blocks
14163280Smckusick 	 *			0..NDADDR-1
14263280Smckusick 	 *
14363280Smckusick 	 * di_ib[0]		index block 0 is the single indirect block
14463280Smckusick 	 *			holds block numbers for blocks
14563280Smckusick 	 *			NDADDR .. NDADDR + NINDIR(fs)-1
14663280Smckusick 	 *
14763280Smckusick 	 * di_ib[1]		index block 1 is the double indirect block
14863280Smckusick 	 *			holds block numbers for INDEX blocks for blocks
14963280Smckusick 	 *			NDADDR + NINDIR(fs) ..
15063280Smckusick 	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1
15163280Smckusick 	 *
15263280Smckusick 	 * di_ib[2]		index block 2 is the triple indirect block
15363280Smckusick 	 *			holds block numbers for double-indirect
15463280Smckusick 	 *			blocks for blocks
15563280Smckusick 	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2 ..
15663280Smckusick 	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2
15763280Smckusick 	 *				+ NINDIR(fs)**3 - 1
15863280Smckusick 	 */
15963280Smckusick 
16063280Smckusick 	if (file_block < NDADDR) {
16163280Smckusick 		/* Direct block. */
16263280Smckusick 		*disk_block_p = fp->f_di.di_db[file_block];
16363280Smckusick 		return (0);
16463280Smckusick 	}
16563280Smckusick 
16663280Smckusick 	file_block -= NDADDR;
16763280Smckusick 
16863280Smckusick 	/*
16963280Smckusick 	 * nindir[0] = NINDIR
17063280Smckusick 	 * nindir[1] = NINDIR**2
17163280Smckusick 	 * nindir[2] = NINDIR**3
17263280Smckusick 	 *	etc
17363280Smckusick 	 */
17463280Smckusick 	for (level = 0; level < NIADDR; level++) {
17563280Smckusick 		if (file_block < fp->f_nindir[level])
17663280Smckusick 			break;
17763280Smckusick 		file_block -= fp->f_nindir[level];
17863280Smckusick 	}
17963280Smckusick 	if (level == NIADDR) {
18063280Smckusick 		/* Block number too high */
18163280Smckusick 		return (EFBIG);
18263280Smckusick 	}
18363280Smckusick 
18463280Smckusick 	ind_block_num = fp->f_di.di_ib[level];
18563280Smckusick 
18663280Smckusick 	for (; level >= 0; level--) {
18763280Smckusick 		if (ind_block_num == 0) {
18863280Smckusick 			*disk_block_p = 0;	/* missing */
18963280Smckusick 			return (0);
19063280Smckusick 		}
19163280Smckusick 
19263280Smckusick 		if (fp->f_blkno[level] != ind_block_num) {
19363280Smckusick 			if (fp->f_blk[level] == (char *)0)
19463280Smckusick 				fp->f_blk[level] =
19563280Smckusick 					alloc(fs->fs_bsize);
19663280Smckusick 			rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
19763280Smckusick 				fsbtodb(fp->f_fs, ind_block_num),
19863280Smckusick 				fs->fs_bsize,
19963280Smckusick 				fp->f_blk[level],
20063280Smckusick 				&fp->f_blksize[level]);
20163280Smckusick 			if (rc)
20263280Smckusick 				return (rc);
20363280Smckusick 			if (fp->f_blksize[level] != fs->fs_bsize)
20463280Smckusick 				return (EIO);
20563280Smckusick 			fp->f_blkno[level] = ind_block_num;
20663280Smckusick 		}
20763280Smckusick 
20863280Smckusick 		ind_p = (daddr_t *)fp->f_blk[level];
20963280Smckusick 
21063280Smckusick 		if (level > 0) {
21163280Smckusick 			idx = file_block / fp->f_nindir[level - 1];
21263280Smckusick 			file_block %= fp->f_nindir[level - 1];
21363280Smckusick 		} else
21463280Smckusick 			idx = file_block;
21563280Smckusick 
21663280Smckusick 		ind_block_num = ind_p[idx];
21763280Smckusick 	}
21863280Smckusick 
21963280Smckusick 	*disk_block_p = ind_block_num;
22063280Smckusick 
22163280Smckusick 	return (0);
22263280Smckusick }
22363280Smckusick 
22463280Smckusick /*
22563280Smckusick  * Read a portion of a file into an internal buffer.  Return
22663280Smckusick  * the location in the buffer and the amount in the buffer.
22763280Smckusick  */
22863280Smckusick static int
22963280Smckusick buf_read_file(f, buf_p, size_p)
23063280Smckusick 	struct open_file *f;
23163280Smckusick 	char **buf_p;		/* out */
23263280Smckusick 	u_int *size_p;		/* out */
23363280Smckusick {
23463280Smckusick 	register struct file *fp = (struct file *)f->f_fsdata;
23563280Smckusick 	register struct fs *fs = fp->f_fs;
23663280Smckusick 	long off;
23763280Smckusick 	register daddr_t file_block;
23863280Smckusick 	daddr_t	disk_block;
23963280Smckusick 	long block_size;
24063280Smckusick 	int rc;
24163280Smckusick 
24263280Smckusick 	off = blkoff(fs, fp->f_seekp);
24363280Smckusick 	file_block = lblkno(fs, fp->f_seekp);
24463280Smckusick 	block_size = dblksize(fs, &fp->f_di, file_block);
24563280Smckusick 
24663280Smckusick 	if (file_block != fp->f_buf_blkno) {
24763280Smckusick 		rc = block_map(f, file_block, &disk_block);
24863280Smckusick 		if (rc)
24963280Smckusick 			return (rc);
25063280Smckusick 
25163280Smckusick 		if (fp->f_buf == (char *)0)
25263280Smckusick 			fp->f_buf = alloc(fs->fs_bsize);
25363280Smckusick 
25463280Smckusick 		if (disk_block == 0) {
25563280Smckusick 			bzero(fp->f_buf, block_size);
25663280Smckusick 			fp->f_buf_size = block_size;
25763280Smckusick 		} else {
25863280Smckusick 			rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
25963280Smckusick 				fsbtodb(fs, disk_block),
26063280Smckusick 				block_size, fp->f_buf, &fp->f_buf_size);
26163280Smckusick 			if (rc)
26263280Smckusick 				return (rc);
26363280Smckusick 		}
26463280Smckusick 
26563280Smckusick 		fp->f_buf_blkno = file_block;
26663280Smckusick 	}
26763280Smckusick 
26863280Smckusick 	/*
26963280Smckusick 	 * Return address of byte in buffer corresponding to
27063280Smckusick 	 * offset, and size of remainder of buffer after that
27163280Smckusick 	 * byte.
27263280Smckusick 	 */
27363280Smckusick 	*buf_p = fp->f_buf + off;
27463280Smckusick 	*size_p = block_size - off;
27563280Smckusick 
27663280Smckusick 	/*
27763280Smckusick 	 * But truncate buffer at end of file.
27863280Smckusick 	 */
27963280Smckusick 	if (*size_p > fp->f_di.di_size - fp->f_seekp)
28063280Smckusick 		*size_p = fp->f_di.di_size - fp->f_seekp;
28163280Smckusick 
28263280Smckusick 	return (0);
28363280Smckusick }
28463280Smckusick 
28563280Smckusick /*
28663280Smckusick  * Search a directory for a name and return its
28763280Smckusick  * i_number.
28863280Smckusick  */
28963280Smckusick static int
29063280Smckusick search_directory(name, f, inumber_p)
29163280Smckusick 	char *name;
29263280Smckusick 	struct open_file *f;
29363280Smckusick 	ino_t *inumber_p;		/* out */
29463280Smckusick {
29563280Smckusick 	register struct file *fp = (struct file *)f->f_fsdata;
29663280Smckusick 	register struct direct *dp;
29763280Smckusick 	struct direct *edp;
29863280Smckusick 	char *buf;
29963280Smckusick 	u_int buf_size;
30063280Smckusick 	int namlen, length;
30163280Smckusick 	int rc;
30263280Smckusick 
30363280Smckusick 	length = strlen(name);
30463280Smckusick 
30563280Smckusick 	fp->f_seekp = 0;
30663280Smckusick 	while (fp->f_seekp < fp->f_di.di_size) {
30763280Smckusick 		rc = buf_read_file(f, &buf, &buf_size);
30863280Smckusick 		if (rc)
30963280Smckusick 			return (rc);
31063280Smckusick 
31163280Smckusick 		dp = (struct direct *)buf;
31263280Smckusick 		edp = (struct direct *)(buf + buf_size);
31363280Smckusick 		while (dp < edp) {
31463280Smckusick 			if (dp->d_ino == (ino_t)0)
31563280Smckusick 				goto next;
31663280Smckusick #if BYTE_ORDER == LITTLE_ENDIAN
31763280Smckusick 			if (fp->f_fs->fs_maxsymlinklen <= 0)
31863280Smckusick 				namlen = dp->d_type;
31963280Smckusick 			else
32063280Smckusick #endif
32163280Smckusick 				namlen = dp->d_namlen;
32263280Smckusick 			if (namlen == length &&
32363280Smckusick 			    !strcmp(name, dp->d_name)) {
32463280Smckusick 				/* found entry */
32563280Smckusick 				*inumber_p = dp->d_ino;
32663280Smckusick 				return (0);
32763280Smckusick 			}
32863280Smckusick 		next:
32963280Smckusick 			dp = (struct direct *)((char *)dp + dp->d_reclen);
33063280Smckusick 		}
33163280Smckusick 		fp->f_seekp += buf_size;
33263280Smckusick 	}
33363280Smckusick 	return (ENOENT);
33463280Smckusick }
33563280Smckusick 
33663280Smckusick /*
33763280Smckusick  * Open a file.
33863280Smckusick  */
33963280Smckusick int
34063280Smckusick ufs_open(path, f)
34163280Smckusick 	char *path;
34263280Smckusick 	struct open_file *f;
34363280Smckusick {
34463280Smckusick 	register char *cp, *ncp;
34563280Smckusick 	register int c;
34663280Smckusick 	ino_t inumber, parent_inumber;
34763280Smckusick 	int nlinks = 0;
34863280Smckusick 	struct file *fp;
34963280Smckusick 	struct fs *fs;
35063280Smckusick 	int rc;
35163280Smckusick 	u_int buf_size;
35263280Smckusick #if 0
35363280Smckusick 	char namebuf[MAXPATHLEN+1];
35463280Smckusick #endif
35563280Smckusick 
35663280Smckusick 	/* allocate file system specific data structure */
35763280Smckusick 	fp = alloc(sizeof(struct file));
35863280Smckusick 	bzero(fp, sizeof(struct file));
35963280Smckusick 	f->f_fsdata = (void *)fp;
36063280Smckusick 
36163280Smckusick 	/* allocate space and read super block */
36263280Smckusick 	fs = alloc(SBSIZE);
36363280Smckusick 	fp->f_fs = fs;
36463280Smckusick 	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
36563280Smckusick 		SBLOCK, SBSIZE, (char *)fs, &buf_size);
36663280Smckusick 	if (rc)
36763280Smckusick 		goto out;
36863280Smckusick 
36963280Smckusick 	if (buf_size != SBSIZE || fs->fs_magic != FS_MAGIC ||
37063280Smckusick 	    fs->fs_bsize > MAXBSIZE || fs->fs_bsize < sizeof(struct fs)) {
37163280Smckusick 		rc = EINVAL;
37263280Smckusick 		goto out;
37363280Smckusick 	}
37463280Smckusick 
37563280Smckusick 	/*
37663280Smckusick 	 * Calculate indirect block levels.
37763280Smckusick 	 */
37863280Smckusick 	{
37963280Smckusick 		register int mult;
38063280Smckusick 		register int level;
38163280Smckusick 
38263280Smckusick 		mult = 1;
38363280Smckusick 		for (level = 0; level < NIADDR; level++) {
38463280Smckusick 			mult *= NINDIR(fs);
38563280Smckusick 			fp->f_nindir[level] = mult;
38663280Smckusick 		}
38763280Smckusick 	}
38863280Smckusick 
38963280Smckusick 	inumber = ROOTINO;
39063280Smckusick 	if ((rc = read_inode(inumber, f)) != 0)
39163280Smckusick 		goto out;
39263280Smckusick 
39363280Smckusick 	cp = path;
39463280Smckusick 	while (*cp) {
39563280Smckusick 
39663280Smckusick 		/*
39763280Smckusick 		 * Remove extra separators
39863280Smckusick 		 */
39963280Smckusick 		while (*cp == '/')
40063280Smckusick 			cp++;
40163280Smckusick 		if (*cp == '\0')
40263280Smckusick 			break;
40363280Smckusick 
40463280Smckusick 		/*
40563280Smckusick 		 * Check that current node is a directory.
40663280Smckusick 		 */
40763280Smckusick 		if ((fp->f_di.di_mode & IFMT) != IFDIR) {
40863280Smckusick 			rc = ENOTDIR;
40963280Smckusick 			goto out;
41063280Smckusick 		}
41163280Smckusick 
41263280Smckusick 		/*
41363280Smckusick 		 * Get next component of path name.
41463280Smckusick 		 */
41563280Smckusick 		{
41663280Smckusick 			register int len = 0;
41763280Smckusick 
41863280Smckusick 			ncp = cp;
41963280Smckusick 			while ((c = *cp) != '\0' && c != '/') {
42063280Smckusick 				if (++len > MAXNAMLEN) {
42163280Smckusick 					rc = ENOENT;
42263280Smckusick 					goto out;
42363280Smckusick 				}
42463280Smckusick 				cp++;
42563280Smckusick 			}
42663280Smckusick 			*cp = '\0';
42763280Smckusick 		}
42863280Smckusick 
42963280Smckusick 		/*
43063280Smckusick 		 * Look up component in current directory.
43163280Smckusick 		 * Save directory inumber in case we find a
43263280Smckusick 		 * symbolic link.
43363280Smckusick 		 */
43463280Smckusick 		parent_inumber = inumber;
43563280Smckusick 		rc = search_directory(ncp, f, &inumber);
43663280Smckusick 		*cp = c;
43763280Smckusick 		if (rc)
43863280Smckusick 			goto out;
43963280Smckusick 
44063280Smckusick 		/*
44163280Smckusick 		 * Open next component.
44263280Smckusick 		 */
44363280Smckusick 		if ((rc = read_inode(inumber, f)) != 0)
44463280Smckusick 			goto out;
44563280Smckusick 
44663280Smckusick #if 0
44763280Smckusick 		/*
44863280Smckusick 		 * Check for symbolic link.
44963280Smckusick 		 */
45063280Smckusick 		if ((fp->i_mode & IFMT) == IFLNK) {
45163280Smckusick 			int link_len = fp->f_di.di_size;
45263280Smckusick 			int len;
45363280Smckusick 
45463280Smckusick 			len = strlen(cp) + 1;
45563280Smckusick 
45663280Smckusick 			if (fp->f_di.di_size >= MAXPATHLEN - 1 ||
45763280Smckusick 			    ++nlinks > MAXSYMLINKS) {
45863280Smckusick 				rc = ENOENT;
45963280Smckusick 				goto out;
46063280Smckusick 			}
46163280Smckusick 
46263280Smckusick 			strcpy(&namebuf[link_len], cp);
46363280Smckusick 
46463280Smckusick 			if ((fp->i_flags & IC_FASTLINK) != 0) {
46563280Smckusick 				bcopy(fp->i_symlink, namebuf, (unsigned) link_len);
46663280Smckusick 			} else {
46763280Smckusick 				/*
46863280Smckusick 				 * Read file for symbolic link
46963280Smckusick 				 */
47063280Smckusick 				char *buf;
47163280Smckusick 				u_int buf_size;
47263280Smckusick 				daddr_t	disk_block;
47363280Smckusick 				register struct fs *fs = fp->f_fs;
47463280Smckusick 
47563280Smckusick 				(void) block_map(f, (daddr_t)0, &disk_block);
47663280Smckusick 				rc = device_read(&fp->f_dev,
47763280Smckusick 						 fsbtodb(fs, disk_block),
47863280Smckusick 						 blksize(fs, fp, 0),
47963280Smckusick 						 &buf, &buf_size);
48063280Smckusick 				if (rc)
48163280Smckusick 					goto out;
48263280Smckusick 
48363280Smckusick 				bcopy((char *)buf, namebuf, (unsigned)link_len);
48463280Smckusick 				free(buf, buf_size);
48563280Smckusick 			}
48663280Smckusick 
48763280Smckusick 			/*
48863280Smckusick 			 * If relative pathname, restart at parent directory.
48963280Smckusick 			 * If absolute pathname, restart at root.
49063280Smckusick 			 */
49163280Smckusick 			cp = namebuf;
49263280Smckusick 			if (*cp != '/')
49363280Smckusick 				inumber = parent_inumber;
49463280Smckusick 			else
49563280Smckusick 				inumber = (ino_t)ROOTINO;
49663280Smckusick 
49763280Smckusick 			if ((rc = read_inode(inumber, fp)) != 0)
49863280Smckusick 				goto out;
49963280Smckusick 		}
50063280Smckusick #endif
50163280Smckusick 	}
50263280Smckusick 
50363280Smckusick 	/*
50463280Smckusick 	 * Found terminal component.
50563280Smckusick 	 */
50663280Smckusick 	rc = 0;
50763280Smckusick out:
50863280Smckusick 	if (rc)
50963280Smckusick 		free(fp, sizeof(struct file));
51063280Smckusick 	return (rc);
51163280Smckusick }
51263280Smckusick 
51363280Smckusick int
51463280Smckusick ufs_close(f)
51563280Smckusick 	struct open_file *f;
51663280Smckusick {
51763280Smckusick 	register struct file *fp = (struct file *)f->f_fsdata;
51863280Smckusick 	int level;
51963280Smckusick 
52063280Smckusick 	f->f_fsdata = (void *)0;
52163280Smckusick 	if (fp == (struct file *)0)
52263280Smckusick 		return (0);
52363280Smckusick 
52463280Smckusick 	for (level = 0; level < NIADDR; level++) {
52563280Smckusick 		if (fp->f_blk[level])
52663280Smckusick 			free(fp->f_blk[level], fp->f_fs->fs_bsize);
52763280Smckusick 	}
52863280Smckusick 	if (fp->f_buf)
52963280Smckusick 		free(fp->f_buf, fp->f_fs->fs_bsize);
53063280Smckusick 	free(fp->f_fs, SBSIZE);
53163280Smckusick 	free(fp, sizeof(struct file));
53263280Smckusick 	return (0);
53363280Smckusick }
53463280Smckusick 
53563280Smckusick /*
53663280Smckusick  * Copy a portion of a file into kernel memory.
53763280Smckusick  * Cross block boundaries when necessary.
53863280Smckusick  */
53963280Smckusick int
54063280Smckusick ufs_read(f, start, size, resid)
54163280Smckusick 	struct open_file *f;
54263280Smckusick 	char *start;
54363280Smckusick 	u_int size;
54463280Smckusick 	u_int *resid;	/* out */
54563280Smckusick {
54663280Smckusick 	register struct file *fp = (struct file *)f->f_fsdata;
54763280Smckusick 	register u_int csize;
54863280Smckusick 	char *buf;
54963280Smckusick 	u_int buf_size;
55063280Smckusick 	int rc = 0;
55163280Smckusick 
55263280Smckusick 	while (size != 0) {
55363280Smckusick 		if (fp->f_seekp >= fp->f_di.di_size)
55463280Smckusick 			break;
55563280Smckusick 
55663280Smckusick 		rc = buf_read_file(f, &buf, &buf_size);
55763280Smckusick 		if (rc)
55863280Smckusick 			break;
55963280Smckusick 
56063280Smckusick 		csize = size;
56163280Smckusick 		if (csize > buf_size)
56263280Smckusick 			csize = buf_size;
56363280Smckusick 
56463280Smckusick 		bcopy(buf, start, csize);
56563280Smckusick 
56663280Smckusick 		fp->f_seekp += csize;
56763280Smckusick 		start += csize;
56863280Smckusick 		size -= csize;
56963280Smckusick 	}
57063280Smckusick 	if (resid)
57163280Smckusick 		*resid = size;
57263280Smckusick 	return (rc);
57363280Smckusick }
57463280Smckusick 
57563280Smckusick /*
57663280Smckusick  * Not implemented.
57763280Smckusick  */
57863280Smckusick int
57963280Smckusick ufs_write(f, start, size, resid)
58063280Smckusick 	struct open_file *f;
58163280Smckusick 	char *start;
58263280Smckusick 	u_int size;
58363280Smckusick 	u_int *resid;	/* out */
58463280Smckusick {
58563280Smckusick 
58663280Smckusick 	return (EROFS);
58763280Smckusick }
58863280Smckusick 
58963280Smckusick off_t
59063280Smckusick ufs_seek(f, offset, where)
59163280Smckusick 	struct open_file *f;
59263280Smckusick 	off_t offset;
59363280Smckusick 	int where;
59463280Smckusick {
59563280Smckusick 	register struct file *fp = (struct file *)f->f_fsdata;
59663280Smckusick 
59763280Smckusick 	switch (where) {
59863280Smckusick 	case SEEK_SET:
59963280Smckusick 		fp->f_seekp = offset;
60063280Smckusick 		break;
60163280Smckusick 	case SEEK_CUR:
60263280Smckusick 		fp->f_seekp += offset;
60363280Smckusick 		break;
60463280Smckusick 	case SEEK_END:
60563280Smckusick 		fp->f_seekp = fp->f_di.di_size - offset;
60663280Smckusick 		break;
60763280Smckusick 	default:
60863280Smckusick 		return (-1);
60963280Smckusick 	}
61063280Smckusick 	return (fp->f_seekp);
61163280Smckusick }
61263280Smckusick 
61363280Smckusick int
61463280Smckusick ufs_stat(f, sb)
61563280Smckusick 	struct open_file *f;
61663280Smckusick 	struct stat *sb;
61763280Smckusick {
61863280Smckusick 	register struct file *fp = (struct file *)f->f_fsdata;
61963280Smckusick 
62063280Smckusick 	/* only important stuff */
62163280Smckusick 	sb->st_mode = fp->f_di.di_mode;
62263280Smckusick 	sb->st_uid = fp->f_di.di_uid;
62363280Smckusick 	sb->st_gid = fp->f_di.di_gid;
62463280Smckusick 	sb->st_size = fp->f_di.di_size;
62563280Smckusick 	return (0);
62663280Smckusick }
627