xref: /csrg-svn/sys/stand/ufs.c (revision 63280)
1*63280Smckusick /*-
2*63280Smckusick  * Copyright (c) 1993 The Regents of the University of California.
3*63280Smckusick  * All rights reserved.
4*63280Smckusick  *
5*63280Smckusick  * This code is derived from software contributed to Berkeley by
6*63280Smckusick  * The Mach Operating System project at Carnegie-Mellon University.
7*63280Smckusick  *
8*63280Smckusick  * %sccs.include.redist.c%
9*63280Smckusick  *
10*63280Smckusick  *	@(#)ufs.c	7.1 (Berkeley) 06/11/93
11*63280Smckusick  *
12*63280Smckusick  *
13*63280Smckusick  * Copyright (c) 1990, 1991 Carnegie Mellon University
14*63280Smckusick  * All Rights Reserved.
15*63280Smckusick  *
16*63280Smckusick  * Author: David Golub
17*63280Smckusick  *
18*63280Smckusick  * Permission to use, copy, modify and distribute this software and its
19*63280Smckusick  * documentation is hereby granted, provided that both the copyright
20*63280Smckusick  * notice and this permission notice appear in all copies of the
21*63280Smckusick  * software, derivative works or modified versions, and any portions
22*63280Smckusick  * thereof, and that both notices appear in supporting documentation.
23*63280Smckusick  *
24*63280Smckusick  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
25*63280Smckusick  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
26*63280Smckusick  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
27*63280Smckusick  *
28*63280Smckusick  * Carnegie Mellon requests users of this software to return to
29*63280Smckusick  *
30*63280Smckusick  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
31*63280Smckusick  *  School of Computer Science
32*63280Smckusick  *  Carnegie Mellon University
33*63280Smckusick  *  Pittsburgh PA 15213-3890
34*63280Smckusick  *
35*63280Smckusick  * any improvements or extensions that they make and grant Carnegie the
36*63280Smckusick  * rights to redistribute these changes.
37*63280Smckusick  */
38*63280Smckusick 
39*63280Smckusick /*
40*63280Smckusick  *	Stand-alone file reading package.
41*63280Smckusick  */
42*63280Smckusick 
43*63280Smckusick #include <sys/param.h>
44*63280Smckusick #include <sys/time.h>
45*63280Smckusick #include <ufs/ffs/fs.h>
46*63280Smckusick #include <ufs/ufs/dinode.h>
47*63280Smckusick #include <ufs/ufs/dir.h>
48*63280Smckusick #include <stand/stand.h>
49*63280Smckusick 
50*63280Smckusick /*
51*63280Smckusick  * In-core open file.
52*63280Smckusick  */
53*63280Smckusick struct file {
54*63280Smckusick 	off_t		f_seekp;	/* seek pointer */
55*63280Smckusick 	struct fs	*f_fs;		/* pointer to super-block */
56*63280Smckusick 	struct dinode	f_di;		/* copy of on-disk inode */
57*63280Smckusick 	int		f_nindir[NIADDR];
58*63280Smckusick 					/* number of blocks mapped by
59*63280Smckusick 					   indirect block at level i */
60*63280Smckusick 	char		*f_blk[NIADDR];	/* buffer for indirect block at
61*63280Smckusick 					   level i */
62*63280Smckusick 	u_long		f_blksize[NIADDR];
63*63280Smckusick 					/* size of buffer */
64*63280Smckusick 	daddr_t		f_blkno[NIADDR];/* disk address of block in buffer */
65*63280Smckusick 	char		*f_buf;		/* buffer for data block */
66*63280Smckusick 	u_int		f_buf_size;	/* size of data block */
67*63280Smckusick 	daddr_t		f_buf_blkno;	/* block number of data block */
68*63280Smckusick };
69*63280Smckusick 
70*63280Smckusick /*
71*63280Smckusick  * Read a new inode into a file structure.
72*63280Smckusick  */
73*63280Smckusick static int
74*63280Smckusick read_inode(inumber, f)
75*63280Smckusick 	ino_t inumber;
76*63280Smckusick 	struct open_file *f;
77*63280Smckusick {
78*63280Smckusick 	register struct file *fp = (struct file *)f->f_fsdata;
79*63280Smckusick 	register struct fs *fs = fp->f_fs;
80*63280Smckusick 	char *buf;
81*63280Smckusick 	u_int rsize;
82*63280Smckusick 	int rc;
83*63280Smckusick 
84*63280Smckusick 	/*
85*63280Smckusick 	 * Read inode and save it.
86*63280Smckusick 	 */
87*63280Smckusick 	buf = alloc(fs->fs_bsize);
88*63280Smckusick 	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
89*63280Smckusick 		fsbtodb(fs, itod(fs, inumber)), fs->fs_bsize, buf, &rsize);
90*63280Smckusick 	if (rc)
91*63280Smckusick 		goto out;
92*63280Smckusick 	if (rsize != fs->fs_bsize) {
93*63280Smckusick 		rc = EIO;
94*63280Smckusick 		goto out;
95*63280Smckusick 	}
96*63280Smckusick 
97*63280Smckusick 	{
98*63280Smckusick 		register struct dinode *dp;
99*63280Smckusick 
100*63280Smckusick 		dp = (struct dinode *)buf;
101*63280Smckusick 		fp->f_di = dp[itoo(fs, inumber)];
102*63280Smckusick 	}
103*63280Smckusick 
104*63280Smckusick 	/*
105*63280Smckusick 	 * Clear out the old buffers
106*63280Smckusick 	 */
107*63280Smckusick 	{
108*63280Smckusick 		register int level;
109*63280Smckusick 
110*63280Smckusick 		for (level = 0; level < NIADDR; level++)
111*63280Smckusick 			fp->f_blkno[level] = -1;
112*63280Smckusick 		fp->f_buf_blkno = -1;
113*63280Smckusick 	}
114*63280Smckusick out:
115*63280Smckusick 	free(buf, fs->fs_bsize);
116*63280Smckusick 	return (0);
117*63280Smckusick }
118*63280Smckusick 
119*63280Smckusick /*
120*63280Smckusick  * Given an offset in a file, find the disk block number that
121*63280Smckusick  * contains that block.
122*63280Smckusick  */
123*63280Smckusick static int
124*63280Smckusick block_map(f, file_block, disk_block_p)
125*63280Smckusick 	struct open_file *f;
126*63280Smckusick 	daddr_t file_block;
127*63280Smckusick 	daddr_t *disk_block_p;	/* out */
128*63280Smckusick {
129*63280Smckusick 	register struct file *fp = (struct file *)f->f_fsdata;
130*63280Smckusick 	register struct fs *fs = fp->f_fs;
131*63280Smckusick 	int level;
132*63280Smckusick 	int idx;
133*63280Smckusick 	daddr_t ind_block_num;
134*63280Smckusick 	daddr_t *ind_p;
135*63280Smckusick 	int rc;
136*63280Smckusick 
137*63280Smckusick 	/*
138*63280Smckusick 	 * Index structure of an inode:
139*63280Smckusick 	 *
140*63280Smckusick 	 * di_db[0..NDADDR-1]	hold block numbers for blocks
141*63280Smckusick 	 *			0..NDADDR-1
142*63280Smckusick 	 *
143*63280Smckusick 	 * di_ib[0]		index block 0 is the single indirect block
144*63280Smckusick 	 *			holds block numbers for blocks
145*63280Smckusick 	 *			NDADDR .. NDADDR + NINDIR(fs)-1
146*63280Smckusick 	 *
147*63280Smckusick 	 * di_ib[1]		index block 1 is the double indirect block
148*63280Smckusick 	 *			holds block numbers for INDEX blocks for blocks
149*63280Smckusick 	 *			NDADDR + NINDIR(fs) ..
150*63280Smckusick 	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1
151*63280Smckusick 	 *
152*63280Smckusick 	 * di_ib[2]		index block 2 is the triple indirect block
153*63280Smckusick 	 *			holds block numbers for double-indirect
154*63280Smckusick 	 *			blocks for blocks
155*63280Smckusick 	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2 ..
156*63280Smckusick 	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2
157*63280Smckusick 	 *				+ NINDIR(fs)**3 - 1
158*63280Smckusick 	 */
159*63280Smckusick 
160*63280Smckusick 	if (file_block < NDADDR) {
161*63280Smckusick 		/* Direct block. */
162*63280Smckusick 		*disk_block_p = fp->f_di.di_db[file_block];
163*63280Smckusick 		return (0);
164*63280Smckusick 	}
165*63280Smckusick 
166*63280Smckusick 	file_block -= NDADDR;
167*63280Smckusick 
168*63280Smckusick 	/*
169*63280Smckusick 	 * nindir[0] = NINDIR
170*63280Smckusick 	 * nindir[1] = NINDIR**2
171*63280Smckusick 	 * nindir[2] = NINDIR**3
172*63280Smckusick 	 *	etc
173*63280Smckusick 	 */
174*63280Smckusick 	for (level = 0; level < NIADDR; level++) {
175*63280Smckusick 		if (file_block < fp->f_nindir[level])
176*63280Smckusick 			break;
177*63280Smckusick 		file_block -= fp->f_nindir[level];
178*63280Smckusick 	}
179*63280Smckusick 	if (level == NIADDR) {
180*63280Smckusick 		/* Block number too high */
181*63280Smckusick 		return (EFBIG);
182*63280Smckusick 	}
183*63280Smckusick 
184*63280Smckusick 	ind_block_num = fp->f_di.di_ib[level];
185*63280Smckusick 
186*63280Smckusick 	for (; level >= 0; level--) {
187*63280Smckusick 		if (ind_block_num == 0) {
188*63280Smckusick 			*disk_block_p = 0;	/* missing */
189*63280Smckusick 			return (0);
190*63280Smckusick 		}
191*63280Smckusick 
192*63280Smckusick 		if (fp->f_blkno[level] != ind_block_num) {
193*63280Smckusick 			if (fp->f_blk[level] == (char *)0)
194*63280Smckusick 				fp->f_blk[level] =
195*63280Smckusick 					alloc(fs->fs_bsize);
196*63280Smckusick 			rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
197*63280Smckusick 				fsbtodb(fp->f_fs, ind_block_num),
198*63280Smckusick 				fs->fs_bsize,
199*63280Smckusick 				fp->f_blk[level],
200*63280Smckusick 				&fp->f_blksize[level]);
201*63280Smckusick 			if (rc)
202*63280Smckusick 				return (rc);
203*63280Smckusick 			if (fp->f_blksize[level] != fs->fs_bsize)
204*63280Smckusick 				return (EIO);
205*63280Smckusick 			fp->f_blkno[level] = ind_block_num;
206*63280Smckusick 		}
207*63280Smckusick 
208*63280Smckusick 		ind_p = (daddr_t *)fp->f_blk[level];
209*63280Smckusick 
210*63280Smckusick 		if (level > 0) {
211*63280Smckusick 			idx = file_block / fp->f_nindir[level - 1];
212*63280Smckusick 			file_block %= fp->f_nindir[level - 1];
213*63280Smckusick 		} else
214*63280Smckusick 			idx = file_block;
215*63280Smckusick 
216*63280Smckusick 		ind_block_num = ind_p[idx];
217*63280Smckusick 	}
218*63280Smckusick 
219*63280Smckusick 	*disk_block_p = ind_block_num;
220*63280Smckusick 
221*63280Smckusick 	return (0);
222*63280Smckusick }
223*63280Smckusick 
224*63280Smckusick /*
225*63280Smckusick  * Read a portion of a file into an internal buffer.  Return
226*63280Smckusick  * the location in the buffer and the amount in the buffer.
227*63280Smckusick  */
228*63280Smckusick static int
229*63280Smckusick buf_read_file(f, buf_p, size_p)
230*63280Smckusick 	struct open_file *f;
231*63280Smckusick 	char **buf_p;		/* out */
232*63280Smckusick 	u_int *size_p;		/* out */
233*63280Smckusick {
234*63280Smckusick 	register struct file *fp = (struct file *)f->f_fsdata;
235*63280Smckusick 	register struct fs *fs = fp->f_fs;
236*63280Smckusick 	long off;
237*63280Smckusick 	register daddr_t file_block;
238*63280Smckusick 	daddr_t	disk_block;
239*63280Smckusick 	long block_size;
240*63280Smckusick 	int rc;
241*63280Smckusick 
242*63280Smckusick 	off = blkoff(fs, fp->f_seekp);
243*63280Smckusick 	file_block = lblkno(fs, fp->f_seekp);
244*63280Smckusick 	block_size = dblksize(fs, &fp->f_di, file_block);
245*63280Smckusick 
246*63280Smckusick 	if (file_block != fp->f_buf_blkno) {
247*63280Smckusick 		rc = block_map(f, file_block, &disk_block);
248*63280Smckusick 		if (rc)
249*63280Smckusick 			return (rc);
250*63280Smckusick 
251*63280Smckusick 		if (fp->f_buf == (char *)0)
252*63280Smckusick 			fp->f_buf = alloc(fs->fs_bsize);
253*63280Smckusick 
254*63280Smckusick 		if (disk_block == 0) {
255*63280Smckusick 			bzero(fp->f_buf, block_size);
256*63280Smckusick 			fp->f_buf_size = block_size;
257*63280Smckusick 		} else {
258*63280Smckusick 			rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
259*63280Smckusick 				fsbtodb(fs, disk_block),
260*63280Smckusick 				block_size, fp->f_buf, &fp->f_buf_size);
261*63280Smckusick 			if (rc)
262*63280Smckusick 				return (rc);
263*63280Smckusick 		}
264*63280Smckusick 
265*63280Smckusick 		fp->f_buf_blkno = file_block;
266*63280Smckusick 	}
267*63280Smckusick 
268*63280Smckusick 	/*
269*63280Smckusick 	 * Return address of byte in buffer corresponding to
270*63280Smckusick 	 * offset, and size of remainder of buffer after that
271*63280Smckusick 	 * byte.
272*63280Smckusick 	 */
273*63280Smckusick 	*buf_p = fp->f_buf + off;
274*63280Smckusick 	*size_p = block_size - off;
275*63280Smckusick 
276*63280Smckusick 	/*
277*63280Smckusick 	 * But truncate buffer at end of file.
278*63280Smckusick 	 */
279*63280Smckusick 	if (*size_p > fp->f_di.di_size - fp->f_seekp)
280*63280Smckusick 		*size_p = fp->f_di.di_size - fp->f_seekp;
281*63280Smckusick 
282*63280Smckusick 	return (0);
283*63280Smckusick }
284*63280Smckusick 
285*63280Smckusick /*
286*63280Smckusick  * Search a directory for a name and return its
287*63280Smckusick  * i_number.
288*63280Smckusick  */
289*63280Smckusick static int
290*63280Smckusick search_directory(name, f, inumber_p)
291*63280Smckusick 	char *name;
292*63280Smckusick 	struct open_file *f;
293*63280Smckusick 	ino_t *inumber_p;		/* out */
294*63280Smckusick {
295*63280Smckusick 	register struct file *fp = (struct file *)f->f_fsdata;
296*63280Smckusick 	register struct direct *dp;
297*63280Smckusick 	struct direct *edp;
298*63280Smckusick 	char *buf;
299*63280Smckusick 	u_int buf_size;
300*63280Smckusick 	int namlen, length;
301*63280Smckusick 	int rc;
302*63280Smckusick 
303*63280Smckusick 	length = strlen(name);
304*63280Smckusick 
305*63280Smckusick 	fp->f_seekp = 0;
306*63280Smckusick 	while (fp->f_seekp < fp->f_di.di_size) {
307*63280Smckusick 		rc = buf_read_file(f, &buf, &buf_size);
308*63280Smckusick 		if (rc)
309*63280Smckusick 			return (rc);
310*63280Smckusick 
311*63280Smckusick 		dp = (struct direct *)buf;
312*63280Smckusick 		edp = (struct direct *)(buf + buf_size);
313*63280Smckusick 		while (dp < edp) {
314*63280Smckusick 			if (dp->d_ino == (ino_t)0)
315*63280Smckusick 				goto next;
316*63280Smckusick #if BYTE_ORDER == LITTLE_ENDIAN
317*63280Smckusick 			if (fp->f_fs->fs_maxsymlinklen <= 0)
318*63280Smckusick 				namlen = dp->d_type;
319*63280Smckusick 			else
320*63280Smckusick #endif
321*63280Smckusick 				namlen = dp->d_namlen;
322*63280Smckusick 			if (namlen == length &&
323*63280Smckusick 			    !strcmp(name, dp->d_name)) {
324*63280Smckusick 				/* found entry */
325*63280Smckusick 				*inumber_p = dp->d_ino;
326*63280Smckusick 				return (0);
327*63280Smckusick 			}
328*63280Smckusick 		next:
329*63280Smckusick 			dp = (struct direct *)((char *)dp + dp->d_reclen);
330*63280Smckusick 		}
331*63280Smckusick 		fp->f_seekp += buf_size;
332*63280Smckusick 	}
333*63280Smckusick 	return (ENOENT);
334*63280Smckusick }
335*63280Smckusick 
336*63280Smckusick /*
337*63280Smckusick  * Open a file.
338*63280Smckusick  */
339*63280Smckusick int
340*63280Smckusick ufs_open(path, f)
341*63280Smckusick 	char *path;
342*63280Smckusick 	struct open_file *f;
343*63280Smckusick {
344*63280Smckusick 	register char *cp, *ncp;
345*63280Smckusick 	register int c;
346*63280Smckusick 	ino_t inumber, parent_inumber;
347*63280Smckusick 	int nlinks = 0;
348*63280Smckusick 	struct file *fp;
349*63280Smckusick 	struct fs *fs;
350*63280Smckusick 	int rc;
351*63280Smckusick 	u_int buf_size;
352*63280Smckusick #if 0
353*63280Smckusick 	char namebuf[MAXPATHLEN+1];
354*63280Smckusick #endif
355*63280Smckusick 
356*63280Smckusick 	/* allocate file system specific data structure */
357*63280Smckusick 	fp = alloc(sizeof(struct file));
358*63280Smckusick 	bzero(fp, sizeof(struct file));
359*63280Smckusick 	f->f_fsdata = (void *)fp;
360*63280Smckusick 
361*63280Smckusick 	/* allocate space and read super block */
362*63280Smckusick 	fs = alloc(SBSIZE);
363*63280Smckusick 	fp->f_fs = fs;
364*63280Smckusick 	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
365*63280Smckusick 		SBLOCK, SBSIZE, (char *)fs, &buf_size);
366*63280Smckusick 	if (rc)
367*63280Smckusick 		goto out;
368*63280Smckusick 
369*63280Smckusick 	if (buf_size != SBSIZE || fs->fs_magic != FS_MAGIC ||
370*63280Smckusick 	    fs->fs_bsize > MAXBSIZE || fs->fs_bsize < sizeof(struct fs)) {
371*63280Smckusick 		rc = EINVAL;
372*63280Smckusick 		goto out;
373*63280Smckusick 	}
374*63280Smckusick 
375*63280Smckusick 	/*
376*63280Smckusick 	 * Calculate indirect block levels.
377*63280Smckusick 	 */
378*63280Smckusick 	{
379*63280Smckusick 		register int mult;
380*63280Smckusick 		register int level;
381*63280Smckusick 
382*63280Smckusick 		mult = 1;
383*63280Smckusick 		for (level = 0; level < NIADDR; level++) {
384*63280Smckusick 			mult *= NINDIR(fs);
385*63280Smckusick 			fp->f_nindir[level] = mult;
386*63280Smckusick 		}
387*63280Smckusick 	}
388*63280Smckusick 
389*63280Smckusick 	inumber = ROOTINO;
390*63280Smckusick 	if ((rc = read_inode(inumber, f)) != 0)
391*63280Smckusick 		goto out;
392*63280Smckusick 
393*63280Smckusick 	cp = path;
394*63280Smckusick 	while (*cp) {
395*63280Smckusick 
396*63280Smckusick 		/*
397*63280Smckusick 		 * Remove extra separators
398*63280Smckusick 		 */
399*63280Smckusick 		while (*cp == '/')
400*63280Smckusick 			cp++;
401*63280Smckusick 		if (*cp == '\0')
402*63280Smckusick 			break;
403*63280Smckusick 
404*63280Smckusick 		/*
405*63280Smckusick 		 * Check that current node is a directory.
406*63280Smckusick 		 */
407*63280Smckusick 		if ((fp->f_di.di_mode & IFMT) != IFDIR) {
408*63280Smckusick 			rc = ENOTDIR;
409*63280Smckusick 			goto out;
410*63280Smckusick 		}
411*63280Smckusick 
412*63280Smckusick 		/*
413*63280Smckusick 		 * Get next component of path name.
414*63280Smckusick 		 */
415*63280Smckusick 		{
416*63280Smckusick 			register int len = 0;
417*63280Smckusick 
418*63280Smckusick 			ncp = cp;
419*63280Smckusick 			while ((c = *cp) != '\0' && c != '/') {
420*63280Smckusick 				if (++len > MAXNAMLEN) {
421*63280Smckusick 					rc = ENOENT;
422*63280Smckusick 					goto out;
423*63280Smckusick 				}
424*63280Smckusick 				cp++;
425*63280Smckusick 			}
426*63280Smckusick 			*cp = '\0';
427*63280Smckusick 		}
428*63280Smckusick 
429*63280Smckusick 		/*
430*63280Smckusick 		 * Look up component in current directory.
431*63280Smckusick 		 * Save directory inumber in case we find a
432*63280Smckusick 		 * symbolic link.
433*63280Smckusick 		 */
434*63280Smckusick 		parent_inumber = inumber;
435*63280Smckusick 		rc = search_directory(ncp, f, &inumber);
436*63280Smckusick 		*cp = c;
437*63280Smckusick 		if (rc)
438*63280Smckusick 			goto out;
439*63280Smckusick 
440*63280Smckusick 		/*
441*63280Smckusick 		 * Open next component.
442*63280Smckusick 		 */
443*63280Smckusick 		if ((rc = read_inode(inumber, f)) != 0)
444*63280Smckusick 			goto out;
445*63280Smckusick 
446*63280Smckusick #if 0
447*63280Smckusick 		/*
448*63280Smckusick 		 * Check for symbolic link.
449*63280Smckusick 		 */
450*63280Smckusick 		if ((fp->i_mode & IFMT) == IFLNK) {
451*63280Smckusick 			int link_len = fp->f_di.di_size;
452*63280Smckusick 			int len;
453*63280Smckusick 
454*63280Smckusick 			len = strlen(cp) + 1;
455*63280Smckusick 
456*63280Smckusick 			if (fp->f_di.di_size >= MAXPATHLEN - 1 ||
457*63280Smckusick 			    ++nlinks > MAXSYMLINKS) {
458*63280Smckusick 				rc = ENOENT;
459*63280Smckusick 				goto out;
460*63280Smckusick 			}
461*63280Smckusick 
462*63280Smckusick 			strcpy(&namebuf[link_len], cp);
463*63280Smckusick 
464*63280Smckusick 			if ((fp->i_flags & IC_FASTLINK) != 0) {
465*63280Smckusick 				bcopy(fp->i_symlink, namebuf, (unsigned) link_len);
466*63280Smckusick 			} else {
467*63280Smckusick 				/*
468*63280Smckusick 				 * Read file for symbolic link
469*63280Smckusick 				 */
470*63280Smckusick 				char *buf;
471*63280Smckusick 				u_int buf_size;
472*63280Smckusick 				daddr_t	disk_block;
473*63280Smckusick 				register struct fs *fs = fp->f_fs;
474*63280Smckusick 
475*63280Smckusick 				(void) block_map(f, (daddr_t)0, &disk_block);
476*63280Smckusick 				rc = device_read(&fp->f_dev,
477*63280Smckusick 						 fsbtodb(fs, disk_block),
478*63280Smckusick 						 blksize(fs, fp, 0),
479*63280Smckusick 						 &buf, &buf_size);
480*63280Smckusick 				if (rc)
481*63280Smckusick 					goto out;
482*63280Smckusick 
483*63280Smckusick 				bcopy((char *)buf, namebuf, (unsigned)link_len);
484*63280Smckusick 				free(buf, buf_size);
485*63280Smckusick 			}
486*63280Smckusick 
487*63280Smckusick 			/*
488*63280Smckusick 			 * If relative pathname, restart at parent directory.
489*63280Smckusick 			 * If absolute pathname, restart at root.
490*63280Smckusick 			 */
491*63280Smckusick 			cp = namebuf;
492*63280Smckusick 			if (*cp != '/')
493*63280Smckusick 				inumber = parent_inumber;
494*63280Smckusick 			else
495*63280Smckusick 				inumber = (ino_t)ROOTINO;
496*63280Smckusick 
497*63280Smckusick 			if ((rc = read_inode(inumber, fp)) != 0)
498*63280Smckusick 				goto out;
499*63280Smckusick 		}
500*63280Smckusick #endif
501*63280Smckusick 	}
502*63280Smckusick 
503*63280Smckusick 	/*
504*63280Smckusick 	 * Found terminal component.
505*63280Smckusick 	 */
506*63280Smckusick 	rc = 0;
507*63280Smckusick out:
508*63280Smckusick 	if (rc)
509*63280Smckusick 		free(fp, sizeof(struct file));
510*63280Smckusick 	return (rc);
511*63280Smckusick }
512*63280Smckusick 
513*63280Smckusick int
514*63280Smckusick ufs_close(f)
515*63280Smckusick 	struct open_file *f;
516*63280Smckusick {
517*63280Smckusick 	register struct file *fp = (struct file *)f->f_fsdata;
518*63280Smckusick 	int level;
519*63280Smckusick 
520*63280Smckusick 	f->f_fsdata = (void *)0;
521*63280Smckusick 	if (fp == (struct file *)0)
522*63280Smckusick 		return (0);
523*63280Smckusick 
524*63280Smckusick 	for (level = 0; level < NIADDR; level++) {
525*63280Smckusick 		if (fp->f_blk[level])
526*63280Smckusick 			free(fp->f_blk[level], fp->f_fs->fs_bsize);
527*63280Smckusick 	}
528*63280Smckusick 	if (fp->f_buf)
529*63280Smckusick 		free(fp->f_buf, fp->f_fs->fs_bsize);
530*63280Smckusick 	free(fp->f_fs, SBSIZE);
531*63280Smckusick 	free(fp, sizeof(struct file));
532*63280Smckusick 	return (0);
533*63280Smckusick }
534*63280Smckusick 
535*63280Smckusick /*
536*63280Smckusick  * Copy a portion of a file into kernel memory.
537*63280Smckusick  * Cross block boundaries when necessary.
538*63280Smckusick  */
539*63280Smckusick int
540*63280Smckusick ufs_read(f, start, size, resid)
541*63280Smckusick 	struct open_file *f;
542*63280Smckusick 	char *start;
543*63280Smckusick 	u_int size;
544*63280Smckusick 	u_int *resid;	/* out */
545*63280Smckusick {
546*63280Smckusick 	register struct file *fp = (struct file *)f->f_fsdata;
547*63280Smckusick 	register u_int csize;
548*63280Smckusick 	char *buf;
549*63280Smckusick 	u_int buf_size;
550*63280Smckusick 	int rc = 0;
551*63280Smckusick 
552*63280Smckusick 	while (size != 0) {
553*63280Smckusick 		if (fp->f_seekp >= fp->f_di.di_size)
554*63280Smckusick 			break;
555*63280Smckusick 
556*63280Smckusick 		rc = buf_read_file(f, &buf, &buf_size);
557*63280Smckusick 		if (rc)
558*63280Smckusick 			break;
559*63280Smckusick 
560*63280Smckusick 		csize = size;
561*63280Smckusick 		if (csize > buf_size)
562*63280Smckusick 			csize = buf_size;
563*63280Smckusick 
564*63280Smckusick 		bcopy(buf, start, csize);
565*63280Smckusick 
566*63280Smckusick 		fp->f_seekp += csize;
567*63280Smckusick 		start += csize;
568*63280Smckusick 		size -= csize;
569*63280Smckusick 	}
570*63280Smckusick 	if (resid)
571*63280Smckusick 		*resid = size;
572*63280Smckusick 	return (rc);
573*63280Smckusick }
574*63280Smckusick 
575*63280Smckusick /*
576*63280Smckusick  * Not implemented.
577*63280Smckusick  */
578*63280Smckusick int
579*63280Smckusick ufs_write(f, start, size, resid)
580*63280Smckusick 	struct open_file *f;
581*63280Smckusick 	char *start;
582*63280Smckusick 	u_int size;
583*63280Smckusick 	u_int *resid;	/* out */
584*63280Smckusick {
585*63280Smckusick 
586*63280Smckusick 	return (EROFS);
587*63280Smckusick }
588*63280Smckusick 
589*63280Smckusick off_t
590*63280Smckusick ufs_seek(f, offset, where)
591*63280Smckusick 	struct open_file *f;
592*63280Smckusick 	off_t offset;
593*63280Smckusick 	int where;
594*63280Smckusick {
595*63280Smckusick 	register struct file *fp = (struct file *)f->f_fsdata;
596*63280Smckusick 
597*63280Smckusick 	switch (where) {
598*63280Smckusick 	case SEEK_SET:
599*63280Smckusick 		fp->f_seekp = offset;
600*63280Smckusick 		break;
601*63280Smckusick 	case SEEK_CUR:
602*63280Smckusick 		fp->f_seekp += offset;
603*63280Smckusick 		break;
604*63280Smckusick 	case SEEK_END:
605*63280Smckusick 		fp->f_seekp = fp->f_di.di_size - offset;
606*63280Smckusick 		break;
607*63280Smckusick 	default:
608*63280Smckusick 		return (-1);
609*63280Smckusick 	}
610*63280Smckusick 	return (fp->f_seekp);
611*63280Smckusick }
612*63280Smckusick 
613*63280Smckusick int
614*63280Smckusick ufs_stat(f, sb)
615*63280Smckusick 	struct open_file *f;
616*63280Smckusick 	struct stat *sb;
617*63280Smckusick {
618*63280Smckusick 	register struct file *fp = (struct file *)f->f_fsdata;
619*63280Smckusick 
620*63280Smckusick 	/* only important stuff */
621*63280Smckusick 	sb->st_mode = fp->f_di.di_mode;
622*63280Smckusick 	sb->st_uid = fp->f_di.di_uid;
623*63280Smckusick 	sb->st_gid = fp->f_di.di_gid;
624*63280Smckusick 	sb->st_size = fp->f_di.di_size;
625*63280Smckusick 	return (0);
626*63280Smckusick }
627