xref: /minix3/sys/lib/libsa/minixfs3.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: minixfs3.c,v 1.7 2014/03/20 03:13:18 christos Exp $	*/
258a2b000SEvgeniy Ivanov 
358a2b000SEvgeniy Ivanov /*-
458a2b000SEvgeniy Ivanov  * Copyright (c) 2012
558a2b000SEvgeniy Ivanov  *	Vrije Universiteit, Amsterdam, The Netherlands. All rights reserved.
658a2b000SEvgeniy Ivanov  *
758a2b000SEvgeniy Ivanov  * Author: Evgeniy Ivanov (based on libsa/ext2fs.c).
858a2b000SEvgeniy Ivanov  *
958a2b000SEvgeniy Ivanov  * This code is derived from src/sys/lib/libsa/ext2fs.c contributed to
1058a2b000SEvgeniy Ivanov  * The NetBSD Foundation, see copyrights below.
1158a2b000SEvgeniy Ivanov  *
1258a2b000SEvgeniy Ivanov  * Redistribution and use in source and binary forms, with or without
1358a2b000SEvgeniy Ivanov  * modification, are permitted provided that the following conditions
1458a2b000SEvgeniy Ivanov  * are met:
1558a2b000SEvgeniy Ivanov  * 1. Redistributions of source code must retain the above copyright
1658a2b000SEvgeniy Ivanov  *    notice, this list of conditions and the following disclaimer.
1758a2b000SEvgeniy Ivanov  * 2. Redistributions in binary form must reproduce the above copyright
1858a2b000SEvgeniy Ivanov  *    notice, this list of conditions and the following disclaimer in the
1958a2b000SEvgeniy Ivanov  *    documentation and/or other materials provided with the distribution.
2058a2b000SEvgeniy Ivanov  *
2158a2b000SEvgeniy Ivanov  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
2258a2b000SEvgeniy Ivanov  * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
2358a2b000SEvgeniy Ivanov  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2458a2b000SEvgeniy Ivanov  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE
2558a2b000SEvgeniy Ivanov  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2658a2b000SEvgeniy Ivanov  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2758a2b000SEvgeniy Ivanov  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2858a2b000SEvgeniy Ivanov  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2958a2b000SEvgeniy Ivanov  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3058a2b000SEvgeniy Ivanov  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3158a2b000SEvgeniy Ivanov  * POSSIBILITY OF SUCH DAMAGE.
3258a2b000SEvgeniy Ivanov  */
3358a2b000SEvgeniy Ivanov 
3458a2b000SEvgeniy Ivanov /*
3558a2b000SEvgeniy Ivanov  * Copyright (c) 1997 Manuel Bouyer.
3658a2b000SEvgeniy Ivanov  *
3758a2b000SEvgeniy Ivanov  * Redistribution and use in source and binary forms, with or without
3858a2b000SEvgeniy Ivanov  * modification, are permitted provided that the following conditions
3958a2b000SEvgeniy Ivanov  * are met:
4058a2b000SEvgeniy Ivanov  * 1. Redistributions of source code must retain the above copyright
4158a2b000SEvgeniy Ivanov  *    notice, this list of conditions and the following disclaimer.
4258a2b000SEvgeniy Ivanov  * 2. Redistributions in binary form must reproduce the above copyright
4358a2b000SEvgeniy Ivanov  *    notice, this list of conditions and the following disclaimer in the
4458a2b000SEvgeniy Ivanov  *    documentation and/or other materials provided with the distribution.
4558a2b000SEvgeniy Ivanov  *
4658a2b000SEvgeniy Ivanov  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
4758a2b000SEvgeniy Ivanov  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
4858a2b000SEvgeniy Ivanov  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
4958a2b000SEvgeniy Ivanov  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
5058a2b000SEvgeniy Ivanov  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
5158a2b000SEvgeniy Ivanov  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
5258a2b000SEvgeniy Ivanov  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
5358a2b000SEvgeniy Ivanov  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
5458a2b000SEvgeniy Ivanov  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
5558a2b000SEvgeniy Ivanov  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5658a2b000SEvgeniy Ivanov  */
5758a2b000SEvgeniy Ivanov 
5858a2b000SEvgeniy Ivanov /*-
5958a2b000SEvgeniy Ivanov  * Copyright (c) 1993
6058a2b000SEvgeniy Ivanov  *	The Regents of the University of California.  All rights reserved.
6158a2b000SEvgeniy Ivanov  *
6258a2b000SEvgeniy Ivanov  * This code is derived from software contributed to Berkeley by
6358a2b000SEvgeniy Ivanov  * The Mach Operating System project at Carnegie-Mellon University.
6458a2b000SEvgeniy Ivanov  *
6558a2b000SEvgeniy Ivanov  * Redistribution and use in source and binary forms, with or without
6658a2b000SEvgeniy Ivanov  * modification, are permitted provided that the following conditions
6758a2b000SEvgeniy Ivanov  * are met:
6858a2b000SEvgeniy Ivanov  * 1. Redistributions of source code must retain the above copyright
6958a2b000SEvgeniy Ivanov  *    notice, this list of conditions and the following disclaimer.
7058a2b000SEvgeniy Ivanov  * 2. Redistributions in binary form must reproduce the above copyright
7158a2b000SEvgeniy Ivanov  *    notice, this list of conditions and the following disclaimer in the
7258a2b000SEvgeniy Ivanov  *    documentation and/or other materials provided with the distribution.
7358a2b000SEvgeniy Ivanov  * 3. Neither the name of the University nor the names of its contributors
7458a2b000SEvgeniy Ivanov  *    may be used to endorse or promote products derived from this software
7558a2b000SEvgeniy Ivanov  *    without specific prior written permission.
7658a2b000SEvgeniy Ivanov  *
7758a2b000SEvgeniy Ivanov  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
7858a2b000SEvgeniy Ivanov  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
7958a2b000SEvgeniy Ivanov  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
8058a2b000SEvgeniy Ivanov  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
8158a2b000SEvgeniy Ivanov  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
8258a2b000SEvgeniy Ivanov  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
8358a2b000SEvgeniy Ivanov  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
8458a2b000SEvgeniy Ivanov  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
8558a2b000SEvgeniy Ivanov  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
8658a2b000SEvgeniy Ivanov  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
8758a2b000SEvgeniy Ivanov  * SUCH DAMAGE.
8858a2b000SEvgeniy Ivanov  *
8958a2b000SEvgeniy Ivanov  *
9058a2b000SEvgeniy Ivanov  * Copyright (c) 1990, 1991 Carnegie Mellon University
9158a2b000SEvgeniy Ivanov  * All Rights Reserved.
9258a2b000SEvgeniy Ivanov  *
9358a2b000SEvgeniy Ivanov  * Author: David Golub
9458a2b000SEvgeniy Ivanov  *
9558a2b000SEvgeniy Ivanov  * Permission to use, copy, modify and distribute this software and its
9658a2b000SEvgeniy Ivanov  * documentation is hereby granted, provided that both the copyright
9758a2b000SEvgeniy Ivanov  * notice and this permission notice appear in all copies of the
9858a2b000SEvgeniy Ivanov  * software, derivative works or modified versions, and any portions
9958a2b000SEvgeniy Ivanov  * thereof, and that both notices appear in supporting documentation.
10058a2b000SEvgeniy Ivanov  *
10158a2b000SEvgeniy Ivanov  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
10258a2b000SEvgeniy Ivanov  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
10358a2b000SEvgeniy Ivanov  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
10458a2b000SEvgeniy Ivanov  *
10558a2b000SEvgeniy Ivanov  * Carnegie Mellon requests users of this software to return to
10658a2b000SEvgeniy Ivanov  *
10758a2b000SEvgeniy Ivanov  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
10858a2b000SEvgeniy Ivanov  *  School of Computer Science
10958a2b000SEvgeniy Ivanov  *  Carnegie Mellon University
11058a2b000SEvgeniy Ivanov  *  Pittsburgh PA 15213-3890
11158a2b000SEvgeniy Ivanov  *
11258a2b000SEvgeniy Ivanov  * any improvements or extensions that they make and grant Carnegie the
11358a2b000SEvgeniy Ivanov  * rights to redistribute these changes.
11458a2b000SEvgeniy Ivanov  */
11558a2b000SEvgeniy Ivanov 
11658a2b000SEvgeniy Ivanov /*
11758a2b000SEvgeniy Ivanov  *	Stand-alone file reading package for MFS file system.
11858a2b000SEvgeniy Ivanov  */
11958a2b000SEvgeniy Ivanov 
12058a2b000SEvgeniy Ivanov #include <sys/param.h>
12158a2b000SEvgeniy Ivanov #include <sys/time.h>
12258a2b000SEvgeniy Ivanov #ifdef _STANDALONE
12358a2b000SEvgeniy Ivanov #include <lib/libkern/libkern.h>
12458a2b000SEvgeniy Ivanov #else
12558a2b000SEvgeniy Ivanov #include <string.h>
12658a2b000SEvgeniy Ivanov #endif
12758a2b000SEvgeniy Ivanov 
12858a2b000SEvgeniy Ivanov #include "stand.h"
12958a2b000SEvgeniy Ivanov #include "minixfs3.h"
13058a2b000SEvgeniy Ivanov 
13158a2b000SEvgeniy Ivanov #if defined(LIBSA_FS_SINGLECOMPONENT) && !defined(LIBSA_NO_FS_SYMLINK)
13258a2b000SEvgeniy Ivanov #define LIBSA_NO_FS_SYMLINK
13358a2b000SEvgeniy Ivanov #endif
13458a2b000SEvgeniy Ivanov 
13558a2b000SEvgeniy Ivanov #if defined(LIBSA_NO_TWIDDLE)
13658a2b000SEvgeniy Ivanov #define twiddle()
13758a2b000SEvgeniy Ivanov #endif
13858a2b000SEvgeniy Ivanov 
13958a2b000SEvgeniy Ivanov typedef uint32_t	ino32_t;
14058a2b000SEvgeniy Ivanov #ifndef FSBTODB
14184d9c625SLionel Sambuc #define FSBTODB(fs, indp) MFS_FSBTODB(fs, indp)
14258a2b000SEvgeniy Ivanov #endif
14358a2b000SEvgeniy Ivanov 
14458a2b000SEvgeniy Ivanov /*
14558a2b000SEvgeniy Ivanov  * To avoid having a lot of filesystem-block sized buffers lurking (which
14658a2b000SEvgeniy Ivanov  * could be 32k) we only keep a few entries of the indirect block map.
14758a2b000SEvgeniy Ivanov  * With 8k blocks, 2^8 blocks is ~500k so we reread the indirect block
14858a2b000SEvgeniy Ivanov  * ~13 times pulling in a 6M kernel.
14958a2b000SEvgeniy Ivanov  * The cache size must be smaller than the smallest filesystem block,
15058a2b000SEvgeniy Ivanov  * so LN2_IND_CACHE_SZ <= 9 (UFS2 and 4k blocks).
15158a2b000SEvgeniy Ivanov  */
15258a2b000SEvgeniy Ivanov #define LN2_IND_CACHE_SZ	6
15358a2b000SEvgeniy Ivanov #define IND_CACHE_SZ		(1 << LN2_IND_CACHE_SZ)
15458a2b000SEvgeniy Ivanov #define IND_CACHE_MASK		(IND_CACHE_SZ - 1)
15558a2b000SEvgeniy Ivanov 
15658a2b000SEvgeniy Ivanov /*
15758a2b000SEvgeniy Ivanov  * In-core open file.
15858a2b000SEvgeniy Ivanov  */
15958a2b000SEvgeniy Ivanov struct file {
16058a2b000SEvgeniy Ivanov 	off_t		f_seekp;	/* seek pointer */
16158a2b000SEvgeniy Ivanov 	struct mfs_sblock  *f_fs;	/* pointer to super-block */
16258a2b000SEvgeniy Ivanov 	struct mfs_dinode  f_di;	/* copy of on-disk inode */
16358a2b000SEvgeniy Ivanov 	uint		f_nishift;	/* for blocks in indirect block */
16458a2b000SEvgeniy Ivanov 	block_t		f_ind_cache_block;
16558a2b000SEvgeniy Ivanov 	block_t		f_ind_cache[IND_CACHE_SZ];
16658a2b000SEvgeniy Ivanov 
16758a2b000SEvgeniy Ivanov 	char		*f_buf;		/* buffer for data block */
16858a2b000SEvgeniy Ivanov 	size_t		f_buf_size;	/* size of data block */
16958a2b000SEvgeniy Ivanov 	daddr_t		f_buf_blkno;	/* block number of data block */
17058a2b000SEvgeniy Ivanov };
17158a2b000SEvgeniy Ivanov 
17258a2b000SEvgeniy Ivanov static int read_inode(ino32_t, struct open_file *);
17358a2b000SEvgeniy Ivanov static int block_map(struct open_file *, block_t, block_t *);
174f14fb602SLionel Sambuc static int buf_read_file(struct open_file *, void *, size_t *);
17558a2b000SEvgeniy Ivanov static int search_directory(const char *, int, struct open_file *, ino32_t *);
17658a2b000SEvgeniy Ivanov static int read_sblock(struct open_file *, struct mfs_sblock *);
17758a2b000SEvgeniy Ivanov 
17858a2b000SEvgeniy Ivanov /*
17958a2b000SEvgeniy Ivanov  * Read a new inode into a file structure.
18058a2b000SEvgeniy Ivanov  */
18158a2b000SEvgeniy Ivanov static int
read_inode(ino32_t inumber,struct open_file * f)18258a2b000SEvgeniy Ivanov read_inode(ino32_t inumber, struct open_file *f)
18358a2b000SEvgeniy Ivanov {
18458a2b000SEvgeniy Ivanov 	struct file *fp = (struct file *)f->f_fsdata;
18558a2b000SEvgeniy Ivanov 	struct mfs_sblock *fs = fp->f_fs;
18658a2b000SEvgeniy Ivanov 	char *buf;
18758a2b000SEvgeniy Ivanov 	size_t rsize;
18858a2b000SEvgeniy Ivanov 	int rc;
18958a2b000SEvgeniy Ivanov 	daddr_t inode_sector;
19058a2b000SEvgeniy Ivanov 	struct mfs_dinode *dip;
19158a2b000SEvgeniy Ivanov 
19258a2b000SEvgeniy Ivanov 	inode_sector = FSBTODB(fs, ino_to_fsba(fs, inumber));
19358a2b000SEvgeniy Ivanov 
19458a2b000SEvgeniy Ivanov 	/*
19558a2b000SEvgeniy Ivanov 	 * Read inode and save it.
19658a2b000SEvgeniy Ivanov 	 */
19758a2b000SEvgeniy Ivanov 	buf = fp->f_buf;
19858a2b000SEvgeniy Ivanov 	twiddle();
19958a2b000SEvgeniy Ivanov 	rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
20058a2b000SEvgeniy Ivanov 	    inode_sector, fs->mfs_block_size, buf, &rsize);
20158a2b000SEvgeniy Ivanov 	if (rc)
20258a2b000SEvgeniy Ivanov 		return rc;
20358a2b000SEvgeniy Ivanov 	if (rsize != fs->mfs_block_size)
20458a2b000SEvgeniy Ivanov 		return EIO;
20558a2b000SEvgeniy Ivanov 
20658a2b000SEvgeniy Ivanov 	dip = (struct mfs_dinode *)(buf +
20758a2b000SEvgeniy Ivanov 	    INODE_SIZE * ino_to_fsbo(fs, inumber));
20858a2b000SEvgeniy Ivanov 	mfs_iload(dip, &fp->f_di);
20958a2b000SEvgeniy Ivanov 
21058a2b000SEvgeniy Ivanov 	/*
21158a2b000SEvgeniy Ivanov 	 * Clear out the old buffers
21258a2b000SEvgeniy Ivanov 	 */
21358a2b000SEvgeniy Ivanov 	fp->f_ind_cache_block = ~0;
21458a2b000SEvgeniy Ivanov 	fp->f_buf_blkno = -1;
21558a2b000SEvgeniy Ivanov 	return rc;
21658a2b000SEvgeniy Ivanov }
21758a2b000SEvgeniy Ivanov 
21858a2b000SEvgeniy Ivanov /*
21958a2b000SEvgeniy Ivanov  * Given an offset in a file, find the disk block number (not zone!)
22058a2b000SEvgeniy Ivanov  * that contains that block.
22158a2b000SEvgeniy Ivanov  */
22258a2b000SEvgeniy Ivanov static int
block_map(struct open_file * f,block_t file_block,block_t * disk_block_p)22358a2b000SEvgeniy Ivanov block_map(struct open_file *f, block_t file_block, block_t *disk_block_p)
22458a2b000SEvgeniy Ivanov {
22558a2b000SEvgeniy Ivanov 	struct file *fp = (struct file *)f->f_fsdata;
22658a2b000SEvgeniy Ivanov 	struct mfs_sblock *fs = fp->f_fs;
22758a2b000SEvgeniy Ivanov 	uint level;
22858a2b000SEvgeniy Ivanov 	block_t ind_cache;
22958a2b000SEvgeniy Ivanov 	block_t ind_block_num;
23058a2b000SEvgeniy Ivanov 	zone_t zone;
23158a2b000SEvgeniy Ivanov 	size_t rsize;
23258a2b000SEvgeniy Ivanov 	int rc;
23358a2b000SEvgeniy Ivanov 	int boff;
23458a2b000SEvgeniy Ivanov 	int scale = fs->mfs_log_zone_size; /* for block-zone conversion */
23558a2b000SEvgeniy Ivanov 	block_t *buf = (void *)fp->f_buf;
23658a2b000SEvgeniy Ivanov 
23758a2b000SEvgeniy Ivanov 	/*
23858a2b000SEvgeniy Ivanov 	 * Index structure of an inode:
23958a2b000SEvgeniy Ivanov 	 *
24058a2b000SEvgeniy Ivanov 	 * mdi_blocks[0..NR_DZONES-1]
24158a2b000SEvgeniy Ivanov 	 *			hold zone numbers for zones
24258a2b000SEvgeniy Ivanov 	 *			0..NR_DZONES-1
24358a2b000SEvgeniy Ivanov 	 *
24458a2b000SEvgeniy Ivanov 	 * mdi_blocks[NR_DZONES+0]
24558a2b000SEvgeniy Ivanov 	 *			block NDADDR+0 is the single indirect block
24658a2b000SEvgeniy Ivanov 	 *			holds zone numbers for zones
24784d9c625SLionel Sambuc 	 *			NR_DZONES .. NR_DZONES + MFS_NINDIR(fs)-1
24858a2b000SEvgeniy Ivanov 	 *
24958a2b000SEvgeniy Ivanov 	 * mdi_blocks[NR_DZONES+1]
25058a2b000SEvgeniy Ivanov 	 *			block NDADDR+1 is the double indirect block
25158a2b000SEvgeniy Ivanov 	 *			holds zone numbers for INDEX blocks for zones
25284d9c625SLionel Sambuc 	 *			NR_DZONES + MFS_NINDIR(fs) ..
25384d9c625SLionel Sambuc 	 *			NR_TZONES + MFS_NINDIR(fs) + MFS_NINDIR(fs)**2 - 1
25458a2b000SEvgeniy Ivanov 	 */
25558a2b000SEvgeniy Ivanov 
25658a2b000SEvgeniy Ivanov 	zone = file_block >> scale;
25758a2b000SEvgeniy Ivanov 	boff = (int) (file_block - (zone << scale) ); /* relative blk in zone */
25858a2b000SEvgeniy Ivanov 
25958a2b000SEvgeniy Ivanov 	if (zone < NR_DZONES) {
26058a2b000SEvgeniy Ivanov 		/* Direct zone */
26158a2b000SEvgeniy Ivanov 		zone_t z = fs2h32(fp->f_di.mdi_zone[zone]);
26258a2b000SEvgeniy Ivanov 		if (z == NO_ZONE) {
26358a2b000SEvgeniy Ivanov 			*disk_block_p = NO_BLOCK;
26458a2b000SEvgeniy Ivanov 			return 0;
26558a2b000SEvgeniy Ivanov 		}
26658a2b000SEvgeniy Ivanov 		*disk_block_p = (block_t) ((z << scale) + boff);
26758a2b000SEvgeniy Ivanov 		return 0;
26858a2b000SEvgeniy Ivanov 	}
26958a2b000SEvgeniy Ivanov 
27058a2b000SEvgeniy Ivanov 	zone -= NR_DZONES;
27158a2b000SEvgeniy Ivanov 
27258a2b000SEvgeniy Ivanov 	ind_cache = zone >> LN2_IND_CACHE_SZ;
27358a2b000SEvgeniy Ivanov 	if (ind_cache == fp->f_ind_cache_block) {
27458a2b000SEvgeniy Ivanov 		*disk_block_p =
27558a2b000SEvgeniy Ivanov 		    fs2h32(fp->f_ind_cache[zone & IND_CACHE_MASK]);
27658a2b000SEvgeniy Ivanov 		return 0;
27758a2b000SEvgeniy Ivanov 	}
27858a2b000SEvgeniy Ivanov 
27958a2b000SEvgeniy Ivanov 	for (level = 0;;) {
28058a2b000SEvgeniy Ivanov 		level += fp->f_nishift;
28158a2b000SEvgeniy Ivanov 
28258a2b000SEvgeniy Ivanov 		if (zone < (block_t)1 << level)
28358a2b000SEvgeniy Ivanov 			break;
28458a2b000SEvgeniy Ivanov 		if (level > NIADDR * fp->f_nishift)
28558a2b000SEvgeniy Ivanov 			/* Zone number too high */
28658a2b000SEvgeniy Ivanov 			return EFBIG;
28758a2b000SEvgeniy Ivanov 		zone -= (block_t)1 << level;
28858a2b000SEvgeniy Ivanov 	}
28958a2b000SEvgeniy Ivanov 
29058a2b000SEvgeniy Ivanov 	ind_block_num =
29158a2b000SEvgeniy Ivanov 	    fs2h32(fp->f_di.mdi_zone[NR_DZONES + (level / fp->f_nishift - 1)]);
29258a2b000SEvgeniy Ivanov 
29358a2b000SEvgeniy Ivanov 	for (;;) {
29458a2b000SEvgeniy Ivanov 		level -= fp->f_nishift;
29558a2b000SEvgeniy Ivanov 		if (ind_block_num == 0) {
29658a2b000SEvgeniy Ivanov 			*disk_block_p = NO_BLOCK;	/* missing */
29758a2b000SEvgeniy Ivanov 			return 0;
29858a2b000SEvgeniy Ivanov 		}
29958a2b000SEvgeniy Ivanov 
30058a2b000SEvgeniy Ivanov 		twiddle();
30158a2b000SEvgeniy Ivanov 		/*
30258a2b000SEvgeniy Ivanov 		 * If we were feeling brave, we could work out the number
30358a2b000SEvgeniy Ivanov 		 * of the disk sector and read a single disk sector instead
30458a2b000SEvgeniy Ivanov 		 * of a filesystem block.
30558a2b000SEvgeniy Ivanov 		 * However we don't do this very often anyway...
30658a2b000SEvgeniy Ivanov 		 */
30758a2b000SEvgeniy Ivanov 		rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
30858a2b000SEvgeniy Ivanov 			FSBTODB(fs, ind_block_num), fs->mfs_block_size,
30958a2b000SEvgeniy Ivanov 			buf, &rsize);
31058a2b000SEvgeniy Ivanov 		if (rc)
31158a2b000SEvgeniy Ivanov 			return rc;
31258a2b000SEvgeniy Ivanov 		if (rsize != fs->mfs_block_size)
31358a2b000SEvgeniy Ivanov 			return EIO;
31458a2b000SEvgeniy Ivanov 
31558a2b000SEvgeniy Ivanov 		ind_block_num = fs2h32(buf[zone >> level]);
31658a2b000SEvgeniy Ivanov 		if (level == 0)
31758a2b000SEvgeniy Ivanov 			break;
31858a2b000SEvgeniy Ivanov 		zone &= (1 << level) - 1;
31958a2b000SEvgeniy Ivanov 	}
32058a2b000SEvgeniy Ivanov 
32158a2b000SEvgeniy Ivanov 	/* Save the part of the block that contains this sector */
32258a2b000SEvgeniy Ivanov 	memcpy(fp->f_ind_cache, &buf[zone & ~IND_CACHE_MASK],
32358a2b000SEvgeniy Ivanov 	    IND_CACHE_SZ * sizeof fp->f_ind_cache[0]);
32458a2b000SEvgeniy Ivanov 	fp->f_ind_cache_block = ind_cache;
32558a2b000SEvgeniy Ivanov 
32658a2b000SEvgeniy Ivanov 	zone = (zone_t)ind_block_num;
32758a2b000SEvgeniy Ivanov 	*disk_block_p = (block_t)((zone << scale) + boff);
32858a2b000SEvgeniy Ivanov 	return 0;
32958a2b000SEvgeniy Ivanov }
33058a2b000SEvgeniy Ivanov 
33158a2b000SEvgeniy Ivanov /*
33258a2b000SEvgeniy Ivanov  * Read a portion of a file into an internal buffer.
33358a2b000SEvgeniy Ivanov  * Return the location in the buffer and the amount in the buffer.
33458a2b000SEvgeniy Ivanov  */
33558a2b000SEvgeniy Ivanov static int
buf_read_file(struct open_file * f,void * v,size_t * size_p)336f14fb602SLionel Sambuc buf_read_file(struct open_file *f, void *v, size_t *size_p)
33758a2b000SEvgeniy Ivanov {
338f14fb602SLionel Sambuc 	char **buf_p = v;
33958a2b000SEvgeniy Ivanov 	struct file *fp = (struct file *)f->f_fsdata;
34058a2b000SEvgeniy Ivanov 	struct mfs_sblock *fs = fp->f_fs;
34158a2b000SEvgeniy Ivanov 	long off;
34258a2b000SEvgeniy Ivanov 	block_t file_block;
34384d9c625SLionel Sambuc 	block_t disk_block = 0;	/* XXX: gcc */
34458a2b000SEvgeniy Ivanov 	size_t block_size;
34558a2b000SEvgeniy Ivanov 	int rc;
34658a2b000SEvgeniy Ivanov 
34784d9c625SLionel Sambuc 	off = mfs_blkoff(fs, fp->f_seekp);
34884d9c625SLionel Sambuc 	file_block = mfs_lblkno(fs, fp->f_seekp);
34958a2b000SEvgeniy Ivanov 	block_size = fs->mfs_block_size;
35058a2b000SEvgeniy Ivanov 
35158a2b000SEvgeniy Ivanov 	if (file_block != fp->f_buf_blkno) {
35258a2b000SEvgeniy Ivanov 		rc = block_map(f, file_block, &disk_block);
35358a2b000SEvgeniy Ivanov 		if (rc)
35458a2b000SEvgeniy Ivanov 			return rc;
35558a2b000SEvgeniy Ivanov 
35658a2b000SEvgeniy Ivanov 		if (disk_block == 0) {
35758a2b000SEvgeniy Ivanov 			memset(fp->f_buf, 0, block_size);
35858a2b000SEvgeniy Ivanov 			fp->f_buf_size = block_size;
35958a2b000SEvgeniy Ivanov 		} else {
36058a2b000SEvgeniy Ivanov 			twiddle();
36158a2b000SEvgeniy Ivanov 			rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
36258a2b000SEvgeniy Ivanov 				FSBTODB(fs, disk_block),
36358a2b000SEvgeniy Ivanov 				block_size, fp->f_buf, &fp->f_buf_size);
36458a2b000SEvgeniy Ivanov 			if (rc)
36558a2b000SEvgeniy Ivanov 				return rc;
36658a2b000SEvgeniy Ivanov 		}
36758a2b000SEvgeniy Ivanov 
36858a2b000SEvgeniy Ivanov 		fp->f_buf_blkno = file_block;
36958a2b000SEvgeniy Ivanov 	}
37058a2b000SEvgeniy Ivanov 
37158a2b000SEvgeniy Ivanov 	/*
37258a2b000SEvgeniy Ivanov 	 * Return address of byte in buffer corresponding to
37358a2b000SEvgeniy Ivanov 	 * offset, and size of remainder of buffer after that
37458a2b000SEvgeniy Ivanov 	 * byte.
37558a2b000SEvgeniy Ivanov 	 */
37658a2b000SEvgeniy Ivanov 	*buf_p = fp->f_buf + off;
37758a2b000SEvgeniy Ivanov 	*size_p = block_size - off;
37858a2b000SEvgeniy Ivanov 
37958a2b000SEvgeniy Ivanov 	/*
38058a2b000SEvgeniy Ivanov 	 * But truncate buffer at end of file.
38158a2b000SEvgeniy Ivanov 	 */
38258a2b000SEvgeniy Ivanov 	if (*size_p > fp->f_di.mdi_size - fp->f_seekp)
38358a2b000SEvgeniy Ivanov 		*size_p = fp->f_di.mdi_size - fp->f_seekp;
38458a2b000SEvgeniy Ivanov 
38558a2b000SEvgeniy Ivanov 	return 0;
38658a2b000SEvgeniy Ivanov }
38758a2b000SEvgeniy Ivanov 
38858a2b000SEvgeniy Ivanov /*
38958a2b000SEvgeniy Ivanov  * Search a directory for a name and return its
39058a2b000SEvgeniy Ivanov  * inode number.
39158a2b000SEvgeniy Ivanov  */
39258a2b000SEvgeniy Ivanov static int
search_directory(const char * name,int length,struct open_file * f,ino32_t * inumber_p)39358a2b000SEvgeniy Ivanov search_directory(const char *name, int length, struct open_file *f,
39458a2b000SEvgeniy Ivanov 	ino32_t *inumber_p)
39558a2b000SEvgeniy Ivanov {
39658a2b000SEvgeniy Ivanov 	struct file *fp = (struct file *)f->f_fsdata;
39758a2b000SEvgeniy Ivanov 	struct mfs_sblock *fs = fp->f_fs;
39858a2b000SEvgeniy Ivanov 	struct mfs_direct *dp;
39958a2b000SEvgeniy Ivanov 	struct mfs_direct *dbuf;
40058a2b000SEvgeniy Ivanov 	size_t buf_size;
40158a2b000SEvgeniy Ivanov 	int namlen;
40258a2b000SEvgeniy Ivanov 	int rc;
40358a2b000SEvgeniy Ivanov 
40458a2b000SEvgeniy Ivanov 	fp->f_seekp = 0;
40558a2b000SEvgeniy Ivanov 
40658a2b000SEvgeniy Ivanov 	while (fp->f_seekp < (off_t)fp->f_di.mdi_size) {
407f14fb602SLionel Sambuc 		rc = buf_read_file(f, (void *)&dbuf, &buf_size);
40858a2b000SEvgeniy Ivanov 		if (rc)
40958a2b000SEvgeniy Ivanov 			return rc;
41058a2b000SEvgeniy Ivanov 		if (buf_size == 0)
41158a2b000SEvgeniy Ivanov 			return EIO;
41258a2b000SEvgeniy Ivanov 
41358a2b000SEvgeniy Ivanov 		/* XXX we assume, that buf_read_file reads an fs block and
41458a2b000SEvgeniy Ivanov 		 * doesn't truncate buffer. Currently i_size in MFS doesn't
41558a2b000SEvgeniy Ivanov 		 * the same as size of allocated blocks, it makes buf_read_file
41658a2b000SEvgeniy Ivanov 		 * to truncate buf_size.
41758a2b000SEvgeniy Ivanov 		 */
41858a2b000SEvgeniy Ivanov 		if (buf_size < fs->mfs_block_size)
41958a2b000SEvgeniy Ivanov 			buf_size = fs->mfs_block_size;
42058a2b000SEvgeniy Ivanov 
42158a2b000SEvgeniy Ivanov 		for (dp = dbuf; dp < &dbuf[NR_DIR_ENTRIES(fs)]; dp++) {
42258a2b000SEvgeniy Ivanov 			char *cp;
42358a2b000SEvgeniy Ivanov 			if (fs2h32(dp->mfsd_ino) == (ino32_t) 0)
42458a2b000SEvgeniy Ivanov 				continue;
42558a2b000SEvgeniy Ivanov 			/* Compute the length of the name */
42658a2b000SEvgeniy Ivanov 			cp = memchr(dp->mfsd_name, '\0', sizeof(dp->mfsd_name));
42758a2b000SEvgeniy Ivanov 			if (cp == NULL)
42858a2b000SEvgeniy Ivanov 				namlen = sizeof(dp->mfsd_name);
42958a2b000SEvgeniy Ivanov 			else
43058a2b000SEvgeniy Ivanov 				namlen = cp - (dp->mfsd_name);
43158a2b000SEvgeniy Ivanov 
43258a2b000SEvgeniy Ivanov 			if (namlen == length &&
43358a2b000SEvgeniy Ivanov 			    !memcmp(name, dp->mfsd_name, length)) {
43458a2b000SEvgeniy Ivanov 				/* found entry */
43558a2b000SEvgeniy Ivanov 				*inumber_p = fs2h32(dp->mfsd_ino);
43658a2b000SEvgeniy Ivanov 				return 0;
43758a2b000SEvgeniy Ivanov 			}
43858a2b000SEvgeniy Ivanov 		}
43958a2b000SEvgeniy Ivanov 		fp->f_seekp += buf_size;
44058a2b000SEvgeniy Ivanov 	}
44158a2b000SEvgeniy Ivanov 	return ENOENT;
44258a2b000SEvgeniy Ivanov }
44358a2b000SEvgeniy Ivanov 
44458a2b000SEvgeniy Ivanov int
read_sblock(struct open_file * f,struct mfs_sblock * fs)44558a2b000SEvgeniy Ivanov read_sblock(struct open_file *f, struct mfs_sblock *fs)
44658a2b000SEvgeniy Ivanov {
44758a2b000SEvgeniy Ivanov 	static uint8_t sbbuf[MINBSIZE];
44858a2b000SEvgeniy Ivanov 	size_t buf_size;
44958a2b000SEvgeniy Ivanov 	int rc;
45058a2b000SEvgeniy Ivanov 
45158a2b000SEvgeniy Ivanov 	/* We must read amount multiple of sector size, hence we can't
45258a2b000SEvgeniy Ivanov 	 * read SBSIZE and read MINBSIZE.
45358a2b000SEvgeniy Ivanov 	 */
45458a2b000SEvgeniy Ivanov 	if (SBSIZE > MINBSIZE)
45558a2b000SEvgeniy Ivanov 		return EINVAL;
45658a2b000SEvgeniy Ivanov 
45758a2b000SEvgeniy Ivanov 	rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
45858a2b000SEvgeniy Ivanov 	    SUPER_BLOCK_OFF / DEV_BSIZE, MINBSIZE, sbbuf, &buf_size);
45958a2b000SEvgeniy Ivanov 	if (rc)
46058a2b000SEvgeniy Ivanov 		return rc;
46158a2b000SEvgeniy Ivanov 
46258a2b000SEvgeniy Ivanov 	if (buf_size != MINBSIZE)
46358a2b000SEvgeniy Ivanov 		return EIO;
46458a2b000SEvgeniy Ivanov 
46558a2b000SEvgeniy Ivanov 	mfs_sbload((void *)sbbuf, fs);
46658a2b000SEvgeniy Ivanov 
46758a2b000SEvgeniy Ivanov 	if (fs->mfs_magic != SUPER_MAGIC)
46858a2b000SEvgeniy Ivanov 		return EINVAL;
46958a2b000SEvgeniy Ivanov 	if (fs->mfs_block_size < MINBSIZE)
47058a2b000SEvgeniy Ivanov 		return EINVAL;
47158a2b000SEvgeniy Ivanov 	if ((fs->mfs_block_size % 512) != 0)
47258a2b000SEvgeniy Ivanov 		return EINVAL;
47358a2b000SEvgeniy Ivanov 	if (SBSIZE > fs->mfs_block_size)
47458a2b000SEvgeniy Ivanov 		return EINVAL;
47558a2b000SEvgeniy Ivanov 	if ((fs->mfs_block_size % INODE_SIZE) != 0)
47658a2b000SEvgeniy Ivanov 		return EINVAL;
47758a2b000SEvgeniy Ivanov 
47858a2b000SEvgeniy Ivanov 	/* For even larger disks, a similar problem occurs with s_firstdatazone.
47958a2b000SEvgeniy Ivanov 	 * If the on-disk field contains zero, we assume that the value was too
48058a2b000SEvgeniy Ivanov 	 * large to fit, and compute it on the fly.
48158a2b000SEvgeniy Ivanov 	 */
48258a2b000SEvgeniy Ivanov 	if (fs->mfs_firstdatazone_old == 0) {
48358a2b000SEvgeniy Ivanov 		block_t offset;
48458a2b000SEvgeniy Ivanov 		offset = START_BLOCK + fs->mfs_imap_blocks + fs->mfs_zmap_blocks;
48558a2b000SEvgeniy Ivanov 		offset += (fs->mfs_ninodes + fs->mfs_inodes_per_block - 1) /
48658a2b000SEvgeniy Ivanov 				fs->mfs_inodes_per_block;
48758a2b000SEvgeniy Ivanov 
48858a2b000SEvgeniy Ivanov 		fs->mfs_firstdatazone =
48958a2b000SEvgeniy Ivanov 			(offset + (1 << fs->mfs_log_zone_size) - 1) >>
49058a2b000SEvgeniy Ivanov 				fs->mfs_log_zone_size;
49158a2b000SEvgeniy Ivanov 	} else {
49258a2b000SEvgeniy Ivanov 		fs->mfs_firstdatazone = (zone_t) fs->mfs_firstdatazone_old;
49358a2b000SEvgeniy Ivanov 	}
49458a2b000SEvgeniy Ivanov 
49558a2b000SEvgeniy Ivanov 	if (fs->mfs_imap_blocks < 1 || fs->mfs_zmap_blocks < 1
49658a2b000SEvgeniy Ivanov 			|| fs->mfs_ninodes < 1 || fs->mfs_zones < 1
49758a2b000SEvgeniy Ivanov 			|| fs->mfs_firstdatazone <= 4
49858a2b000SEvgeniy Ivanov 			|| fs->mfs_firstdatazone >= fs->mfs_zones
49958a2b000SEvgeniy Ivanov 			|| (unsigned) fs->mfs_log_zone_size > 4)
50058a2b000SEvgeniy Ivanov 		return EINVAL;
50158a2b000SEvgeniy Ivanov 
50258a2b000SEvgeniy Ivanov 	/* compute in-memory mfs_sblock values */
50358a2b000SEvgeniy Ivanov 	fs->mfs_inodes_per_block = fs->mfs_block_size / INODE_SIZE;
50458a2b000SEvgeniy Ivanov 
50558a2b000SEvgeniy Ivanov 
50658a2b000SEvgeniy Ivanov 	{
50758a2b000SEvgeniy Ivanov 		int32_t mult = fs->mfs_block_size >> LOG_MINBSIZE;
50858a2b000SEvgeniy Ivanov 		int ln2 = LOG_MINBSIZE;
50958a2b000SEvgeniy Ivanov 
51058a2b000SEvgeniy Ivanov 		for (; mult != 1; ln2++)
51158a2b000SEvgeniy Ivanov 			mult >>= 1;
51258a2b000SEvgeniy Ivanov 
51358a2b000SEvgeniy Ivanov 		fs->mfs_bshift = ln2;
51458a2b000SEvgeniy Ivanov 		/* XXX assume hw bsize = 512 */
51558a2b000SEvgeniy Ivanov 		fs->mfs_fsbtodb = ln2 - LOG_MINBSIZE + 1;
51658a2b000SEvgeniy Ivanov 	}
51758a2b000SEvgeniy Ivanov 
51858a2b000SEvgeniy Ivanov 	fs->mfs_qbmask = fs->mfs_block_size - 1;
51958a2b000SEvgeniy Ivanov 	fs->mfs_bmask = ~fs->mfs_qbmask;
52058a2b000SEvgeniy Ivanov 
52158a2b000SEvgeniy Ivanov 	return 0;
52258a2b000SEvgeniy Ivanov }
52358a2b000SEvgeniy Ivanov 
52458a2b000SEvgeniy Ivanov /*
52558a2b000SEvgeniy Ivanov  * Open a file.
52658a2b000SEvgeniy Ivanov  */
52758a2b000SEvgeniy Ivanov __compactcall int
minixfs3_open(const char * path,struct open_file * f)52858a2b000SEvgeniy Ivanov minixfs3_open(const char *path, struct open_file *f)
52958a2b000SEvgeniy Ivanov {
53058a2b000SEvgeniy Ivanov #ifndef LIBSA_FS_SINGLECOMPONENT
53158a2b000SEvgeniy Ivanov 	const char *cp, *ncp;
53258a2b000SEvgeniy Ivanov 	int c;
53358a2b000SEvgeniy Ivanov #endif
53458a2b000SEvgeniy Ivanov 	ino32_t inumber;
53558a2b000SEvgeniy Ivanov 	struct file *fp;
53658a2b000SEvgeniy Ivanov 	struct mfs_sblock *fs;
53758a2b000SEvgeniy Ivanov 	int rc;
53858a2b000SEvgeniy Ivanov #ifndef LIBSA_NO_FS_SYMLINK
53958a2b000SEvgeniy Ivanov 	ino32_t parent_inumber;
54058a2b000SEvgeniy Ivanov 	int nlinks = 0;
54158a2b000SEvgeniy Ivanov 	char namebuf[MAXPATHLEN+1];
54258a2b000SEvgeniy Ivanov 	char *buf;
54358a2b000SEvgeniy Ivanov #endif
54458a2b000SEvgeniy Ivanov 
54558a2b000SEvgeniy Ivanov 	/* allocate file system specific data structure */
54658a2b000SEvgeniy Ivanov 	fp = alloc(sizeof(struct file));
54758a2b000SEvgeniy Ivanov 	memset(fp, 0, sizeof(struct file));
54858a2b000SEvgeniy Ivanov 	f->f_fsdata = (void *)fp;
54958a2b000SEvgeniy Ivanov 
55058a2b000SEvgeniy Ivanov 	/* allocate space and read super block */
55158a2b000SEvgeniy Ivanov 	fs = alloc(sizeof(*fs));
55258a2b000SEvgeniy Ivanov 	memset(fs, 0, sizeof(*fs));
55358a2b000SEvgeniy Ivanov 	fp->f_fs = fs;
55458a2b000SEvgeniy Ivanov 	twiddle();
55558a2b000SEvgeniy Ivanov 
55658a2b000SEvgeniy Ivanov 	rc = read_sblock(f, fs);
55758a2b000SEvgeniy Ivanov 	if (rc)
55858a2b000SEvgeniy Ivanov 		goto out;
55958a2b000SEvgeniy Ivanov 
56058a2b000SEvgeniy Ivanov 	/* alloc a block sized buffer used for all fs transfers */
56158a2b000SEvgeniy Ivanov 	fp->f_buf = alloc(fs->mfs_block_size);
56258a2b000SEvgeniy Ivanov 
56358a2b000SEvgeniy Ivanov 	/*
56458a2b000SEvgeniy Ivanov 	 * Calculate indirect block levels.
56558a2b000SEvgeniy Ivanov 	 */
56658a2b000SEvgeniy Ivanov 	{
56758a2b000SEvgeniy Ivanov 		int32_t mult;
56858a2b000SEvgeniy Ivanov 		int ln2;
56958a2b000SEvgeniy Ivanov 
57058a2b000SEvgeniy Ivanov 		/*
57158a2b000SEvgeniy Ivanov 		 * We note that the number of indirect blocks is always
57258a2b000SEvgeniy Ivanov 		 * a power of 2.  This lets us use shifts and masks instead
57358a2b000SEvgeniy Ivanov 		 * of divide and remainder and avoinds pulling in the
57458a2b000SEvgeniy Ivanov 		 * 64bit division routine into the boot code.
57558a2b000SEvgeniy Ivanov 		 */
57684d9c625SLionel Sambuc 		mult = MFS_NINDIR(fs);
57758a2b000SEvgeniy Ivanov #ifdef DEBUG
57858a2b000SEvgeniy Ivanov 		if (!powerof2(mult)) {
57958a2b000SEvgeniy Ivanov 			/* Hummm was't a power of 2 */
58058a2b000SEvgeniy Ivanov 			rc = EINVAL;
58158a2b000SEvgeniy Ivanov 			goto out;
58258a2b000SEvgeniy Ivanov 		}
58358a2b000SEvgeniy Ivanov #endif
58458a2b000SEvgeniy Ivanov 		for (ln2 = 0; mult != 1; ln2++)
58558a2b000SEvgeniy Ivanov 			mult >>= 1;
58658a2b000SEvgeniy Ivanov 
58758a2b000SEvgeniy Ivanov 		fp->f_nishift = ln2;
58858a2b000SEvgeniy Ivanov 	}
58958a2b000SEvgeniy Ivanov 
59058a2b000SEvgeniy Ivanov 	inumber = ROOT_INODE;
59158a2b000SEvgeniy Ivanov 	if ((rc = read_inode(inumber, f)) != 0)
59258a2b000SEvgeniy Ivanov 		goto out;
59358a2b000SEvgeniy Ivanov 
59458a2b000SEvgeniy Ivanov #ifndef LIBSA_FS_SINGLECOMPONENT
59558a2b000SEvgeniy Ivanov 	cp = path;
59658a2b000SEvgeniy Ivanov 	while (*cp) {
59758a2b000SEvgeniy Ivanov 
59858a2b000SEvgeniy Ivanov 		/*
59958a2b000SEvgeniy Ivanov 		 * Remove extra separators
60058a2b000SEvgeniy Ivanov 		 */
60158a2b000SEvgeniy Ivanov 		while (*cp == '/')
60258a2b000SEvgeniy Ivanov 			cp++;
60358a2b000SEvgeniy Ivanov 		if (*cp == '\0')
60458a2b000SEvgeniy Ivanov 			break;
60558a2b000SEvgeniy Ivanov 
60658a2b000SEvgeniy Ivanov 		/*
60758a2b000SEvgeniy Ivanov 		 * Check that current node is a directory.
60858a2b000SEvgeniy Ivanov 		 */
60958a2b000SEvgeniy Ivanov 		if ((fp->f_di.mdi_mode & I_TYPE) != I_DIRECTORY) {
61058a2b000SEvgeniy Ivanov 			rc = ENOTDIR;
61158a2b000SEvgeniy Ivanov 			goto out;
61258a2b000SEvgeniy Ivanov 		}
61358a2b000SEvgeniy Ivanov 
61458a2b000SEvgeniy Ivanov 		/*
61558a2b000SEvgeniy Ivanov 		 * Get next component of path name.
61658a2b000SEvgeniy Ivanov 		 */
61758a2b000SEvgeniy Ivanov 		ncp = cp;
61858a2b000SEvgeniy Ivanov 		while ((c = *cp) != '\0' && c != '/')
61958a2b000SEvgeniy Ivanov 			cp++;
62058a2b000SEvgeniy Ivanov 
62158a2b000SEvgeniy Ivanov 		/*
62258a2b000SEvgeniy Ivanov 		 * Look up component in current directory.
62358a2b000SEvgeniy Ivanov 		 * Save directory inumber in case we find a
62458a2b000SEvgeniy Ivanov 		 * symbolic link.
62558a2b000SEvgeniy Ivanov 		 */
62658a2b000SEvgeniy Ivanov #ifndef LIBSA_NO_FS_SYMLINK
62758a2b000SEvgeniy Ivanov 		parent_inumber = inumber;
62858a2b000SEvgeniy Ivanov #endif
62958a2b000SEvgeniy Ivanov 		rc = search_directory(ncp, cp - ncp, f, &inumber);
63058a2b000SEvgeniy Ivanov 		if (rc)
63158a2b000SEvgeniy Ivanov 			goto out;
63258a2b000SEvgeniy Ivanov 
63358a2b000SEvgeniy Ivanov 		/*
63458a2b000SEvgeniy Ivanov 		 * Open next component.
63558a2b000SEvgeniy Ivanov 		 */
63658a2b000SEvgeniy Ivanov 		if ((rc = read_inode(inumber, f)) != 0)
63758a2b000SEvgeniy Ivanov 			goto out;
63858a2b000SEvgeniy Ivanov 
63958a2b000SEvgeniy Ivanov #ifndef LIBSA_NO_FS_SYMLINK
64058a2b000SEvgeniy Ivanov 		/*
64158a2b000SEvgeniy Ivanov 		 * Check for symbolic link.
64258a2b000SEvgeniy Ivanov 		 */
64358a2b000SEvgeniy Ivanov 		if ((fp->f_di.mdi_mode & I_TYPE) == I_SYMBOLIC_LINK) {
64458a2b000SEvgeniy Ivanov 			int link_len = fp->f_di.mdi_size;
64558a2b000SEvgeniy Ivanov 			int len;
64658a2b000SEvgeniy Ivanov 			size_t buf_size;
64758a2b000SEvgeniy Ivanov 			block_t	disk_block;
64858a2b000SEvgeniy Ivanov 
64958a2b000SEvgeniy Ivanov 			len = strlen(cp);
65058a2b000SEvgeniy Ivanov 
65158a2b000SEvgeniy Ivanov 			if (link_len + len > MAXPATHLEN ||
65258a2b000SEvgeniy Ivanov 			    ++nlinks > MAXSYMLINKS) {
65358a2b000SEvgeniy Ivanov 				rc = ENOENT;
65458a2b000SEvgeniy Ivanov 				goto out;
65558a2b000SEvgeniy Ivanov 			}
65658a2b000SEvgeniy Ivanov 
65758a2b000SEvgeniy Ivanov 			memmove(&namebuf[link_len], cp, len + 1);
65858a2b000SEvgeniy Ivanov 
65958a2b000SEvgeniy Ivanov 			/*
66058a2b000SEvgeniy Ivanov 			 * Read file for symbolic link
66158a2b000SEvgeniy Ivanov 			 */
66258a2b000SEvgeniy Ivanov 			buf = fp->f_buf;
66358a2b000SEvgeniy Ivanov 			rc = block_map(f, (block_t)0, &disk_block);
66458a2b000SEvgeniy Ivanov 			if (rc)
66558a2b000SEvgeniy Ivanov 				goto out;
66658a2b000SEvgeniy Ivanov 
66758a2b000SEvgeniy Ivanov 			twiddle();
66858a2b000SEvgeniy Ivanov 			rc = DEV_STRATEGY(f->f_dev)(f->f_devdata,
66958a2b000SEvgeniy Ivanov 					F_READ, FSBTODB(fs, disk_block),
67058a2b000SEvgeniy Ivanov 					fs->mfs_block_size, buf, &buf_size);
67158a2b000SEvgeniy Ivanov 			if (rc)
67258a2b000SEvgeniy Ivanov 				goto out;
67358a2b000SEvgeniy Ivanov 
67458a2b000SEvgeniy Ivanov 			memcpy(namebuf, buf, link_len);
67558a2b000SEvgeniy Ivanov 
67658a2b000SEvgeniy Ivanov 			/*
67758a2b000SEvgeniy Ivanov 			 * If relative pathname, restart at parent directory.
67858a2b000SEvgeniy Ivanov 			 * If absolute pathname, restart at root.
67958a2b000SEvgeniy Ivanov 			 */
68058a2b000SEvgeniy Ivanov 			cp = namebuf;
68158a2b000SEvgeniy Ivanov 			if (*cp != '/')
68258a2b000SEvgeniy Ivanov 				inumber = parent_inumber;
68358a2b000SEvgeniy Ivanov 			else
68458a2b000SEvgeniy Ivanov 				inumber = (ino32_t) ROOT_INODE;
68558a2b000SEvgeniy Ivanov 
68658a2b000SEvgeniy Ivanov 			if ((rc = read_inode(inumber, f)) != 0)
68758a2b000SEvgeniy Ivanov 				goto out;
68858a2b000SEvgeniy Ivanov 		}
68958a2b000SEvgeniy Ivanov #endif	/* !LIBSA_NO_FS_SYMLINK */
69058a2b000SEvgeniy Ivanov 	}
69158a2b000SEvgeniy Ivanov 
69258a2b000SEvgeniy Ivanov 	/*
69358a2b000SEvgeniy Ivanov 	 * Found terminal component.
69458a2b000SEvgeniy Ivanov 	 */
69558a2b000SEvgeniy Ivanov 	rc = 0;
69658a2b000SEvgeniy Ivanov 
69758a2b000SEvgeniy Ivanov #else /* !LIBSA_FS_SINGLECOMPONENT */
69858a2b000SEvgeniy Ivanov 
69958a2b000SEvgeniy Ivanov 	/* look up component in the current (root) directory */
70058a2b000SEvgeniy Ivanov 	rc = search_directory(path, strlen(path), f, &inumber);
70158a2b000SEvgeniy Ivanov 	if (rc)
70258a2b000SEvgeniy Ivanov 		goto out;
70358a2b000SEvgeniy Ivanov 
70458a2b000SEvgeniy Ivanov 	/* open it */
70558a2b000SEvgeniy Ivanov 	rc = read_inode(inumber, f);
70658a2b000SEvgeniy Ivanov 
70758a2b000SEvgeniy Ivanov #endif /* !LIBSA_FS_SINGLECOMPONENT */
70858a2b000SEvgeniy Ivanov 
70958a2b000SEvgeniy Ivanov 	fp->f_seekp = 0;		/* reset seek pointer */
71058a2b000SEvgeniy Ivanov 
71158a2b000SEvgeniy Ivanov out:
71258a2b000SEvgeniy Ivanov 	if (rc)
71358a2b000SEvgeniy Ivanov 		minixfs3_close(f);
71458a2b000SEvgeniy Ivanov 
71558a2b000SEvgeniy Ivanov 	return rc;
71658a2b000SEvgeniy Ivanov }
71758a2b000SEvgeniy Ivanov 
71858a2b000SEvgeniy Ivanov __compactcall int
minixfs3_close(struct open_file * f)71958a2b000SEvgeniy Ivanov minixfs3_close(struct open_file *f)
72058a2b000SEvgeniy Ivanov {
72158a2b000SEvgeniy Ivanov 	struct file *fp = (struct file *)f->f_fsdata;
72258a2b000SEvgeniy Ivanov 
72358a2b000SEvgeniy Ivanov 	f->f_fsdata = NULL;
72458a2b000SEvgeniy Ivanov 	if (fp == NULL)
72558a2b000SEvgeniy Ivanov 		return 0;
72658a2b000SEvgeniy Ivanov 
72758a2b000SEvgeniy Ivanov 	if (fp->f_buf)
72858a2b000SEvgeniy Ivanov 		dealloc(fp->f_buf, fp->f_fs->mfs_block_size);
72958a2b000SEvgeniy Ivanov 	dealloc(fp->f_fs, sizeof(*fp->f_fs));
73058a2b000SEvgeniy Ivanov 	dealloc(fp, sizeof(struct file));
73158a2b000SEvgeniy Ivanov 	return 0;
73258a2b000SEvgeniy Ivanov }
73358a2b000SEvgeniy Ivanov 
73458a2b000SEvgeniy Ivanov /*
73558a2b000SEvgeniy Ivanov  * Copy a portion of a file into kernel memory.
73658a2b000SEvgeniy Ivanov  * Cross block boundaries when necessary.
73758a2b000SEvgeniy Ivanov  */
73858a2b000SEvgeniy Ivanov __compactcall int
minixfs3_read(struct open_file * f,void * start,size_t size,size_t * resid)73958a2b000SEvgeniy Ivanov minixfs3_read(struct open_file *f, void *start, size_t size, size_t *resid)
74058a2b000SEvgeniy Ivanov {
74158a2b000SEvgeniy Ivanov 	struct file *fp = (struct file *)f->f_fsdata;
74258a2b000SEvgeniy Ivanov 	size_t csize;
74358a2b000SEvgeniy Ivanov 	char *buf;
74458a2b000SEvgeniy Ivanov 	size_t buf_size;
74558a2b000SEvgeniy Ivanov 	int rc = 0;
74658a2b000SEvgeniy Ivanov 	char *addr = start;
74758a2b000SEvgeniy Ivanov 
74858a2b000SEvgeniy Ivanov 	while (size != 0) {
74958a2b000SEvgeniy Ivanov 		if (fp->f_seekp >= (off_t)fp->f_di.mdi_size)
75058a2b000SEvgeniy Ivanov 			break;
75158a2b000SEvgeniy Ivanov 
75258a2b000SEvgeniy Ivanov 		rc = buf_read_file(f, &buf, &buf_size);
75358a2b000SEvgeniy Ivanov 		if (rc)
75458a2b000SEvgeniy Ivanov 			break;
75558a2b000SEvgeniy Ivanov 
75658a2b000SEvgeniy Ivanov 		csize = size;
75758a2b000SEvgeniy Ivanov 		if (csize > buf_size)
75858a2b000SEvgeniy Ivanov 			csize = buf_size;
75958a2b000SEvgeniy Ivanov 
76058a2b000SEvgeniy Ivanov 		memcpy(addr, buf, csize);
76158a2b000SEvgeniy Ivanov 
76258a2b000SEvgeniy Ivanov 		fp->f_seekp += csize;
76358a2b000SEvgeniy Ivanov 		addr += csize;
76458a2b000SEvgeniy Ivanov 		size -= csize;
76558a2b000SEvgeniy Ivanov 	}
76658a2b000SEvgeniy Ivanov 
76758a2b000SEvgeniy Ivanov 	if (resid)
76858a2b000SEvgeniy Ivanov 		*resid = size;
76958a2b000SEvgeniy Ivanov 	return rc;
77058a2b000SEvgeniy Ivanov }
77158a2b000SEvgeniy Ivanov 
77258a2b000SEvgeniy Ivanov /*
77358a2b000SEvgeniy Ivanov  * Not implemented.
77458a2b000SEvgeniy Ivanov  */
77558a2b000SEvgeniy Ivanov #ifndef LIBSA_NO_FS_WRITE
77658a2b000SEvgeniy Ivanov __compactcall int
minixfs3_write(struct open_file * f,void * start,size_t size,size_t * resid)77758a2b000SEvgeniy Ivanov minixfs3_write(struct open_file *f, void *start, size_t size, size_t *resid)
77858a2b000SEvgeniy Ivanov {
77958a2b000SEvgeniy Ivanov 
78058a2b000SEvgeniy Ivanov 	return EROFS;
78158a2b000SEvgeniy Ivanov }
78258a2b000SEvgeniy Ivanov #endif /* !LIBSA_NO_FS_WRITE */
78358a2b000SEvgeniy Ivanov 
78458a2b000SEvgeniy Ivanov #ifndef LIBSA_NO_FS_SEEK
78558a2b000SEvgeniy Ivanov __compactcall off_t
minixfs3_seek(struct open_file * f,off_t offset,int where)78658a2b000SEvgeniy Ivanov minixfs3_seek(struct open_file *f, off_t offset, int where)
78758a2b000SEvgeniy Ivanov {
78858a2b000SEvgeniy Ivanov 	struct file *fp = (struct file *)f->f_fsdata;
78958a2b000SEvgeniy Ivanov 
79058a2b000SEvgeniy Ivanov 	switch (where) {
79158a2b000SEvgeniy Ivanov 	case SEEK_SET:
79258a2b000SEvgeniy Ivanov 		fp->f_seekp = offset;
79358a2b000SEvgeniy Ivanov 		break;
79458a2b000SEvgeniy Ivanov 	case SEEK_CUR:
79558a2b000SEvgeniy Ivanov 		fp->f_seekp += offset;
79658a2b000SEvgeniy Ivanov 		break;
79758a2b000SEvgeniy Ivanov 	case SEEK_END:
79858a2b000SEvgeniy Ivanov 		fp->f_seekp = fp->f_di.mdi_size - offset;
79958a2b000SEvgeniy Ivanov 		break;
80058a2b000SEvgeniy Ivanov 	default:
80158a2b000SEvgeniy Ivanov 		return -1;
80258a2b000SEvgeniy Ivanov 	}
80358a2b000SEvgeniy Ivanov 	return fp->f_seekp;
80458a2b000SEvgeniy Ivanov }
80558a2b000SEvgeniy Ivanov #endif /* !LIBSA_NO_FS_SEEK */
80658a2b000SEvgeniy Ivanov 
80758a2b000SEvgeniy Ivanov __compactcall int
minixfs3_stat(struct open_file * f,struct stat * sb)80858a2b000SEvgeniy Ivanov minixfs3_stat(struct open_file *f, struct stat *sb)
80958a2b000SEvgeniy Ivanov {
81058a2b000SEvgeniy Ivanov 	struct file *fp = (struct file *)f->f_fsdata;
81158a2b000SEvgeniy Ivanov 
81258a2b000SEvgeniy Ivanov 	/* only important stuff */
81358a2b000SEvgeniy Ivanov 	memset(sb, 0, sizeof *sb);
81458a2b000SEvgeniy Ivanov 	sb->st_mode = fp->f_di.mdi_mode;
81558a2b000SEvgeniy Ivanov 	sb->st_uid = fp->f_di.mdi_uid;
81658a2b000SEvgeniy Ivanov 	sb->st_gid = fp->f_di.mdi_gid;
81758a2b000SEvgeniy Ivanov 	sb->st_size = fp->f_di.mdi_size;
81858a2b000SEvgeniy Ivanov 	return 0;
81958a2b000SEvgeniy Ivanov }
82058a2b000SEvgeniy Ivanov 
82158a2b000SEvgeniy Ivanov #if defined(LIBSA_ENABLE_LS_OP)
822*0a6a1f1dSLionel Sambuc #include "ls.h"
823*0a6a1f1dSLionel Sambuc #if defined(__minix) && !defined(LIBSA_ENABLE_LOAD_MODS_OP)
82458a2b000SEvgeniy Ivanov __compactcall void
minixfs3_ls(struct open_file * f,const char * pattern)825*0a6a1f1dSLionel Sambuc minixfs3_ls(struct open_file *f, const char *pattern)
826*0a6a1f1dSLionel Sambuc #else
827*0a6a1f1dSLionel Sambuc __compactcall lsentry_t *
828*0a6a1f1dSLionel Sambuc minixfs3_list(struct open_file *f, const char *pattern);
829*0a6a1f1dSLionel Sambuc 
830*0a6a1f1dSLionel Sambuc __compactcall void
831*0a6a1f1dSLionel Sambuc minixfs3_ls(struct open_file *f, const char *pattern)
832*0a6a1f1dSLionel Sambuc {
833*0a6a1f1dSLionel Sambuc 	lsentry_t *names = minixfs3_list(f, pattern);
834*0a6a1f1dSLionel Sambuc 	lsprint(names);
835*0a6a1f1dSLionel Sambuc 	lsfree(names);
836*0a6a1f1dSLionel Sambuc }
837*0a6a1f1dSLionel Sambuc 
838*0a6a1f1dSLionel Sambuc __compactcall void
839*0a6a1f1dSLionel Sambuc minixfs3_load_mods(struct open_file *f, const char *pattern,
840*0a6a1f1dSLionel Sambuc 	void (*funcp)(char *), char *path)
841*0a6a1f1dSLionel Sambuc {
842*0a6a1f1dSLionel Sambuc 	lsentry_t *names = minixfs3_list(f, pattern);
843*0a6a1f1dSLionel Sambuc 	lsapply(names, pattern, funcp, path);
844*0a6a1f1dSLionel Sambuc 	lsfree(names);
845*0a6a1f1dSLionel Sambuc }
846*0a6a1f1dSLionel Sambuc 
847*0a6a1f1dSLionel Sambuc __compactcall lsentry_t *
848*0a6a1f1dSLionel Sambuc minixfs3_list(struct open_file *f, const char *pattern)
849*0a6a1f1dSLionel Sambuc #endif /* defined(__minix) && defined(LIBSA_ENABLE_LOAD_MODS_OP) */
85058a2b000SEvgeniy Ivanov {
85158a2b000SEvgeniy Ivanov 	struct file *fp = (struct file *)f->f_fsdata;
85258a2b000SEvgeniy Ivanov 	struct mfs_sblock *fs = fp->f_fs;
85358a2b000SEvgeniy Ivanov 	struct mfs_direct *dp;
85458a2b000SEvgeniy Ivanov 	struct mfs_direct *dbuf;
85558a2b000SEvgeniy Ivanov 	size_t buf_size;
856*0a6a1f1dSLionel Sambuc 	lsentry_t *names = 0;
85758a2b000SEvgeniy Ivanov 
85858a2b000SEvgeniy Ivanov 	fp->f_seekp = 0;
85958a2b000SEvgeniy Ivanov 	while (fp->f_seekp < (off_t)fp->f_di.mdi_size) {
860f14fb602SLionel Sambuc 		int rc = buf_read_file(f, &dbuf, &buf_size);
86158a2b000SEvgeniy Ivanov 		if (rc)
86258a2b000SEvgeniy Ivanov 			goto out;
86358a2b000SEvgeniy Ivanov 
86458a2b000SEvgeniy Ivanov 		/* XXX we assume, that buf_read_file reads an fs block and
86558a2b000SEvgeniy Ivanov 		 * doesn't truncate buffer. Currently i_size in MFS doesn't
86658a2b000SEvgeniy Ivanov 		 * the same as size of allocated blocks, it makes buf_read_file
86758a2b000SEvgeniy Ivanov 		 * to truncate buf_size.
86858a2b000SEvgeniy Ivanov 		 */
86958a2b000SEvgeniy Ivanov 		if (buf_size < fs->mfs_block_size)
87058a2b000SEvgeniy Ivanov 			buf_size = fs->mfs_block_size;
87158a2b000SEvgeniy Ivanov 
87258a2b000SEvgeniy Ivanov 		for (dp = dbuf; dp < &dbuf[NR_DIR_ENTRIES(fs)]; dp++) {
87358a2b000SEvgeniy Ivanov 			char *cp;
87458a2b000SEvgeniy Ivanov 			int namlen;
87558a2b000SEvgeniy Ivanov 
87658a2b000SEvgeniy Ivanov 			if (fs2h32(dp->mfsd_ino) == 0)
87758a2b000SEvgeniy Ivanov 				continue;
87858a2b000SEvgeniy Ivanov 
87958a2b000SEvgeniy Ivanov 			/* Compute the length of the name,
88058a2b000SEvgeniy Ivanov 			 * We don't use strlen and strcpy, because original MFS
88158a2b000SEvgeniy Ivanov 			 * code doesn't.
88258a2b000SEvgeniy Ivanov 			 */
88358a2b000SEvgeniy Ivanov 			cp = memchr(dp->mfsd_name, '\0', sizeof(dp->mfsd_name));
88458a2b000SEvgeniy Ivanov 			if (cp == NULL)
88558a2b000SEvgeniy Ivanov 				namlen = sizeof(dp->mfsd_name);
88658a2b000SEvgeniy Ivanov 			else
88758a2b000SEvgeniy Ivanov 				namlen = cp - (dp->mfsd_name);
88858a2b000SEvgeniy Ivanov 
889*0a6a1f1dSLionel Sambuc 			lsadd(&names, pattern, dp->mfsd_name, namlen,
890*0a6a1f1dSLionel Sambuc 			    fs2h32(dp->mfsd_ino), "?");
89158a2b000SEvgeniy Ivanov 		}
89258a2b000SEvgeniy Ivanov 		fp->f_seekp += buf_size;
89358a2b000SEvgeniy Ivanov 	}
89458a2b000SEvgeniy Ivanov 
895*0a6a1f1dSLionel Sambuc #if defined(__minix) && defined(LIBSA_ENABLE_LOAD_MODS_OP)
896*0a6a1f1dSLionel Sambuc out:	return names;
897*0a6a1f1dSLionel Sambuc #else
898*0a6a1f1dSLionel Sambuc 	lsprint(names);
899*0a6a1f1dSLionel Sambuc out:	lsfree(names);
900*0a6a1f1dSLionel Sambuc #endif /* defined(__minix) && defined(LIBSA_ENABLE_LOAD_MODS_OP) */
90158a2b000SEvgeniy Ivanov }
90258a2b000SEvgeniy Ivanov #endif
90358a2b000SEvgeniy Ivanov 
90458a2b000SEvgeniy Ivanov /*
90558a2b000SEvgeniy Ivanov  * byte swap functions for big endian machines
90658a2b000SEvgeniy Ivanov  * (mfs is always little endian)
90758a2b000SEvgeniy Ivanov  */
90858a2b000SEvgeniy Ivanov 
90958a2b000SEvgeniy Ivanov /* These functions are only needed if native byte order is not big endian */
91058a2b000SEvgeniy Ivanov #if BYTE_ORDER == BIG_ENDIAN
91158a2b000SEvgeniy Ivanov void
minixfs3_sb_bswap(struct mfs_sblock * old,struct mfs_sblock * new)91258a2b000SEvgeniy Ivanov minixfs3_sb_bswap(struct mfs_sblock *old, struct mfs_sblock *new)
91358a2b000SEvgeniy Ivanov {
91458a2b000SEvgeniy Ivanov 	new->mfs_ninodes	=	bswap32(old->mfs_ninodes);
91558a2b000SEvgeniy Ivanov 	new->mfs_nzones		=	bswap16(old->mfs_nzones);
91658a2b000SEvgeniy Ivanov 	new->mfs_imap_blocks	=	bswap16(old->mfs_imap_blocks);
91758a2b000SEvgeniy Ivanov 	new->mfs_zmap_blocks	=	bswap16(old->mfs_zmap_blocks);
91858a2b000SEvgeniy Ivanov 	new->mfs_firstdatazone_old =	bswap16(old->mfs_firstdatazone_old);
91958a2b000SEvgeniy Ivanov 	new->mfs_log_zone_size	=	bswap16(old->mfs_log_zone_size);
92058a2b000SEvgeniy Ivanov 	new->mfs_max_size	=	bswap32(old->mfs_max_size);
92158a2b000SEvgeniy Ivanov 	new->mfs_zones		=	bswap32(old->mfs_zones);
92258a2b000SEvgeniy Ivanov 	new->mfs_magic		=	bswap16(old->mfs_magic);
92358a2b000SEvgeniy Ivanov 	new->mfs_block_size	=	bswap16(old->mfs_block_size);
92458a2b000SEvgeniy Ivanov 	new->mfs_disk_version	=	old->mfs_disk_version;
92558a2b000SEvgeniy Ivanov }
92658a2b000SEvgeniy Ivanov 
minixfs3_i_bswap(struct mfs_dinode * old,struct mfs_dinode * new)92758a2b000SEvgeniy Ivanov void minixfs3_i_bswap(struct mfs_dinode *old, struct mfs_dinode *new)
92858a2b000SEvgeniy Ivanov {
92958a2b000SEvgeniy Ivanov 	int i;
93058a2b000SEvgeniy Ivanov 
93158a2b000SEvgeniy Ivanov 	new->mdi_mode		=	bswap16(old->mdi_mode);
93258a2b000SEvgeniy Ivanov 	new->mdi_nlinks		=	bswap16(old->mdi_nlinks);
93358a2b000SEvgeniy Ivanov 	new->mdi_uid		=	bswap16(old->mdi_uid);
93458a2b000SEvgeniy Ivanov 	new->mdi_gid		=	bswap16(old->mdi_gid);
93558a2b000SEvgeniy Ivanov 	new->mdi_size		=	bswap32(old->mdi_size);
93658a2b000SEvgeniy Ivanov 	new->mdi_atime		=	bswap32(old->mdi_atime);
93758a2b000SEvgeniy Ivanov 	new->mdi_mtime		=	bswap32(old->mdi_mtime);
93858a2b000SEvgeniy Ivanov 	new->mdi_ctime		=	bswap32(old->mdi_ctime);
93958a2b000SEvgeniy Ivanov 
94058a2b000SEvgeniy Ivanov 	/* We don't swap here, because indirects must be swapped later
94158a2b000SEvgeniy Ivanov 	 * anyway, hence everything is done by block_map().
94258a2b000SEvgeniy Ivanov 	 */
94358a2b000SEvgeniy Ivanov 	for (i = 0; i < NR_TZONES; i++)
94458a2b000SEvgeniy Ivanov 		new->mdi_zone[i] = old->mdi_zone[i];
94558a2b000SEvgeniy Ivanov }
94658a2b000SEvgeniy Ivanov #endif
947