xref: /freebsd/stand/libsa/ufs.c (revision 4d3fc8b0)
1 /*	$NetBSD: ufs.c,v 1.20 1998/03/01 07:15:39 ross Exp $	*/
2 
3 /*-
4  * Copyright (c) 2002 Networks Associates Technology, Inc.
5  * All rights reserved.
6  *
7  * This software was developed for the FreeBSD Project by Marshall
8  * Kirk McKusick and Network Associates Laboratories, the Security
9  * Research Division of Network Associates, Inc. under DARPA/SPAWAR
10  * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS
11  * research program
12  *
13  * Copyright (c) 1982, 1989, 1993
14  *	The Regents of the University of California.  All rights reserved.
15  *
16  * This code is derived from software contributed to Berkeley by
17  * The Mach Operating System project at Carnegie-Mellon University.
18  *
19  * Redistribution and use in source and binary forms, with or without
20  * modification, are permitted provided that the following conditions
21  * are met:
22  * 1. Redistributions of source code must retain the above copyright
23  *    notice, this list of conditions and the following disclaimer.
24  * 2. Redistributions in binary form must reproduce the above copyright
25  *    notice, this list of conditions and the following disclaimer in the
26  *    documentation and/or other materials provided with the distribution.
27  * 3. Neither the name of the University nor the names of its contributors
28  *    may be used to endorse or promote products derived from this software
29  *    without specific prior written permission.
30  *
31  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
32  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
33  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
35  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
39  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
40  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
41  * SUCH DAMAGE.
42  *
43  *
44  * Copyright (c) 1990, 1991 Carnegie Mellon University
45  * All Rights Reserved.
46  *
47  * Author: David Golub
48  *
49  * Permission to use, copy, modify and distribute this software and its
50  * documentation is hereby granted, provided that both the copyright
51  * notice and this permission notice appear in all copies of the
52  * software, derivative works or modified versions, and any portions
53  * thereof, and that both notices appear in supporting documentation.
54  *
55  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
56  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
57  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
58  *
59  * Carnegie Mellon requests users of this software to return to
60  *
61  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
62  *  School of Computer Science
63  *  Carnegie Mellon University
64  *  Pittsburgh PA 15213-3890
65  *
66  * any improvements or extensions that they make and grant Carnegie the
67  * rights to redistribute these changes.
68  */
69 
70 #include <sys/cdefs.h>
71 __FBSDID("$FreeBSD$");
72 
73 /*
74  *	Stand-alone file reading package.
75  */
76 
77 #include <sys/param.h>
78 #include <sys/disklabel.h>
79 #include <sys/time.h>
80 #include <ufs/ufs/dinode.h>
81 #include <ufs/ufs/dir.h>
82 #include <ufs/ffs/fs.h>
83 #include "stand.h"
84 #include "string.h"
85 
86 static int	ufs_open(const char *path, struct open_file *f);
87 static int	ufs_write(struct open_file *f, const void *buf, size_t size,
88 		size_t *resid);
89 static int	ufs_close(struct open_file *f);
90 static int	ufs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
91 static off_t	ufs_seek(struct open_file *f, off_t offset, int where);
92 static int	ufs_stat(struct open_file *f, struct stat *sb);
93 static int	ufs_readdir(struct open_file *f, struct dirent *d);
94 static int	ufs_mount(const char *dev, const char *path, void **data);
95 static int	ufs_unmount(const char *dev, void *data);
96 
97 struct fs_ops ufs_fsops = {
98 	.fs_name = "ufs",
99 	.fo_open = ufs_open,
100 	.fo_close = ufs_close,
101 	.fo_read = ufs_read,
102 	.fo_write = ufs_write,
103 	.fo_seek = ufs_seek,
104 	.fo_stat = ufs_stat,
105 	.fo_readdir = ufs_readdir,
106 	.fo_mount = ufs_mount,
107 	.fo_unmount = ufs_unmount
108 };
109 
110 /*
111  * In-core open file.
112  */
113 struct file {
114 	off_t		f_seekp;	/* seek pointer */
115 	struct fs	*f_fs;		/* pointer to super-block */
116 	union dinode {
117 		struct ufs1_dinode di1;
118 		struct ufs2_dinode di2;
119 	}		f_di;		/* copy of on-disk inode */
120 	int		f_nindir[UFS_NIADDR];
121 					/* number of blocks mapped by
122 					   indirect block at level i */
123 	char		*f_blk[UFS_NIADDR];	/* buffer for indirect block at
124 					   level i */
125 	size_t		f_blksize[UFS_NIADDR];
126 					/* size of buffer */
127 	ufs2_daddr_t	f_blkno[UFS_NIADDR];/* disk address of block in buffer */
128 	ufs2_daddr_t	f_buf_blkno;	/* block number of data block */
129 	char		*f_buf;		/* buffer for data block */
130 	size_t		f_buf_size;	/* size of data block */
131 	int		f_inumber;	/* inumber */
132 };
133 #define DIP(fp, field) \
134 	((fp)->f_fs->fs_magic == FS_UFS1_MAGIC ? \
135 	(fp)->f_di.di1.field : (fp)->f_di.di2.field)
136 
137 typedef struct ufs_mnt {
138 	char			*um_dev;
139 	int			um_fd;
140 	STAILQ_ENTRY(ufs_mnt)	um_link;
141 } ufs_mnt_t;
142 
143 typedef STAILQ_HEAD(ufs_mnt_list, ufs_mnt) ufs_mnt_list_t;
144 static ufs_mnt_list_t mnt_list = STAILQ_HEAD_INITIALIZER(mnt_list);
145 
146 static int	read_inode(ino_t, struct open_file *);
147 static int	block_map(struct open_file *, ufs2_daddr_t, ufs2_daddr_t *);
148 static int	buf_read_file(struct open_file *, char **, size_t *);
149 static int	buf_write_file(struct open_file *, const char *, size_t *);
150 static int	search_directory(char *, struct open_file *, ino_t *);
151 static int	ufs_use_sa_read(void *, off_t, void **, int);
152 
153 /* from ffs_subr.c */
154 int	ffs_sbget(void *devfd, struct fs **fsp, off_t sblock, int flags,
155 	    char *filltype,
156 	    int (*readfunc)(void *devfd, off_t loc, void **bufp, int size));
157 int	ffs_sbsearch(void *, struct fs **, int, char *,
158 	    int (*)(void *, off_t, void **, int));
159 
160 /*
161  * Read a new inode into a file structure.
162  */
163 static int
164 read_inode(ino_t inumber, struct open_file *f)
165 {
166 	struct file *fp = (struct file *)f->f_fsdata;
167 	struct fs *fs = fp->f_fs;
168 	char *buf;
169 	size_t rsize;
170 	int rc;
171 
172 	if (fs == NULL)
173 	    panic("fs == NULL");
174 
175 	/*
176 	 * Read inode and save it.
177 	 */
178 	buf = malloc(fs->fs_bsize);
179 	twiddle(1);
180 	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
181 		fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize,
182 		buf, &rsize);
183 	if (rc)
184 		goto out;
185 	if (rsize != fs->fs_bsize) {
186 		rc = EIO;
187 		goto out;
188 	}
189 
190 	if (fp->f_fs->fs_magic == FS_UFS1_MAGIC)
191 		fp->f_di.di1 = ((struct ufs1_dinode *)buf)
192 		    [ino_to_fsbo(fs, inumber)];
193 	else
194 		fp->f_di.di2 = ((struct ufs2_dinode *)buf)
195 		    [ino_to_fsbo(fs, inumber)];
196 
197 	/*
198 	 * Clear out the old buffers
199 	 */
200 	{
201 		int level;
202 
203 		for (level = 0; level < UFS_NIADDR; level++)
204 			fp->f_blkno[level] = -1;
205 		fp->f_buf_blkno = -1;
206 	}
207 	fp->f_seekp = 0;
208 	fp->f_inumber = inumber;
209 out:
210 	free(buf);
211 	return (rc);
212 }
213 
214 /*
215  * Given an offset in a file, find the disk block number that
216  * contains that block.
217  */
218 static int
219 block_map(struct open_file *f, ufs2_daddr_t file_block,
220     ufs2_daddr_t *disk_block_p)
221 {
222 	struct file *fp = (struct file *)f->f_fsdata;
223 	struct fs *fs = fp->f_fs;
224 	int level;
225 	int idx;
226 	ufs2_daddr_t ind_block_num;
227 	int rc;
228 
229 	/*
230 	 * Index structure of an inode:
231 	 *
232 	 * di_db[0..UFS_NDADDR-1] hold block numbers for blocks
233 	 *			0..UFS_NDADDR-1
234 	 *
235 	 * di_ib[0]		index block 0 is the single indirect block
236 	 *			holds block numbers for blocks
237 	 *			UFS_NDADDR .. UFS_NDADDR + NINDIR(fs)-1
238 	 *
239 	 * di_ib[1]		index block 1 is the double indirect block
240 	 *			holds block numbers for INDEX blocks for blocks
241 	 *			UFS_NDADDR + NINDIR(fs) ..
242 	 *			UFS_NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1
243 	 *
244 	 * di_ib[2]		index block 2 is the triple indirect block
245 	 *			holds block numbers for double-indirect
246 	 *			blocks for blocks
247 	 *			UFS_NDADDR + NINDIR(fs) + NINDIR(fs)**2 ..
248 	 *			UFS_NDADDR + NINDIR(fs) + NINDIR(fs)**2
249 	 *				+ NINDIR(fs)**3 - 1
250 	 */
251 
252 	if (file_block < UFS_NDADDR) {
253 		/* Direct block. */
254 		*disk_block_p = DIP(fp, di_db[file_block]);
255 		return (0);
256 	}
257 
258 	file_block -= UFS_NDADDR;
259 
260 	/*
261 	 * nindir[0] = NINDIR
262 	 * nindir[1] = NINDIR**2
263 	 * nindir[2] = NINDIR**3
264 	 *	etc
265 	 */
266 	for (level = 0; level < UFS_NIADDR; level++) {
267 		if (file_block < fp->f_nindir[level])
268 			break;
269 		file_block -= fp->f_nindir[level];
270 	}
271 	if (level == UFS_NIADDR) {
272 		/* Block number too high */
273 		return (EFBIG);
274 	}
275 
276 	ind_block_num = DIP(fp, di_ib[level]);
277 
278 	for (; level >= 0; level--) {
279 		if (ind_block_num == 0) {
280 			*disk_block_p = 0;	/* missing */
281 			return (0);
282 		}
283 
284 		if (fp->f_blkno[level] != ind_block_num) {
285 			if (fp->f_blk[level] == (char *)0)
286 				fp->f_blk[level] =
287 					malloc(fs->fs_bsize);
288 			twiddle(1);
289 			rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
290 				fsbtodb(fp->f_fs, ind_block_num),
291 				fs->fs_bsize,
292 				fp->f_blk[level],
293 				&fp->f_blksize[level]);
294 			if (rc)
295 				return (rc);
296 			if (fp->f_blksize[level] != fs->fs_bsize)
297 				return (EIO);
298 			fp->f_blkno[level] = ind_block_num;
299 		}
300 
301 		if (level > 0) {
302 			idx = file_block / fp->f_nindir[level - 1];
303 			file_block %= fp->f_nindir[level - 1];
304 		} else
305 			idx = file_block;
306 
307 		if (fp->f_fs->fs_magic == FS_UFS1_MAGIC)
308 			ind_block_num = ((ufs1_daddr_t *)fp->f_blk[level])[idx];
309 		else
310 			ind_block_num = ((ufs2_daddr_t *)fp->f_blk[level])[idx];
311 	}
312 
313 	*disk_block_p = ind_block_num;
314 
315 	return (0);
316 }
317 
318 /*
319  * Write a portion of a file from an internal buffer.
320  */
321 static int
322 buf_write_file(struct open_file *f, const char *buf_p, size_t *size_p)
323 {
324 	struct file *fp = (struct file *)f->f_fsdata;
325 	struct fs *fs = fp->f_fs;
326 	long off;
327 	ufs_lbn_t file_block;
328 	ufs2_daddr_t disk_block;
329 	size_t block_size;
330 	int rc;
331 
332 	/*
333 	 * Calculate the starting block address and offset.
334 	 */
335 	off = blkoff(fs, fp->f_seekp);
336 	file_block = lblkno(fs, fp->f_seekp);
337 	block_size = sblksize(fs, DIP(fp, di_size), file_block);
338 
339 	rc = block_map(f, file_block, &disk_block);
340 	if (rc)
341 		return (rc);
342 
343  	if (disk_block == 0)
344 		/* Because we can't allocate space on the drive */
345 		return (EFBIG);
346 
347 	/*
348 	 * Truncate buffer at end of file, and at the end of
349 	 * this block.
350 	 */
351 	if (*size_p > DIP(fp, di_size) - fp->f_seekp)
352 		*size_p = DIP(fp, di_size) - fp->f_seekp;
353 	if (*size_p > block_size - off)
354 		*size_p = block_size - off;
355 
356 	/*
357 	 * If we don't entirely occlude the block and it's not
358 	 * in memory already, read it in first.
359 	 */
360 	if (((off > 0) || (*size_p + off < block_size)) &&
361 	    (file_block != fp->f_buf_blkno)) {
362 
363 		if (fp->f_buf == (char *)0)
364 			fp->f_buf = malloc(fs->fs_bsize);
365 
366 		twiddle(4);
367 		rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
368 			fsbtodb(fs, disk_block),
369 			block_size, fp->f_buf, &fp->f_buf_size);
370 		if (rc)
371 			return (rc);
372 
373 		fp->f_buf_blkno = file_block;
374 	}
375 
376 	/*
377 	 *	Copy the user data into the cached block.
378 	 */
379 	bcopy(buf_p, fp->f_buf + off, *size_p);
380 
381 	/*
382 	 *	Write the block out to storage.
383 	 */
384 
385 	twiddle(4);
386 	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_WRITE,
387 		fsbtodb(fs, disk_block),
388 		block_size, fp->f_buf, &fp->f_buf_size);
389 	return (rc);
390 }
391 
392 /*
393  * Read a portion of a file into an internal buffer.  Return
394  * the location in the buffer and the amount in the buffer.
395  */
396 static int
397 buf_read_file(struct open_file *f, char **buf_p, size_t *size_p)
398 {
399 	struct file *fp = (struct file *)f->f_fsdata;
400 	struct fs *fs = fp->f_fs;
401 	long off;
402 	ufs_lbn_t file_block;
403 	ufs2_daddr_t disk_block;
404 	size_t block_size;
405 	int rc;
406 
407 	off = blkoff(fs, fp->f_seekp);
408 	file_block = lblkno(fs, fp->f_seekp);
409 	block_size = sblksize(fs, DIP(fp, di_size), file_block);
410 
411 	if (file_block != fp->f_buf_blkno) {
412 		if (fp->f_buf == NULL)
413 			fp->f_buf = malloc(fs->fs_bsize);
414 
415 		rc = block_map(f, file_block, &disk_block);
416 		if (rc)
417 			return (rc);
418 
419 		if (disk_block == 0) {
420 			bzero(fp->f_buf, block_size);
421 			fp->f_buf_size = block_size;
422 		} else {
423 			twiddle(4);
424 			rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
425 				fsbtodb(fs, disk_block),
426 				block_size, fp->f_buf, &fp->f_buf_size);
427 			if (rc)
428 				return (rc);
429 		}
430 
431 		fp->f_buf_blkno = file_block;
432 	}
433 
434 	/*
435 	 * Return address of byte in buffer corresponding to
436 	 * offset, and size of remainder of buffer after that
437 	 * byte.
438 	 */
439 	*buf_p = fp->f_buf + off;
440 	*size_p = block_size - off;
441 
442 	/*
443 	 * But truncate buffer at end of file.
444 	 */
445 	if (*size_p > DIP(fp, di_size) - fp->f_seekp)
446 		*size_p = DIP(fp, di_size) - fp->f_seekp;
447 
448 	return (0);
449 }
450 
451 /*
452  * Search a directory for a name and return its
453  * i_number.
454  */
455 static int
456 search_directory(char *name, struct open_file *f, ino_t *inumber_p)
457 {
458 	struct file *fp = (struct file *)f->f_fsdata;
459 	struct direct *dp;
460 	struct direct *edp;
461 	char *buf;
462 	size_t buf_size;
463 	int namlen, length;
464 	int rc;
465 
466 	length = strlen(name);
467 
468 	fp->f_seekp = 0;
469 	while (fp->f_seekp < DIP(fp, di_size)) {
470 		rc = buf_read_file(f, &buf, &buf_size);
471 		if (rc)
472 			return (rc);
473 
474 		dp = (struct direct *)buf;
475 		edp = (struct direct *)(buf + buf_size);
476 		while (dp < edp) {
477 			if (dp->d_ino == (ino_t)0)
478 				goto next;
479 #if BYTE_ORDER == LITTLE_ENDIAN
480 			if (fp->f_fs->fs_maxsymlinklen <= 0)
481 				namlen = dp->d_type;
482 			else
483 #endif
484 				namlen = dp->d_namlen;
485 			if (namlen == length &&
486 			    !strcmp(name, dp->d_name)) {
487 				/* found entry */
488 				*inumber_p = dp->d_ino;
489 				return (0);
490 			}
491 		next:
492 			dp = (struct direct *)((char *)dp + dp->d_reclen);
493 		}
494 		fp->f_seekp += buf_size;
495 	}
496 	return (ENOENT);
497 }
498 
499 /*
500  * Open a file.
501  */
502 static int
503 ufs_open(const char *upath, struct open_file *f)
504 {
505 	char *cp, *ncp;
506 	int c;
507 	ino_t inumber, parent_inumber;
508 	struct file *fp;
509 	struct fs *fs;
510 	int rc;
511 	int nlinks = 0;
512 	char namebuf[MAXPATHLEN+1];
513 	char *buf = NULL;
514 	char *path = NULL;
515 	const char *dev;
516 	ufs_mnt_t *mnt;
517 
518 	/* allocate file system specific data structure */
519 	errno = 0;
520 	fp = calloc(1, sizeof(struct file));
521 	if (fp == NULL)
522 		return (errno);
523 	f->f_fsdata = (void *)fp;
524 
525 	dev = devformat((struct devdesc *)f->f_devdata);
526 	/* Is this device mounted? */
527 	STAILQ_FOREACH(mnt, &mnt_list, um_link) {
528 		if (strcmp(dev, mnt->um_dev) == 0)
529 			break;
530 	}
531 
532 	if (mnt == NULL) {
533 		/* read super block */
534 		twiddle(1);
535 		if ((rc = ffs_sbget(f, &fs, UFS_STDSB, UFS_NOHASHFAIL, "stand",
536 		    ufs_use_sa_read)) != 0) {
537 			goto out;
538 		}
539 	} else {
540 		struct open_file *sbf;
541 		struct file *sfp;
542 
543 		/* get superblock from mounted file system */
544 		sbf = fd2open_file(mnt->um_fd);
545 		sfp = sbf->f_fsdata;
546 		fs = sfp->f_fs;
547 	}
548 	fp->f_fs = fs;
549 
550 	/*
551 	 * Calculate indirect block levels.
552 	 */
553 	{
554 		ufs2_daddr_t mult;
555 		int level;
556 
557 		mult = 1;
558 		for (level = 0; level < UFS_NIADDR; level++) {
559 			mult *= NINDIR(fs);
560 			fp->f_nindir[level] = mult;
561 		}
562 	}
563 
564 	inumber = UFS_ROOTINO;
565 	if ((rc = read_inode(inumber, f)) != 0)
566 		goto out;
567 
568 	cp = path = strdup(upath);
569 	if (path == NULL) {
570 	    rc = ENOMEM;
571 	    goto out;
572 	}
573 	while (*cp) {
574 
575 		/*
576 		 * Remove extra separators
577 		 */
578 		while (*cp == '/')
579 			cp++;
580 		if (*cp == '\0')
581 			break;
582 
583 		/*
584 		 * Check that current node is a directory.
585 		 */
586 		if ((DIP(fp, di_mode) & IFMT) != IFDIR) {
587 			rc = ENOTDIR;
588 			goto out;
589 		}
590 
591 		/*
592 		 * Get next component of path name.
593 		 */
594 		{
595 			int len = 0;
596 
597 			ncp = cp;
598 			while ((c = *cp) != '\0' && c != '/') {
599 				if (++len > UFS_MAXNAMLEN) {
600 					rc = ENOENT;
601 					goto out;
602 				}
603 				cp++;
604 			}
605 			*cp = '\0';
606 		}
607 
608 		/*
609 		 * Look up component in current directory.
610 		 * Save directory inumber in case we find a
611 		 * symbolic link.
612 		 */
613 		parent_inumber = inumber;
614 		rc = search_directory(ncp, f, &inumber);
615 		*cp = c;
616 		if (rc)
617 			goto out;
618 
619 		/*
620 		 * Open next component.
621 		 */
622 		if ((rc = read_inode(inumber, f)) != 0)
623 			goto out;
624 
625 		/*
626 		 * Check for symbolic link.
627 		 */
628 		if ((DIP(fp, di_mode) & IFMT) == IFLNK) {
629 			int link_len = DIP(fp, di_size);
630 			int len;
631 
632 			len = strlen(cp);
633 
634 			if (link_len + len > MAXPATHLEN ||
635 			    ++nlinks > MAXSYMLINKS) {
636 				rc = ENOENT;
637 				goto out;
638 			}
639 
640 			bcopy(cp, &namebuf[link_len], len + 1);
641 
642 			if (link_len < fs->fs_maxsymlinklen) {
643 				bcopy(DIP(fp, di_shortlink), namebuf,
644 				    (unsigned) link_len);
645 			} else {
646 				/*
647 				 * Read file for symbolic link
648 				 */
649 				size_t buf_size;
650 				ufs2_daddr_t disk_block;
651 				struct fs *fs = fp->f_fs;
652 
653 				if (!buf)
654 					buf = malloc(fs->fs_bsize);
655 				rc = block_map(f, (ufs2_daddr_t)0, &disk_block);
656 				if (rc)
657 					goto out;
658 
659 				twiddle(1);
660 				rc = (f->f_dev->dv_strategy)(f->f_devdata,
661 					F_READ, fsbtodb(fs, disk_block),
662 					fs->fs_bsize, buf, &buf_size);
663 				if (rc)
664 					goto out;
665 
666 				bcopy((char *)buf, namebuf, (unsigned)link_len);
667 			}
668 
669 			/*
670 			 * If relative pathname, restart at parent directory.
671 			 * If absolute pathname, restart at root.
672 			 */
673 			cp = namebuf;
674 			if (*cp != '/')
675 				inumber = parent_inumber;
676 			else
677 				inumber = (ino_t)UFS_ROOTINO;
678 
679 			if ((rc = read_inode(inumber, f)) != 0)
680 				goto out;
681 		}
682 	}
683 
684 	/*
685 	 * Found terminal component.
686 	 */
687 	rc = 0;
688 	fp->f_seekp = 0;
689 out:
690 	free(buf);
691 	free(path);
692 	if (rc) {
693 		free(fp->f_buf);
694 
695 		if (mnt == NULL && fp->f_fs != NULL) {
696 			free(fp->f_fs->fs_csp);
697 			free(fp->f_fs->fs_si);
698 			free(fp->f_fs);
699 		}
700 		free(fp);
701 	}
702 	return (rc);
703 }
704 
705 /*
706  * A read function for use by standalone-layer routines.
707  */
708 static int
709 ufs_use_sa_read(void *devfd, off_t loc, void **bufp, int size)
710 {
711 	struct open_file *f;
712 	size_t buf_size;
713 	int error;
714 
715 	f = (struct open_file *)devfd;
716 	if ((*bufp = malloc(size)) == NULL)
717 		return (ENOSPC);
718 	error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, loc / DEV_BSIZE,
719 	    size, *bufp, &buf_size);
720 	if (error != 0)
721 		return (error);
722 	if (buf_size != size)
723 		return (EIO);
724 	return (0);
725 }
726 
727 static int
728 ufs_close(struct open_file *f)
729 {
730 	ufs_mnt_t *mnt;
731 	struct file *fp = (struct file *)f->f_fsdata;
732 	int level;
733 	char *dev;
734 
735 	f->f_fsdata = NULL;
736 	if (fp == NULL)
737 		return (0);
738 
739 	for (level = 0; level < UFS_NIADDR; level++) {
740 		free(fp->f_blk[level]);
741 	}
742 	free(fp->f_buf);
743 
744 	dev = devformat((struct devdesc *)f->f_devdata);
745 	STAILQ_FOREACH(mnt, &mnt_list, um_link) {
746 		if (strcmp(dev, mnt->um_dev) == 0)
747 			break;
748 	}
749 
750 	if (mnt == NULL && fp->f_fs != NULL) {
751 		free(fp->f_fs->fs_csp);
752 		free(fp->f_fs->fs_si);
753 		free(fp->f_fs);
754 	}
755 
756 	free(fp);
757 	return (0);
758 }
759 
760 /*
761  * Copy a portion of a file into kernel memory.
762  * Cross block boundaries when necessary.
763  */
764 static int
765 ufs_read(struct open_file *f, void *start, size_t size, size_t *resid)
766 {
767 	struct file *fp = (struct file *)f->f_fsdata;
768 	size_t csize;
769 	char *buf;
770 	size_t buf_size;
771 	int rc = 0;
772 	char *addr = start;
773 
774 	while (size != 0) {
775 		if (fp->f_seekp >= DIP(fp, di_size))
776 			break;
777 
778 		rc = buf_read_file(f, &buf, &buf_size);
779 		if (rc)
780 			break;
781 
782 		csize = size;
783 		if (csize > buf_size)
784 			csize = buf_size;
785 
786 		bcopy(buf, addr, csize);
787 
788 		fp->f_seekp += csize;
789 		addr += csize;
790 		size -= csize;
791 	}
792 	if (resid)
793 		*resid = size;
794 	return (rc);
795 }
796 
797 /*
798  * Write to a portion of an already allocated file.
799  * Cross block boundaries when necessary. Can not
800  * extend the file.
801  */
802 static int
803 ufs_write(struct open_file *f, const void *start, size_t size, size_t *resid)
804 {
805 	struct file *fp = (struct file *)f->f_fsdata;
806 	size_t csize;
807 	int rc = 0;
808 	const char *addr = start;
809 
810 	csize = size;
811 	while ((size != 0) && (csize != 0)) {
812 		if (fp->f_seekp >= DIP(fp, di_size))
813 			break;
814 
815 		if (csize >= 512) csize = 512; /* XXX */
816 
817 		rc = buf_write_file(f, addr, &csize);
818 		if (rc)
819 			break;
820 
821 		fp->f_seekp += csize;
822 		addr += csize;
823 		size -= csize;
824 	}
825 	if (resid)
826 		*resid = size;
827 	return (rc);
828 }
829 
830 static off_t
831 ufs_seek(struct open_file *f, off_t offset, int where)
832 {
833 	struct file *fp = (struct file *)f->f_fsdata;
834 
835 	switch (where) {
836 	case SEEK_SET:
837 		fp->f_seekp = offset;
838 		break;
839 	case SEEK_CUR:
840 		fp->f_seekp += offset;
841 		break;
842 	case SEEK_END:
843 		fp->f_seekp = DIP(fp, di_size) - offset;
844 		break;
845 	default:
846 		errno = EINVAL;
847 		return (-1);
848 	}
849 	return (fp->f_seekp);
850 }
851 
852 static int
853 ufs_stat(struct open_file *f, struct stat *sb)
854 {
855 	struct file *fp = (struct file *)f->f_fsdata;
856 
857 	/* only important stuff */
858 	sb->st_mode = DIP(fp, di_mode);
859 	sb->st_uid = DIP(fp, di_uid);
860 	sb->st_gid = DIP(fp, di_gid);
861 	sb->st_size = DIP(fp, di_size);
862 	sb->st_mtime = DIP(fp, di_mtime);
863 	/*
864 	 * The items below are ufs specific!
865 	 * Other fs types will need their own solution
866 	 * if these fields are needed.
867 	 */
868 	sb->st_ino = fp->f_inumber;
869 	/*
870 	 * We need something to differentiate devs.
871 	 * fs_id is unique but 64bit, we xor the two
872 	 * halves to squeeze it into 32bits.
873 	 */
874 	sb->st_dev = (dev_t)(fp->f_fs->fs_id[0] ^ fp->f_fs->fs_id[1]);
875 
876 	return (0);
877 }
878 
879 static int
880 ufs_readdir(struct open_file *f, struct dirent *d)
881 {
882 	struct file *fp = (struct file *)f->f_fsdata;
883 	struct direct *dp;
884 	char *buf;
885 	size_t buf_size;
886 	int error;
887 
888 	/*
889 	 * assume that a directory entry will not be split across blocks
890 	 */
891 
892 	do {
893 		if (fp->f_seekp >= DIP(fp, di_size))
894 			return (ENOENT);
895 		error = buf_read_file(f, &buf, &buf_size);
896 		if (error)
897 			return (error);
898 		dp = (struct direct *)buf;
899 		fp->f_seekp += dp->d_reclen;
900 	} while (dp->d_ino == (ino_t)0);
901 
902 	d->d_type = dp->d_type;
903 	strcpy(d->d_name, dp->d_name);
904 	return (0);
905 }
906 
907 static int
908 ufs_mount(const char *dev, const char *path, void **data)
909 {
910 	char *fs;
911 	ufs_mnt_t *mnt;
912 	struct open_file *f;
913 
914 	errno = 0;
915 	mnt = calloc(1, sizeof(*mnt));
916 	if (mnt == NULL)
917 		return (errno);
918 	mnt->um_fd = -1;
919 	mnt->um_dev = strdup(dev);
920 	if (mnt->um_dev == NULL)
921 		goto done;
922 
923 	if (asprintf(&fs, "%s%s", dev, path) < 0)
924 		goto done;
925 
926 	mnt->um_fd = open(fs, O_RDONLY);
927 	free(fs);
928 	if (mnt->um_fd == -1)
929 		goto done;
930 
931 	/* Is it ufs file system? */
932 	f = fd2open_file(mnt->um_fd);
933 	if (strcmp(f->f_ops->fs_name, "ufs") == 0)
934 		STAILQ_INSERT_TAIL(&mnt_list, mnt, um_link);
935 	else
936 		errno = ENXIO;
937 
938 done:
939 	if (errno != 0) {
940 		free(mnt->um_dev);
941 		if (mnt->um_fd >= 0)
942 			close(mnt->um_fd);
943 		free(mnt);
944 	} else {
945 		*data = mnt;
946 	}
947 
948 	return (errno);
949 }
950 
951 static int
952 ufs_unmount(const char *dev __unused, void *data)
953 {
954 	ufs_mnt_t *mnt = data;
955 
956 	STAILQ_REMOVE(&mnt_list, mnt, ufs_mnt, um_link);
957 	free(mnt->um_dev);
958 	close(mnt->um_fd);
959 	free(mnt);
960 	return (0);
961 }
962