Module Name:    src
Committed By:   christos
Date:           Mon Jan 16 18:44:13 UTC 2012

Modified Files:
        src/sys/lib/libsa: Makefile ext2fs.c stand.h ufs.c
Added Files:
        src/sys/lib/libsa: fnmatch.c minixfs3.c minixfs3.h

Log Message:
PR/45796: Evgeniy Ivanov minixfs3 support.
Split out fn_match since we have 3 copies now.


To generate a diff of this commit:
cvs rdiff -u -r1.76 -r1.77 src/sys/lib/libsa/Makefile
cvs rdiff -u -r1.11 -r1.12 src/sys/lib/libsa/ext2fs.c
cvs rdiff -u -r0 -r1.1 src/sys/lib/libsa/fnmatch.c \
    src/sys/lib/libsa/minixfs3.c src/sys/lib/libsa/minixfs3.h
cvs rdiff -u -r1.74 -r1.75 src/sys/lib/libsa/stand.h
cvs rdiff -u -r1.56 -r1.57 src/sys/lib/libsa/ufs.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/lib/libsa/Makefile
diff -u src/sys/lib/libsa/Makefile:1.76 src/sys/lib/libsa/Makefile:1.77
--- src/sys/lib/libsa/Makefile:1.76	Sun Dec 25 01:09:08 2011
+++ src/sys/lib/libsa/Makefile	Mon Jan 16 13:44:13 2012
@@ -1,4 +1,4 @@
-#	$NetBSD: Makefile,v 1.76 2011/12/25 06:09:08 tsutsui Exp $
+#	$NetBSD: Makefile,v 1.77 2012/01/16 18:44:13 christos Exp $
 
 LIB=	sa
 NOPIC=	# defined
@@ -75,6 +75,8 @@ SRCS+=	cd9660.c
 SRCS+=	ustarfs.c
 SRCS+=	dosfs.c
 SRCS+=	ext2fs.c
+SRCS+=	minixfs3.c
+SRCS+=	fnmatch.c
 # for historic compatibility ufs == ffsv1
 SRCS+=	ufs.c
 

Index: src/sys/lib/libsa/ext2fs.c
diff -u src/sys/lib/libsa/ext2fs.c:1.11 src/sys/lib/libsa/ext2fs.c:1.12
--- src/sys/lib/libsa/ext2fs.c:1.11	Sun Dec 25 01:09:08 2011
+++ src/sys/lib/libsa/ext2fs.c	Mon Jan 16 13:44:13 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: ext2fs.c,v 1.11 2011/12/25 06:09:08 tsutsui Exp $	*/
+/*	$NetBSD: ext2fs.c,v 1.12 2012/01/16 18:44:13 christos Exp $	*/
 
 /*
  * Copyright (c) 1997 Manuel Bouyer.
@@ -169,34 +169,6 @@ static const char    *const typestr[] = 
 	"LNK"
 };
 
-static int
-fn_match(const char *fname, const char *pattern)
-{
-	char fc, pc;
-
-	do {
-		fc = *fname++;
-		pc = *pattern++;
-		if (!fc && !pc)
-			return 1;
-		if (pc == '?' && fc)
-			pc = fc;
-	} while (fc == pc);
-
-	if (pc != '*')
-		return 0;
-	/*
-	 * Too hard (and unnecessary really) too check for "*?name" etc....
-	 * "**" will look for a '*' and "*?" a '?'
-	 */
-	pc = *pattern++;
-	if (!pc)
-		return 1;
-	while ((fname = strchr(fname, pc)))
-		if (fn_match(++fname, pattern))
-			return 1;
-	return 0;
-}
 #endif /* LIBSA_ENABLE_LS_OP */
 
 static int read_inode(ino32_t, struct open_file *);
@@ -903,7 +875,7 @@ ext2fs_ls(struct open_file *f, const cha
 				printf("bad dir entry\n");
 				goto out;
 			}
-			if (pattern && !fn_match(dp->e2d_name, pattern))
+			if (pattern && !fnmatch(dp->e2d_name, pattern))
 				continue;
 			n = alloc(sizeof *n + strlen(dp->e2d_name));
 			if (!n) {

Index: src/sys/lib/libsa/stand.h
diff -u src/sys/lib/libsa/stand.h:1.74 src/sys/lib/libsa/stand.h:1.75
--- src/sys/lib/libsa/stand.h:1.74	Sun Dec 25 01:09:08 2011
+++ src/sys/lib/libsa/stand.h	Mon Jan 16 13:44:13 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: stand.h,v 1.74 2011/12/25 06:09:08 tsutsui Exp $	*/
+/*	$NetBSD: stand.h,v 1.75 2012/01/16 18:44:13 christos Exp $	*/
 
 /*
  * Copyright (c) 1999 Christopher G. Demetriou.  All rights reserved.
@@ -320,6 +320,8 @@ off_t	olseek(int, off_t, int);
 
 extern const char hexdigits[];
 
+int	fnmatch(const char *, const char *);
+
 /* XXX: These should be removed eventually. */
 void	bcopy(const void *, void *, size_t);
 void	bzero(void *, size_t);

Index: src/sys/lib/libsa/ufs.c
diff -u src/sys/lib/libsa/ufs.c:1.56 src/sys/lib/libsa/ufs.c:1.57
--- src/sys/lib/libsa/ufs.c:1.56	Sun Dec 25 01:09:08 2011
+++ src/sys/lib/libsa/ufs.c	Mon Jan 16 13:44:13 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: ufs.c,v 1.56 2011/12/25 06:09:08 tsutsui Exp $	*/
+/*	$NetBSD: ufs.c,v 1.57 2012/01/16 18:44:13 christos Exp $	*/
 
 /*-
  * Copyright (c) 1993
@@ -208,35 +208,6 @@ static const char    *const typestr[] = 
 	0,
 	"WHT"
 };
-
-static int
-fn_match(const char *fname, const char *pattern)
-{
-	char fc, pc;
-
-	do {
-		fc = *fname++;
-		pc = *pattern++;
-		if (!fc && !pc)
-			return 1;
-		if (pc == '?' && fc)
-			pc = fc;
-	} while (fc == pc);
-
-	if (pc != '*')
-		return 0;
-	/*
-	 * Too hard (and unnecessary really) too check for "*?name" etc....
-	 * "**" will look for a '*' and "*?" a '?'
-	 */
-	pc = *pattern++;
-	if (!pc)
-		return 1;
-	while ((fname = strchr(fname, pc)))
-		if (fn_match(++fname, pattern))
-			return 1;
-	return 0;
-}
 #endif /* LIBSA_ENABLE_LS_OP */
 
 #ifdef LIBSA_LFS
