xref: /minix3/sys/lib/libsa/ufs.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: ufs.c,v 1.74 2015/09/01 06:16:58 dholland Exp $	*/
258a2b000SEvgeniy Ivanov 
358a2b000SEvgeniy Ivanov /*-
458a2b000SEvgeniy Ivanov  * Copyright (c) 1993
558a2b000SEvgeniy Ivanov  *	The Regents of the University of California.  All rights reserved.
658a2b000SEvgeniy Ivanov  *
758a2b000SEvgeniy Ivanov  * This code is derived from software contributed to Berkeley by
858a2b000SEvgeniy Ivanov  * The Mach Operating System project at Carnegie-Mellon University.
958a2b000SEvgeniy Ivanov  *
1058a2b000SEvgeniy Ivanov  * Redistribution and use in source and binary forms, with or without
1158a2b000SEvgeniy Ivanov  * modification, are permitted provided that the following conditions
1258a2b000SEvgeniy Ivanov  * are met:
1358a2b000SEvgeniy Ivanov  * 1. Redistributions of source code must retain the above copyright
1458a2b000SEvgeniy Ivanov  *    notice, this list of conditions and the following disclaimer.
1558a2b000SEvgeniy Ivanov  * 2. Redistributions in binary form must reproduce the above copyright
1658a2b000SEvgeniy Ivanov  *    notice, this list of conditions and the following disclaimer in the
1758a2b000SEvgeniy Ivanov  *    documentation and/or other materials provided with the distribution.
1858a2b000SEvgeniy Ivanov  * 3. Neither the name of the University nor the names of its contributors
1958a2b000SEvgeniy Ivanov  *    may be used to endorse or promote products derived from this software
2058a2b000SEvgeniy Ivanov  *    without specific prior written permission.
2158a2b000SEvgeniy Ivanov  *
2258a2b000SEvgeniy Ivanov  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2358a2b000SEvgeniy Ivanov  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2458a2b000SEvgeniy Ivanov  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2558a2b000SEvgeniy Ivanov  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2658a2b000SEvgeniy Ivanov  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2758a2b000SEvgeniy Ivanov  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2858a2b000SEvgeniy Ivanov  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2958a2b000SEvgeniy Ivanov  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3058a2b000SEvgeniy Ivanov  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3158a2b000SEvgeniy Ivanov  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3258a2b000SEvgeniy Ivanov  * SUCH DAMAGE.
3358a2b000SEvgeniy Ivanov  *
3458a2b000SEvgeniy Ivanov  *
3558a2b000SEvgeniy Ivanov  * Copyright (c) 1990, 1991 Carnegie Mellon University
3658a2b000SEvgeniy Ivanov  * All Rights Reserved.
3758a2b000SEvgeniy Ivanov  *
3858a2b000SEvgeniy Ivanov  * Author: David Golub
3958a2b000SEvgeniy Ivanov  *
4058a2b000SEvgeniy Ivanov  * Permission to use, copy, modify and distribute this software and its
4158a2b000SEvgeniy Ivanov  * documentation is hereby granted, provided that both the copyright
4258a2b000SEvgeniy Ivanov  * notice and this permission notice appear in all copies of the
4358a2b000SEvgeniy Ivanov  * software, derivative works or modified versions, and any portions
4458a2b000SEvgeniy Ivanov  * thereof, and that both notices appear in supporting documentation.
4558a2b000SEvgeniy Ivanov  *
4658a2b000SEvgeniy Ivanov  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
4758a2b000SEvgeniy Ivanov  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
4858a2b000SEvgeniy Ivanov  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
4958a2b000SEvgeniy Ivanov  *
5058a2b000SEvgeniy Ivanov  * Carnegie Mellon requests users of this software to return to
5158a2b000SEvgeniy Ivanov  *
5258a2b000SEvgeniy Ivanov  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
5358a2b000SEvgeniy Ivanov  *  School of Computer Science
5458a2b000SEvgeniy Ivanov  *  Carnegie Mellon University
5558a2b000SEvgeniy Ivanov  *  Pittsburgh PA 15213-3890
5658a2b000SEvgeniy Ivanov  *
5758a2b000SEvgeniy Ivanov  * any improvements or extensions that they make and grant Carnegie the
5858a2b000SEvgeniy Ivanov  * rights to redistribute these changes.
5958a2b000SEvgeniy Ivanov  */
6058a2b000SEvgeniy Ivanov 
6158a2b000SEvgeniy Ivanov /*
6258a2b000SEvgeniy Ivanov  *	Stand-alone file reading package for UFS and LFS filesystems.
6358a2b000SEvgeniy Ivanov  */
6458a2b000SEvgeniy Ivanov 
6558a2b000SEvgeniy Ivanov #include <sys/param.h>
6658a2b000SEvgeniy Ivanov #include <sys/time.h>
6758a2b000SEvgeniy Ivanov #include <ufs/ufs/dinode.h>
6858a2b000SEvgeniy Ivanov #include <ufs/ufs/dir.h>
6958a2b000SEvgeniy Ivanov #ifdef LIBSA_LFS
7058a2b000SEvgeniy Ivanov #include <sys/queue.h>
7158a2b000SEvgeniy Ivanov #include <sys/condvar.h>
7258a2b000SEvgeniy Ivanov #include <sys/mount.h>			/* XXX for MNAMELEN */
7358a2b000SEvgeniy Ivanov #include <ufs/lfs/lfs.h>
7458a2b000SEvgeniy Ivanov #else
7558a2b000SEvgeniy Ivanov #include <ufs/ffs/fs.h>
7658a2b000SEvgeniy Ivanov #endif
7758a2b000SEvgeniy Ivanov #ifdef _STANDALONE
7858a2b000SEvgeniy Ivanov #include <lib/libkern/libkern.h>
7958a2b000SEvgeniy Ivanov #else
8058a2b000SEvgeniy Ivanov #include <string.h>
8158a2b000SEvgeniy Ivanov #endif
8258a2b000SEvgeniy Ivanov 
8358a2b000SEvgeniy Ivanov #include "stand.h"
8458a2b000SEvgeniy Ivanov #ifdef LIBSA_LFS
8558a2b000SEvgeniy Ivanov #include "lfs.h"
8658a2b000SEvgeniy Ivanov #else
8758a2b000SEvgeniy Ivanov #include "ufs.h"
8858a2b000SEvgeniy Ivanov #endif
8958a2b000SEvgeniy Ivanov 
9058a2b000SEvgeniy Ivanov /* If this file is compiled by itself, build ufs (aka ffsv1) support */
9158a2b000SEvgeniy Ivanov #if !defined(LIBSA_FFSv2) && !defined(LIBSA_LFS)
9258a2b000SEvgeniy Ivanov #define LIBSA_FFSv1
9358a2b000SEvgeniy Ivanov #endif
9458a2b000SEvgeniy Ivanov 
9558a2b000SEvgeniy Ivanov #if defined(LIBSA_FS_SINGLECOMPONENT) && !defined(LIBSA_NO_FS_SYMLINK)
9658a2b000SEvgeniy Ivanov #define LIBSA_NO_FS_SYMLINK
9758a2b000SEvgeniy Ivanov #endif
9858a2b000SEvgeniy Ivanov #if defined(COMPAT_UFS) && defined(LIBSA_NO_COMPAT_UFS)
9958a2b000SEvgeniy Ivanov #undef COMPAT_UFS
10058a2b000SEvgeniy Ivanov #endif
10158a2b000SEvgeniy Ivanov 
10258a2b000SEvgeniy Ivanov #ifdef LIBSA_LFS
10358a2b000SEvgeniy Ivanov /*
104*0a6a1f1dSLionel Sambuc  * In-core LFS superblock - just the on-disk one.
10558a2b000SEvgeniy Ivanov  */
106*0a6a1f1dSLionel Sambuc struct salfs {
107*0a6a1f1dSLionel Sambuc 	union {
108*0a6a1f1dSLionel Sambuc 		struct dlfs u_32;
109*0a6a1f1dSLionel Sambuc 		struct dlfs64 u_64;
110*0a6a1f1dSLionel Sambuc 	} lfs_dlfs_u;
111*0a6a1f1dSLionel Sambuc 	unsigned lfs_is64 : 1,
112*0a6a1f1dSLionel Sambuc 		lfs_dobyteswap : 1,
113*0a6a1f1dSLionel Sambuc 		lfs_hasolddirfmt : 1;
11458a2b000SEvgeniy Ivanov };
115*0a6a1f1dSLionel Sambuc /* Get lfs accessors that use struct salfs. */
116*0a6a1f1dSLionel Sambuc #define STRUCT_LFS struct salfs
117*0a6a1f1dSLionel Sambuc #include <ufs/lfs/lfs_accessors.h>
118*0a6a1f1dSLionel Sambuc 
119*0a6a1f1dSLionel Sambuc /* override this to avoid a mess with the dinode accessors */
120*0a6a1f1dSLionel Sambuc #define lfs_dino_getsize(fs, dp) ((dp)->di_size)
121*0a6a1f1dSLionel Sambuc 
122*0a6a1f1dSLionel Sambuc typedef struct salfs FS;
123*0a6a1f1dSLionel Sambuc #define fs_magic	lfs_dlfs_u.u_32.dlfs_magic
124*0a6a1f1dSLionel Sambuc #define fs_maxsymlinklen lfs_dlfs_u.u_32.dlfs_maxsymlinklen
12558a2b000SEvgeniy Ivanov 
12658a2b000SEvgeniy Ivanov #define FS_MAGIC	LFS_MAGIC
12758a2b000SEvgeniy Ivanov #define SBLOCKSIZE	LFS_SBPAD
12858a2b000SEvgeniy Ivanov #define SBLOCKOFFSET	LFS_LABELPAD
12958a2b000SEvgeniy Ivanov #else
130*0a6a1f1dSLionel Sambuc /* NB ufs2 doesn't use the common superblock code... */
131*0a6a1f1dSLionel Sambuc typedef struct fs FS;
13258a2b000SEvgeniy Ivanov #define FS_MAGIC	FS_UFS1_MAGIC
13358a2b000SEvgeniy Ivanov #define SBLOCKOFFSET	SBLOCK_UFS1
13458a2b000SEvgeniy Ivanov #endif
13558a2b000SEvgeniy Ivanov 
13658a2b000SEvgeniy Ivanov #if defined(LIBSA_NO_TWIDDLE)
13758a2b000SEvgeniy Ivanov #define twiddle()
13858a2b000SEvgeniy Ivanov #endif
13958a2b000SEvgeniy Ivanov 
14058a2b000SEvgeniy Ivanov #undef cgstart
14158a2b000SEvgeniy Ivanov #if defined(LIBSA_FFSv2)
14258a2b000SEvgeniy Ivanov #define cgstart(fc, c) cgstart_ufs2((fs), (c))
14358a2b000SEvgeniy Ivanov #else
14458a2b000SEvgeniy Ivanov #define cgstart(fc, c) cgstart_ufs1((fs), (c))
14558a2b000SEvgeniy Ivanov #endif
14658a2b000SEvgeniy Ivanov 
14758a2b000SEvgeniy Ivanov #ifndef ufs_dinode
14858a2b000SEvgeniy Ivanov #define ufs_dinode	ufs1_dinode
14958a2b000SEvgeniy Ivanov #endif
15058a2b000SEvgeniy Ivanov #ifndef indp_t
15158a2b000SEvgeniy Ivanov #define indp_t		int32_t
15258a2b000SEvgeniy Ivanov #endif
15358a2b000SEvgeniy Ivanov typedef uint32_t	ino32_t;
15484d9c625SLionel Sambuc 
15558a2b000SEvgeniy Ivanov #ifndef FSBTODB
15684d9c625SLionel Sambuc #define FSBTODB(fs, indp) FFS_FSBTODB(fs, indp)
15784d9c625SLionel Sambuc #endif
15884d9c625SLionel Sambuc #ifndef UFS_NINDIR
15984d9c625SLionel Sambuc #define UFS_NINDIR FFS_NINDIR
16084d9c625SLionel Sambuc #endif
16184d9c625SLionel Sambuc #ifndef ufs_blkoff
16284d9c625SLionel Sambuc #define ufs_blkoff ffs_blkoff
16384d9c625SLionel Sambuc #endif
16484d9c625SLionel Sambuc #ifndef ufs_lblkno
16584d9c625SLionel Sambuc #define ufs_lblkno ffs_lblkno
16658a2b000SEvgeniy Ivanov #endif
16758a2b000SEvgeniy Ivanov 
16858a2b000SEvgeniy Ivanov /*
16958a2b000SEvgeniy Ivanov  * To avoid having a lot of filesystem-block sized buffers lurking (which
17058a2b000SEvgeniy Ivanov  * could be 32k) we only keep a few entries of the indirect block map.
17158a2b000SEvgeniy Ivanov  * With 8k blocks, 2^8 blocks is ~500k so we reread the indirect block
17258a2b000SEvgeniy Ivanov  * ~13 times pulling in a 6M kernel.
17358a2b000SEvgeniy Ivanov  * The cache size must be smaller than the smallest filesystem block,
17458a2b000SEvgeniy Ivanov  * so LN2_IND_CACHE_SZ <= 9 (UFS2 and 4k blocks).
17558a2b000SEvgeniy Ivanov  */
17658a2b000SEvgeniy Ivanov #define LN2_IND_CACHE_SZ	6
17758a2b000SEvgeniy Ivanov #define IND_CACHE_SZ		(1 << LN2_IND_CACHE_SZ)
17858a2b000SEvgeniy Ivanov #define IND_CACHE_MASK		(IND_CACHE_SZ - 1)
17958a2b000SEvgeniy Ivanov 
18058a2b000SEvgeniy Ivanov /*
18158a2b000SEvgeniy Ivanov  * In-core open file.
18258a2b000SEvgeniy Ivanov  */
18358a2b000SEvgeniy Ivanov struct file {
18458a2b000SEvgeniy Ivanov 	off_t		f_seekp;	/* seek pointer */
185*0a6a1f1dSLionel Sambuc 	FS		*f_fs;		/* pointer to super-block */
18658a2b000SEvgeniy Ivanov 	struct ufs_dinode	f_di;		/* copy of on-disk inode */
18758a2b000SEvgeniy Ivanov 	uint		f_nishift;	/* for blocks in indirect block */
18858a2b000SEvgeniy Ivanov 	indp_t		f_ind_cache_block;
18958a2b000SEvgeniy Ivanov 	indp_t		f_ind_cache[IND_CACHE_SZ];
19058a2b000SEvgeniy Ivanov 
19158a2b000SEvgeniy Ivanov 	char		*f_buf;		/* buffer for data block */
19258a2b000SEvgeniy Ivanov 	size_t		f_buf_size;	/* size of data block */
19358a2b000SEvgeniy Ivanov 	daddr_t		f_buf_blkno;	/* block number of data block */
19458a2b000SEvgeniy Ivanov };
19558a2b000SEvgeniy Ivanov 
19658a2b000SEvgeniy Ivanov static int read_inode(ino32_t, struct open_file *);
19758a2b000SEvgeniy Ivanov static int block_map(struct open_file *, indp_t, indp_t *);
19858a2b000SEvgeniy Ivanov static int buf_read_file(struct open_file *, char **, size_t *);
19958a2b000SEvgeniy Ivanov static int search_directory(const char *, int, struct open_file *, ino32_t *);
20058a2b000SEvgeniy Ivanov #ifdef LIBSA_FFSv1
201*0a6a1f1dSLionel Sambuc static void ffs_oldfscompat(FS *);
20258a2b000SEvgeniy Ivanov #endif
20358a2b000SEvgeniy Ivanov #ifdef LIBSA_FFSv2
204*0a6a1f1dSLionel Sambuc static int ffs_find_superblock(struct open_file *, FS *);
20558a2b000SEvgeniy Ivanov #endif
20658a2b000SEvgeniy Ivanov 
20758a2b000SEvgeniy Ivanov 
20858a2b000SEvgeniy Ivanov #ifdef LIBSA_LFS
20958a2b000SEvgeniy Ivanov /*
21058a2b000SEvgeniy Ivanov  * Find an inode's block.  Look it up in the ifile.  Whee!
21158a2b000SEvgeniy Ivanov  */
21258a2b000SEvgeniy Ivanov static int
find_inode_sector(ino32_t inumber,struct open_file * f,daddr_t * isp)21358a2b000SEvgeniy Ivanov find_inode_sector(ino32_t inumber, struct open_file *f, daddr_t *isp)
21458a2b000SEvgeniy Ivanov {
21558a2b000SEvgeniy Ivanov 	struct file *fp = (struct file *)f->f_fsdata;
216*0a6a1f1dSLionel Sambuc 	FS *fs = fp->f_fs;
21758a2b000SEvgeniy Ivanov 	daddr_t ifileent_blkno;
21858a2b000SEvgeniy Ivanov 	char *ent_in_buf;
21958a2b000SEvgeniy Ivanov 	size_t buf_after_ent;
220*0a6a1f1dSLionel Sambuc 	size_t entsize;
22158a2b000SEvgeniy Ivanov 	int rc;
22258a2b000SEvgeniy Ivanov 
223*0a6a1f1dSLionel Sambuc 	rc = read_inode(LFS_IFILE_INUM, f);
22458a2b000SEvgeniy Ivanov 	if (rc)
22558a2b000SEvgeniy Ivanov 		return rc;
22658a2b000SEvgeniy Ivanov 
227*0a6a1f1dSLionel Sambuc 	entsize = fs->lfs_is64 ? sizeof(IFILE64) :
228*0a6a1f1dSLionel Sambuc 		(lfs_sb_getversion(fs) > 1 ? sizeof(IFILE32) : sizeof(IFILE_V1));
22958a2b000SEvgeniy Ivanov 	ifileent_blkno =
230*0a6a1f1dSLionel Sambuc 	    (inumber / lfs_sb_getifpb(fs)) + lfs_sb_getcleansz(fs) + lfs_sb_getsegtabsz(fs);
231*0a6a1f1dSLionel Sambuc 	fp->f_seekp = (off_t)ifileent_blkno * lfs_sb_getbsize(fs) +
232*0a6a1f1dSLionel Sambuc 	    (inumber % lfs_sb_getifpb(fs)) * entsize;
23358a2b000SEvgeniy Ivanov 	rc = buf_read_file(f, &ent_in_buf, &buf_after_ent);
23458a2b000SEvgeniy Ivanov 	if (rc)
23558a2b000SEvgeniy Ivanov 		return rc;
23658a2b000SEvgeniy Ivanov 	/* make sure something's not badly wrong, but don't panic. */
237*0a6a1f1dSLionel Sambuc 	if (buf_after_ent < entsize)
23858a2b000SEvgeniy Ivanov 		return EINVAL;
23958a2b000SEvgeniy Ivanov 
240*0a6a1f1dSLionel Sambuc 	*isp = FSBTODB(fs, lfs_if_getdaddr(fs, (IFILE *)ent_in_buf));
24158a2b000SEvgeniy Ivanov 	if (*isp == LFS_UNUSED_DADDR)	/* again, something badly wrong */
24258a2b000SEvgeniy Ivanov 		return EINVAL;
24358a2b000SEvgeniy Ivanov 	return 0;
24458a2b000SEvgeniy Ivanov }
24558a2b000SEvgeniy Ivanov #endif
24658a2b000SEvgeniy Ivanov 
24758a2b000SEvgeniy Ivanov /*
24858a2b000SEvgeniy Ivanov  * Read a new inode into a file structure.
24958a2b000SEvgeniy Ivanov  */
25058a2b000SEvgeniy Ivanov static int
read_inode(ino32_t inumber,struct open_file * f)25158a2b000SEvgeniy Ivanov read_inode(ino32_t inumber, struct open_file *f)
25258a2b000SEvgeniy Ivanov {
25358a2b000SEvgeniy Ivanov 	struct file *fp = (struct file *)f->f_fsdata;
254*0a6a1f1dSLionel Sambuc 	FS *fs = fp->f_fs;
25558a2b000SEvgeniy Ivanov 	char *buf;
25658a2b000SEvgeniy Ivanov 	size_t rsize;
25758a2b000SEvgeniy Ivanov 	int rc;
25884d9c625SLionel Sambuc 	daddr_t inode_sector = 0; /* XXX: gcc */
25958a2b000SEvgeniy Ivanov #ifdef LIBSA_LFS
26058a2b000SEvgeniy Ivanov 	struct ufs_dinode *dip;
26158a2b000SEvgeniy Ivanov 	int cnt;
26258a2b000SEvgeniy Ivanov #endif
26358a2b000SEvgeniy Ivanov 
26458a2b000SEvgeniy Ivanov #ifdef LIBSA_LFS
265*0a6a1f1dSLionel Sambuc 	if (inumber == LFS_IFILE_INUM)
266*0a6a1f1dSLionel Sambuc 		inode_sector = FSBTODB(fs, lfs_sb_getidaddr(fs));
26758a2b000SEvgeniy Ivanov 	else if ((rc = find_inode_sector(inumber, f, &inode_sector)) != 0)
26858a2b000SEvgeniy Ivanov 		return rc;
26958a2b000SEvgeniy Ivanov #else
27058a2b000SEvgeniy Ivanov 	inode_sector = FSBTODB(fs, ino_to_fsba(fs, inumber));
27158a2b000SEvgeniy Ivanov #endif
27258a2b000SEvgeniy Ivanov 
27358a2b000SEvgeniy Ivanov 	/*
27458a2b000SEvgeniy Ivanov 	 * Read inode and save it.
27558a2b000SEvgeniy Ivanov 	 */
27658a2b000SEvgeniy Ivanov 	buf = fp->f_buf;
27758a2b000SEvgeniy Ivanov 	twiddle();
27858a2b000SEvgeniy Ivanov 	rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
27958a2b000SEvgeniy Ivanov 	    inode_sector, fs->fs_bsize, buf, &rsize);
28058a2b000SEvgeniy Ivanov 	if (rc)
28158a2b000SEvgeniy Ivanov 		return rc;
28258a2b000SEvgeniy Ivanov 	if (rsize != fs->fs_bsize)
28358a2b000SEvgeniy Ivanov 		return EIO;
28458a2b000SEvgeniy Ivanov 
28558a2b000SEvgeniy Ivanov #ifdef LIBSA_LFS
28658a2b000SEvgeniy Ivanov 	cnt = INOPBx(fs);
28758a2b000SEvgeniy Ivanov 	dip = (struct ufs_dinode *)buf + (cnt - 1);
28858a2b000SEvgeniy Ivanov 	for (; dip->di_inumber != inumber; --dip) {
28958a2b000SEvgeniy Ivanov 		/* kernel code panics, but boot blocks which panic are Bad. */
29058a2b000SEvgeniy Ivanov 		if (--cnt == 0)
29158a2b000SEvgeniy Ivanov 			return EINVAL;
29258a2b000SEvgeniy Ivanov 	}
29358a2b000SEvgeniy Ivanov 	fp->f_di = *dip;
29458a2b000SEvgeniy Ivanov #else
29558a2b000SEvgeniy Ivanov 	fp->f_di = ((struct ufs_dinode *)buf)[ino_to_fsbo(fs, inumber)];
29658a2b000SEvgeniy Ivanov #endif
29758a2b000SEvgeniy Ivanov 
29858a2b000SEvgeniy Ivanov 	/*
29958a2b000SEvgeniy Ivanov 	 * Clear out the old buffers
30058a2b000SEvgeniy Ivanov 	 */
30158a2b000SEvgeniy Ivanov 	fp->f_ind_cache_block = ~0;
30258a2b000SEvgeniy Ivanov 	fp->f_buf_blkno = -1;
30358a2b000SEvgeniy Ivanov 	return rc;
30458a2b000SEvgeniy Ivanov }
30558a2b000SEvgeniy Ivanov 
30658a2b000SEvgeniy Ivanov /*
30758a2b000SEvgeniy Ivanov  * Given an offset in a file, find the disk block number that
30858a2b000SEvgeniy Ivanov  * contains that block.
30958a2b000SEvgeniy Ivanov  */
31058a2b000SEvgeniy Ivanov static int
block_map(struct open_file * f,indp_t file_block,indp_t * disk_block_p)31158a2b000SEvgeniy Ivanov block_map(struct open_file *f, indp_t file_block, indp_t *disk_block_p)
31258a2b000SEvgeniy Ivanov {
31358a2b000SEvgeniy Ivanov 	struct file *fp = (struct file *)f->f_fsdata;
314*0a6a1f1dSLionel Sambuc 	FS *fs = fp->f_fs;
31558a2b000SEvgeniy Ivanov 	uint level;
31658a2b000SEvgeniy Ivanov 	indp_t ind_cache;
31758a2b000SEvgeniy Ivanov 	indp_t ind_block_num;
31858a2b000SEvgeniy Ivanov 	size_t rsize;
31958a2b000SEvgeniy Ivanov 	int rc;
32058a2b000SEvgeniy Ivanov 	indp_t *buf = (void *)fp->f_buf;
32158a2b000SEvgeniy Ivanov 
32258a2b000SEvgeniy Ivanov 	/*
32358a2b000SEvgeniy Ivanov 	 * Index structure of an inode:
32458a2b000SEvgeniy Ivanov 	 *
32584d9c625SLionel Sambuc 	 * di_db[0..UFS_NDADDR-1]	hold block numbers for blocks
32684d9c625SLionel Sambuc 	 *			0..UFS_NDADDR-1
32758a2b000SEvgeniy Ivanov 	 *
32858a2b000SEvgeniy Ivanov 	 * di_ib[0]		index block 0 is the single indirect block
32958a2b000SEvgeniy Ivanov 	 *			holds block numbers for blocks
33084d9c625SLionel Sambuc 	 *			UFS_NDADDR .. UFS_NDADDR + UFS_NINDIR(fs)-1
33158a2b000SEvgeniy Ivanov 	 *
33258a2b000SEvgeniy Ivanov 	 * di_ib[1]		index block 1 is the double indirect block
33358a2b000SEvgeniy Ivanov 	 *			holds block numbers for INDEX blocks for blocks
33484d9c625SLionel Sambuc 	 *			UFS_NDADDR + UFS_NINDIR(fs) ..
33584d9c625SLionel Sambuc 	 *			UFS_NDADDR + UFS_NINDIR(fs) + UFS_NINDIR(fs)**2 - 1
33658a2b000SEvgeniy Ivanov 	 *
33758a2b000SEvgeniy Ivanov 	 * di_ib[2]		index block 2 is the triple indirect block
33858a2b000SEvgeniy Ivanov 	 *			holds block numbers for double-indirect
33958a2b000SEvgeniy Ivanov 	 *			blocks for blocks
34084d9c625SLionel Sambuc 	 *			UFS_NDADDR + UFS_NINDIR(fs) + UFS_NINDIR(fs)**2 ..
34184d9c625SLionel Sambuc 	 *			UFS_NDADDR + UFS_NINDIR(fs) + UFS_NINDIR(fs)**2
34284d9c625SLionel Sambuc 	 *				+ UFS_NINDIR(fs)**3 - 1
34358a2b000SEvgeniy Ivanov 	 */
34458a2b000SEvgeniy Ivanov 
34584d9c625SLionel Sambuc 	if (file_block < UFS_NDADDR) {
34658a2b000SEvgeniy Ivanov 		/* Direct block. */
34758a2b000SEvgeniy Ivanov 		*disk_block_p = fp->f_di.di_db[file_block];
34858a2b000SEvgeniy Ivanov 		return 0;
34958a2b000SEvgeniy Ivanov 	}
35058a2b000SEvgeniy Ivanov 
35184d9c625SLionel Sambuc 	file_block -= UFS_NDADDR;
35258a2b000SEvgeniy Ivanov 
35358a2b000SEvgeniy Ivanov 	ind_cache = file_block >> LN2_IND_CACHE_SZ;
35458a2b000SEvgeniy Ivanov 	if (ind_cache == fp->f_ind_cache_block) {
35558a2b000SEvgeniy Ivanov 		*disk_block_p = fp->f_ind_cache[file_block & IND_CACHE_MASK];
35658a2b000SEvgeniy Ivanov 		return 0;
35758a2b000SEvgeniy Ivanov 	}
35858a2b000SEvgeniy Ivanov 
35958a2b000SEvgeniy Ivanov 	for (level = 0;;) {
36058a2b000SEvgeniy Ivanov 		level += fp->f_nishift;
36158a2b000SEvgeniy Ivanov 		if (file_block < (indp_t)1 << level)
36258a2b000SEvgeniy Ivanov 			break;
36384d9c625SLionel Sambuc 		if (level > UFS_NIADDR * fp->f_nishift)
36458a2b000SEvgeniy Ivanov 			/* Block number too high */
36558a2b000SEvgeniy Ivanov 			return EFBIG;
36658a2b000SEvgeniy Ivanov 		file_block -= (indp_t)1 << level;
36758a2b000SEvgeniy Ivanov 	}
36858a2b000SEvgeniy Ivanov 
36958a2b000SEvgeniy Ivanov 	ind_block_num = fp->f_di.di_ib[level / fp->f_nishift - 1];
37058a2b000SEvgeniy Ivanov 
37158a2b000SEvgeniy Ivanov 	for (;;) {
37258a2b000SEvgeniy Ivanov 		level -= fp->f_nishift;
37358a2b000SEvgeniy Ivanov 		if (ind_block_num == 0) {
37458a2b000SEvgeniy Ivanov 			*disk_block_p = 0;	/* missing */
37558a2b000SEvgeniy Ivanov 			return 0;
37658a2b000SEvgeniy Ivanov 		}
37758a2b000SEvgeniy Ivanov 
37858a2b000SEvgeniy Ivanov 		twiddle();
37958a2b000SEvgeniy Ivanov 		/*
38058a2b000SEvgeniy Ivanov 		 * If we were feeling brave, we could work out the number
38158a2b000SEvgeniy Ivanov 		 * of the disk sector and read a single disk sector instead
38258a2b000SEvgeniy Ivanov 		 * of a filesystem block.
38358a2b000SEvgeniy Ivanov 		 * However we don't do this very often anyway...
38458a2b000SEvgeniy Ivanov 		 */
38558a2b000SEvgeniy Ivanov 		rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
38658a2b000SEvgeniy Ivanov 			FSBTODB(fp->f_fs, ind_block_num), fs->fs_bsize,
38758a2b000SEvgeniy Ivanov 			buf, &rsize);
38858a2b000SEvgeniy Ivanov 		if (rc)
38958a2b000SEvgeniy Ivanov 			return rc;
39058a2b000SEvgeniy Ivanov 		if (rsize != fs->fs_bsize)
39158a2b000SEvgeniy Ivanov 			return EIO;
39258a2b000SEvgeniy Ivanov 		ind_block_num = buf[file_block >> level];
39358a2b000SEvgeniy Ivanov 		if (level == 0)
39458a2b000SEvgeniy Ivanov 			break;
39558a2b000SEvgeniy Ivanov 		file_block &= (1 << level) - 1;
39658a2b000SEvgeniy Ivanov 	}
39758a2b000SEvgeniy Ivanov 
39858a2b000SEvgeniy Ivanov 	/* Save the part of the block that contains this sector */
39958a2b000SEvgeniy Ivanov 	memcpy(fp->f_ind_cache, &buf[file_block & ~IND_CACHE_MASK],
40058a2b000SEvgeniy Ivanov 	    IND_CACHE_SZ * sizeof fp->f_ind_cache[0]);
40158a2b000SEvgeniy Ivanov 	fp->f_ind_cache_block = ind_cache;
40258a2b000SEvgeniy Ivanov 
40358a2b000SEvgeniy Ivanov 	*disk_block_p = ind_block_num;
40458a2b000SEvgeniy Ivanov 
40558a2b000SEvgeniy Ivanov 	return 0;
40658a2b000SEvgeniy Ivanov }
40758a2b000SEvgeniy Ivanov 
40858a2b000SEvgeniy Ivanov /*
40958a2b000SEvgeniy Ivanov  * Read a portion of a file into an internal buffer.
41058a2b000SEvgeniy Ivanov  * Return the location in the buffer and the amount in the buffer.
41158a2b000SEvgeniy Ivanov  */
41258a2b000SEvgeniy Ivanov static int
buf_read_file(struct open_file * f,char ** buf_p,size_t * size_p)41358a2b000SEvgeniy Ivanov buf_read_file(struct open_file *f, char **buf_p, size_t *size_p)
41458a2b000SEvgeniy Ivanov {
41558a2b000SEvgeniy Ivanov 	struct file *fp = (struct file *)f->f_fsdata;
416*0a6a1f1dSLionel Sambuc 	FS *fs = fp->f_fs;
41758a2b000SEvgeniy Ivanov 	long off;
41858a2b000SEvgeniy Ivanov 	indp_t file_block;
41958a2b000SEvgeniy Ivanov 	size_t block_size;
42058a2b000SEvgeniy Ivanov 	int rc;
42158a2b000SEvgeniy Ivanov 
42284d9c625SLionel Sambuc 	off = ufs_blkoff(fs, fp->f_seekp);
42384d9c625SLionel Sambuc 	file_block = ufs_lblkno(fs, fp->f_seekp);
42458a2b000SEvgeniy Ivanov #ifdef LIBSA_LFS
42558a2b000SEvgeniy Ivanov 	block_size = dblksize(fs, &fp->f_di, file_block);
42658a2b000SEvgeniy Ivanov #else
42784d9c625SLionel Sambuc 	block_size = ffs_sblksize(fs, (int64_t)fp->f_di.di_size, file_block);
42858a2b000SEvgeniy Ivanov #endif
42958a2b000SEvgeniy Ivanov 
43058a2b000SEvgeniy Ivanov 	if (file_block != fp->f_buf_blkno) {
43184d9c625SLionel Sambuc 		indp_t disk_block = 0; /* XXX: gcc */
43258a2b000SEvgeniy Ivanov 		rc = block_map(f, file_block, &disk_block);
43358a2b000SEvgeniy Ivanov 		if (rc)
43458a2b000SEvgeniy Ivanov 			return rc;
43558a2b000SEvgeniy Ivanov 
43658a2b000SEvgeniy Ivanov 		if (disk_block == 0) {
43758a2b000SEvgeniy Ivanov 			memset(fp->f_buf, 0, block_size);
43858a2b000SEvgeniy Ivanov 			fp->f_buf_size = block_size;
43958a2b000SEvgeniy Ivanov 		} else {
44058a2b000SEvgeniy Ivanov 			twiddle();
44158a2b000SEvgeniy Ivanov 			rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
44258a2b000SEvgeniy Ivanov 				FSBTODB(fs, disk_block),
44358a2b000SEvgeniy Ivanov 				block_size, fp->f_buf, &fp->f_buf_size);
44458a2b000SEvgeniy Ivanov 			if (rc)
44558a2b000SEvgeniy Ivanov 				return rc;
44658a2b000SEvgeniy Ivanov 		}
44758a2b000SEvgeniy Ivanov 
44858a2b000SEvgeniy Ivanov 		fp->f_buf_blkno = file_block;
44958a2b000SEvgeniy Ivanov 	}
45058a2b000SEvgeniy Ivanov 
45158a2b000SEvgeniy Ivanov 	/*
45258a2b000SEvgeniy Ivanov 	 * Return address of byte in buffer corresponding to
45358a2b000SEvgeniy Ivanov 	 * offset, and size of remainder of buffer after that
45458a2b000SEvgeniy Ivanov 	 * byte.
45558a2b000SEvgeniy Ivanov 	 */
45658a2b000SEvgeniy Ivanov 	*buf_p = fp->f_buf + off;
45758a2b000SEvgeniy Ivanov 	*size_p = block_size - off;
45858a2b000SEvgeniy Ivanov 
45958a2b000SEvgeniy Ivanov 	/*
46058a2b000SEvgeniy Ivanov 	 * But truncate buffer at end of file.
46158a2b000SEvgeniy Ivanov 	 */
46258a2b000SEvgeniy Ivanov 	if (*size_p > fp->f_di.di_size - fp->f_seekp)
46358a2b000SEvgeniy Ivanov 		*size_p = fp->f_di.di_size - fp->f_seekp;
46458a2b000SEvgeniy Ivanov 
46558a2b000SEvgeniy Ivanov 	return 0;
46658a2b000SEvgeniy Ivanov }
46758a2b000SEvgeniy Ivanov 
46858a2b000SEvgeniy Ivanov /*
46958a2b000SEvgeniy Ivanov  * Search a directory for a name and return its
47058a2b000SEvgeniy Ivanov  * inode number.
47158a2b000SEvgeniy Ivanov  */
47258a2b000SEvgeniy Ivanov static int
search_directory(const char * name,int length,struct open_file * f,ino32_t * inumber_p)47358a2b000SEvgeniy Ivanov search_directory(const char *name, int length, struct open_file *f,
47458a2b000SEvgeniy Ivanov 	ino32_t *inumber_p)
47558a2b000SEvgeniy Ivanov {
47658a2b000SEvgeniy Ivanov 	struct file *fp = (struct file *)f->f_fsdata;
47758a2b000SEvgeniy Ivanov 	struct direct *dp;
47858a2b000SEvgeniy Ivanov 	struct direct *edp;
47958a2b000SEvgeniy Ivanov 	char *buf;
48058a2b000SEvgeniy Ivanov 	size_t buf_size;
48158a2b000SEvgeniy Ivanov 	int namlen;
48258a2b000SEvgeniy Ivanov 	int rc;
48358a2b000SEvgeniy Ivanov 
48458a2b000SEvgeniy Ivanov 	fp->f_seekp = 0;
48558a2b000SEvgeniy Ivanov 	while (fp->f_seekp < (off_t)fp->f_di.di_size) {
48658a2b000SEvgeniy Ivanov 		rc = buf_read_file(f, &buf, &buf_size);
48758a2b000SEvgeniy Ivanov 		if (rc)
48858a2b000SEvgeniy Ivanov 			return rc;
48958a2b000SEvgeniy Ivanov 
49058a2b000SEvgeniy Ivanov 		dp = (struct direct *)buf;
49158a2b000SEvgeniy Ivanov 		edp = (struct direct *)(buf + buf_size);
49258a2b000SEvgeniy Ivanov 		for (;dp < edp; dp = (void *)((char *)dp + dp->d_reclen)) {
49358a2b000SEvgeniy Ivanov 			if (dp->d_reclen <= 0)
49458a2b000SEvgeniy Ivanov 				break;
49558a2b000SEvgeniy Ivanov 			if (dp->d_ino == (ino32_t)0)
49658a2b000SEvgeniy Ivanov 				continue;
49758a2b000SEvgeniy Ivanov #if BYTE_ORDER == LITTLE_ENDIAN
49858a2b000SEvgeniy Ivanov 			if (fp->f_fs->fs_maxsymlinklen <= 0)
49958a2b000SEvgeniy Ivanov 				namlen = dp->d_type;
50058a2b000SEvgeniy Ivanov 			else
50158a2b000SEvgeniy Ivanov #endif
50258a2b000SEvgeniy Ivanov 				namlen = dp->d_namlen;
50358a2b000SEvgeniy Ivanov 			if (namlen == length &&
50458a2b000SEvgeniy Ivanov 			    !memcmp(name, dp->d_name, length)) {
50558a2b000SEvgeniy Ivanov 				/* found entry */
50658a2b000SEvgeniy Ivanov 				*inumber_p = dp->d_ino;
50758a2b000SEvgeniy Ivanov 				return 0;
50858a2b000SEvgeniy Ivanov 			}
50958a2b000SEvgeniy Ivanov 		}
51058a2b000SEvgeniy Ivanov 		fp->f_seekp += buf_size;
51158a2b000SEvgeniy Ivanov 	}
51258a2b000SEvgeniy Ivanov 	return ENOENT;
51358a2b000SEvgeniy Ivanov }
51458a2b000SEvgeniy Ivanov 
51558a2b000SEvgeniy Ivanov #ifdef LIBSA_FFSv2
51658a2b000SEvgeniy Ivanov 
51758a2b000SEvgeniy Ivanov daddr_t sblock_try[] = SBLOCKSEARCH;
51858a2b000SEvgeniy Ivanov 
51958a2b000SEvgeniy Ivanov static int
ffs_find_superblock(struct open_file * f,FS * fs)520*0a6a1f1dSLionel Sambuc ffs_find_superblock(struct open_file *f, FS *fs)
52158a2b000SEvgeniy Ivanov {
52258a2b000SEvgeniy Ivanov 	int i, rc;
52358a2b000SEvgeniy Ivanov 	size_t buf_size;
52458a2b000SEvgeniy Ivanov 
52558a2b000SEvgeniy Ivanov 	for (i = 0; sblock_try[i] != -1; i++) {
52658a2b000SEvgeniy Ivanov 		rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
52758a2b000SEvgeniy Ivanov 		    sblock_try[i] / DEV_BSIZE, SBLOCKSIZE, fs, &buf_size);
52858a2b000SEvgeniy Ivanov 		if (rc != 0 || buf_size != SBLOCKSIZE)
52958a2b000SEvgeniy Ivanov 			return rc;
53058a2b000SEvgeniy Ivanov 		if (fs->fs_sblockloc != sblock_try[i])
53158a2b000SEvgeniy Ivanov 			/* an alternate superblock - try again */
53258a2b000SEvgeniy Ivanov 			continue;
53358a2b000SEvgeniy Ivanov 		if (fs->fs_magic == FS_UFS2_MAGIC) {
53458a2b000SEvgeniy Ivanov 			return 0;
53558a2b000SEvgeniy Ivanov 		}
53658a2b000SEvgeniy Ivanov 	}
53758a2b000SEvgeniy Ivanov 	return EINVAL;
53858a2b000SEvgeniy Ivanov }
53958a2b000SEvgeniy Ivanov 
54058a2b000SEvgeniy Ivanov #endif
54158a2b000SEvgeniy Ivanov 
54258a2b000SEvgeniy Ivanov /*
54358a2b000SEvgeniy Ivanov  * Open a file.
54458a2b000SEvgeniy Ivanov  */
54558a2b000SEvgeniy Ivanov __compactcall int
ufs_open(const char * path,struct open_file * f)54658a2b000SEvgeniy Ivanov ufs_open(const char *path, struct open_file *f)
54758a2b000SEvgeniy Ivanov {
54858a2b000SEvgeniy Ivanov #ifndef LIBSA_FS_SINGLECOMPONENT
54958a2b000SEvgeniy Ivanov 	const char *cp, *ncp;
55058a2b000SEvgeniy Ivanov 	int c;
55158a2b000SEvgeniy Ivanov #endif
55258a2b000SEvgeniy Ivanov 	ino32_t inumber;
55358a2b000SEvgeniy Ivanov 	struct file *fp;
554*0a6a1f1dSLionel Sambuc 	FS *fs;
55558a2b000SEvgeniy Ivanov 	int rc;
55658a2b000SEvgeniy Ivanov #ifndef LIBSA_NO_FS_SYMLINK
55758a2b000SEvgeniy Ivanov 	ino32_t parent_inumber;
55858a2b000SEvgeniy Ivanov 	int nlinks = 0;
55958a2b000SEvgeniy Ivanov 	char namebuf[MAXPATHLEN+1];
56058a2b000SEvgeniy Ivanov 	char *buf;
56158a2b000SEvgeniy Ivanov #endif
56258a2b000SEvgeniy Ivanov 
56358a2b000SEvgeniy Ivanov 	/* allocate file system specific data structure */
56458a2b000SEvgeniy Ivanov 	fp = alloc(sizeof(struct file));
56558a2b000SEvgeniy Ivanov 	memset(fp, 0, sizeof(struct file));
56658a2b000SEvgeniy Ivanov 	f->f_fsdata = (void *)fp;
56758a2b000SEvgeniy Ivanov 
56858a2b000SEvgeniy Ivanov 	/* allocate space and read super block */
56958a2b000SEvgeniy Ivanov 	fs = alloc(SBLOCKSIZE);
57058a2b000SEvgeniy Ivanov 	fp->f_fs = fs;
57158a2b000SEvgeniy Ivanov 	twiddle();
57258a2b000SEvgeniy Ivanov 
57358a2b000SEvgeniy Ivanov #ifdef LIBSA_FFSv2
57458a2b000SEvgeniy Ivanov 	rc = ffs_find_superblock(f, fs);
57558a2b000SEvgeniy Ivanov 	if (rc)
57658a2b000SEvgeniy Ivanov 		goto out;
57758a2b000SEvgeniy Ivanov #else
57858a2b000SEvgeniy Ivanov 	{
57958a2b000SEvgeniy Ivanov 		size_t buf_size;
58058a2b000SEvgeniy Ivanov 		rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
58158a2b000SEvgeniy Ivanov 			SBLOCKOFFSET / DEV_BSIZE, SBLOCKSIZE, fs, &buf_size);
58258a2b000SEvgeniy Ivanov 		if (rc)
58358a2b000SEvgeniy Ivanov 			goto out;
58458a2b000SEvgeniy Ivanov 		if (buf_size != SBLOCKSIZE ||
58558a2b000SEvgeniy Ivanov #ifdef LIBSA_FFS
58658a2b000SEvgeniy Ivanov 		    fs->lfs_version != REQUIRED_LFS_VERSION ||
58758a2b000SEvgeniy Ivanov #endif
58858a2b000SEvgeniy Ivanov 		    fs->fs_magic != FS_MAGIC) {
58958a2b000SEvgeniy Ivanov 			rc = EINVAL;
59058a2b000SEvgeniy Ivanov 			goto out;
59158a2b000SEvgeniy Ivanov 		}
59258a2b000SEvgeniy Ivanov 	}
59358a2b000SEvgeniy Ivanov #if defined(LIBSA_LFS) && REQUIRED_LFS_VERSION == 2
59458a2b000SEvgeniy Ivanov 	/*
59558a2b000SEvgeniy Ivanov 	 * XXX	We should check the second superblock and use the eldest
59658a2b000SEvgeniy Ivanov 	 *	of the two.  See comments near the top of lfs_mountfs()
59758a2b000SEvgeniy Ivanov 	 *	in sys/ufs/lfs/lfs_vfsops.c.
59858a2b000SEvgeniy Ivanov 	 *      This may need a LIBSA_LFS_SMALL check as well.
59958a2b000SEvgeniy Ivanov 	 */
60058a2b000SEvgeniy Ivanov #endif
601*0a6a1f1dSLionel Sambuc #if defined(LIBSA_LFS)
602*0a6a1f1dSLionel Sambuc 	fs->lfs_is64 = 0;
603*0a6a1f1dSLionel Sambuc 	fs->lfs_dobyteswap = 0;
604*0a6a1f1dSLionel Sambuc 	fs->lfs_hasolddirfmt = (fs->fs_maxsymlinklen <= 0);
605*0a6a1f1dSLionel Sambuc #endif
60658a2b000SEvgeniy Ivanov #endif
60758a2b000SEvgeniy Ivanov 
60858a2b000SEvgeniy Ivanov #ifdef LIBSA_FFSv1
60958a2b000SEvgeniy Ivanov 	ffs_oldfscompat(fs);
61058a2b000SEvgeniy Ivanov #endif
61158a2b000SEvgeniy Ivanov 
61258a2b000SEvgeniy Ivanov 	if (fs->fs_bsize > MAXBSIZE ||
613*0a6a1f1dSLionel Sambuc 	    (size_t)fs->fs_bsize < sizeof(FS)) {
61458a2b000SEvgeniy Ivanov 		rc = EINVAL;
61558a2b000SEvgeniy Ivanov 		goto out;
61658a2b000SEvgeniy Ivanov 	}
61758a2b000SEvgeniy Ivanov 
61858a2b000SEvgeniy Ivanov 	/*
61958a2b000SEvgeniy Ivanov 	 * Calculate indirect block levels.
62058a2b000SEvgeniy Ivanov 	 */
62158a2b000SEvgeniy Ivanov 	{
62258a2b000SEvgeniy Ivanov 		indp_t mult;
62358a2b000SEvgeniy Ivanov 		int ln2;
62458a2b000SEvgeniy Ivanov 
62558a2b000SEvgeniy Ivanov 		/*
62658a2b000SEvgeniy Ivanov 		 * We note that the number of indirect blocks is always
62758a2b000SEvgeniy Ivanov 		 * a power of 2.  This lets us use shifts and masks instead
62858a2b000SEvgeniy Ivanov 		 * of divide and remainder and avoinds pulling in the
62958a2b000SEvgeniy Ivanov 		 * 64bit division routine into the boot code.
63058a2b000SEvgeniy Ivanov 		 */
63184d9c625SLionel Sambuc 		mult = UFS_NINDIR(fs);
63258a2b000SEvgeniy Ivanov #ifdef DEBUG
63358a2b000SEvgeniy Ivanov 		if (mult & (mult - 1)) {
63458a2b000SEvgeniy Ivanov 			/* Hummm was't a power of 2 */
63558a2b000SEvgeniy Ivanov 			rc = EINVAL;
63658a2b000SEvgeniy Ivanov 			goto out;
63758a2b000SEvgeniy Ivanov 		}
63858a2b000SEvgeniy Ivanov #endif
63958a2b000SEvgeniy Ivanov 		for (ln2 = 0; mult != 1; ln2++)
64058a2b000SEvgeniy Ivanov 			mult >>= 1;
64158a2b000SEvgeniy Ivanov 
64258a2b000SEvgeniy Ivanov 		fp->f_nishift = ln2;
64358a2b000SEvgeniy Ivanov 	}
64458a2b000SEvgeniy Ivanov 
64558a2b000SEvgeniy Ivanov 	/* alloc a block sized buffer used for all fs transfers */
64658a2b000SEvgeniy Ivanov 	fp->f_buf = alloc(fs->fs_bsize);
64784d9c625SLionel Sambuc 	inumber = UFS_ROOTINO;
64858a2b000SEvgeniy Ivanov 	if ((rc = read_inode(inumber, f)) != 0)
64958a2b000SEvgeniy Ivanov 		goto out;
65058a2b000SEvgeniy Ivanov 
65158a2b000SEvgeniy Ivanov #ifndef LIBSA_FS_SINGLECOMPONENT
65258a2b000SEvgeniy Ivanov 	cp = path;
65358a2b000SEvgeniy Ivanov 	while (*cp) {
65458a2b000SEvgeniy Ivanov 
65558a2b000SEvgeniy Ivanov 		/*
65658a2b000SEvgeniy Ivanov 		 * Remove extra separators
65758a2b000SEvgeniy Ivanov 		 */
65858a2b000SEvgeniy Ivanov 		while (*cp == '/')
65958a2b000SEvgeniy Ivanov 			cp++;
66058a2b000SEvgeniy Ivanov 		if (*cp == '\0')
66158a2b000SEvgeniy Ivanov 			break;
66258a2b000SEvgeniy Ivanov 
66358a2b000SEvgeniy Ivanov 		/*
66458a2b000SEvgeniy Ivanov 		 * Check that current node is a directory.
66558a2b000SEvgeniy Ivanov 		 */
66658a2b000SEvgeniy Ivanov 		if ((fp->f_di.di_mode & IFMT) != IFDIR) {
66758a2b000SEvgeniy Ivanov 			rc = ENOTDIR;
66858a2b000SEvgeniy Ivanov 			goto out;
66958a2b000SEvgeniy Ivanov 		}
67058a2b000SEvgeniy Ivanov 
67158a2b000SEvgeniy Ivanov 		/*
67258a2b000SEvgeniy Ivanov 		 * Get next component of path name.
67358a2b000SEvgeniy Ivanov 		 */
67458a2b000SEvgeniy Ivanov 		ncp = cp;
67558a2b000SEvgeniy Ivanov 		while ((c = *cp) != '\0' && c != '/')
67658a2b000SEvgeniy Ivanov 			cp++;
67758a2b000SEvgeniy Ivanov 
67858a2b000SEvgeniy Ivanov 		/*
67958a2b000SEvgeniy Ivanov 		 * Look up component in current directory.
68058a2b000SEvgeniy Ivanov 		 * Save directory inumber in case we find a
68158a2b000SEvgeniy Ivanov 		 * symbolic link.
68258a2b000SEvgeniy Ivanov 		 */
68358a2b000SEvgeniy Ivanov #ifndef LIBSA_NO_FS_SYMLINK
68458a2b000SEvgeniy Ivanov 		parent_inumber = inumber;
68558a2b000SEvgeniy Ivanov #endif
68658a2b000SEvgeniy Ivanov 		rc = search_directory(ncp, cp - ncp, f, &inumber);
68758a2b000SEvgeniy Ivanov 		if (rc)
68858a2b000SEvgeniy Ivanov 			goto out;
68958a2b000SEvgeniy Ivanov 
69058a2b000SEvgeniy Ivanov 		/*
69158a2b000SEvgeniy Ivanov 		 * Open next component.
69258a2b000SEvgeniy Ivanov 		 */
69358a2b000SEvgeniy Ivanov 		if ((rc = read_inode(inumber, f)) != 0)
69458a2b000SEvgeniy Ivanov 			goto out;
69558a2b000SEvgeniy Ivanov 
69658a2b000SEvgeniy Ivanov #ifndef LIBSA_NO_FS_SYMLINK
69758a2b000SEvgeniy Ivanov 		/*
69858a2b000SEvgeniy Ivanov 		 * Check for symbolic link.
69958a2b000SEvgeniy Ivanov 		 */
70058a2b000SEvgeniy Ivanov 		if ((fp->f_di.di_mode & IFMT) == IFLNK) {
70158a2b000SEvgeniy Ivanov 			int link_len = fp->f_di.di_size;
70258a2b000SEvgeniy Ivanov 			int len;
70358a2b000SEvgeniy Ivanov 
70458a2b000SEvgeniy Ivanov 			len = strlen(cp);
70558a2b000SEvgeniy Ivanov 
70658a2b000SEvgeniy Ivanov 			if (link_len + len > MAXPATHLEN ||
70758a2b000SEvgeniy Ivanov 			    ++nlinks > MAXSYMLINKS) {
70858a2b000SEvgeniy Ivanov 				rc = ENOENT;
70958a2b000SEvgeniy Ivanov 				goto out;
71058a2b000SEvgeniy Ivanov 			}
71158a2b000SEvgeniy Ivanov 
71258a2b000SEvgeniy Ivanov 			memmove(&namebuf[link_len], cp, len + 1);
71358a2b000SEvgeniy Ivanov 
71458a2b000SEvgeniy Ivanov 			if (link_len < fs->fs_maxsymlinklen) {
71558a2b000SEvgeniy Ivanov 				memcpy(namebuf, fp->f_di.di_db, link_len);
71658a2b000SEvgeniy Ivanov 			} else {
71758a2b000SEvgeniy Ivanov 				/*
71858a2b000SEvgeniy Ivanov 				 * Read file for symbolic link
71958a2b000SEvgeniy Ivanov 				 */
72058a2b000SEvgeniy Ivanov 				size_t buf_size;
72158a2b000SEvgeniy Ivanov 				indp_t	disk_block;
72258a2b000SEvgeniy Ivanov 
72358a2b000SEvgeniy Ivanov 				buf = fp->f_buf;
72458a2b000SEvgeniy Ivanov 				rc = block_map(f, (indp_t)0, &disk_block);
72558a2b000SEvgeniy Ivanov 				if (rc)
72658a2b000SEvgeniy Ivanov 					goto out;
72758a2b000SEvgeniy Ivanov 
72858a2b000SEvgeniy Ivanov 				twiddle();
72958a2b000SEvgeniy Ivanov 				rc = DEV_STRATEGY(f->f_dev)(f->f_devdata,
73058a2b000SEvgeniy Ivanov 					F_READ, FSBTODB(fs, disk_block),
73158a2b000SEvgeniy Ivanov 					fs->fs_bsize, buf, &buf_size);
73258a2b000SEvgeniy Ivanov 				if (rc)
73358a2b000SEvgeniy Ivanov 					goto out;
73458a2b000SEvgeniy Ivanov 
73558a2b000SEvgeniy Ivanov 				memcpy(namebuf, buf, link_len);
73658a2b000SEvgeniy Ivanov 			}
73758a2b000SEvgeniy Ivanov 
73858a2b000SEvgeniy Ivanov 			/*
73958a2b000SEvgeniy Ivanov 			 * If relative pathname, restart at parent directory.
74058a2b000SEvgeniy Ivanov 			 * If absolute pathname, restart at root.
74158a2b000SEvgeniy Ivanov 			 */
74258a2b000SEvgeniy Ivanov 			cp = namebuf;
74358a2b000SEvgeniy Ivanov 			if (*cp != '/')
74458a2b000SEvgeniy Ivanov 				inumber = parent_inumber;
74558a2b000SEvgeniy Ivanov 			else
74684d9c625SLionel Sambuc 				inumber = (ino32_t)UFS_ROOTINO;
74758a2b000SEvgeniy Ivanov 
74858a2b000SEvgeniy Ivanov 			if ((rc = read_inode(inumber, f)) != 0)
74958a2b000SEvgeniy Ivanov 				goto out;
75058a2b000SEvgeniy Ivanov 		}
75158a2b000SEvgeniy Ivanov #endif	/* !LIBSA_NO_FS_SYMLINK */
75258a2b000SEvgeniy Ivanov 	}
75358a2b000SEvgeniy Ivanov 
75458a2b000SEvgeniy Ivanov 	/*
75558a2b000SEvgeniy Ivanov 	 * Found terminal component.
75658a2b000SEvgeniy Ivanov 	 */
75758a2b000SEvgeniy Ivanov 	rc = 0;
75858a2b000SEvgeniy Ivanov 
75958a2b000SEvgeniy Ivanov #else /* !LIBSA_FS_SINGLECOMPONENT */
76058a2b000SEvgeniy Ivanov 
76158a2b000SEvgeniy Ivanov 	/* look up component in the current (root) directory */
76258a2b000SEvgeniy Ivanov 	rc = search_directory(path, strlen(path), f, &inumber);
76358a2b000SEvgeniy Ivanov 	if (rc)
76458a2b000SEvgeniy Ivanov 		goto out;
76558a2b000SEvgeniy Ivanov 
76658a2b000SEvgeniy Ivanov 	/* open it */
76758a2b000SEvgeniy Ivanov 	rc = read_inode(inumber, f);
76858a2b000SEvgeniy Ivanov 
76958a2b000SEvgeniy Ivanov #endif /* !LIBSA_FS_SINGLECOMPONENT */
77058a2b000SEvgeniy Ivanov 
77158a2b000SEvgeniy Ivanov 	fp->f_seekp = 0;		/* reset seek pointer */
77258a2b000SEvgeniy Ivanov 
77358a2b000SEvgeniy Ivanov out:
77458a2b000SEvgeniy Ivanov 	if (rc)
77558a2b000SEvgeniy Ivanov 		ufs_close(f);
77684d9c625SLionel Sambuc #ifdef FSMOD		/* Only defined for lfs */
777*0a6a1f1dSLionel Sambuc 	else
77858a2b000SEvgeniy Ivanov 		fsmod = FSMOD;
77958a2b000SEvgeniy Ivanov #endif
78058a2b000SEvgeniy Ivanov 	return rc;
78158a2b000SEvgeniy Ivanov }
78258a2b000SEvgeniy Ivanov 
78358a2b000SEvgeniy Ivanov __compactcall int
ufs_close(struct open_file * f)78458a2b000SEvgeniy Ivanov ufs_close(struct open_file *f)
78558a2b000SEvgeniy Ivanov {
78658a2b000SEvgeniy Ivanov 	struct file *fp = (struct file *)f->f_fsdata;
78758a2b000SEvgeniy Ivanov 
78858a2b000SEvgeniy Ivanov 	f->f_fsdata = NULL;
78958a2b000SEvgeniy Ivanov 	if (fp == NULL)
79058a2b000SEvgeniy Ivanov 		return 0;
79158a2b000SEvgeniy Ivanov 
79258a2b000SEvgeniy Ivanov 	if (fp->f_buf)
79358a2b000SEvgeniy Ivanov 		dealloc(fp->f_buf, fp->f_fs->fs_bsize);
79458a2b000SEvgeniy Ivanov 	dealloc(fp->f_fs, SBLOCKSIZE);
79558a2b000SEvgeniy Ivanov 	dealloc(fp, sizeof(struct file));
79658a2b000SEvgeniy Ivanov 	return 0;
79758a2b000SEvgeniy Ivanov }
79858a2b000SEvgeniy Ivanov 
79958a2b000SEvgeniy Ivanov /*
80058a2b000SEvgeniy Ivanov  * Copy a portion of a file into kernel memory.
80158a2b000SEvgeniy Ivanov  * Cross block boundaries when necessary.
80258a2b000SEvgeniy Ivanov  */
80358a2b000SEvgeniy Ivanov __compactcall int
ufs_read(struct open_file * f,void * start,size_t size,size_t * resid)80458a2b000SEvgeniy Ivanov ufs_read(struct open_file *f, void *start, size_t size, size_t *resid)
80558a2b000SEvgeniy Ivanov {
80658a2b000SEvgeniy Ivanov 	struct file *fp = (struct file *)f->f_fsdata;
80758a2b000SEvgeniy Ivanov 	size_t csize;
80858a2b000SEvgeniy Ivanov 	char *buf;
80958a2b000SEvgeniy Ivanov 	size_t buf_size;
81058a2b000SEvgeniy Ivanov 	int rc = 0;
81158a2b000SEvgeniy Ivanov 	char *addr = start;
81258a2b000SEvgeniy Ivanov 
81358a2b000SEvgeniy Ivanov 	while (size != 0) {
81458a2b000SEvgeniy Ivanov 		if (fp->f_seekp >= (off_t)fp->f_di.di_size)
81558a2b000SEvgeniy Ivanov 			break;
81658a2b000SEvgeniy Ivanov 
81758a2b000SEvgeniy Ivanov 		rc = buf_read_file(f, &buf, &buf_size);
81858a2b000SEvgeniy Ivanov 		if (rc)
81958a2b000SEvgeniy Ivanov 			break;
82058a2b000SEvgeniy Ivanov 
82158a2b000SEvgeniy Ivanov 		csize = size;
82258a2b000SEvgeniy Ivanov 		if (csize > buf_size)
82358a2b000SEvgeniy Ivanov 			csize = buf_size;
82458a2b000SEvgeniy Ivanov 
82558a2b000SEvgeniy Ivanov 		memcpy(addr, buf, csize);
82658a2b000SEvgeniy Ivanov 
82758a2b000SEvgeniy Ivanov 		fp->f_seekp += csize;
82858a2b000SEvgeniy Ivanov 		addr += csize;
82958a2b000SEvgeniy Ivanov 		size -= csize;
83058a2b000SEvgeniy Ivanov 	}
83158a2b000SEvgeniy Ivanov 	if (resid)
83258a2b000SEvgeniy Ivanov 		*resid = size;
83358a2b000SEvgeniy Ivanov 	return rc;
83458a2b000SEvgeniy Ivanov }
83558a2b000SEvgeniy Ivanov 
83658a2b000SEvgeniy Ivanov /*
83758a2b000SEvgeniy Ivanov  * Not implemented.
83858a2b000SEvgeniy Ivanov  */
83958a2b000SEvgeniy Ivanov #ifndef LIBSA_NO_FS_WRITE
84058a2b000SEvgeniy Ivanov __compactcall int
ufs_write(struct open_file * f,void * start,size_t size,size_t * resid)84158a2b000SEvgeniy Ivanov ufs_write(struct open_file *f, void *start, size_t size, size_t *resid)
84258a2b000SEvgeniy Ivanov {
84358a2b000SEvgeniy Ivanov 
84458a2b000SEvgeniy Ivanov 	return EROFS;
84558a2b000SEvgeniy Ivanov }
84658a2b000SEvgeniy Ivanov #endif /* !LIBSA_NO_FS_WRITE */
84758a2b000SEvgeniy Ivanov 
84858a2b000SEvgeniy Ivanov #ifndef LIBSA_NO_FS_SEEK
84958a2b000SEvgeniy Ivanov __compactcall off_t
ufs_seek(struct open_file * f,off_t offset,int where)85058a2b000SEvgeniy Ivanov ufs_seek(struct open_file *f, off_t offset, int where)
85158a2b000SEvgeniy Ivanov {
85258a2b000SEvgeniy Ivanov 	struct file *fp = (struct file *)f->f_fsdata;
85358a2b000SEvgeniy Ivanov 
85458a2b000SEvgeniy Ivanov 	switch (where) {
85558a2b000SEvgeniy Ivanov 	case SEEK_SET:
85658a2b000SEvgeniy Ivanov 		fp->f_seekp = offset;
85758a2b000SEvgeniy Ivanov 		break;
85858a2b000SEvgeniy Ivanov 	case SEEK_CUR:
85958a2b000SEvgeniy Ivanov 		fp->f_seekp += offset;
86058a2b000SEvgeniy Ivanov 		break;
86158a2b000SEvgeniy Ivanov 	case SEEK_END:
86258a2b000SEvgeniy Ivanov 		fp->f_seekp = fp->f_di.di_size - offset;
86358a2b000SEvgeniy Ivanov 		break;
86458a2b000SEvgeniy Ivanov 	default:
86558a2b000SEvgeniy Ivanov 		return -1;
86658a2b000SEvgeniy Ivanov 	}
86758a2b000SEvgeniy Ivanov 	return fp->f_seekp;
86858a2b000SEvgeniy Ivanov }
86958a2b000SEvgeniy Ivanov #endif /* !LIBSA_NO_FS_SEEK */
87058a2b000SEvgeniy Ivanov 
87158a2b000SEvgeniy Ivanov __compactcall int
ufs_stat(struct open_file * f,struct stat * sb)87258a2b000SEvgeniy Ivanov ufs_stat(struct open_file *f, struct stat *sb)
87358a2b000SEvgeniy Ivanov {
87458a2b000SEvgeniy Ivanov 	struct file *fp = (struct file *)f->f_fsdata;
87558a2b000SEvgeniy Ivanov 
87658a2b000SEvgeniy Ivanov 	/* only important stuff */
87758a2b000SEvgeniy Ivanov 	memset(sb, 0, sizeof *sb);
87858a2b000SEvgeniy Ivanov 	sb->st_mode = fp->f_di.di_mode;
87958a2b000SEvgeniy Ivanov 	sb->st_uid = fp->f_di.di_uid;
88058a2b000SEvgeniy Ivanov 	sb->st_gid = fp->f_di.di_gid;
88158a2b000SEvgeniy Ivanov 	sb->st_size = fp->f_di.di_size;
88258a2b000SEvgeniy Ivanov 	return 0;
88358a2b000SEvgeniy Ivanov }
88458a2b000SEvgeniy Ivanov 
88558a2b000SEvgeniy Ivanov #if defined(LIBSA_ENABLE_LS_OP)
886*0a6a1f1dSLionel Sambuc 
887*0a6a1f1dSLionel Sambuc #include "ls.h"
888*0a6a1f1dSLionel Sambuc 
889*0a6a1f1dSLionel Sambuc static const char    *const typestr[] = {
890*0a6a1f1dSLionel Sambuc 	"unknown",
891*0a6a1f1dSLionel Sambuc 	"FIFO",
892*0a6a1f1dSLionel Sambuc 	"CHR",
893*0a6a1f1dSLionel Sambuc 	0,
894*0a6a1f1dSLionel Sambuc 	"DIR",
895*0a6a1f1dSLionel Sambuc 	0,
896*0a6a1f1dSLionel Sambuc 	"BLK",
897*0a6a1f1dSLionel Sambuc 	0,
898*0a6a1f1dSLionel Sambuc 	"REG",
899*0a6a1f1dSLionel Sambuc 	0,
900*0a6a1f1dSLionel Sambuc 	"LNK",
901*0a6a1f1dSLionel Sambuc 	0,
902*0a6a1f1dSLionel Sambuc 	"SOCK",
903*0a6a1f1dSLionel Sambuc 	0,
904*0a6a1f1dSLionel Sambuc 	"WHT"
905*0a6a1f1dSLionel Sambuc };
906*0a6a1f1dSLionel Sambuc 
90758a2b000SEvgeniy Ivanov __compactcall void
ufs_ls(struct open_file * f,const char * pattern)908*0a6a1f1dSLionel Sambuc ufs_ls(struct open_file *f, const char *pattern)
90958a2b000SEvgeniy Ivanov {
91058a2b000SEvgeniy Ivanov 	struct file *fp = (struct file *)f->f_fsdata;
91158a2b000SEvgeniy Ivanov 	char *buf;
91258a2b000SEvgeniy Ivanov 	size_t buf_size;
913*0a6a1f1dSLionel Sambuc 	lsentry_t *names = NULL;
91458a2b000SEvgeniy Ivanov 
91558a2b000SEvgeniy Ivanov 	fp->f_seekp = 0;
91658a2b000SEvgeniy Ivanov 	while (fp->f_seekp < (off_t)fp->f_di.di_size) {
91758a2b000SEvgeniy Ivanov 		struct direct  *dp, *edp;
91858a2b000SEvgeniy Ivanov 		int rc = buf_read_file(f, &buf, &buf_size);
91958a2b000SEvgeniy Ivanov 		if (rc)
92058a2b000SEvgeniy Ivanov 			goto out;
92158a2b000SEvgeniy Ivanov 		/* some firmware might use block size larger than DEV_BSIZE */
92284d9c625SLionel Sambuc 		if (buf_size < UFS_DIRBLKSIZ)
92358a2b000SEvgeniy Ivanov 			goto out;
92458a2b000SEvgeniy Ivanov 
92558a2b000SEvgeniy Ivanov 		dp = (struct direct *)buf;
92658a2b000SEvgeniy Ivanov 		edp = (struct direct *)(buf + buf_size);
92758a2b000SEvgeniy Ivanov 
92858a2b000SEvgeniy Ivanov 		for (; dp < edp; dp = (void *)((char *)dp + dp->d_reclen)) {
92958a2b000SEvgeniy Ivanov 			const char *t;
93058a2b000SEvgeniy Ivanov 			if (dp->d_ino ==  0)
93158a2b000SEvgeniy Ivanov 				continue;
93258a2b000SEvgeniy Ivanov 
93358a2b000SEvgeniy Ivanov 			if (dp->d_type >= NELEM(typestr) ||
93458a2b000SEvgeniy Ivanov 			    !(t = typestr[dp->d_type])) {
93558a2b000SEvgeniy Ivanov 				/*
93658a2b000SEvgeniy Ivanov 				 * This does not handle "old"
93758a2b000SEvgeniy Ivanov 				 * filesystems properly. On little
93858a2b000SEvgeniy Ivanov 				 * endian machines, we get a bogus
93958a2b000SEvgeniy Ivanov 				 * type name if the namlen matches a
94058a2b000SEvgeniy Ivanov 				 * valid type identifier. We could
94158a2b000SEvgeniy Ivanov 				 * check if we read namlen "0" and
94258a2b000SEvgeniy Ivanov 				 * handle this case specially, if
94358a2b000SEvgeniy Ivanov 				 * there were a pressing need...
94458a2b000SEvgeniy Ivanov 				 */
94558a2b000SEvgeniy Ivanov 				printf("bad dir entry\n");
94658a2b000SEvgeniy Ivanov 				goto out;
94758a2b000SEvgeniy Ivanov 			}
948*0a6a1f1dSLionel Sambuc 			lsadd(&names, pattern, dp->d_name, strlen(dp->d_name),
949*0a6a1f1dSLionel Sambuc 			    dp->d_ino, t);
95058a2b000SEvgeniy Ivanov 		}
95158a2b000SEvgeniy Ivanov 		fp->f_seekp += buf_size;
95258a2b000SEvgeniy Ivanov 	}
953*0a6a1f1dSLionel Sambuc 	lsprint(names);
954*0a6a1f1dSLionel Sambuc out:	lsfree(names);
955*0a6a1f1dSLionel Sambuc }
95658a2b000SEvgeniy Ivanov 
957*0a6a1f1dSLionel Sambuc #if defined(__minix) && defined(LIBSA_ENABLE_LOAD_MODS_OP)
958*0a6a1f1dSLionel Sambuc __compactcall void
ufs_load_mods(struct open_file * f,const char * pattern,void (* funcp)(char *),char * path)959*0a6a1f1dSLionel Sambuc ufs_load_mods(struct open_file *f, const char *pattern,
960*0a6a1f1dSLionel Sambuc 	void (*funcp)(char *), char *path)
961*0a6a1f1dSLionel Sambuc {
962*0a6a1f1dSLionel Sambuc 	load_modsunsup("ufs");
96358a2b000SEvgeniy Ivanov }
964*0a6a1f1dSLionel Sambuc #endif /* defined(__minix) && defined(LIBSA_ENABLE_LOAD_MODS_OP) */
96558a2b000SEvgeniy Ivanov #endif /* LIBSA_ENABLE_LS_OP */
96658a2b000SEvgeniy Ivanov 
96758a2b000SEvgeniy Ivanov #ifdef LIBSA_FFSv1
96858a2b000SEvgeniy Ivanov /*
96958a2b000SEvgeniy Ivanov  * Sanity checks for old file systems.
97058a2b000SEvgeniy Ivanov  *
97158a2b000SEvgeniy Ivanov  * XXX - goes away some day.
97258a2b000SEvgeniy Ivanov  * Stripped of stuff libsa doesn't need.....
97358a2b000SEvgeniy Ivanov  */
97458a2b000SEvgeniy Ivanov static void
ffs_oldfscompat(FS * fs)975*0a6a1f1dSLionel Sambuc ffs_oldfscompat(FS *fs)
97658a2b000SEvgeniy Ivanov {
97758a2b000SEvgeniy Ivanov 
97858a2b000SEvgeniy Ivanov #ifdef COMPAT_UFS
97958a2b000SEvgeniy Ivanov 	/*
98058a2b000SEvgeniy Ivanov 	 * Newer Solaris versions have a slightly incompatible
98158a2b000SEvgeniy Ivanov 	 * superblock - so always calculate this values on the fly, which
98258a2b000SEvgeniy Ivanov 	 * is good enough for libsa purposes
98358a2b000SEvgeniy Ivanov 	 */
98458a2b000SEvgeniy Ivanov 	if (fs->fs_magic == FS_UFS1_MAGIC
98558a2b000SEvgeniy Ivanov #ifndef COMPAT_SOLARIS_UFS
98658a2b000SEvgeniy Ivanov 	    && fs->fs_old_inodefmt < FS_44INODEFMT
98758a2b000SEvgeniy Ivanov #endif
98858a2b000SEvgeniy Ivanov 	    ) {
98958a2b000SEvgeniy Ivanov 		fs->fs_qbmask = ~fs->fs_bmask;
99058a2b000SEvgeniy Ivanov 		fs->fs_qfmask = ~fs->fs_fmask;
99158a2b000SEvgeniy Ivanov 	}
99258a2b000SEvgeniy Ivanov #endif
99358a2b000SEvgeniy Ivanov }
99458a2b000SEvgeniy Ivanov #endif
995