1/*	$OpenBSD: ufs12.c,v 1.1 2022/09/02 10:15:35 miod Exp $	*/
2/*	$NetBSD: ufs.c,v 1.16 1996/09/30 16:01:22 ws Exp $	*/
3
4/*-
5 * Copyright (c) 1993
6 *	The Regents of the University of California.  All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * The Mach Operating System project at Carnegie-Mellon University.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 *
36 * Copyright (c) 1990, 1991 Carnegie Mellon University
37 * All Rights Reserved.
38 *
39 * Author: David Golub
40 *
41 * Permission to use, copy, modify and distribute this software and its
42 * documentation is hereby granted, provided that both the copyright
43 * notice and this permission notice appear in all copies of the
44 * software, derivative works or modified versions, and any portions
45 * thereof, and that both notices appear in supporting documentation.
46 *
47 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
48 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
49 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
50 *
51 * Carnegie Mellon requests users of this software to return to
52 *
53 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
54 *  School of Computer Science
55 *  Carnegie Mellon University
56 *  Pittsburgh PA 15213-3890
57 *
58 * any improvements or extensions that they make and grant Carnegie the
59 * rights to redistribute these changes.
60 */
61
62/*
63 *	Stand-alone file reading package.
64 */
65
66#include <sys/param.h>
67#include <sys/time.h>
68#include <sys/stat.h>
69#include <ufs/ffs/fs.h>
70#include <ufs/ufs/dinode.h>
71#include <ufs/ufs/dir.h>
72#include <lib/libkern/libkern.h>
73
74#include <lib/libsa/stand.h>
75#include "ufs12.h"
76
77/*
78 * In-core open file.
79 */
80struct file {
81	int		f_is2;		/* 0 if ufs1, nonzero if ufs2 */
82	off_t		f_seekp;	/* seek pointer */
83	struct fs	*f_fs;		/* pointer to super-block */
84	union {
85		struct ufs1_dinode i1;
86		struct ufs2_dinode i2;
87	}		f_di;		/* copy of on-disk inode */
88	ufsino_t	f_ino;		/* our inode number */
89	int		f_nindir[NIADDR];
90					/* number of blocks mapped by
91					   indirect block at level i */
92	char		*f_blk[NIADDR];	/* buffer for indirect block at
93					   level i */
94	size_t		f_blksize[NIADDR];
95					/* size of buffer */
96	daddr_t		f_blkno[NIADDR];/* disk address of block in buffer */
97	char		*f_buf;		/* buffer for data block */
98	size_t		f_buf_size;	/* size of data block */
99	daddr_t		f_buf_blkno;	/* block number of data block */
100};
101
102static int	read_inode(ufsino_t, struct open_file *);
103#if 0
104static int	chmod_inode(ufsino_t, struct open_file *, mode_t);
105#endif
106static int	block_map(struct open_file *, daddr_t, daddr_t *);
107static int	buf_read_file(struct open_file *, char **, size_t *);
108static int	search_directory(char *, struct open_file *, ufsino_t *);
109static int	ufs12_close_internal(struct file *);
110#ifdef COMPAT_UFS
111static void	ffs_oldfscompat(struct fs *);
112#endif
113
114/*
115 * Read a new inode into a file structure.
116 */
117static int
118read_inode(ufsino_t inumber, struct open_file *f)
119{
120	struct file *fp = (struct file *)f->f_fsdata;
121	struct fs *fs = fp->f_fs;
122	char *buf;
123	size_t rsize;
124	int rc;
125
126	/*
127	 * Read inode and save it.
128	 */
129	buf = alloc(fs->fs_bsize);
130	twiddle();
131	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
132	    fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize, buf, &rsize);
133	if (rc)
134		goto out;
135	if (rsize != (size_t)fs->fs_bsize) {
136		rc = EIO;
137		goto out;
138	}
139
140	if (fp->f_is2) {
141		struct ufs2_dinode *dp;
142
143		dp = (struct ufs2_dinode *)buf;
144		fp->f_di.i2 = dp[ino_to_fsbo(fs, inumber)];
145	} else {
146		struct ufs1_dinode *dp;
147
148		dp = (struct ufs1_dinode *)buf;
149		fp->f_di.i1 = dp[ino_to_fsbo(fs, inumber)];
150	}
151
152	/*
153	 * Clear out the old buffers
154	 */
155	{
156		int level;
157
158		for (level = 0; level < NIADDR; level++)
159			fp->f_blkno[level] = -1;
160		fp->f_buf_blkno = -1;
161		fp->f_seekp = 0;
162	}
163out:
164	free(buf, fs->fs_bsize);
165	return (rc);
166}
167
168#if 0
169/*
170 * Read a new inode into a file structure.
171 */
172static int
173chmod_inode(ufsino_t inumber, struct open_file *f, mode_t mode)
174{
175	struct file *fp = (struct file *)f->f_fsdata;
176	struct fs *fs = fp->f_fs;
177	char *buf;
178	size_t rsize;
179	int rc;
180
181	/*
182	 * Read inode and save it.
183	 */
184	buf = alloc(fs->fs_bsize);
185	twiddle();
186	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
187	    fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize, buf, &rsize);
188	if (rc)
189		goto out;
190	if (rsize != (size_t)fs->fs_bsize) {
191		rc = EIO;
192		goto out;
193	}
194
195	if (fp->f_is2) {
196		struct ufs2_dinode *dp;
197
198		dp = &((struct ufs2_dinode *)buf)[ino_to_fsbo(fs, inumber)];
199		dp->di_mode = mode;
200	} else {
201		struct ufs1_dinode *dp;
202
203		dp = &((struct ufs1_dinode *)buf)[ino_to_fsbo(fs, inumber)];
204		dp->di_mode = mode;
205	}
206
207	twiddle();
208	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_WRITE,
209	    fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize, buf, NULL);
210
211out:
212	free(buf, fs->fs_bsize);
213	return (rc);
214}
215#endif
216
217/*
218 * Given an offset in a file, find the disk block number that
219 * contains that block.
220 */
221static int
222block_map(struct open_file *f, daddr_t file_block, daddr_t *disk_block_p)
223{
224	struct file *fp = (struct file *)f->f_fsdata;
225	daddr_t ind_block_num, *ind_p;
226	struct fs *fs = fp->f_fs;
227	int level, idx, rc;
228
229	/*
230	 * Index structure of an inode:
231	 *
232	 * di_db[0..NDADDR-1]	hold block numbers for blocks
233	 *			0..NDADDR-1
234	 *
235	 * di_ib[0]		index block 0 is the single indirect block
236	 *			holds block numbers for blocks
237	 *			NDADDR .. 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	 *			NDADDR + NINDIR(fs) ..
242	 *			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	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2 ..
248	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2
249	 *				+ NINDIR(fs)**3 - 1
250	 */
251
252	if (file_block < NDADDR) {
253		/* Direct block. */
254		if (fp->f_is2)
255			*disk_block_p = fp->f_di.i2.di_db[file_block];
256		else
257			*disk_block_p = fp->f_di.i1.di_db[file_block];
258		return (0);
259	}
260
261	file_block -= NDADDR;
262
263	/*
264	 * nindir[0] = NINDIR
265	 * nindir[1] = NINDIR**2
266	 * nindir[2] = NINDIR**3
267	 *	etc
268	 */
269	for (level = 0; level < NIADDR; level++) {
270		if (file_block < fp->f_nindir[level])
271			break;
272		file_block -= fp->f_nindir[level];
273	}
274	if (level == NIADDR) {
275		/* Block number too high */
276		return (EFBIG);
277	}
278
279	if (fp->f_is2)
280		ind_block_num = fp->f_di.i2.di_ib[level];
281	else
282		ind_block_num = fp->f_di.i1.di_ib[level];
283
284	for (; level >= 0; level--) {
285		if (ind_block_num == 0) {
286			*disk_block_p = 0;	/* missing */
287			return (0);
288		}
289
290		if (fp->f_blkno[level] != ind_block_num) {
291			if (fp->f_blk[level] == NULL)
292				fp->f_blk[level] =
293				    alloc(fs->fs_bsize);
294			twiddle();
295			rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
296			    fsbtodb(fp->f_fs, ind_block_num), fs->fs_bsize,
297			    fp->f_blk[level], &fp->f_blksize[level]);
298			if (rc)
299				return (rc);
300			if (fp->f_blksize[level] != (size_t)fs->fs_bsize)
301				return (EIO);
302			fp->f_blkno[level] = ind_block_num;
303		}
304
305		ind_p = (daddr_t *)fp->f_blk[level];
306
307		if (level > 0) {
308			idx = file_block / fp->f_nindir[level - 1];
309			file_block %= fp->f_nindir[level - 1];
310		} else
311			idx = file_block;
312
313		ind_block_num = ind_p[idx];
314	}
315
316	*disk_block_p = ind_block_num;
317	return (0);
318}
319
320/*
321 * Read a portion of a file into an internal buffer.  Return
322 * the location in the buffer and the amount in the buffer.
323 */
324static int
325buf_read_file(struct open_file *f, char **buf_p, size_t *size_p)
326{
327	struct file *fp = (struct file *)f->f_fsdata;
328	struct fs *fs = fp->f_fs;
329	daddr_t file_block, disk_block;
330	size_t block_size;
331	long off;
332	int rc;
333	u_int64_t fsize;
334
335	off = blkoff(fs, fp->f_seekp);
336	file_block = lblkno(fs, fp->f_seekp);
337	if (fp->f_is2)
338		block_size = dblksize(fs, &fp->f_di.i2, (u_int64_t)file_block);
339	else
340		block_size = dblksize(fs, &fp->f_di.i1, (u_int64_t)file_block);
341
342	if (file_block != fp->f_buf_blkno) {
343		rc = block_map(f, file_block, &disk_block);
344		if (rc)
345			return (rc);
346
347		if (fp->f_buf == NULL)
348			fp->f_buf = alloc(fs->fs_bsize);
349
350		if (disk_block == 0) {
351			bzero(fp->f_buf, block_size);
352			fp->f_buf_size = block_size;
353		} else {
354			twiddle();
355			rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
356			    fsbtodb(fs, disk_block),
357			    block_size, fp->f_buf, &fp->f_buf_size);
358			if (rc)
359				return (rc);
360		}
361
362		fp->f_buf_blkno = file_block;
363	}
364
365	/*
366	 * Return address of byte in buffer corresponding to
367	 * offset, and size of remainder of buffer after that
368	 * byte.
369	 */
370	*buf_p = fp->f_buf + off;
371	*size_p = block_size - off;
372
373	/*
374	 * But truncate buffer at end of file.
375	 */
376	if (fp->f_is2)
377		fsize = fp->f_di.i2.di_size;
378	else
379		fsize = fp->f_di.i1.di_size;
380	if (*size_p > fsize - fp->f_seekp)
381		*size_p = fsize - fp->f_seekp;
382
383	return (0);
384}
385
386/*
387 * Search a directory for a name and return its
388 * i_number.
389 */
390static int
391search_directory(char *name, struct open_file *f, ufsino_t *inumber_p)
392{
393	struct file *fp = (struct file *)f->f_fsdata;
394	int namlen, length, rc;
395	struct direct *dp, *edp;
396	size_t buf_size;
397	char *buf;
398	u_int64_t fsize;
399
400	length = strlen(name);
401
402	fp->f_seekp = 0;
403	if (fp->f_is2)
404		fsize = fp->f_di.i2.di_size;
405	else
406		fsize = fp->f_di.i1.di_size;
407	while ((u_int64_t)fp->f_seekp < fsize) {
408		rc = buf_read_file(f, &buf, &buf_size);
409		if (rc)
410			return (rc);
411
412		dp = (struct direct *)buf;
413		edp = (struct direct *)(buf + buf_size);
414		while (dp < edp) {
415			if (dp->d_ino == 0)
416				goto next;
417#if BYTE_ORDER == LITTLE_ENDIAN
418			if (fp->f_fs->fs_maxsymlinklen <= 0)
419				namlen = dp->d_type;
420			else
421#endif
422				namlen = dp->d_namlen;
423			if (namlen == length &&
424			    !strcmp(name, dp->d_name)) {
425				/* found entry */
426				*inumber_p = dp->d_ino;
427				return (0);
428			}
429		next:
430			dp = (struct direct *)((char *)dp + dp->d_reclen);
431		}
432		fp->f_seekp += buf_size;
433	}
434	return (ENOENT);
435}
436
437/*
438 * Open a file.
439 */
440int
441ufs12_open(char *path, struct open_file *f)
442{
443	char namebuf[MAXPATHLEN+1], *cp, *ncp, *buf = NULL;
444	ufsino_t inumber, parent_inumber;
445	int rc, c, nlinks = 0;
446	struct file *fp;
447	size_t buf_size;
448	struct fs *fs;
449	u_int16_t mode;
450
451	/* allocate file system specific data structure */
452	fp = alloc(sizeof(struct file));
453	bzero(fp, sizeof(struct file));
454	f->f_fsdata = (void *)fp;
455
456	/* allocate space and read super block */
457	fs = alloc(SBSIZE);
458	fp->f_fs = fs;
459	fp->f_is2 = 0;
460	twiddle();
461	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
462	    SBLOCK, SBSIZE, (char *)fs, &buf_size);
463	if (rc)
464		goto out;
465
466	if (buf_size != SBSIZE || fs->fs_magic != FS_MAGIC ||
467	    (size_t)fs->fs_bsize > MAXBSIZE ||
468	    (size_t)fs->fs_bsize < sizeof(struct fs)) {
469		/* try ufs2 */
470		rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
471		    SBLOCK_UFS2 / DEV_BSIZE, SBSIZE, (char *)fs, &buf_size);
472		if (rc)
473			goto out;
474
475		if (buf_size != SBSIZE || fs->fs_magic != FS_UFS2_MAGIC ||
476		    (u_int64_t)fs->fs_bsize > MAXBSIZE ||
477		    (u_int64_t)fs->fs_bsize < sizeof(struct fs)) {
478			rc = EINVAL;
479			goto out;
480		}
481		fp->f_is2 = 1;
482	}
483#ifdef COMPAT_UFS
484	ffs_oldfscompat(fs);
485#endif
486
487	/*
488	 * Calculate indirect block levels.
489	 */
490	{
491		int mult;
492		int level;
493
494		mult = 1;
495		for (level = 0; level < NIADDR; level++) {
496			mult *= NINDIR(fs);
497			fp->f_nindir[level] = mult;
498		}
499	}
500
501	inumber = ROOTINO;
502	if ((rc = read_inode(inumber, f)) != 0)
503		goto out;
504
505	cp = path;
506	while (*cp) {
507
508		/*
509		 * Remove extra separators
510		 */
511		while (*cp == '/')
512			cp++;
513		if (*cp == '\0')
514			break;
515
516		/*
517		 * Check that current node is a directory.
518		 */
519		if (fp->f_is2)
520			mode = fp->f_di.i2.di_mode;
521		else
522			mode = fp->f_di.i1.di_mode;
523		if ((mode & IFMT) != IFDIR) {
524			rc = ENOTDIR;
525			goto out;
526		}
527
528		/*
529		 * Get next component of path name.
530		 */
531		{
532			int len = 0;
533
534			ncp = cp;
535			while ((c = *cp) != '\0' && c != '/') {
536				if (++len > MAXNAMLEN) {
537					rc = ENOENT;
538					goto out;
539				}
540				cp++;
541			}
542			*cp = '\0';
543		}
544
545		/*
546		 * Look up component in current directory.
547		 * Save directory inumber in case we find a
548		 * symbolic link.
549		 */
550		parent_inumber = inumber;
551		rc = search_directory(ncp, f, &inumber);
552		*cp = c;
553		if (rc)
554			goto out;
555
556		/*
557		 * Open next component.
558		 */
559		if ((rc = read_inode(inumber, f)) != 0)
560			goto out;
561
562		/*
563		 * Check for symbolic link.
564		 */
565		if (fp->f_is2)
566			mode = fp->f_di.i2.di_mode;
567		else
568			mode = fp->f_di.i1.di_mode;
569		if ((mode & IFMT) == IFLNK) {
570			u_int64_t link_len;
571			size_t len;
572
573			if (fp->f_is2)
574				link_len = fp->f_di.i2.di_size;
575			else
576				link_len = fp->f_di.i1.di_size;
577			len = strlen(cp);
578
579			if (link_len + len > MAXPATHLEN ||
580			    ++nlinks > MAXSYMLINKS) {
581				rc = ENOENT;
582				goto out;
583			}
584
585			bcopy(cp, &namebuf[link_len], len + 1);
586
587			if (link_len < (u_int64_t)fs->fs_maxsymlinklen) {
588				if (fp->f_is2) {
589					bcopy(fp->f_di.i2.di_shortlink, namebuf,
590					    link_len);
591				} else {
592					bcopy(fp->f_di.i1.di_shortlink, namebuf,
593					    link_len);
594				}
595			} else {
596				/*
597				 * Read file for symbolic link
598				 */
599				daddr_t disk_block;
600				fs = fp->f_fs;
601
602				if (!buf)
603					buf = alloc(fs->fs_bsize);
604				rc = block_map(f, (daddr_t)0, &disk_block);
605				if (rc)
606					goto out;
607
608				twiddle();
609				rc = (f->f_dev->dv_strategy)(f->f_devdata,
610				    F_READ, fsbtodb(fs, disk_block),
611				    fs->fs_bsize, buf, &buf_size);
612				if (rc)
613					goto out;
614
615				bcopy(buf, namebuf, link_len);
616			}
617
618			/*
619			 * If relative pathname, restart at parent directory.
620			 * If absolute pathname, restart at root.
621			 */
622			cp = namebuf;
623			if (*cp != '/')
624				inumber = parent_inumber;
625			else
626				inumber = ROOTINO;
627
628			if ((rc = read_inode(inumber, f)) != 0)
629				goto out;
630		}
631	}
632
633	/*
634	 * Found terminal component.
635	 */
636	fp->f_ino = inumber;
637	rc = 0;
638out:
639	if (buf)
640		free(buf, fs->fs_bsize);
641	if (rc)
642		(void)ufs12_close_internal(fp);
643
644	return (rc);
645}
646
647int
648ufs12_close(struct open_file *f)
649{
650	struct file *fp = (struct file *)f->f_fsdata;
651
652	f->f_fsdata = NULL;
653	if (fp == NULL)
654		return (0);
655
656	return (ufs12_close_internal(fp));
657}
658
659static int
660ufs12_close_internal(struct file *fp)
661{
662	int level;
663
664	for (level = 0; level < NIADDR; level++) {
665		if (fp->f_blk[level])
666			free(fp->f_blk[level], fp->f_fs->fs_bsize);
667	}
668	if (fp->f_buf)
669		free(fp->f_buf, fp->f_fs->fs_bsize);
670	free(fp->f_fs, SBSIZE);
671	free(fp, sizeof(struct file));
672	return (0);
673}
674
675/*
676 * Copy a portion of a file into kernel memory.
677 * Cross block boundaries when necessary.
678 */
679int
680ufs12_read(struct open_file *f, void *start, size_t size, size_t *resid)
681{
682	struct file *fp = (struct file *)f->f_fsdata;
683	char *buf, *addr = start;
684	size_t csize, buf_size;
685	u_int64_t fsize;
686	int rc = 0;
687
688	while (size != 0) {
689		if (fp->f_is2)
690			fsize = fp->f_di.i2.di_size;
691		else
692			fsize = fp->f_di.i1.di_size;
693		if ((u_int64_t)fp->f_seekp >= fsize)
694			break;
695
696		rc = buf_read_file(f, &buf, &buf_size);
697		if (rc)
698			break;
699
700		csize = size;
701		if (csize > buf_size)
702			csize = buf_size;
703
704		bcopy(buf, addr, csize);
705
706		fp->f_seekp += csize;
707		addr += csize;
708		size -= csize;
709	}
710	if (resid)
711		*resid = size;
712	return (rc);
713}
714
715/*
716 * Not implemented.
717 */
718int
719ufs12_write(struct open_file *f, void *start, size_t size, size_t *resid)
720{
721
722	return (EROFS);
723}
724
725off_t
726ufs12_seek(struct open_file *f, off_t offset, int where)
727{
728	struct file *fp = (struct file *)f->f_fsdata;
729	u_int64_t fsize;
730
731	switch (where) {
732	case SEEK_SET:
733		fp->f_seekp = offset;
734		break;
735	case SEEK_CUR:
736		fp->f_seekp += offset;
737		break;
738	case SEEK_END:
739		if (fp->f_is2)
740			fsize = fp->f_di.i2.di_size;
741		else
742			fsize = fp->f_di.i1.di_size;
743		fp->f_seekp = fsize - offset;
744		break;
745	default:
746		return (-1);
747	}
748	return (fp->f_seekp);
749}
750
751int
752ufs12_stat(struct open_file *f, struct stat *sb)
753{
754	struct file *fp = (struct file *)f->f_fsdata;
755
756	/* only important stuff */
757	if (fp->f_is2) {
758		sb->st_mode = fp->f_di.i2.di_mode;
759		sb->st_uid = fp->f_di.i2.di_uid;
760		sb->st_gid = fp->f_di.i2.di_gid;
761		sb->st_size = fp->f_di.i2.di_size;
762	} else {
763		sb->st_mode = fp->f_di.i1.di_mode;
764		sb->st_uid = fp->f_di.i1.di_uid;
765		sb->st_gid = fp->f_di.i1.di_gid;
766		sb->st_size = fp->f_di.i1.di_size;
767	}
768	return (0);
769}
770
771int
772ufs12_fchmod(struct open_file *f, mode_t mode)
773{
774#if 0
775	struct file *fp = (struct file *)f->f_fsdata;
776
777	return chmod_inode(fp->f_ino, f, mode);
778#else
779	return EIO;
780#endif
781}
782
783#ifndef	NO_READDIR
784int
785ufs12_readdir(struct open_file *f, char *name)
786{
787#if 0
788	struct file *fp = (struct file *)f->f_fsdata;
789	struct direct *dp, *edp;
790	size_t buf_size;
791	int rc, namlen;
792	char *buf;
793	u_int64_t fsize;
794
795	if (name == NULL)
796		fp->f_seekp = 0;
797	else {
798			/* end of dir */
799		if (fp->f_is2)
800			fsize = fp->f_di.i2.di_size;
801		else
802			fsize = fp->f_di.i1.di_size;
803		if ((u_int64_t)fp->f_seekp >= fsize) {
804			*name = '\0';
805			return -1;
806		}
807
808		do {
809			if ((rc = buf_read_file(f, &buf, &buf_size)) != 0)
810				return rc;
811
812			dp = (struct direct *)buf;
813			edp = (struct direct *)(buf + buf_size);
814			while (dp < edp && dp->d_ino == 0)
815				dp = (struct direct *)((char *)dp + dp->d_reclen);
816			fp->f_seekp += buf_size -
817			    ((u_int8_t *)edp - (u_int8_t *)dp);
818		} while (dp >= edp);
819
820#if BYTE_ORDER == LITTLE_ENDIAN
821		if (fp->f_fs->fs_maxsymlinklen <= 0)
822			namlen = dp->d_type;
823		else
824#endif
825			namlen = dp->d_namlen;
826		strncpy(name, dp->d_name, namlen + 1);
827
828		fp->f_seekp += dp->d_reclen;
829	}
830
831	return 0;
832#else
833	return EIO;
834#endif
835}
836#endif
837
838#ifdef COMPAT_UFS
839/*
840 * Sanity checks for old file systems.
841 *
842 * XXX - goes away some day.
843 */
844static void
845ffs_oldfscompat(struct fs *fs)
846{
847	int i;
848
849	fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect);	/* XXX */
850	fs->fs_interleave = max(fs->fs_interleave, 1);		/* XXX */
851	if (fs->fs_postblformat == FS_42POSTBLFMT)		/* XXX */
852		fs->fs_nrpos = 8;				/* XXX */
853	if (fs->fs_inodefmt < FS_44INODEFMT) {			/* XXX */
854		quad_t sizepb = fs->fs_bsize;			/* XXX */
855								/* XXX */
856		fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1;	/* XXX */
857		for (i = 0; i < NIADDR; i++) {			/* XXX */
858			sizepb *= NINDIR(fs);			/* XXX */
859			fs->fs_maxfilesize += sizepb;		/* XXX */
860		}						/* XXX */
861		fs->fs_qbmask = ~fs->fs_bmask;			/* XXX */
862		fs->fs_qfmask = ~fs->fs_fmask;			/* XXX */
863	}							/* XXX */
864}
865#endif
866