@@ -954,7 +925,7 @@ ufs_ls(struct open_file *f, const char *
 				printf("bad dir entry\n");
 				goto out;
 			}
-			if (pattern && !fn_match(dp->d_name, pattern))
+			if (pattern && !fnmatch(dp->d_name, pattern))
 				continue;
 			n = alloc(sizeof *n + strlen(dp->d_name));
 			if (!n) {

Added files:

Index: src/sys/lib/libsa/fnmatch.c
diff -u /dev/null src/sys/lib/libsa/fnmatch.c:1.1
--- /dev/null	Mon Jan 16 13:44:13 2012
+++ src/sys/lib/libsa/fnmatch.c	Mon Jan 16 13:44:13 2012
@@ -0,0 +1,93 @@
+/*	$NetBSD: fnmatch.c,v 1.1 2012/01/16 18:44:13 christos Exp $	*/
+
+/*-
+ * Copyright (c) 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * The Mach Operating System project at Carnegie-Mellon University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *
+ * Copyright (c) 1990, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Author: David Golub
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  software.distribut...@cs.cmu.edu
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#include "stand.h"
+#include <lib/libkern/libkern.h>
+
+#if defined(LIBSA_ENABLE_LS_OP)
+int
+fnmatch(const char *fname, const char *pattern)
+{
+	char fc, pc;
+
+	do {
+		fc = *fname++;
+		pc = *pattern++;
+		if (!fc && !pc)
+			return 1;
+		if (pc == '?' && fc)
+			pc = fc;
+	} while (fc == pc);
+
+	if (pc != '*')
+		return 0;
+	/*
+	 * Too hard (and unnecessary really) too check for "*?name" etc....
+	 * "**" will look for a '*' and "*?" a '?'
+	 */
+	pc = *pattern++;
+	if (!pc)
+		return 1;
+	while ((fname = strchr(fname, pc)))
+		if (fnmatch(++fname, pattern))
+			return 1;
+	return 0;
+}
+#endif /* LIBSA_ENABLE_LS_OP */
Index: src/sys/lib/libsa/minixfs3.c
diff -u /dev/null src/sys/lib/libsa/minixfs3.c:1.1
--- /dev/null	Mon Jan 16 13:44:13 2012
+++ src/sys/lib/libsa/minixfs3.c	Mon Jan 16 13:44:13 2012
@@ -0,0 +1,964 @@
+/*	$NetBSD: minixfs3.c,v 1.1 2012/01/16 18:44:13 christos Exp $	*/
+
+/*-
+ * Copyright (c) 2012
+ *	Vrije Universiteit, Amsterdam, The Netherlands. All rights reserved.
+ *
+ * Author: Evgeniy Ivanov (based on libsa/ext2fs.c).
+ *
+ * This code is derived from src/sys/lib/libsa/ext2fs.c contributed to 
+ * The NetBSD Foundation, see copyrights below.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
+ * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 1997 Manuel Bouyer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*-
+ * Copyright (c) 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * The Mach Operating System project at Carnegie-Mellon University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *
+ * Copyright (c) 1990, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Author: David Golub
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  software.distribut...@cs.cmu.edu
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/*
+ *	Stand-alone file reading package for MFS file system.
+ */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#ifdef _STANDALONE
+#include <lib/libkern/libkern.h>
+#else
+#include <string.h>
+#endif
+
+#include "stand.h"
+#include "minixfs3.h"
+
+#if defined(LIBSA_FS_SINGLECOMPONENT) && !defined(LIBSA_NO_FS_SYMLINK)
+#define LIBSA_NO_FS_SYMLINK
+#endif
+
+#if defined(LIBSA_NO_TWIDDLE)
+#define twiddle()
+#endif
+
+typedef uint32_t	ino32_t;
+#ifndef FSBTODB
+#define FSBTODB(fs, indp) fsbtodb(fs, indp)
+#endif
+
+/*
+ * To avoid having a lot of filesystem-block sized buffers lurking (which
+ * could be 32k) we only keep a few entries of the indirect block map.
+ * With 8k blocks, 2^8 blocks is ~500k so we reread the indirect block
+ * ~13 times pulling in a 6M kernel.
+ * The cache size must be smaller than the smallest filesystem block,
+ * so LN2_IND_CACHE_SZ <= 9 (UFS2 and 4k blocks).
+ */
+#define LN2_IND_CACHE_SZ	6
+#define IND_CACHE_SZ		(1 << LN2_IND_CACHE_SZ)
+#define IND_CACHE_MASK		(IND_CACHE_SZ - 1)
+
+/*
+ * In-core open file.
+ */
+struct file {
+	off_t		f_seekp;	/* seek pointer */
+	struct mfs_sblock  *f_fs;	/* pointer to super-block */
+	struct mfs_dinode  f_di;	/* copy of on-disk inode */
+	uint		f_nishift;	/* for blocks in indirect block */
+	block_t		f_ind_cache_block;
+	block_t		f_ind_cache[IND_CACHE_SZ];
+
+	char		*f_buf;		/* buffer for data block */
+	size_t		f_buf_size;	/* size of data block */
+	daddr_t		f_buf_blkno;	/* block number of data block */
+};
+
+#if defined(LIBSA_ENABLE_LS_OP)
+
+#define NELEM(x) (sizeof (x) / sizeof(*x))
+
+typedef struct entry_t entry_t;
+struct entry_t {
+	entry_t	*e_next;
+	ino32_t	e_ino;
+	char	e_name[1];
+};
+
+#endif /* LIBSA_ENABLE_LS_OP */
+
+
+static int read_inode(ino32_t, struct open_file *);
+static int block_map(struct open_file *, block_t, block_t *);
+static int buf_read_file(struct open_file *, void *, size_t *);
+static int search_directory(const char *, int, struct open_file *, ino32_t *);
+static int read_sblock(struct open_file *, struct mfs_sblock *);
+
+/*
+ * Read a new inode into a file structure.
+ */
+static int
+read_inode(ino32_t inumber, struct open_file *f)
+{
+	struct file *fp = (struct file *)f->f_fsdata;
+	struct mfs_sblock *fs = fp->f_fs;
+	char *buf;
+	size_t rsize;
+	int rc;
+	daddr_t inode_sector;
+	struct mfs_dinode *dip;
+
+	inode_sector = FSBTODB(fs, ino_to_fsba(fs, inumber));
+
+	/*
+	 * Read inode and save it.
+	 */
+	buf = fp->f_buf;
+	twiddle();
+	rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
+	    inode_sector, fs->mfs_block_size, buf, &rsize);
+	if (rc)
+		return rc;
+	if (rsize != fs->mfs_block_size)
+		return EIO;
+
+	dip = (struct mfs_dinode *)(buf +
+	    INODE_SIZE * ino_to_fsbo(fs, inumber));
+	mfs_iload(dip, &fp->f_di);
+
+	/*
+	 * Clear out the old buffers
+	 */
+	fp->f_ind_cache_block = ~0;
+	fp->f_buf_blkno = -1;
+	return rc;
+}
+
+/*
+ * Given an offset in a file, find the disk block number (not zone!)
+ * that contains that block.
+ */
+static int
+block_map(struct open_file *f, block_t file_block, block_t *disk_block_p)
+{
+	struct file *fp = (struct file *)f->f_fsdata;
+	struct mfs_sblock *fs = fp->f_fs;
+	uint level;
+	block_t ind_cache;
+	block_t ind_block_num;
+	zone_t zone;
+	size_t rsize;
+	int rc;
+	int boff;
+	int scale = fs->mfs_log_zone_size; /* for block-zone conversion */
+	block_t *buf = (void *)fp->f_buf;
+
+	/*
+	 * Index structure of an inode:
+	 *
+	 * mdi_blocks[0..NR_DZONES-1]
+	 *			hold zone numbers for zones
+	 *			0..NR_DZONES-1
+	 *
+	 * mdi_blocks[NR_DZONES+0]
+	 *			block NDADDR+0 is the single indirect block
+	 *			holds zone numbers for zones
+	 *			NR_DZONES .. NR_DZONES + NINDIR(fs)-1
+	 *
+	 * mdi_blocks[NR_DZONES+1]
+	 *			block NDADDR+1 is the double indirect block
+	 *			holds zone numbers for INDEX blocks for zones
+	 *			NR_DZONES + NINDIR(fs) ..
+	 *			NR_TZONES + NINDIR(fs) + NINDIR(fs)**2 - 1
+	 */
+
+	zone = file_block >> scale;
+	boff = (int) (file_block - (zone << scale) ); /* relative blk in zone */
+
+	if (zone < NR_DZONES) {
+		/* Direct zone */
+		zone_t z = fs2h32(fp->f_di.mdi_zone[zone]);
+		if (z == NO_ZONE) {
+			*disk_block_p = NO_BLOCK;
+			return 0;
+		}
+		*disk_block_p = (block_t) ((z << scale) + boff);
+		return 0;
+	}
+
+	zone -= NR_DZONES;
+
+	ind_cache = zone >> LN2_IND_CACHE_SZ;
+	if (ind_cache == fp->f_ind_cache_block) {
+		*disk_block_p =
+		    fs2h32(fp->f_ind_cache[zone & IND_CACHE_MASK]);
+		return 0;
+	}
+
+	for (level = 0;;) {
+		level += fp->f_nishift;
+
+		if (zone < (block_t)1 << level)
+			break;
+		if (level > NIADDR * fp->f_nishift)
+			/* Zone number too high */
+			return EFBIG;
+		zone -= (block_t)1 << level;
+	}
+
+	ind_block_num =
+	    fs2h32(fp->f_di.mdi_zone[NR_DZONES + (level / fp->f_nishift - 1)]);
+
+	for (;;) {
+		level -= fp->f_nishift;
+		if (ind_block_num == 0) {
+			*disk_block_p = NO_BLOCK;	/* missing */
+			return 0;
+		}
+
+		twiddle();
+		/*
+		 * If we were feeling brave, we could work out the number
+		 * of the disk sector and read a single disk sector instead
+		 * of a filesystem block.
+		 * However we don't do this very often anyway...
+		 */
+		rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
+			FSBTODB(fs, ind_block_num), fs->mfs_block_size,
+			buf, &rsize);
+		if (rc)
+			return rc;
+		if (rsize != fs->mfs_block_size)
+			return EIO;
+
+		ind_block_num = fs2h32(buf[zone >> level]);
+		if (level == 0)
+			break;
+		zone &= (1 << level) - 1;
+	}
+
+	/* Save the part of the block that contains this sector */
+	memcpy(fp->f_ind_cache, &buf[zone & ~IND_CACHE_MASK],
+	    IND_CACHE_SZ * sizeof fp->f_ind_cache[0]);
+	fp->f_ind_cache_block = ind_cache;
+
+	zone = (zone_t)ind_block_num;
+	*disk_block_p = (block_t)((zone << scale) + boff);
+	return 0;
+}
+
+/*
+ * Read a portion of a file into an internal buffer.
+ * Return the location in the buffer and the amount in the buffer.
+ */
+static int
+buf_read_file(struct open_file *f, void *v, size_t *size_p)
+{
+	char **buf_p = v;
+	struct file *fp = (struct file *)f->f_fsdata;
+	struct mfs_sblock *fs = fp->f_fs;
+	long off;
+	block_t file_block;
+	block_t disk_block;
+	size_t block_size;
+	int rc;
+
+	off = blkoff(fs, fp->f_seekp);
+	file_block = lblkno(fs, fp->f_seekp);
+	block_size = fs->mfs_block_size;
+
+	if (file_block != fp->f_buf_blkno) {
+		rc = block_map(f, file_block, &disk_block);
+		if (rc)
+			return rc;
+
+		if (disk_block == 0) {
+			memset(fp->f_buf, 0, block_size);
+			fp->f_buf_size = block_size;
+		} else {
+			twiddle();
+			rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
+				FSBTODB(fs, disk_block),
+				block_size, fp->f_buf, &fp->f_buf_size);
+			if (rc)
+				return rc;
+		}
+
+		fp->f_buf_blkno = file_block;
+	}
+
+	/*
+	 * Return address of byte in buffer corresponding to
+	 * offset, and size of remainder of buffer after that
+	 * byte.
+	 */
+	*buf_p = fp->f_buf + off;
+	*size_p = block_size - off;
+
+	/*
+	 * But truncate buffer at end of file.
+	 */
+	if (*size_p > fp->f_di.mdi_size - fp->f_seekp)
+		*size_p = fp->f_di.mdi_size - fp->f_seekp;
+
+	return 0;
+}
+
+/*
+ * Search a directory for a name and return its
+ * inode number.
+ */
+static int
+search_directory(const char *name, int length, struct open_file *f,
+	ino32_t *inumber_p)
+{
+	struct file *fp = (struct file *)f->f_fsdata;
+	struct mfs_sblock *fs = fp->f_fs;
+	struct mfs_direct *dp;
+	struct mfs_direct *dbuf;
+	size_t buf_size;
+	int namlen;
+	int rc;
+
+	fp->f_seekp = 0;
+
+	while (fp->f_seekp < (off_t)fp->f_di.mdi_size) {
+		rc = buf_read_file(f, (void *)&dbuf, &buf_size);
+		if (rc)
+			return rc;
+		if (buf_size == 0)
+			return EIO;
+
+		/* XXX we assume, that buf_read_file reads an fs block and
+		 * doesn't truncate buffer. Currently i_size in MFS doesn't
+		 * the same as size of allocated blocks, it makes buf_read_file
+		 * to truncate buf_size.
+		 */
+		if (buf_size < fs->mfs_block_size)
+			buf_size = fs->mfs_block_size;
+
+		for (dp = dbuf; dp < &dbuf[NR_DIR_ENTRIES(fs)]; dp++) {
+			char *cp;
+			if (fs2h32(dp->mfsd_ino) == (ino32_t) 0)
+				continue;
+			/* Compute the length of the name */
+			cp = memchr(dp->mfsd_name, '\0', sizeof(dp->mfsd_name));
+			if (cp == NULL)
+				namlen = sizeof(dp->mfsd_name);
+			else
+				namlen = cp - (dp->mfsd_name);
+
+			if (namlen == length &&
+			    !memcmp(name, dp->mfsd_name, length)) {
+				/* found entry */
+				*inumber_p = fs2h32(dp->mfsd_ino);
+				return 0;
+			}
+		}
+		fp->f_seekp += buf_size;
+	}
+	return ENOENT;
+}
+
+int
+read_sblock(struct open_file *f, struct mfs_sblock *fs)
+{
+	static uint8_t sbbuf[MINBSIZE];
+	size_t buf_size;
+	int rc;
+
+	/* We must read amount multiple of sector size, hence we can't
+	 * read SBSIZE and read MINBSIZE.
+	 */
+	if (SBSIZE > MINBSIZE)
+		return EINVAL;
+
+	rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
+	    SUPER_BLOCK_OFF / DEV_BSIZE, MINBSIZE, sbbuf, &buf_size);
+	if (rc)
+		return rc;
+
+	if (buf_size != MINBSIZE)
+		return EIO;
+
+	mfs_sbload((void *)sbbuf, fs);
+
+	if (fs->mfs_magic != SUPER_MAGIC)
+		return EINVAL;
+	if (fs->mfs_block_size < MINBSIZE)
+		return EINVAL;
+	if ((fs->mfs_block_size % 512) != 0)
+		return EINVAL;
+	if (SBSIZE > fs->mfs_block_size)
+		return EINVAL;
+	if ((fs->mfs_block_size % INODE_SIZE) != 0)
+		return EINVAL;
+
+	/* For even larger disks, a similar problem occurs with s_firstdatazone.
+	 * If the on-disk field contains zero, we assume that the value was too
+	 * large to fit, and compute it on the fly.
+	 */
+	if (fs->mfs_firstdatazone_old == 0) {
+		block_t offset;
+		offset = START_BLOCK + fs->mfs_imap_blocks + fs->mfs_zmap_blocks;
+		offset += (fs->mfs_ninodes + fs->mfs_inodes_per_block - 1) /
+				fs->mfs_inodes_per_block;
+
+		fs->mfs_firstdatazone =
+			(offset + (1 << fs->mfs_log_zone_size) - 1) >>
+				fs->mfs_log_zone_size;
+	} else {
+		fs->mfs_firstdatazone = (zone_t) fs->mfs_firstdatazone_old;
+	}
+
+	if (fs->mfs_imap_blocks < 1 || fs->mfs_zmap_blocks < 1
+			|| fs->mfs_ninodes < 1 || fs->mfs_zones < 1
+			|| fs->mfs_firstdatazone <= 4
+			|| fs->mfs_firstdatazone >= fs->mfs_zones
+			|| (unsigned) fs->mfs_log_zone_size > 4)
+		return EINVAL;
+
+	/* compute in-memory mfs_sblock values */
+	fs->mfs_inodes_per_block = fs->mfs_block_size / INODE_SIZE;
+
+
+	{
+		int32_t mult = fs->mfs_block_size >> LOG_MINBSIZE;
+		int ln2 = LOG_MINBSIZE;
+
+		for (; mult != 1; ln2++)
+			mult >>= 1;
+
+		fs->mfs_bshift = ln2;
+		/* XXX assume hw bsize = 512 */
+		fs->mfs_fsbtodb = ln2 - LOG_MINBSIZE + 1;
+	}
+
+	fs->mfs_qbmask = fs->mfs_block_size - 1;
+	fs->mfs_bmask = ~fs->mfs_qbmask;
+
+	return 0;
+}
+
+/*
+ * Open a file.
+ */
+__compactcall int
+minixfs3_open(const char *path, struct open_file *f)
+{
+#ifndef LIBSA_FS_SINGLECOMPONENT
+	const char *cp, *ncp;
+	int c;
+#endif
+	ino32_t inumber;
+	struct file *fp;
+	struct mfs_sblock *fs;
+	int rc;
+#ifndef LIBSA_NO_FS_SYMLINK
+	ino32_t parent_inumber;
+	int nlinks = 0;
+	char namebuf[MAXPATHLEN+1];
+	char *buf;
+#endif
+
+	/* allocate file system specific data structure */
+	fp = alloc(sizeof(struct file));
+	memset(fp, 0, sizeof(struct file));
+	f->f_fsdata = (void *)fp;
+
+	/* allocate space and read super block */
+	fs = alloc(sizeof(*fs));
+	memset(fs, 0, sizeof(*fs));
+	fp->f_fs = fs;
+	twiddle();
+
+	rc = read_sblock(f, fs);
+	if (rc)
+		goto out;
+
+	/* alloc a block sized buffer used for all fs transfers */
+	fp->f_buf = alloc(fs->mfs_block_size);
+
+	/*
+	 * Calculate indirect block levels.
+	 */
+	{
+		int32_t mult;
+		int ln2;
+
+		/*
+		 * We note that the number of indirect blocks is always
+		 * a power of 2.  This lets us use shifts and masks instead
+		 * of divide and remainder and avoinds pulling in the
+		 * 64bit division routine into the boot code.
+		 */
+		mult = NINDIR(fs);
+#ifdef DEBUG
+		if (!powerof2(mult)) {
+			/* Hummm was't a power of 2 */
+			rc = EINVAL;
+			goto out;
+		}
+#endif
+		for (ln2 = 0; mult != 1; ln2++)
+			mult >>= 1;
+
+		fp->f_nishift = ln2;
+	}
+
+	inumber = ROOT_INODE;
+	if ((rc = read_inode(inumber, f)) != 0)
+		goto out;
+
+#ifndef LIBSA_FS_SINGLECOMPONENT
+	cp = path;
+	while (*cp) {
+
+		/*
+		 * Remove extra separators
+		 */
+		while (*cp == '/')
+			cp++;
+		if (*cp == '\0')
+			break;
+
+		/*
+		 * Check that current node is a directory.
+		 */
+		if ((fp->f_di.mdi_mode & I_TYPE) != I_DIRECTORY) {
+			rc = ENOTDIR;
+			goto out;
+		}
+
+		/*
+		 * Get next component of path name.
+		 */
+		ncp = cp;
+		while ((c = *cp) != '\0' && c != '/')
+			cp++;
+
+		/*
+		 * Look up component in current directory.
+		 * Save directory inumber in case we find a
+		 * symbolic link.
+		 */
+#ifndef LIBSA_NO_FS_SYMLINK
+		parent_inumber = inumber;
+#endif
+		rc = search_directory(ncp, cp - ncp, f, &inumber);
+		if (rc)
+			goto out;
+
+		/*
+		 * Open next component.
+		 */
+		if ((rc = read_inode(inumber, f)) != 0)
+			goto out;
+
+#ifndef LIBSA_NO_FS_SYMLINK
+		/*
+		 * Check for symbolic link.
+		 */
+		if ((fp->f_di.mdi_mode & I_TYPE) == I_SYMBOLIC_LINK) {
+			int link_len = fp->f_di.mdi_size;
+			int len;
+			size_t buf_size;
+			block_t	disk_block;
+
+			len = strlen(cp);
+
+			if (link_len + len > MAXPATHLEN ||
+			    ++nlinks > MAXSYMLINKS) {
+				rc = ENOENT;
+				goto out;
+			}
+
+			memmove(&namebuf[link_len], cp, len + 1);
+
+			/*
+			 * Read file for symbolic link
+			 */
+			buf = fp->f_buf;
+			rc = block_map(f, (block_t)0, &disk_block);
+			if (rc)
+				goto out;
+
+			twiddle();
+			rc = DEV_STRATEGY(f->f_dev)(f->f_devdata,
+					F_READ, FSBTODB(fs, disk_block),
+					fs->mfs_block_size, buf, &buf_size);
+			if (rc)
+				goto out;
+
+			memcpy(namebuf, buf, link_len);
+
+			/*
+			 * If relative pathname, restart at parent directory.
+			 * If absolute pathname, restart at root.
+			 */
+			cp = namebuf;
+			if (*cp != '/')
+				inumber = parent_inumber;
+			else
+				inumber = (ino32_t) ROOT_INODE;
+
+			if ((rc = read_inode(inumber, f)) != 0)
+				goto out;
+		}
+#endif	/* !LIBSA_NO_FS_SYMLINK */
+	}
+
+	/*
+	 * Found terminal component.
+	 */
+	rc = 0;
+
+#else /* !LIBSA_FS_SINGLECOMPONENT */
+
+	/* look up component in the current (root) directory */
+	rc = search_directory(path, strlen(path), f, &inumber);
+	if (rc)
+		goto out;
+
+	/* open it */
+	rc = read_inode(inumber, f);
+
+#endif /* !LIBSA_FS_SINGLECOMPONENT */
+
+	fp->f_seekp = 0;		/* reset seek pointer */
+
+out:
+	if (rc)
+		minixfs3_close(f);
+
+	return rc;
+}
+
+__compactcall int
+minixfs3_close(struct open_file *f)
+{
+	struct file *fp = (struct file *)f->f_fsdata;
+
+	f->f_fsdata = NULL;
+	if (fp == NULL)
+		return 0;
+
+	if (fp->f_buf)
+		dealloc(fp->f_buf, fp->f_fs->mfs_block_size);
+	dealloc(fp->f_fs, sizeof(*fp->f_fs));
+	dealloc(fp, sizeof(struct file));
+	return 0;
+}
+
+/*
+ * Copy a portion of a file into kernel memory.
+ * Cross block boundaries when necessary.
+ */
+__compactcall int
+minixfs3_read(struct open_file *f, void *start, size_t size, size_t *resid)
+{
+	struct file *fp = (struct file *)f->f_fsdata;
+	size_t csize;
+	char *buf;
+	size_t buf_size;
+	int rc = 0;
+	char *addr = start;
+
+	while (size != 0) {
+		if (fp->f_seekp >= (off_t)fp->f_di.mdi_size)
+			break;
+
+		rc = buf_read_file(f, &buf, &buf_size);
+		if (rc)
+			break;
+
+		csize = size;
+		if (csize > buf_size)
+			csize = buf_size;
+
+		memcpy(addr, buf, csize);
+
+		fp->f_seekp += csize;
+		addr += csize;
+		size -= csize;
+	}
+
+	if (resid)
+		*resid = size;
+	return rc;
+}
+
+/*
+ * Not implemented.
+ */
+#ifndef LIBSA_NO_FS_WRITE
+__compactcall int
+minixfs3_write(struct open_file *f, void *start, size_t size, size_t *resid)
+{
+
+	return EROFS;
+}
+#endif /* !LIBSA_NO_FS_WRITE */
+
+#ifndef LIBSA_NO_FS_SEEK
+__compactcall off_t
+minixfs3_seek(struct open_file *f, off_t offset, int where)
+{
+	struct file *fp = (struct file *)f->f_fsdata;
+
+	switch (where) {
+	case SEEK_SET:
+		fp->f_seekp = offset;
+		break;
+	case SEEK_CUR:
+		fp->f_seekp += offset;
+		break;
+	case SEEK_END:
+		fp->f_seekp = fp->f_di.mdi_size - offset;
+		break;
+	default:
+		return -1;
+	}
+	return fp->f_seekp;
+}
+#endif /* !LIBSA_NO_FS_SEEK */
+
+__compactcall int
+minixfs3_stat(struct open_file *f, struct stat *sb)
+{
+	struct file *fp = (struct file *)f->f_fsdata;
+
+	/* only important stuff */
+	memset(sb, 0, sizeof *sb);
+	sb->st_mode = fp->f_di.mdi_mode;
+	sb->st_uid = fp->f_di.mdi_uid;
+	sb->st_gid = fp->f_di.mdi_gid;
+	sb->st_size = fp->f_di.mdi_size;
+	return 0;
+}
+
+#if defined(LIBSA_ENABLE_LS_OP)
+__compactcall void
+minixfs3_ls(struct open_file *f, const char *pattern)
+{
+	struct file *fp = (struct file *)f->f_fsdata;
+	struct mfs_sblock *fs = fp->f_fs;
+	struct mfs_direct *dp;
+	struct mfs_direct *dbuf;
+	size_t buf_size;
+	entry_t	*names = 0, *n, **np;
+
+	fp->f_seekp = 0;
+	while (fp->f_seekp < (off_t)fp->f_di.mdi_size) {
+		int rc = buf_read_file(f, &dbuf, &buf_size);
+		if (rc)
+			goto out;
+
+		/* XXX we assume, that buf_read_file reads an fs block and
+		 * doesn't truncate buffer. Currently i_size in MFS doesn't
+		 * the same as size of allocated blocks, it makes buf_read_file
+		 * to truncate buf_size.
+		 */
+		if (buf_size < fs->mfs_block_size)
+			buf_size = fs->mfs_block_size;
+
+		for (dp = dbuf; dp < &dbuf[NR_DIR_ENTRIES(fs)]; dp++) {
+			char *cp;
+			int namlen;
+
+			if (fs2h32(dp->mfsd_ino) == 0)
+				continue;
+
+			if (pattern && !fnmatch(dp->mfsd_name, pattern))
+				continue;
+
+			/* Compute the length of the name,
+			 * We don't use strlen and strcpy, because original MFS
+			 * code doesn't.
+			 */
+			cp = memchr(dp->mfsd_name, '\0', sizeof(dp->mfsd_name));
+			if (cp == NULL)
+				namlen = sizeof(dp->mfsd_name);
+			else
+				namlen = cp - (dp->mfsd_name);
+
+			n = alloc(sizeof *n + namlen);
+			if (!n) {
+				printf("%d: %s\n",
+					fs2h32(dp->mfsd_ino), dp->mfsd_name);
+				continue;
+			}
+			n->e_ino = fs2h32(dp->mfsd_ino);
+			strncpy(n->e_name, dp->mfsd_name, namlen);
+			n->e_name[namlen] = '\0';
+			for (np = &names; *np; np = &(*np)->e_next) {
+				if (strcmp(n->e_name, (*np)->e_name) < 0)
+					break;
+			}
+			n->e_next = *np;
+			*np = n;
+		}
+		fp->f_seekp += buf_size;
+	}
+
+	if (names) {
+		entry_t *p_names = names;
+		do {
+			n = p_names;
+			printf("%d: %s\n",
+				n->e_ino, n->e_name);
+			p_names = n->e_next;
+		} while (p_names);
+	} else {
+		printf("not found\n");
+	}
+out:
+	if (names) {
+		do {
+			n = names;
+			names = n->e_next;
+			dealloc(n, 0);
+		} while (names);
+	}
+	return;
+}
+#endif
+
+/*
+ * byte swap functions for big endian machines
+ * (mfs is always little endian)
+ */
+
+/* These functions are only needed if native byte order is not big endian */
+#if BYTE_ORDER == BIG_ENDIAN
+void
+minixfs3_sb_bswap(struct mfs_sblock *old, struct mfs_sblock *new)
+{
+	new->mfs_ninodes	=	bswap32(old->mfs_ninodes);
+	new->mfs_nzones		=	bswap16(old->mfs_nzones);
+	new->mfs_imap_blocks	=	bswap16(old->mfs_imap_blocks);
+	new->mfs_zmap_blocks	=	bswap16(old->mfs_zmap_blocks);
+	new->mfs_firstdatazone_old =	bswap16(old->mfs_firstdatazone_old);
+	new->mfs_log_zone_size	=	bswap16(old->mfs_log_zone_size);
+	new->mfs_max_size	=	bswap32(old->mfs_max_size);
+	new->mfs_zones		=	bswap32(old->mfs_zones);
+	new->mfs_magic		=	bswap16(old->mfs_magic);
+	new->mfs_block_size	=	bswap16(old->mfs_block_size);
+	new->mfs_disk_version	=	old->mfs_disk_version;
+}
+
+void minixfs3_i_bswap(struct mfs_dinode *old, struct mfs_dinode *new)
+{
+	int i;
+
+	new->mdi_mode		=	bswap16(old->mdi_mode);
+	new->mdi_nlinks		=	bswap16(old->mdi_nlinks);
+	new->mdi_uid		=	bswap16(old->mdi_uid);
+	new->mdi_gid		=	bswap16(old->mdi_gid);
+	new->mdi_size		=	bswap32(old->mdi_size);
+	new->mdi_atime		=	bswap32(old->mdi_atime);
+	new->mdi_mtime		=	bswap32(old->mdi_mtime);
+	new->mdi_ctime		=	bswap32(old->mdi_ctime);
+
+	/* We don't swap here, because indirects must be swapped later
+	 * anyway, hence everything is done by block_map().
+	 */
+	for (i = 0; i < NR_TZONES; i++)
+		new->mdi_zone[i] = old->mdi_zone[i];
+}
+#endif
Index: src/sys/lib/libsa/minixfs3.h
diff -u /dev/null src/sys/lib/libsa/minixfs3.h:1.1
--- /dev/null	Mon Jan 16 13:44:13 2012
+++ src/sys/lib/libsa/minixfs3.h	Mon Jan 16 13:44:13 2012
@@ -0,0 +1,176 @@
+/*	$NetBSD: minixfs3.h,v 1.1 2012/01/16 18:44:13 christos Exp $ */
+
+/*-
+ * Copyright (c) 2012
+ *	Vrije Universiteit, Amsterdam, The Netherlands. All rights reserved.
+ *
+ * Author: Evgeniy Ivanov
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
+ * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MINIX_FS_3_H
+#define MINIX_FS_3_H
+
+FS_DEF(minixfs3);
+
+typedef uint32_t zone_t;
+typedef uint16_t zone1_t;
+typedef uint32_t block_t;
+
+#define NR_DZONES	7	/* # direct zone numbers in an inode */
+#define NR_TZONES	10	/* total # zone numbers in an inode */
+#define NIADDR		2       /* Indirect addresses in inode */
+
+struct mfs_dinode {
+	uint16_t  mdi_mode;	/* file type, protection, etc. */
+	uint16_t  mdi_nlinks;	/* how many links to this file */
+	int16_t   mdi_uid;	/* user id of the file's owner */
+	uint16_t  mdi_gid;	/* group number */
+	uint32_t  mdi_size;	/* current file size in bytes */
+	uint32_t  mdi_atime;	/* time of last access */
+	uint32_t  mdi_mtime;	/* when was file data last changed */
+	uint32_t  mdi_ctime;	/* when was inode itself changed */
+	zone_t    mdi_zone[NR_TZONES]; /* zone numbers for direct, ind, and
+						dbl ind */
+};
+
+/* Maximum Minix MFS on-disk directory filename.
+ * MFS uses 'struct direct' to write and parse
+ * directory entries, so this can't be changed
+ * without breaking filesystems.
+ */
+#define MFS_DIRSIZ	60
+
+struct mfs_direct {
+	uint32_t  mfsd_ino;
+	char      mfsd_name[MFS_DIRSIZ];
+} __packed;
+
+struct mfs_sblock {
+	uint32_t  mfs_ninodes;		/* # usable inodes on the minor device */
+	zone1_t   mfs_nzones;		/* total device size, including bit maps etc */
+	int16_t   mfs_imap_blocks;	/* # of blocks used by inode bit map */
+	int16_t   mfs_zmap_blocks;	/* # of blocks used by zone bit map */
+	zone1_t   mfs_firstdatazone_old;/* number of first data zone (small) */
+	int16_t   mfs_log_zone_size;	/* log2 of blocks/zone */
+	int16_t   mfs_pad;		/* try to avoid compiler-dependent padding */
+	int32_t   mfs_max_size;		/* maximum file size on this device */
+	zone_t    mfs_zones;		/* number of zones (replaces s_nzones in V2) */
+	int16_t   mfs_magic;		/* magic number to recognize super-blocks */
+	int16_t   mfs_pad2;		/* try to avoid compiler-dependent padding */
+	uint16_t  mfs_block_size;	/* block size in bytes. */
+	char      mfs_disk_version;	/* filesystem format sub-version */
+
+  /* The following items are only used when the super_block is in memory,
+   * mfs_inodes_per_block must be the firs one (see SBSIZE)
+   */
+	unsigned mfs_inodes_per_block;	/* precalculated from magic number */
+	zone_t   mfs_firstdatazone;	/* number of first data zone (big) */
+	int32_t  mfs_bshift;		/* ``lblkno'' calc of logical blkno */
+	int32_t  mfs_bmask;		/* ``blkoff'' calc of blk offsets */
+	int64_t  mfs_qbmask;		/* ~fs_bmask - for use with quad size */
+	int32_t  mfs_fsbtodb;		/* fsbtodb and dbtofsb shift constant */
+};
+
+#define LOG_MINBSIZE	10
+#define MINBSIZE	(1 << LOG_MINBSIZE)
+
+#define SUPER_MAGIC	0x4d5a	/* magic # for MFSv3 file systems */
+
+#define ROOT_INODE	((uint32_t) 1)	/* inode number for root directory */
+#define SUPER_BLOCK_OFF (1024)		/* bytes offset */
+#define START_BLOCK	((block_t) 2)	/* first fs block (not counting SB) */
+
+/* # bytes/dir entry */
+#define DIR_ENTRY_SIZE		sizeof(struct mfs_direct)
+/* # dir entries/blk */
+#define NR_DIR_ENTRIES(fs)	((fs)->mfs_block_size/DIR_ENTRY_SIZE)
+/* mfs_sblock on-disk part size */
+#define SBSIZE			offsetof(struct mfs_sblock, mfs_inodes_per_block)
+
+#define ZONE_NUM_SIZE		sizeof(zone_t) /* # bytes in zone  */
+#define INODE_SIZE		sizeof(struct mfs_dinode) /* bytes in dsk ino */
+/* # zones/indir block */
+#define NINDIR(fs)		((fs)->mfs_block_size/ZONE_NUM_SIZE)
+
+#define NO_ZONE			((zone_t) 0)	/* absence of a zone number */
+#define NO_BLOCK		((block_t) 0)	/* absence of a block number */
+
+/* Turn file system block numbers into disk block addresses */
+#define fsbtodb(fs, b)	((b) << (fs)->mfs_fsbtodb)
+
+#define	ino_to_fsba(fs, x)						\
+	(((x) - 1) / (fs)->mfs_inodes_per_block +			\
+	START_BLOCK + (fs)->mfs_imap_blocks + (fs)->mfs_zmap_blocks)
+#define	ino_to_fsbo(fs, x)	(((x) - 1) % (fs)->mfs_inodes_per_block)
+
+/*
+ * MFS metadatas are stored in little-endian byte order. These macros
+ * helps reading theses metadatas.
+ */
+#if BYTE_ORDER == LITTLE_ENDIAN
+#	define fs2h16(x) (x)
+#	define fs2h32(x) (x)
+#	define mfs_sbload(old, new)	\
+		memcpy((new), (old), SBSIZE);
+#	define mfs_iload(old, new)	\
+		memcpy((new),(old),sizeof(struct mfs_dinode))
+#else
+void minixfs3_sb_bswap(struct mfs_sblock *, struct mfs_sblock *);
+void minixfs3_i_bswap(struct mfs_dinode *, struct mfs_dinode *);
+#	define fs2h16(x) bswap16(x)
+#	define fs2h32(x) bswap32(x)
+#	define mfs_sbload(old, new) minixfs3_sb_bswap((old), (new))
+#	define mfs_iload(old, new) minixfs3_i_bswap((old), (new))
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+
+/*
+ * The following macros optimize certain frequently calculated
+ * quantities by using shifts and masks in place of divisions
+ * modulos and multiplications.
+ */
+#define blkoff(fs, loc)		/* calculates (loc % fs->mfs_bsize) */ \
+	((loc) & (fs)->mfs_qbmask)
+#define lblkno(fs, loc)		/* calculates (loc / fs->mfs_bsize) */ \
+	((loc) >> (fs)->mfs_bshift)
+
+/* Flag bits for i_mode in the inode. */
+#define I_TYPE          0170000 /* this field gives inode type */
+#define I_UNIX_SOCKET   0140000 /* unix domain socket */
+#define I_SYMBOLIC_LINK 0120000 /* file is a symbolic link */
+#define I_REGULAR       0100000 /* regular file, not dir or special */
+#define I_BLOCK_SPECIAL 0060000 /* block special file */
+#define I_DIRECTORY     0040000 /* file is a directory */
+#define I_CHAR_SPECIAL  0020000 /* character special file */
+#define I_NAMED_PIPE    0010000 /* named pipe (FIFO) */
+#define I_SET_UID_BIT   0004000 /* set effective uid_t on exec */
+#define I_SET_GID_BIT   0002000 /* set effective gid_t on exec */
+#define I_SET_STCKY_BIT 0001000 /* sticky bit */
+#define ALL_MODES       0007777 /* all bits for user, group and others */
+#define RWX_MODES       0000777 /* mode bits for RWX only */
+#define R_BIT           0000004 /* Rwx protection bit */
+#define W_BIT           0000002 /* rWx protection bit */
+#define X_BIT           0000001 /* rwX protection bit */
+#define I_NOT_ALLOC     0000000 /* this inode is free */
+
+#endif /* MINIX_FS_3_H */

Reply via email to