ufs.c revision 92913
1275970Scy/*	$NetBSD: ufs.c,v 1.20 1998/03/01 07:15:39 ross Exp $	*/
2275970Scy
3275970Scy/*-
4275970Scy * Copyright (c) 1993
5275970Scy *	The Regents of the University of California.  All rights reserved.
6275970Scy *
7275970Scy * This code is derived from software contributed to Berkeley by
8275970Scy * The Mach Operating System project at Carnegie-Mellon University.
9275970Scy *
10275970Scy * Redistribution and use in source and binary forms, with or without
11275970Scy * modification, are permitted provided that the following conditions
12275970Scy * are met:
13275970Scy * 1. Redistributions of source code must retain the above copyright
14275970Scy *    notice, this list of conditions and the following disclaimer.
15275970Scy * 2. Redistributions in binary form must reproduce the above copyright
16275970Scy *    notice, this list of conditions and the following disclaimer in the
17275970Scy *    documentation and/or other materials provided with the distribution.
18275970Scy * 3. All advertising materials mentioning features or use of this software
19275970Scy *    must display the following acknowledgement:
20275970Scy *	This product includes software developed by the University of
21275970Scy *	California, Berkeley and its contributors.
22275970Scy * 4. Neither the name of the University nor the names of its contributors
23275970Scy *    may be used to endorse or promote products derived from this software
24275970Scy *    without specific prior written permission.
25275970Scy *
26275970Scy * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27275970Scy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28275970Scy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29275970Scy * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30275970Scy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31275970Scy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32275970Scy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33275970Scy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34275970Scy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35275970Scy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36275970Scy * SUCH DAMAGE.
37275970Scy *
38275970Scy *
39275970Scy * Copyright (c) 1990, 1991 Carnegie Mellon University
40275970Scy * All Rights Reserved.
41275970Scy *
42275970Scy * Author: David Golub
43275970Scy *
44275970Scy * Permission to use, copy, modify and distribute this software and its
45275970Scy * documentation is hereby granted, provided that both the copyright
46275970Scy * notice and this permission notice appear in all copies of the
47275970Scy * software, derivative works or modified versions, and any portions
48275970Scy * thereof, and that both notices appear in supporting documentation.
49275970Scy *
50275970Scy * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
51275970Scy * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
52275970Scy * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
53275970Scy *
54275970Scy * Carnegie Mellon requests users of this software to return to
55275970Scy *
56275970Scy *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
57275970Scy *  School of Computer Science
58275970Scy *  Carnegie Mellon University
59275970Scy *  Pittsburgh PA 15213-3890
60275970Scy *
61275970Scy * any improvements or extensions that they make and grant Carnegie the
62275970Scy * rights to redistribute these changes.
63275970Scy */
64275970Scy
65275970Scy#include <sys/cdefs.h>
66275970Scy__FBSDID("$FreeBSD: head/lib/libstand/ufs.c 92913 2002-03-21 23:39:28Z obrien $");
67275970Scy
68275970Scy/*
69275970Scy *	Stand-alone file reading package.
70275970Scy */
71275970Scy
72275970Scy#include <sys/param.h>
73275970Scy#include <sys/time.h>
74275970Scy#include <ufs/ufs/dinode.h>
75275970Scy#include <ufs/ufs/dir.h>
76275970Scy#include <ufs/ffs/fs.h>
77275970Scy#include "stand.h"
78275970Scy#include "string.h"
79275970Scy
80275970Scy#ifdef __alpha__
81275970Scy#define COMPAT_UFS		/* DUX has old format file systems */
82275970Scy#endif
83275970Scy
84275970Scystatic int	ufs_open(const char *path, struct open_file *f);
85275970Scystatic int	ufs_write(struct open_file *f, void *buf, size_t size, size_t *resid);
86275970Scystatic int	ufs_close(struct open_file *f);
87275970Scystatic int	ufs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
88275970Scystatic off_t	ufs_seek(struct open_file *f, off_t offset, int where);
89275970Scystatic int	ufs_stat(struct open_file *f, struct stat *sb);
90275970Scystatic int	ufs_readdir(struct open_file *f, struct dirent *d);
91275970Scy
92275970Scystruct fs_ops ufs_fsops = {
93275970Scy	"ufs",
94275970Scy	ufs_open,
95275970Scy	ufs_close,
96275970Scy	ufs_read,
97275970Scy	ufs_write,
98275970Scy	ufs_seek,
99275970Scy	ufs_stat,
100275970Scy	ufs_readdir
101275970Scy};
102275970Scy
103275970Scy/*
104275970Scy * In-core open file.
105275970Scy */
106struct file {
107	off_t		f_seekp;	/* seek pointer */
108	struct fs	*f_fs;		/* pointer to super-block */
109	struct dinode	f_di;		/* copy of on-disk inode */
110	int		f_nindir[NIADDR];
111					/* number of blocks mapped by
112					   indirect block at level i */
113	char		*f_blk[NIADDR];	/* buffer for indirect block at
114					   level i */
115	size_t		f_blksize[NIADDR];
116					/* size of buffer */
117	daddr_t		f_blkno[NIADDR];/* disk address of block in buffer */
118	char		*f_buf;		/* buffer for data block */
119	size_t		f_buf_size;	/* size of data block */
120	daddr_t		f_buf_blkno;	/* block number of data block */
121};
122
123static int	read_inode(ino_t, struct open_file *);
124static int	block_map(struct open_file *, daddr_t, daddr_t *);
125static int	buf_read_file(struct open_file *, char **, size_t *);
126static int	buf_write_file(struct open_file *, char *, size_t *);
127static int	search_directory(char *, struct open_file *, ino_t *);
128#ifdef COMPAT_UFS
129static void	ffs_oldfscompat(struct fs *);
130#endif
131
132/*
133 * Read a new inode into a file structure.
134 */
135static int
136read_inode(inumber, f)
137	ino_t inumber;
138	struct open_file *f;
139{
140	struct file *fp = (struct file *)f->f_fsdata;
141	struct fs *fs = fp->f_fs;
142	char *buf;
143	size_t rsize;
144	int rc;
145
146	if (fs == NULL)
147	    panic("fs == NULL");
148
149	/*
150	 * Read inode and save it.
151	 */
152	buf = malloc(fs->fs_bsize);
153	twiddle();
154	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
155		fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize,
156		buf, &rsize);
157	if (rc)
158		goto out;
159	if (rsize != fs->fs_bsize) {
160		rc = EIO;
161		goto out;
162	}
163
164	{
165		struct dinode *dp;
166
167		dp = (struct dinode *)buf;
168		fp->f_di = dp[ino_to_fsbo(fs, inumber)];
169	}
170
171	/*
172	 * Clear out the old buffers
173	 */
174	{
175		int level;
176
177		for (level = 0; level < NIADDR; level++)
178			fp->f_blkno[level] = -1;
179		fp->f_buf_blkno = -1;
180	}
181out:
182	free(buf);
183	return (rc);
184}
185
186/*
187 * Given an offset in a file, find the disk block number that
188 * contains that block.
189 */
190static int
191block_map(f, file_block, disk_block_p)
192	struct open_file *f;
193	daddr_t file_block;
194	daddr_t *disk_block_p;	/* out */
195{
196	struct file *fp = (struct file *)f->f_fsdata;
197	struct fs *fs = fp->f_fs;
198	int level;
199	int idx;
200	daddr_t ind_block_num;
201	daddr_t *ind_p;
202	int rc;
203
204	/*
205	 * Index structure of an inode:
206	 *
207	 * di_db[0..NDADDR-1]	hold block numbers for blocks
208	 *			0..NDADDR-1
209	 *
210	 * di_ib[0]		index block 0 is the single indirect block
211	 *			holds block numbers for blocks
212	 *			NDADDR .. NDADDR + NINDIR(fs)-1
213	 *
214	 * di_ib[1]		index block 1 is the double indirect block
215	 *			holds block numbers for INDEX blocks for blocks
216	 *			NDADDR + NINDIR(fs) ..
217	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1
218	 *
219	 * di_ib[2]		index block 2 is the triple indirect block
220	 *			holds block numbers for double-indirect
221	 *			blocks for blocks
222	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2 ..
223	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2
224	 *				+ NINDIR(fs)**3 - 1
225	 */
226
227	if (file_block < NDADDR) {
228		/* Direct block. */
229		*disk_block_p = fp->f_di.di_db[file_block];
230		return (0);
231	}
232
233	file_block -= NDADDR;
234
235	/*
236	 * nindir[0] = NINDIR
237	 * nindir[1] = NINDIR**2
238	 * nindir[2] = NINDIR**3
239	 *	etc
240	 */
241	for (level = 0; level < NIADDR; level++) {
242		if (file_block < fp->f_nindir[level])
243			break;
244		file_block -= fp->f_nindir[level];
245	}
246	if (level == NIADDR) {
247		/* Block number too high */
248		return (EFBIG);
249	}
250
251	ind_block_num = fp->f_di.di_ib[level];
252
253	for (; level >= 0; level--) {
254		if (ind_block_num == 0) {
255			*disk_block_p = 0;	/* missing */
256			return (0);
257		}
258
259		if (fp->f_blkno[level] != ind_block_num) {
260			if (fp->f_blk[level] == (char *)0)
261				fp->f_blk[level] =
262					malloc(fs->fs_bsize);
263			twiddle();
264			rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
265				fsbtodb(fp->f_fs, ind_block_num),
266				fs->fs_bsize,
267				fp->f_blk[level],
268				&fp->f_blksize[level]);
269			if (rc)
270				return (rc);
271			if (fp->f_blksize[level] != fs->fs_bsize)
272				return (EIO);
273			fp->f_blkno[level] = ind_block_num;
274		}
275
276		ind_p = (daddr_t *)fp->f_blk[level];
277
278		if (level > 0) {
279			idx = file_block / fp->f_nindir[level - 1];
280			file_block %= fp->f_nindir[level - 1];
281		} else
282			idx = file_block;
283
284		ind_block_num = ind_p[idx];
285	}
286
287	*disk_block_p = ind_block_num;
288
289	return (0);
290}
291
292/*
293 * Write a portion of a file from an internal buffer.
294 */
295static int
296buf_write_file(f, buf_p, size_p)
297	struct open_file *f;
298	char *buf_p;
299	size_t *size_p;		/* out */
300{
301	struct file *fp = (struct file *)f->f_fsdata;
302	struct fs *fs = fp->f_fs;
303	long off;
304	daddr_t file_block;
305	daddr_t	disk_block;
306	size_t block_size;
307	int rc;
308
309	/*
310	 * Calculate the starting block address and offset.
311	 */
312	off = blkoff(fs, fp->f_seekp);
313	file_block = lblkno(fs, fp->f_seekp);
314	block_size = dblksize(fs, &fp->f_di, file_block);
315
316	rc = block_map(f, file_block, &disk_block);
317	if (rc)
318		return (rc);
319
320 	if (disk_block == 0)
321		return (EFBIG); /* Because we can't allocate space on the drive */
322
323	/*
324	 * Truncate buffer at end of file, and at the end of
325	 * this block.
326	 */
327	if (*size_p > fp->f_di.di_size - fp->f_seekp)
328		*size_p = fp->f_di.di_size - fp->f_seekp;
329	if (*size_p > block_size - off)
330		*size_p = block_size - off;
331
332	/*
333	 * If we don't entirely occlude the block and it's not
334	 * in memory already, read it in first.
335	 */
336	if (((off > 0) || (*size_p + off < block_size)) &&
337	    (file_block != fp->f_buf_blkno)) {
338
339		if (fp->f_buf == (char *)0)
340			fp->f_buf = malloc(fs->fs_bsize);
341
342		twiddle();
343		rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
344			fsbtodb(fs, disk_block),
345			block_size, fp->f_buf, &fp->f_buf_size);
346		if (rc)
347			return (rc);
348
349		fp->f_buf_blkno = file_block;
350	}
351
352	/*
353	 *	Copy the user data into the cached block.
354	 */
355	bcopy(buf_p,fp->f_buf + off,*size_p);
356
357	/*
358	 *	Write the block out to storage.
359	 */
360
361	twiddle();
362	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_WRITE,
363		fsbtodb(fs, disk_block),
364		block_size, fp->f_buf, &fp->f_buf_size);
365	return (rc);
366}
367
368/*
369 * Read a portion of a file into an internal buffer.  Return
370 * the location in the buffer and the amount in the buffer.
371 */
372static int
373buf_read_file(f, buf_p, size_p)
374	struct open_file *f;
375	char **buf_p;		/* out */
376	size_t *size_p;		/* out */
377{
378	struct file *fp = (struct file *)f->f_fsdata;
379	struct fs *fs = fp->f_fs;
380	long off;
381	daddr_t file_block;
382	daddr_t	disk_block;
383	size_t block_size;
384	int rc;
385
386	off = blkoff(fs, fp->f_seekp);
387	file_block = lblkno(fs, fp->f_seekp);
388	block_size = dblksize(fs, &fp->f_di, file_block);
389
390	if (file_block != fp->f_buf_blkno) {
391		if (fp->f_buf == (char *)0)
392			fp->f_buf = malloc(fs->fs_bsize);
393
394		rc = block_map(f, file_block, &disk_block);
395		if (rc)
396			return (rc);
397
398		if (disk_block == 0) {
399			bzero(fp->f_buf, block_size);
400			fp->f_buf_size = block_size;
401		} else {
402			twiddle();
403			rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
404				fsbtodb(fs, disk_block),
405				block_size, fp->f_buf, &fp->f_buf_size);
406			if (rc)
407				return (rc);
408		}
409
410		fp->f_buf_blkno = file_block;
411	}
412
413	/*
414	 * Return address of byte in buffer corresponding to
415	 * offset, and size of remainder of buffer after that
416	 * byte.
417	 */
418	*buf_p = fp->f_buf + off;
419	*size_p = block_size - off;
420
421	/*
422	 * But truncate buffer at end of file.
423	 */
424	if (*size_p > fp->f_di.di_size - fp->f_seekp)
425		*size_p = fp->f_di.di_size - fp->f_seekp;
426
427	return (0);
428}
429
430/*
431 * Search a directory for a name and return its
432 * i_number.
433 */
434static int
435search_directory(name, f, inumber_p)
436	char *name;
437	struct open_file *f;
438	ino_t *inumber_p;		/* out */
439{
440	struct file *fp = (struct file *)f->f_fsdata;
441	struct direct *dp;
442	struct direct *edp;
443	char *buf;
444	size_t buf_size;
445	int namlen, length;
446	int rc;
447
448	length = strlen(name);
449
450	fp->f_seekp = 0;
451	while (fp->f_seekp < fp->f_di.di_size) {
452		rc = buf_read_file(f, &buf, &buf_size);
453		if (rc)
454			return (rc);
455
456		dp = (struct direct *)buf;
457		edp = (struct direct *)(buf + buf_size);
458		while (dp < edp) {
459			if (dp->d_ino == (ino_t)0)
460				goto next;
461#if BYTE_ORDER == LITTLE_ENDIAN
462			if (fp->f_fs->fs_maxsymlinklen <= 0)
463				namlen = dp->d_type;
464			else
465#endif
466				namlen = dp->d_namlen;
467			if (namlen == length &&
468			    !strcmp(name, dp->d_name)) {
469				/* found entry */
470				*inumber_p = dp->d_ino;
471				return (0);
472			}
473		next:
474			dp = (struct direct *)((char *)dp + dp->d_reclen);
475		}
476		fp->f_seekp += buf_size;
477	}
478	return (ENOENT);
479}
480
481/*
482 * Open a file.
483 */
484static int
485ufs_open(upath, f)
486	const char *upath;
487	struct open_file *f;
488{
489	char *cp, *ncp;
490	int c;
491	ino_t inumber, parent_inumber;
492	struct file *fp;
493	struct fs *fs;
494	int rc;
495	size_t buf_size;
496	int nlinks = 0;
497	char namebuf[MAXPATHLEN+1];
498	char *buf = NULL;
499	char *path = NULL;
500
501	/* allocate file system specific data structure */
502	fp = malloc(sizeof(struct file));
503	bzero(fp, sizeof(struct file));
504	f->f_fsdata = (void *)fp;
505
506	/* allocate space and read super block */
507	fs = malloc(SBSIZE);
508	fp->f_fs = fs;
509	twiddle();
510	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
511		SBLOCK, SBSIZE, (char *)fs, &buf_size);
512	if (rc)
513		goto out;
514
515	if (buf_size != SBSIZE || fs->fs_magic != FS_MAGIC ||
516	    fs->fs_bsize > MAXBSIZE || fs->fs_bsize < sizeof(struct fs)) {
517		rc = EINVAL;
518		goto out;
519	}
520#ifdef COMPAT_UFS
521	ffs_oldfscompat(fs);
522#endif
523
524	/*
525	 * Calculate indirect block levels.
526	 */
527	{
528		int mult;
529		int level;
530
531		mult = 1;
532		for (level = 0; level < NIADDR; level++) {
533			mult *= NINDIR(fs);
534			fp->f_nindir[level] = mult;
535		}
536	}
537
538	inumber = ROOTINO;
539	if ((rc = read_inode(inumber, f)) != 0)
540		goto out;
541
542	cp = path = strdup(upath);
543	if (path == NULL) {
544	    rc = ENOMEM;
545	    goto out;
546	}
547	while (*cp) {
548
549		/*
550		 * Remove extra separators
551		 */
552		while (*cp == '/')
553			cp++;
554		if (*cp == '\0')
555			break;
556
557		/*
558		 * Check that current node is a directory.
559		 */
560		if ((fp->f_di.di_mode & IFMT) != IFDIR) {
561			rc = ENOTDIR;
562			goto out;
563		}
564
565		/*
566		 * Get next component of path name.
567		 */
568		{
569			int len = 0;
570
571			ncp = cp;
572			while ((c = *cp) != '\0' && c != '/') {
573				if (++len > MAXNAMLEN) {
574					rc = ENOENT;
575					goto out;
576				}
577				cp++;
578			}
579			*cp = '\0';
580		}
581
582		/*
583		 * Look up component in current directory.
584		 * Save directory inumber in case we find a
585		 * symbolic link.
586		 */
587		parent_inumber = inumber;
588		rc = search_directory(ncp, f, &inumber);
589		*cp = c;
590		if (rc)
591			goto out;
592
593		/*
594		 * Open next component.
595		 */
596		if ((rc = read_inode(inumber, f)) != 0)
597			goto out;
598
599		/*
600		 * Check for symbolic link.
601		 */
602		if ((fp->f_di.di_mode & IFMT) == IFLNK) {
603			int link_len = fp->f_di.di_size;
604			int len;
605
606			len = strlen(cp);
607
608			if (link_len + len > MAXPATHLEN ||
609			    ++nlinks > MAXSYMLINKS) {
610				rc = ENOENT;
611				goto out;
612			}
613
614			bcopy(cp, &namebuf[link_len], len + 1);
615
616			if (link_len < fs->fs_maxsymlinklen) {
617				bcopy(fp->f_di.di_shortlink, namebuf,
618				      (unsigned) link_len);
619			} else {
620				/*
621				 * Read file for symbolic link
622				 */
623				size_t buf_size;
624				daddr_t	disk_block;
625				struct fs *fs = fp->f_fs;
626
627				if (!buf)
628					buf = malloc(fs->fs_bsize);
629				rc = block_map(f, (daddr_t)0, &disk_block);
630				if (rc)
631					goto out;
632
633				twiddle();
634				rc = (f->f_dev->dv_strategy)(f->f_devdata,
635					F_READ, fsbtodb(fs, disk_block),
636					fs->fs_bsize, buf, &buf_size);
637				if (rc)
638					goto out;
639
640				bcopy((char *)buf, namebuf, (unsigned)link_len);
641			}
642
643			/*
644			 * If relative pathname, restart at parent directory.
645			 * If absolute pathname, restart at root.
646			 */
647			cp = namebuf;
648			if (*cp != '/')
649				inumber = parent_inumber;
650			else
651				inumber = (ino_t)ROOTINO;
652
653			if ((rc = read_inode(inumber, f)) != 0)
654				goto out;
655		}
656	}
657
658	/*
659	 * Found terminal component.
660	 */
661	rc = 0;
662out:
663	if (buf)
664		free(buf);
665	if (path)
666		free(path);
667	if (rc) {
668		if (fp->f_buf)
669			free(fp->f_buf);
670		free(fp->f_fs);
671		free(fp);
672	}
673	return (rc);
674}
675
676static int
677ufs_close(f)
678	struct open_file *f;
679{
680	struct file *fp = (struct file *)f->f_fsdata;
681	int level;
682
683	f->f_fsdata = (void *)0;
684	if (fp == (struct file *)0)
685		return (0);
686
687	for (level = 0; level < NIADDR; level++) {
688		if (fp->f_blk[level])
689			free(fp->f_blk[level]);
690	}
691	if (fp->f_buf)
692		free(fp->f_buf);
693	free(fp->f_fs);
694	free(fp);
695	return (0);
696}
697
698/*
699 * Copy a portion of a file into kernel memory.
700 * Cross block boundaries when necessary.
701 */
702static int
703ufs_read(f, start, size, resid)
704	struct open_file *f;
705	void *start;
706	size_t size;
707	size_t *resid;	/* out */
708{
709	struct file *fp = (struct file *)f->f_fsdata;
710	size_t csize;
711	char *buf;
712	size_t buf_size;
713	int rc = 0;
714	char *addr = start;
715
716	while (size != 0) {
717		if (fp->f_seekp >= fp->f_di.di_size)
718			break;
719
720		rc = buf_read_file(f, &buf, &buf_size);
721		if (rc)
722			break;
723
724		csize = size;
725		if (csize > buf_size)
726			csize = buf_size;
727
728		bcopy(buf, addr, csize);
729
730		fp->f_seekp += csize;
731		addr += csize;
732		size -= csize;
733	}
734	if (resid)
735		*resid = size;
736	return (rc);
737}
738
739/*
740 * Write to a portion of an already allocated file.
741 * Cross block boundaries when necessary. Can not
742 * extend the file.
743 */
744static int
745ufs_write(f, start, size, resid)
746	struct open_file *f;
747	void *start;
748	size_t size;
749	size_t *resid;	/* out */
750{
751	struct file *fp = (struct file *)f->f_fsdata;
752	size_t csize;
753	int rc = 0;
754	char *addr = start;
755
756	csize = size;
757	while ((size != 0) && (csize != 0)) {
758		if (fp->f_seekp >= fp->f_di.di_size)
759			break;
760
761		if (csize >= 512) csize = 512; /* XXX */
762
763		rc = buf_write_file(f, addr, &csize);
764		if (rc)
765			break;
766
767		fp->f_seekp += csize;
768		addr += csize;
769		size -= csize;
770	}
771	if (resid)
772		*resid = size;
773	return (rc);
774}
775
776static off_t
777ufs_seek(f, offset, where)
778	struct open_file *f;
779	off_t offset;
780	int where;
781{
782	struct file *fp = (struct file *)f->f_fsdata;
783
784	switch (where) {
785	case SEEK_SET:
786		fp->f_seekp = offset;
787		break;
788	case SEEK_CUR:
789		fp->f_seekp += offset;
790		break;
791	case SEEK_END:
792		fp->f_seekp = fp->f_di.di_size - offset;
793		break;
794	default:
795		return (-1);
796	}
797	return (fp->f_seekp);
798}
799
800static int
801ufs_stat(f, sb)
802	struct open_file *f;
803	struct stat *sb;
804{
805	struct file *fp = (struct file *)f->f_fsdata;
806
807	/* only important stuff */
808	sb->st_mode = fp->f_di.di_mode;
809	sb->st_uid = fp->f_di.di_uid;
810	sb->st_gid = fp->f_di.di_gid;
811	sb->st_size = fp->f_di.di_size;
812	return (0);
813}
814
815static int
816ufs_readdir(struct open_file *f, struct dirent *d)
817{
818	struct file *fp = (struct file *)f->f_fsdata;
819	struct direct *dp;
820	char *buf;
821	size_t buf_size;
822	int error;
823
824	/*
825	 * assume that a directory entry will not be split across blocks
826	 */
827again:
828	if (fp->f_seekp >= fp->f_di.di_size)
829		return (ENOENT);
830	error = buf_read_file(f, &buf, &buf_size);
831	if (error)
832		return (error);
833	dp = (struct direct *)buf;
834	fp->f_seekp += dp->d_reclen;
835	if (dp->d_ino == (ino_t)0)
836		goto again;
837	d->d_type = dp->d_type;
838	strcpy(d->d_name, dp->d_name);
839	return (0);
840}
841
842#ifdef COMPAT_UFS
843/*
844 * Sanity checks for old file systems.
845 *
846 * XXX - goes away some day.
847 */
848static void
849ffs_oldfscompat(fs)
850	struct fs *fs;
851{
852	int i;
853
854	fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect);	/* XXX */
855	fs->fs_interleave = max(fs->fs_interleave, 1);		/* XXX */
856	if (fs->fs_postblformat == FS_42POSTBLFMT)		/* XXX */
857		fs->fs_nrpos = 8;				/* XXX */
858	if (fs->fs_inodefmt < FS_44INODEFMT) {			/* XXX */
859		quad_t sizepb = fs->fs_bsize;			/* XXX */
860								/* XXX */
861		fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1;	/* XXX */
862		for (i = 0; i < NIADDR; i++) {			/* XXX */
863			sizepb *= NINDIR(fs);			/* XXX */
864			fs->fs_maxfilesize += sizepb;		/* XXX */
865		}						/* XXX */
866		fs->fs_qbmask = ~fs->fs_bmask;			/* XXX */
867		fs->fs_qfmask = ~fs->fs_fmask;			/* XXX */
868	}							/* XXX */
869}
870#endif
871