Home | History | Annotate | Line # | Download | only in libsa
ext2fs.c revision 1.33
      1  1.32       rin /*	$NetBSD: ext2fs.c,v 1.33 2022/04/27 14:48:50 rin Exp $	*/
      2   1.1   tsutsui 
      3   1.1   tsutsui /*
      4   1.1   tsutsui  * Copyright (c) 1997 Manuel Bouyer.
      5   1.1   tsutsui  *
      6   1.1   tsutsui  * Redistribution and use in source and binary forms, with or without
      7   1.1   tsutsui  * modification, are permitted provided that the following conditions
      8   1.1   tsutsui  * are met:
      9   1.1   tsutsui  * 1. Redistributions of source code must retain the above copyright
     10   1.1   tsutsui  *    notice, this list of conditions and the following disclaimer.
     11   1.1   tsutsui  * 2. Redistributions in binary form must reproduce the above copyright
     12   1.1   tsutsui  *    notice, this list of conditions and the following disclaimer in the
     13   1.1   tsutsui  *    documentation and/or other materials provided with the distribution.
     14   1.1   tsutsui  *
     15   1.1   tsutsui  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     16   1.1   tsutsui  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     17   1.1   tsutsui  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     18   1.1   tsutsui  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     19   1.1   tsutsui  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     20   1.1   tsutsui  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     21   1.1   tsutsui  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     22   1.1   tsutsui  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23   1.1   tsutsui  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     24   1.1   tsutsui  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25   1.1   tsutsui  */
     26   1.1   tsutsui 
     27   1.1   tsutsui /*-
     28   1.1   tsutsui  * Copyright (c) 1993
     29   1.1   tsutsui  *	The Regents of the University of California.  All rights reserved.
     30   1.1   tsutsui  *
     31   1.1   tsutsui  * This code is derived from software contributed to Berkeley by
     32   1.1   tsutsui  * The Mach Operating System project at Carnegie-Mellon University.
     33   1.1   tsutsui  *
     34   1.1   tsutsui  * Redistribution and use in source and binary forms, with or without
     35   1.1   tsutsui  * modification, are permitted provided that the following conditions
     36   1.1   tsutsui  * are met:
     37   1.1   tsutsui  * 1. Redistributions of source code must retain the above copyright
     38   1.1   tsutsui  *    notice, this list of conditions and the following disclaimer.
     39   1.1   tsutsui  * 2. Redistributions in binary form must reproduce the above copyright
     40   1.1   tsutsui  *    notice, this list of conditions and the following disclaimer in the
     41   1.1   tsutsui  *    documentation and/or other materials provided with the distribution.
     42   1.1   tsutsui  * 3. Neither the name of the University nor the names of its contributors
     43   1.1   tsutsui  *    may be used to endorse or promote products derived from this software
     44   1.1   tsutsui  *    without specific prior written permission.
     45   1.1   tsutsui  *
     46   1.1   tsutsui  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     47   1.1   tsutsui  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     48   1.1   tsutsui  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     49   1.1   tsutsui  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     50   1.1   tsutsui  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     51   1.1   tsutsui  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     52   1.1   tsutsui  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     53   1.1   tsutsui  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     54   1.1   tsutsui  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     55   1.1   tsutsui  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     56   1.1   tsutsui  * SUCH DAMAGE.
     57   1.1   tsutsui  *
     58   1.1   tsutsui  *
     59   1.1   tsutsui  * Copyright (c) 1990, 1991 Carnegie Mellon University
     60   1.1   tsutsui  * All Rights Reserved.
     61   1.1   tsutsui  *
     62   1.1   tsutsui  * Author: David Golub
     63   1.1   tsutsui  *
     64   1.1   tsutsui  * Permission to use, copy, modify and distribute this software and its
     65   1.1   tsutsui  * documentation is hereby granted, provided that both the copyright
     66   1.1   tsutsui  * notice and this permission notice appear in all copies of the
     67   1.1   tsutsui  * software, derivative works or modified versions, and any portions
     68   1.1   tsutsui  * thereof, and that both notices appear in supporting documentation.
     69   1.1   tsutsui  *
     70   1.1   tsutsui  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
     71   1.1   tsutsui  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
     72   1.1   tsutsui  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
     73   1.1   tsutsui  *
     74   1.1   tsutsui  * Carnegie Mellon requests users of this software to return to
     75   1.1   tsutsui  *
     76   1.1   tsutsui  *  Software Distribution Coordinator  or  Software.Distribution (at) CS.CMU.EDU
     77   1.1   tsutsui  *  School of Computer Science
     78   1.1   tsutsui  *  Carnegie Mellon University
     79   1.1   tsutsui  *  Pittsburgh PA 15213-3890
     80   1.1   tsutsui  *
     81   1.1   tsutsui  * any improvements or extensions that they make and grant Carnegie the
     82   1.1   tsutsui  * rights to redistribute these changes.
     83   1.1   tsutsui  */
     84   1.1   tsutsui 
     85   1.1   tsutsui /*
     86   1.1   tsutsui  *	Stand-alone file reading package for Ext2 file system.
     87   1.1   tsutsui  */
     88   1.1   tsutsui 
     89   1.1   tsutsui /* #define EXT2FS_DEBUG */
     90   1.1   tsutsui 
     91   1.1   tsutsui #include <sys/param.h>
     92   1.1   tsutsui #include <sys/time.h>
     93   1.1   tsutsui #include <ufs/ext2fs/ext2fs_dinode.h>
     94   1.1   tsutsui #include <ufs/ext2fs/ext2fs_dir.h>
     95   1.1   tsutsui #include <ufs/ext2fs/ext2fs.h>
     96   1.1   tsutsui #ifdef _STANDALONE
     97   1.1   tsutsui #include <lib/libkern/libkern.h>
     98   1.1   tsutsui #else
     99   1.1   tsutsui #include <string.h>
    100   1.1   tsutsui #endif
    101   1.1   tsutsui 
    102   1.1   tsutsui #include "stand.h"
    103   1.1   tsutsui #include "ext2fs.h"
    104   1.1   tsutsui 
    105   1.1   tsutsui #if defined(LIBSA_FS_SINGLECOMPONENT) && !defined(LIBSA_NO_FS_SYMLINK)
    106   1.1   tsutsui #define LIBSA_NO_FS_SYMLINK
    107   1.1   tsutsui #endif
    108   1.1   tsutsui 
    109   1.1   tsutsui #if defined(LIBSA_NO_TWIDDLE)
    110   1.1   tsutsui #define twiddle()
    111   1.1   tsutsui #endif
    112   1.1   tsutsui 
    113   1.1   tsutsui #ifndef indp_t
    114   1.1   tsutsui #define indp_t		int32_t
    115   1.1   tsutsui #endif
    116   1.1   tsutsui typedef uint32_t	ino32_t;
    117   1.1   tsutsui #ifndef FSBTODB
    118  1.17  dholland #define FSBTODB(fs, indp) EXT2_FSBTODB(fs, indp)
    119   1.1   tsutsui #endif
    120   1.1   tsutsui 
    121   1.1   tsutsui /*
    122   1.1   tsutsui  * To avoid having a lot of filesystem-block sized buffers lurking (which
    123   1.1   tsutsui  * could be 32k) we only keep a few entries of the indirect block map.
    124   1.1   tsutsui  * With 8k blocks, 2^8 blocks is ~500k so we reread the indirect block
    125   1.1   tsutsui  * ~13 times pulling in a 6M kernel.
    126   1.1   tsutsui  * The cache size must be smaller than the smallest filesystem block,
    127   1.1   tsutsui  * so LN2_IND_CACHE_SZ <= 9 (UFS2 and 4k blocks).
    128   1.1   tsutsui  */
    129   1.1   tsutsui #define LN2_IND_CACHE_SZ	6
    130   1.1   tsutsui #define IND_CACHE_SZ		(1 << LN2_IND_CACHE_SZ)
    131   1.1   tsutsui #define IND_CACHE_MASK		(IND_CACHE_SZ - 1)
    132   1.1   tsutsui 
    133   1.1   tsutsui /*
    134   1.1   tsutsui  * In-core open file.
    135   1.1   tsutsui  */
    136   1.1   tsutsui struct file {
    137   1.1   tsutsui 	off_t		f_seekp;	/* seek pointer */
    138   1.1   tsutsui 	struct m_ext2fs	*f_fs;		/* pointer to super-block */
    139   1.1   tsutsui 	struct ext2fs_dinode	f_di;		/* copy of on-disk inode */
    140   1.1   tsutsui 	uint		f_nishift;	/* for blocks in indirect block */
    141   1.1   tsutsui 	indp_t		f_ind_cache_block;
    142   1.1   tsutsui 	indp_t		f_ind_cache[IND_CACHE_SZ];
    143   1.1   tsutsui 
    144   1.1   tsutsui 	char		*f_buf;		/* buffer for data block */
    145   1.1   tsutsui 	size_t		f_buf_size;	/* size of data block */
    146   1.1   tsutsui 	daddr_t		f_buf_blkno;	/* block number of data block */
    147   1.1   tsutsui };
    148   1.1   tsutsui 
    149  1.11   tsutsui 
    150   1.1   tsutsui static int read_inode(ino32_t, struct open_file *);
    151   1.1   tsutsui static int block_map(struct open_file *, indp_t, indp_t *);
    152   1.1   tsutsui static int buf_read_file(struct open_file *, char **, size_t *);
    153   1.1   tsutsui static int search_directory(const char *, int, struct open_file *, ino32_t *);
    154   1.1   tsutsui static int read_sblock(struct open_file *, struct m_ext2fs *);
    155   1.1   tsutsui static int read_gdblock(struct open_file *, struct m_ext2fs *);
    156   1.1   tsutsui #ifdef EXT2FS_DEBUG
    157   1.1   tsutsui static void dump_sblock(struct m_ext2fs *);
    158   1.1   tsutsui #endif
    159   1.1   tsutsui 
    160   1.1   tsutsui /*
    161   1.1   tsutsui  * Read a new inode into a file structure.
    162   1.1   tsutsui  */
    163   1.1   tsutsui static int
    164   1.1   tsutsui read_inode(ino32_t inumber, struct open_file *f)
    165   1.1   tsutsui {
    166   1.1   tsutsui 	struct file *fp = (struct file *)f->f_fsdata;
    167   1.1   tsutsui 	struct m_ext2fs *fs = fp->f_fs;
    168   1.1   tsutsui 	char *buf;
    169   1.1   tsutsui 	size_t rsize;
    170   1.1   tsutsui 	int rc;
    171   1.1   tsutsui 	daddr_t inode_sector;
    172   1.1   tsutsui 	struct ext2fs_dinode *dip;
    173   1.1   tsutsui 
    174   1.1   tsutsui 	inode_sector = FSBTODB(fs, ino_to_fsba(fs, inumber));
    175   1.1   tsutsui 
    176   1.1   tsutsui 	/*
    177   1.1   tsutsui 	 * Read inode and save it.
    178   1.1   tsutsui 	 */
    179   1.1   tsutsui 	buf = fp->f_buf;
    180   1.1   tsutsui 	twiddle();
    181   1.1   tsutsui 	rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
    182   1.1   tsutsui 	    inode_sector, fs->e2fs_bsize, buf, &rsize);
    183   1.1   tsutsui 	if (rc)
    184   1.1   tsutsui 		return rc;
    185  1.26  christos 	if (rsize != (size_t)fs->e2fs_bsize)
    186   1.1   tsutsui 		return EIO;
    187   1.1   tsutsui 
    188   1.7   tsutsui 	dip = (struct ext2fs_dinode *)(buf +
    189   1.7   tsutsui 	    EXT2_DINODE_SIZE(fs) * ino_to_fsbo(fs, inumber));
    190  1.22    nonaka 	e2fs_iload(dip, &fp->f_di, EXT2_DINODE_SIZE(fs));
    191   1.1   tsutsui 
    192   1.1   tsutsui 	/*
    193   1.1   tsutsui 	 * Clear out the old buffers
    194   1.1   tsutsui 	 */
    195   1.1   tsutsui 	fp->f_ind_cache_block = ~0;
    196   1.1   tsutsui 	fp->f_buf_blkno = -1;
    197   1.1   tsutsui 	return rc;
    198   1.1   tsutsui }
    199   1.1   tsutsui 
    200   1.1   tsutsui /*
    201   1.1   tsutsui  * Given an offset in a file, find the disk block number that
    202   1.1   tsutsui  * contains that block.
    203   1.1   tsutsui  */
    204   1.1   tsutsui static int
    205   1.1   tsutsui block_map(struct open_file *f, indp_t file_block, indp_t *disk_block_p)
    206   1.1   tsutsui {
    207   1.1   tsutsui 	struct file *fp = (struct file *)f->f_fsdata;
    208   1.1   tsutsui 	struct m_ext2fs *fs = fp->f_fs;
    209   1.1   tsutsui 	uint level;
    210   1.1   tsutsui 	indp_t ind_cache;
    211   1.1   tsutsui 	indp_t ind_block_num;
    212   1.1   tsutsui 	size_t rsize;
    213   1.1   tsutsui 	int rc;
    214   1.1   tsutsui 	indp_t *buf = (void *)fp->f_buf;
    215   1.1   tsutsui 
    216   1.1   tsutsui 	/*
    217   1.1   tsutsui 	 * Index structure of an inode:
    218   1.1   tsutsui 	 *
    219  1.14  dholland 	 * e2di_blocks[0..EXT2FS_NDADDR-1]
    220  1.15   tsutsui 	 *		hold block numbers for blocks
    221  1.15   tsutsui 	 *		0..EXT2FS_NDADDR-1
    222   1.1   tsutsui 	 *
    223  1.14  dholland 	 * e2di_blocks[EXT2FS_NDADDR+0]
    224  1.15   tsutsui 	 *		block EXT2FS_NDADDR+0 is the single indirect block
    225  1.15   tsutsui 	 *		holds block numbers for blocks
    226  1.16  dholland 	 *		EXT2FS_NDADDR .. EXT2FS_NDADDR + EXT2_NINDIR(fs)-1
    227   1.1   tsutsui 	 *
    228  1.14  dholland 	 * e2di_blocks[EXT2FS_NDADDR+1]
    229  1.15   tsutsui 	 *		block EXT2FS_NDADDR+1 is the double indirect block
    230  1.15   tsutsui 	 *		holds block numbers for INDEX blocks for blocks
    231  1.16  dholland 	 *		EXT2FS_NDADDR + EXT2_NINDIR(fs) ..
    232  1.16  dholland 	 *		EXT2FS_NDADDR + EXT2_NINDIR(fs) + EXT2_NINDIR(fs)**2 - 1
    233   1.1   tsutsui 	 *
    234  1.14  dholland 	 * e2di_blocks[EXT2FS_NDADDR+2]
    235  1.15   tsutsui 	 *		block EXT2FS_NDADDR+2 is the triple indirect block
    236  1.15   tsutsui 	 *		holds block numbers for	double-indirect
    237  1.15   tsutsui 	 *		blocks for blocks
    238  1.16  dholland 	 *		EXT2FS_NDADDR + EXT2_NINDIR(fs) + EXT2_NINDIR(fs)**2 ..
    239  1.16  dholland 	 *		EXT2FS_NDADDR + EXT2_NINDIR(fs) + EXT2_NINDIR(fs)**2
    240  1.16  dholland 	 *			+ EXT2_NINDIR(fs)**3 - 1
    241   1.1   tsutsui 	 */
    242   1.1   tsutsui 
    243  1.14  dholland 	if (file_block < EXT2FS_NDADDR) {
    244   1.1   tsutsui 		/* Direct block. */
    245   1.1   tsutsui 		*disk_block_p = fs2h32(fp->f_di.e2di_blocks[file_block]);
    246   1.1   tsutsui 		return 0;
    247   1.1   tsutsui 	}
    248   1.1   tsutsui 
    249  1.14  dholland 	file_block -= EXT2FS_NDADDR;
    250   1.1   tsutsui 
    251   1.1   tsutsui 	ind_cache = file_block >> LN2_IND_CACHE_SZ;
    252   1.1   tsutsui 	if (ind_cache == fp->f_ind_cache_block) {
    253   1.2   tsutsui 		*disk_block_p =
    254   1.2   tsutsui 		    fs2h32(fp->f_ind_cache[file_block & IND_CACHE_MASK]);
    255   1.1   tsutsui 		return 0;
    256   1.1   tsutsui 	}
    257   1.1   tsutsui 
    258   1.1   tsutsui 	for (level = 0;;) {
    259   1.1   tsutsui 		level += fp->f_nishift;
    260   1.1   tsutsui 		if (file_block < (indp_t)1 << level)
    261   1.1   tsutsui 			break;
    262  1.14  dholland 		if (level > EXT2FS_NIADDR * fp->f_nishift)
    263   1.1   tsutsui 			/* Block number too high */
    264   1.1   tsutsui 			return EFBIG;
    265   1.1   tsutsui 		file_block -= (indp_t)1 << level;
    266   1.1   tsutsui 	}
    267   1.1   tsutsui 
    268   1.1   tsutsui 	ind_block_num =
    269  1.15   tsutsui 	    fs2h32(fp->f_di.e2di_blocks[EXT2FS_NDADDR +
    270  1.15   tsutsui 	    (level / fp->f_nishift - 1)]);
    271   1.1   tsutsui 
    272   1.1   tsutsui 	for (;;) {
    273   1.1   tsutsui 		level -= fp->f_nishift;
    274   1.1   tsutsui 		if (ind_block_num == 0) {
    275   1.1   tsutsui 			*disk_block_p = 0;	/* missing */
    276   1.1   tsutsui 			return 0;
    277   1.1   tsutsui 		}
    278   1.1   tsutsui 
    279   1.1   tsutsui 		twiddle();
    280   1.1   tsutsui 		/*
    281   1.1   tsutsui 		 * If we were feeling brave, we could work out the number
    282   1.1   tsutsui 		 * of the disk sector and read a single disk sector instead
    283   1.1   tsutsui 		 * of a filesystem block.
    284   1.1   tsutsui 		 * However we don't do this very often anyway...
    285   1.1   tsutsui 		 */
    286   1.1   tsutsui 		rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
    287   1.1   tsutsui 			FSBTODB(fp->f_fs, ind_block_num), fs->e2fs_bsize,
    288   1.1   tsutsui 			buf, &rsize);
    289   1.1   tsutsui 		if (rc)
    290   1.1   tsutsui 			return rc;
    291  1.26  christos 		if (rsize != (size_t)fs->e2fs_bsize)
    292   1.1   tsutsui 			return EIO;
    293   1.2   tsutsui 		ind_block_num = fs2h32(buf[file_block >> level]);
    294   1.1   tsutsui 		if (level == 0)
    295   1.1   tsutsui 			break;
    296   1.1   tsutsui 		file_block &= (1 << level) - 1;
    297   1.1   tsutsui 	}
    298   1.1   tsutsui 
    299   1.1   tsutsui 	/* Save the part of the block that contains this sector */
    300   1.1   tsutsui 	memcpy(fp->f_ind_cache, &buf[file_block & ~IND_CACHE_MASK],
    301   1.1   tsutsui 	    IND_CACHE_SZ * sizeof fp->f_ind_cache[0]);
    302   1.1   tsutsui 	fp->f_ind_cache_block = ind_cache;
    303   1.1   tsutsui 
    304   1.1   tsutsui 	*disk_block_p = ind_block_num;
    305   1.1   tsutsui 
    306   1.1   tsutsui 	return 0;
    307   1.1   tsutsui }
    308   1.1   tsutsui 
    309   1.1   tsutsui /*
    310   1.1   tsutsui  * Read a portion of a file into an internal buffer.
    311   1.1   tsutsui  * Return the location in the buffer and the amount in the buffer.
    312   1.1   tsutsui  */
    313   1.1   tsutsui static int
    314   1.1   tsutsui buf_read_file(struct open_file *f, char **buf_p, size_t *size_p)
    315   1.1   tsutsui {
    316   1.1   tsutsui 	struct file *fp = (struct file *)f->f_fsdata;
    317   1.1   tsutsui 	struct m_ext2fs *fs = fp->f_fs;
    318   1.1   tsutsui 	long off;
    319   1.1   tsutsui 	indp_t file_block;
    320  1.19  christos 	indp_t disk_block = 0;	/* XXX: gcc */
    321  1.26  christos 	size_t block_size, tsz;
    322   1.1   tsutsui 	int rc;
    323   1.1   tsutsui 
    324  1.16  dholland 	off = ext2_blkoff(fs, fp->f_seekp);
    325  1.18  dholland 	file_block = ext2_lblkno(fs, fp->f_seekp);
    326   1.1   tsutsui 	block_size = fs->e2fs_bsize;	/* no fragment */
    327   1.1   tsutsui 
    328   1.1   tsutsui 	if (file_block != fp->f_buf_blkno) {
    329   1.1   tsutsui 		rc = block_map(f, file_block, &disk_block);
    330   1.1   tsutsui 		if (rc)
    331   1.1   tsutsui 			return rc;
    332   1.1   tsutsui 
    333   1.1   tsutsui 		if (disk_block == 0) {
    334   1.1   tsutsui 			memset(fp->f_buf, 0, block_size);
    335   1.1   tsutsui 			fp->f_buf_size = block_size;
    336   1.1   tsutsui 		} else {
    337   1.1   tsutsui 			twiddle();
    338   1.1   tsutsui 			rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
    339   1.1   tsutsui 				FSBTODB(fs, disk_block),
    340   1.1   tsutsui 				block_size, fp->f_buf, &fp->f_buf_size);
    341   1.1   tsutsui 			if (rc)
    342   1.1   tsutsui 				return rc;
    343   1.1   tsutsui 		}
    344   1.1   tsutsui 
    345   1.1   tsutsui 		fp->f_buf_blkno = file_block;
    346   1.1   tsutsui 	}
    347   1.1   tsutsui 
    348   1.1   tsutsui 	/*
    349   1.1   tsutsui 	 * Return address of byte in buffer corresponding to
    350   1.1   tsutsui 	 * offset, and size of remainder of buffer after that
    351   1.1   tsutsui 	 * byte.
    352   1.1   tsutsui 	 */
    353   1.1   tsutsui 	*buf_p = fp->f_buf + off;
    354   1.1   tsutsui 	*size_p = block_size - off;
    355   1.1   tsutsui 
    356   1.1   tsutsui 	/*
    357   1.1   tsutsui 	 * But truncate buffer at end of file.
    358   1.1   tsutsui 	 */
    359   1.1   tsutsui 	/* XXX should handle LARGEFILE */
    360  1.26  christos 	tsz = (size_t)(fp->f_di.e2di_size - fp->f_seekp);
    361  1.26  christos 	if (*size_p > tsz)
    362  1.26  christos 		*size_p = tsz;
    363   1.1   tsutsui 
    364   1.1   tsutsui 	return 0;
    365   1.1   tsutsui }
    366   1.1   tsutsui 
    367   1.1   tsutsui /*
    368   1.1   tsutsui  * Search a directory for a name and return its
    369   1.1   tsutsui  * inode number.
    370   1.1   tsutsui  */
    371   1.1   tsutsui static int
    372   1.1   tsutsui search_directory(const char *name, int length, struct open_file *f,
    373   1.1   tsutsui 	ino32_t *inumber_p)
    374   1.1   tsutsui {
    375   1.1   tsutsui 	struct file *fp = (struct file *)f->f_fsdata;
    376   1.1   tsutsui 	struct ext2fs_direct *dp;
    377   1.1   tsutsui 	struct ext2fs_direct *edp;
    378   1.1   tsutsui 	char *buf;
    379   1.1   tsutsui 	size_t buf_size;
    380   1.1   tsutsui 	int namlen;
    381   1.1   tsutsui 	int rc;
    382   1.1   tsutsui 
    383   1.1   tsutsui 	fp->f_seekp = 0;
    384   1.1   tsutsui 	/* XXX should handle LARGEFILE */
    385   1.1   tsutsui 	while (fp->f_seekp < (off_t)fp->f_di.e2di_size) {
    386   1.1   tsutsui 		rc = buf_read_file(f, &buf, &buf_size);
    387   1.1   tsutsui 		if (rc)
    388   1.1   tsutsui 			return rc;
    389   1.1   tsutsui 
    390   1.1   tsutsui 		dp = (struct ext2fs_direct *)buf;
    391   1.1   tsutsui 		edp = (struct ext2fs_direct *)(buf + buf_size);
    392   1.1   tsutsui 		for (; dp < edp;
    393   1.1   tsutsui 		    dp = (void *)((char *)dp + fs2h16(dp->e2d_reclen))) {
    394   1.1   tsutsui 			if (fs2h16(dp->e2d_reclen) <= 0)
    395   1.1   tsutsui 				break;
    396   1.1   tsutsui 			if (fs2h32(dp->e2d_ino) == (ino32_t)0)
    397   1.1   tsutsui 				continue;
    398   1.1   tsutsui 			namlen = dp->e2d_namlen;
    399   1.1   tsutsui 			if (namlen == length &&
    400   1.1   tsutsui 			    !memcmp(name, dp->e2d_name, length)) {
    401   1.1   tsutsui 				/* found entry */
    402   1.1   tsutsui 				*inumber_p = fs2h32(dp->e2d_ino);
    403   1.1   tsutsui 				return 0;
    404   1.1   tsutsui 			}
    405   1.1   tsutsui 		}
    406   1.1   tsutsui 		fp->f_seekp += buf_size;
    407   1.1   tsutsui 	}
    408   1.1   tsutsui 	return ENOENT;
    409   1.1   tsutsui }
    410   1.1   tsutsui 
    411   1.1   tsutsui int
    412   1.1   tsutsui read_sblock(struct open_file *f, struct m_ext2fs *fs)
    413   1.1   tsutsui {
    414   1.1   tsutsui 	static uint8_t sbbuf[SBSIZE];
    415   1.1   tsutsui 	struct ext2fs ext2fs;
    416   1.1   tsutsui 	size_t buf_size;
    417   1.1   tsutsui 	int rc;
    418  1.33       rin 	u_int secsize;
    419  1.33       rin 
    420  1.33       rin 	secsize = 0;
    421  1.33       rin 	rc = DEV_IOCTL(f->f_dev)(f, SAIOSECSIZE, &secsize);
    422  1.33       rin 	if (rc != 0 || secsize == 0)
    423  1.33       rin 		secsize = DEV_BSIZE;
    424   1.1   tsutsui 
    425   1.1   tsutsui 	rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
    426  1.33       rin 	    SBOFF / secsize, SBSIZE, sbbuf, &buf_size);
    427   1.1   tsutsui 	if (rc)
    428   1.1   tsutsui 		return rc;
    429   1.1   tsutsui 
    430   1.1   tsutsui 	if (buf_size != SBSIZE)
    431   1.1   tsutsui 		return EIO;
    432   1.1   tsutsui 
    433   1.1   tsutsui 	e2fs_sbload((void *)sbbuf, &ext2fs);
    434   1.1   tsutsui 	if (ext2fs.e2fs_magic != E2FS_MAGIC)
    435   1.1   tsutsui 		return EINVAL;
    436   1.1   tsutsui 	if (ext2fs.e2fs_rev > E2FS_REV1 ||
    437   1.1   tsutsui 	    (ext2fs.e2fs_rev == E2FS_REV1 &&
    438   1.1   tsutsui 	     (ext2fs.e2fs_first_ino != EXT2_FIRSTINO ||
    439   1.6  christos 	     (ext2fs.e2fs_inode_size != 128 && ext2fs.e2fs_inode_size != 256) ||
    440   1.1   tsutsui 	      ext2fs.e2fs_features_incompat & ~EXT2F_INCOMPAT_SUPP))) {
    441   1.1   tsutsui 		return ENODEV;
    442   1.1   tsutsui 	}
    443   1.1   tsutsui 
    444   1.1   tsutsui 	e2fs_sbload((void *)sbbuf, &fs->e2fs);
    445   1.1   tsutsui 	/* compute in-memory m_ext2fs values */
    446   1.1   tsutsui 	fs->e2fs_ncg =
    447   1.1   tsutsui 	    howmany(fs->e2fs.e2fs_bcount - fs->e2fs.e2fs_first_dblock,
    448   1.1   tsutsui 	    fs->e2fs.e2fs_bpg);
    449   1.1   tsutsui 	/* XXX assume hw bsize = 512 */
    450   1.1   tsutsui 	fs->e2fs_fsbtodb = fs->e2fs.e2fs_log_bsize + 1;
    451   1.1   tsutsui 	fs->e2fs_bsize = MINBSIZE << fs->e2fs.e2fs_log_bsize;
    452   1.1   tsutsui 	fs->e2fs_bshift = LOG_MINBSIZE + fs->e2fs.e2fs_log_bsize;
    453   1.1   tsutsui 	fs->e2fs_qbmask = fs->e2fs_bsize - 1;
    454   1.1   tsutsui 	fs->e2fs_bmask = ~fs->e2fs_qbmask;
    455   1.1   tsutsui 	fs->e2fs_ngdb =
    456   1.1   tsutsui 	    howmany(fs->e2fs_ncg, fs->e2fs_bsize / sizeof(struct ext2_gd));
    457   1.6  christos 	fs->e2fs_ipb = fs->e2fs_bsize / ext2fs.e2fs_inode_size;
    458   1.1   tsutsui 	fs->e2fs_itpg = fs->e2fs.e2fs_ipg / fs->e2fs_ipb;
    459   1.1   tsutsui 
    460   1.1   tsutsui 	return 0;
    461   1.1   tsutsui }
    462   1.1   tsutsui 
    463   1.1   tsutsui int
    464   1.1   tsutsui read_gdblock(struct open_file *f, struct m_ext2fs *fs)
    465   1.1   tsutsui {
    466   1.1   tsutsui 	struct file *fp = (struct file *)f->f_fsdata;
    467   1.1   tsutsui 	size_t rsize;
    468   1.1   tsutsui 	uint gdpb;
    469   1.1   tsutsui 	int i, rc;
    470   1.1   tsutsui 
    471   1.1   tsutsui 	gdpb = fs->e2fs_bsize / sizeof(struct ext2_gd);
    472   1.1   tsutsui 
    473   1.1   tsutsui 	for (i = 0; i < fs->e2fs_ngdb; i++) {
    474   1.1   tsutsui 		rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
    475   1.1   tsutsui 		    FSBTODB(fs, fs->e2fs.e2fs_first_dblock +
    476   1.1   tsutsui 		    1 /* superblock */ + i),
    477   1.1   tsutsui 		    fs->e2fs_bsize, fp->f_buf, &rsize);
    478   1.1   tsutsui 		if (rc)
    479   1.1   tsutsui 			return rc;
    480  1.26  christos 		if (rsize != (size_t)fs->e2fs_bsize)
    481   1.1   tsutsui 			return EIO;
    482   1.1   tsutsui 
    483   1.1   tsutsui 		e2fs_cgload((struct ext2_gd *)fp->f_buf,
    484   1.1   tsutsui 		    &fs->e2fs_gd[i * gdpb],
    485   1.1   tsutsui 		    (i == (fs->e2fs_ngdb - 1)) ?
    486   1.1   tsutsui 		    (fs->e2fs_ncg - gdpb * i) * sizeof(struct ext2_gd):
    487  1.26  christos 		    (size_t)fs->e2fs_bsize);
    488   1.1   tsutsui 	}
    489   1.1   tsutsui 
    490   1.1   tsutsui 	return 0;
    491   1.1   tsutsui }
    492   1.1   tsutsui 
    493   1.1   tsutsui 
    494   1.1   tsutsui /*
    495   1.1   tsutsui  * Open a file.
    496   1.1   tsutsui  */
    497  1.10     joerg __compactcall int
    498   1.1   tsutsui ext2fs_open(const char *path, struct open_file *f)
    499   1.1   tsutsui {
    500   1.1   tsutsui #ifndef LIBSA_FS_SINGLECOMPONENT
    501   1.1   tsutsui 	const char *cp, *ncp;
    502   1.1   tsutsui 	int c;
    503   1.1   tsutsui #endif
    504   1.1   tsutsui 	ino32_t inumber;
    505   1.1   tsutsui 	struct file *fp;
    506   1.1   tsutsui 	struct m_ext2fs *fs;
    507   1.1   tsutsui 	int rc;
    508   1.1   tsutsui #ifndef LIBSA_NO_FS_SYMLINK
    509   1.1   tsutsui 	ino32_t parent_inumber;
    510   1.1   tsutsui 	int nlinks = 0;
    511   1.1   tsutsui 	char namebuf[MAXPATHLEN+1];
    512   1.1   tsutsui 	char *buf;
    513   1.1   tsutsui #endif
    514   1.1   tsutsui 
    515   1.1   tsutsui 	/* allocate file system specific data structure */
    516   1.1   tsutsui 	fp = alloc(sizeof(struct file));
    517   1.1   tsutsui 	memset(fp, 0, sizeof(struct file));
    518   1.1   tsutsui 	f->f_fsdata = (void *)fp;
    519   1.1   tsutsui 
    520   1.1   tsutsui 	/* allocate space and read super block */
    521   1.3   tsutsui 	fs = alloc(sizeof(*fs));
    522   1.9  jakllsch 	memset(fs, 0, sizeof(*fs));
    523   1.1   tsutsui 	fp->f_fs = fs;
    524   1.1   tsutsui 	twiddle();
    525   1.1   tsutsui 
    526   1.1   tsutsui 	rc = read_sblock(f, fs);
    527   1.1   tsutsui 	if (rc)
    528   1.1   tsutsui 		goto out;
    529   1.1   tsutsui 
    530   1.1   tsutsui #ifdef EXT2FS_DEBUG
    531   1.1   tsutsui 	dump_sblock(fs);
    532   1.1   tsutsui #endif
    533   1.1   tsutsui 
    534   1.1   tsutsui 	/* alloc a block sized buffer used for all fs transfers */
    535   1.1   tsutsui 	fp->f_buf = alloc(fs->e2fs_bsize);
    536   1.1   tsutsui 
    537   1.1   tsutsui 	/* read group descriptor blocks */
    538   1.1   tsutsui 	fs->e2fs_gd = alloc(sizeof(struct ext2_gd) * fs->e2fs_ncg);
    539   1.1   tsutsui 	rc = read_gdblock(f, fs);
    540   1.1   tsutsui 	if (rc)
    541   1.1   tsutsui 		goto out;
    542   1.1   tsutsui 
    543   1.1   tsutsui 	/*
    544   1.1   tsutsui 	 * Calculate indirect block levels.
    545   1.1   tsutsui 	 */
    546   1.1   tsutsui 	{
    547   1.1   tsutsui 		indp_t mult;
    548   1.1   tsutsui 		int ln2;
    549   1.1   tsutsui 
    550   1.1   tsutsui 		/*
    551   1.1   tsutsui 		 * We note that the number of indirect blocks is always
    552   1.1   tsutsui 		 * a power of 2.  This lets us use shifts and masks instead
    553  1.30     skrll 		 * of divide and remainder and avoids pulling in the
    554   1.1   tsutsui 		 * 64bit division routine into the boot code.
    555   1.1   tsutsui 		 */
    556  1.16  dholland 		mult = EXT2_NINDIR(fs);
    557   1.1   tsutsui #ifdef DEBUG
    558   1.1   tsutsui 		if (!powerof2(mult)) {
    559   1.1   tsutsui 			/* Hummm was't a power of 2 */
    560   1.1   tsutsui 			rc = EINVAL;
    561   1.1   tsutsui 			goto out;
    562   1.1   tsutsui 		}
    563   1.1   tsutsui #endif
    564   1.1   tsutsui 		for (ln2 = 0; mult != 1; ln2++)
    565   1.1   tsutsui 			mult >>= 1;
    566   1.1   tsutsui 
    567   1.1   tsutsui 		fp->f_nishift = ln2;
    568   1.1   tsutsui 	}
    569   1.1   tsutsui 
    570   1.1   tsutsui 	inumber = EXT2_ROOTINO;
    571   1.1   tsutsui 	if ((rc = read_inode(inumber, f)) != 0)
    572   1.1   tsutsui 		goto out;
    573   1.1   tsutsui 
    574   1.1   tsutsui #ifndef LIBSA_FS_SINGLECOMPONENT
    575   1.1   tsutsui 	cp = path;
    576   1.1   tsutsui 	while (*cp) {
    577   1.1   tsutsui 
    578   1.1   tsutsui 		/*
    579   1.1   tsutsui 		 * Remove extra separators
    580   1.1   tsutsui 		 */
    581   1.1   tsutsui 		while (*cp == '/')
    582   1.1   tsutsui 			cp++;
    583   1.1   tsutsui 		if (*cp == '\0')
    584   1.1   tsutsui 			break;
    585   1.1   tsutsui 
    586   1.1   tsutsui 		/*
    587   1.1   tsutsui 		 * Check that current node is a directory.
    588   1.1   tsutsui 		 */
    589   1.1   tsutsui 		if ((fp->f_di.e2di_mode & EXT2_IFMT) != EXT2_IFDIR) {
    590   1.1   tsutsui 			rc = ENOTDIR;
    591   1.1   tsutsui 			goto out;
    592   1.1   tsutsui 		}
    593   1.1   tsutsui 
    594   1.1   tsutsui 		/*
    595   1.1   tsutsui 		 * Get next component of path name.
    596   1.1   tsutsui 		 */
    597   1.1   tsutsui 		ncp = cp;
    598   1.1   tsutsui 		while ((c = *cp) != '\0' && c != '/')
    599   1.1   tsutsui 			cp++;
    600   1.1   tsutsui 
    601   1.1   tsutsui 		/*
    602   1.1   tsutsui 		 * Look up component in current directory.
    603   1.1   tsutsui 		 * Save directory inumber in case we find a
    604   1.1   tsutsui 		 * symbolic link.
    605   1.1   tsutsui 		 */
    606   1.1   tsutsui #ifndef LIBSA_NO_FS_SYMLINK
    607   1.1   tsutsui 		parent_inumber = inumber;
    608   1.1   tsutsui #endif
    609   1.1   tsutsui 		rc = search_directory(ncp, cp - ncp, f, &inumber);
    610   1.1   tsutsui 		if (rc)
    611   1.1   tsutsui 			goto out;
    612   1.1   tsutsui 
    613   1.1   tsutsui 		/*
    614   1.1   tsutsui 		 * Open next component.
    615   1.1   tsutsui 		 */
    616   1.1   tsutsui 		if ((rc = read_inode(inumber, f)) != 0)
    617   1.1   tsutsui 			goto out;
    618   1.1   tsutsui 
    619   1.1   tsutsui #ifndef LIBSA_NO_FS_SYMLINK
    620   1.1   tsutsui 		/*
    621   1.1   tsutsui 		 * Check for symbolic link.
    622   1.1   tsutsui 		 */
    623   1.1   tsutsui 		if ((fp->f_di.e2di_mode & EXT2_IFMT) == EXT2_IFLNK) {
    624   1.1   tsutsui 			/* XXX should handle LARGEFILE */
    625  1.26  christos 			size_t link_len = fp->f_di.e2di_size;
    626  1.26  christos 			size_t len;
    627   1.1   tsutsui 
    628   1.1   tsutsui 			len = strlen(cp);
    629   1.1   tsutsui 
    630   1.1   tsutsui 			if (link_len + len > MAXPATHLEN ||
    631   1.1   tsutsui 			    ++nlinks > MAXSYMLINKS) {
    632   1.1   tsutsui 				rc = ENOENT;
    633   1.1   tsutsui 				goto out;
    634   1.1   tsutsui 			}
    635   1.1   tsutsui 
    636   1.1   tsutsui 			memmove(&namebuf[link_len], cp, len + 1);
    637   1.1   tsutsui 
    638   1.1   tsutsui 			if (link_len < EXT2_MAXSYMLINKLEN) {
    639   1.1   tsutsui 				memcpy(namebuf, fp->f_di.e2di_blocks, link_len);
    640   1.1   tsutsui 			} else {
    641   1.1   tsutsui 				/*
    642   1.1   tsutsui 				 * Read file for symbolic link
    643   1.1   tsutsui 				 */
    644   1.1   tsutsui 				size_t buf_size;
    645   1.1   tsutsui 				indp_t	disk_block;
    646   1.1   tsutsui 
    647   1.1   tsutsui 				buf = fp->f_buf;
    648   1.1   tsutsui 				rc = block_map(f, (indp_t)0, &disk_block);
    649   1.1   tsutsui 				if (rc)
    650   1.1   tsutsui 					goto out;
    651   1.1   tsutsui 
    652   1.1   tsutsui 				twiddle();
    653   1.1   tsutsui 				rc = DEV_STRATEGY(f->f_dev)(f->f_devdata,
    654   1.1   tsutsui 					F_READ, FSBTODB(fs, disk_block),
    655   1.1   tsutsui 					fs->e2fs_bsize, buf, &buf_size);
    656   1.1   tsutsui 				if (rc)
    657   1.1   tsutsui 					goto out;
    658   1.1   tsutsui 
    659   1.1   tsutsui 				memcpy(namebuf, buf, link_len);
    660   1.1   tsutsui 			}
    661   1.1   tsutsui 
    662   1.1   tsutsui 			/*
    663   1.1   tsutsui 			 * If relative pathname, restart at parent directory.
    664   1.1   tsutsui 			 * If absolute pathname, restart at root.
    665   1.1   tsutsui 			 */
    666   1.1   tsutsui 			cp = namebuf;
    667   1.1   tsutsui 			if (*cp != '/')
    668   1.1   tsutsui 				inumber = parent_inumber;
    669   1.1   tsutsui 			else
    670   1.1   tsutsui 				inumber = (ino32_t)EXT2_ROOTINO;
    671   1.1   tsutsui 
    672   1.1   tsutsui 			if ((rc = read_inode(inumber, f)) != 0)
    673   1.1   tsutsui 				goto out;
    674   1.1   tsutsui 		}
    675   1.1   tsutsui #endif	/* !LIBSA_NO_FS_SYMLINK */
    676   1.1   tsutsui 	}
    677   1.1   tsutsui 
    678   1.1   tsutsui 	/*
    679   1.1   tsutsui 	 * Found terminal component.
    680   1.1   tsutsui 	 */
    681   1.1   tsutsui 	rc = 0;
    682   1.1   tsutsui 
    683   1.1   tsutsui #else /* !LIBSA_FS_SINGLECOMPONENT */
    684   1.1   tsutsui 
    685   1.1   tsutsui 	/* look up component in the current (root) directory */
    686   1.1   tsutsui 	rc = search_directory(path, strlen(path), f, &inumber);
    687   1.1   tsutsui 	if (rc)
    688   1.1   tsutsui 		goto out;
    689   1.1   tsutsui 
    690   1.1   tsutsui 	/* open it */
    691   1.1   tsutsui 	rc = read_inode(inumber, f);
    692   1.1   tsutsui 
    693   1.1   tsutsui #endif /* !LIBSA_FS_SINGLECOMPONENT */
    694   1.1   tsutsui 
    695   1.1   tsutsui 	fp->f_seekp = 0;		/* reset seek pointer */
    696   1.1   tsutsui 
    697   1.1   tsutsui out:
    698   1.1   tsutsui 	if (rc)
    699   1.1   tsutsui 		ext2fs_close(f);
    700  1.13       dsl 	else
    701  1.28  pgoyette 		fsmod = "ufs/ext2fs";
    702   1.1   tsutsui 	return rc;
    703   1.1   tsutsui }
    704   1.1   tsutsui 
    705  1.10     joerg __compactcall int
    706   1.1   tsutsui ext2fs_close(struct open_file *f)
    707   1.1   tsutsui {
    708   1.1   tsutsui 	struct file *fp = (struct file *)f->f_fsdata;
    709   1.1   tsutsui 
    710   1.1   tsutsui 	f->f_fsdata = NULL;
    711   1.1   tsutsui 	if (fp == NULL)
    712   1.1   tsutsui 		return 0;
    713   1.1   tsutsui 
    714   1.4   tsutsui 	if (fp->f_fs->e2fs_gd)
    715   1.4   tsutsui 		dealloc(fp->f_fs->e2fs_gd,
    716   1.4   tsutsui 		    sizeof(struct ext2_gd) * fp->f_fs->e2fs_ncg);
    717   1.1   tsutsui 	if (fp->f_buf)
    718   1.1   tsutsui 		dealloc(fp->f_buf, fp->f_fs->e2fs_bsize);
    719   1.4   tsutsui 	dealloc(fp->f_fs, sizeof(*fp->f_fs));
    720   1.1   tsutsui 	dealloc(fp, sizeof(struct file));
    721   1.1   tsutsui 	return 0;
    722   1.1   tsutsui }
    723   1.1   tsutsui 
    724   1.1   tsutsui /*
    725   1.1   tsutsui  * Copy a portion of a file into kernel memory.
    726   1.1   tsutsui  * Cross block boundaries when necessary.
    727   1.1   tsutsui  */
    728  1.10     joerg __compactcall int
    729   1.1   tsutsui ext2fs_read(struct open_file *f, void *start, size_t size, size_t *resid)
    730   1.1   tsutsui {
    731   1.1   tsutsui 	struct file *fp = (struct file *)f->f_fsdata;
    732   1.1   tsutsui 	size_t csize;
    733   1.1   tsutsui 	char *buf;
    734   1.1   tsutsui 	size_t buf_size;
    735   1.1   tsutsui 	int rc = 0;
    736   1.1   tsutsui 	char *addr = start;
    737   1.1   tsutsui 
    738   1.1   tsutsui 	while (size != 0) {
    739   1.1   tsutsui 		/* XXX should handle LARGEFILE */
    740   1.1   tsutsui 		if (fp->f_seekp >= (off_t)fp->f_di.e2di_size)
    741   1.1   tsutsui 			break;
    742   1.1   tsutsui 
    743   1.1   tsutsui 		rc = buf_read_file(f, &buf, &buf_size);
    744   1.1   tsutsui 		if (rc)
    745   1.1   tsutsui 			break;
    746   1.1   tsutsui 
    747   1.1   tsutsui 		csize = size;
    748   1.1   tsutsui 		if (csize > buf_size)
    749   1.1   tsutsui 			csize = buf_size;
    750   1.1   tsutsui 
    751   1.1   tsutsui 		memcpy(addr, buf, csize);
    752   1.1   tsutsui 
    753   1.1   tsutsui 		fp->f_seekp += csize;
    754   1.1   tsutsui 		addr += csize;
    755   1.1   tsutsui 		size -= csize;
    756   1.1   tsutsui 	}
    757   1.1   tsutsui 	if (resid)
    758   1.1   tsutsui 		*resid = size;
    759   1.1   tsutsui 	return rc;
    760   1.1   tsutsui }
    761   1.1   tsutsui 
    762   1.1   tsutsui /*
    763   1.1   tsutsui  * Not implemented.
    764   1.1   tsutsui  */
    765   1.1   tsutsui #ifndef LIBSA_NO_FS_WRITE
    766  1.10     joerg __compactcall int
    767   1.1   tsutsui ext2fs_write(struct open_file *f, void *start, size_t size, size_t *resid)
    768   1.1   tsutsui {
    769   1.1   tsutsui 
    770   1.1   tsutsui 	return EROFS;
    771   1.1   tsutsui }
    772   1.1   tsutsui #endif /* !LIBSA_NO_FS_WRITE */
    773   1.1   tsutsui 
    774   1.1   tsutsui #ifndef LIBSA_NO_FS_SEEK
    775  1.10     joerg __compactcall off_t
    776   1.1   tsutsui ext2fs_seek(struct open_file *f, off_t offset, int where)
    777   1.1   tsutsui {
    778   1.1   tsutsui 	struct file *fp = (struct file *)f->f_fsdata;
    779   1.1   tsutsui 
    780   1.1   tsutsui 	switch (where) {
    781   1.1   tsutsui 	case SEEK_SET:
    782   1.1   tsutsui 		fp->f_seekp = offset;
    783   1.1   tsutsui 		break;
    784   1.1   tsutsui 	case SEEK_CUR:
    785   1.1   tsutsui 		fp->f_seekp += offset;
    786   1.1   tsutsui 		break;
    787   1.1   tsutsui 	case SEEK_END:
    788   1.1   tsutsui 		/* XXX should handle LARGEFILE */
    789   1.1   tsutsui 		fp->f_seekp = fp->f_di.e2di_size - offset;
    790   1.1   tsutsui 		break;
    791   1.1   tsutsui 	default:
    792   1.1   tsutsui 		return -1;
    793   1.1   tsutsui 	}
    794   1.1   tsutsui 	return fp->f_seekp;
    795   1.1   tsutsui }
    796   1.1   tsutsui #endif /* !LIBSA_NO_FS_SEEK */
    797   1.1   tsutsui 
    798  1.10     joerg __compactcall int
    799   1.1   tsutsui ext2fs_stat(struct open_file *f, struct stat *sb)
    800   1.1   tsutsui {
    801   1.1   tsutsui 	struct file *fp = (struct file *)f->f_fsdata;
    802   1.1   tsutsui 
    803   1.1   tsutsui 	/* only important stuff */
    804   1.1   tsutsui 	memset(sb, 0, sizeof *sb);
    805   1.1   tsutsui 	sb->st_mode = fp->f_di.e2di_mode;
    806   1.1   tsutsui 	sb->st_uid = fp->f_di.e2di_uid;
    807   1.1   tsutsui 	sb->st_gid = fp->f_di.e2di_gid;
    808   1.1   tsutsui 	/* XXX should handle LARGEFILE */
    809   1.1   tsutsui 	sb->st_size = fp->f_di.e2di_size;
    810   1.1   tsutsui 	return 0;
    811   1.1   tsutsui }
    812   1.1   tsutsui 
    813  1.11   tsutsui #if defined(LIBSA_ENABLE_LS_OP)
    814  1.20  christos 
    815  1.20  christos #include "ls.h"
    816  1.20  christos 
    817  1.20  christos static const char    *const typestr[] = {
    818  1.20  christos 	"unknown",
    819  1.20  christos 	"REG",
    820  1.20  christos 	"DIR",
    821  1.20  christos 	"CHR",
    822  1.20  christos 	"BLK",
    823  1.20  christos 	"FIFO",
    824  1.20  christos 	"SOCK",
    825  1.20  christos 	"LNK"
    826  1.20  christos };
    827  1.20  christos 
    828  1.11   tsutsui __compactcall void
    829  1.11   tsutsui ext2fs_ls(struct open_file *f, const char *pattern)
    830  1.11   tsutsui {
    831  1.11   tsutsui 	struct file *fp = (struct file *)f->f_fsdata;
    832  1.11   tsutsui 	size_t block_size = fp->f_fs->e2fs_bsize;
    833  1.11   tsutsui 	char *buf;
    834  1.11   tsutsui 	size_t buf_size;
    835  1.20  christos 	lsentry_t *names = NULL;
    836  1.11   tsutsui 
    837  1.11   tsutsui 	fp->f_seekp = 0;
    838  1.11   tsutsui 	while (fp->f_seekp < (off_t)fp->f_di.e2di_size) {
    839  1.11   tsutsui 		struct ext2fs_direct  *dp, *edp;
    840  1.11   tsutsui 		int rc = buf_read_file(f, &buf, &buf_size);
    841  1.11   tsutsui 		if (rc)
    842  1.11   tsutsui 			goto out;
    843  1.11   tsutsui 		if (buf_size != block_size || buf_size == 0)
    844  1.11   tsutsui 			goto out;
    845  1.11   tsutsui 
    846  1.11   tsutsui 		dp = (struct ext2fs_direct *)buf;
    847  1.11   tsutsui 		edp = (struct ext2fs_direct *)(buf + buf_size);
    848  1.11   tsutsui 
    849  1.11   tsutsui 		for (; dp < edp;
    850  1.11   tsutsui 		     dp = (void *)((char *)dp + fs2h16(dp->e2d_reclen))) {
    851  1.11   tsutsui 			const char *t;
    852  1.11   tsutsui 
    853  1.11   tsutsui 			if (fs2h16(dp->e2d_reclen) <= 0)
    854  1.11   tsutsui 				goto out;
    855  1.11   tsutsui 
    856  1.11   tsutsui 			if (fs2h32(dp->e2d_ino) == 0)
    857  1.11   tsutsui 				continue;
    858  1.11   tsutsui 
    859  1.11   tsutsui 			if (dp->e2d_type >= NELEM(typestr) ||
    860  1.11   tsutsui 			    !(t = typestr[dp->e2d_type])) {
    861  1.11   tsutsui 				/*
    862  1.11   tsutsui 				 * This does not handle "old"
    863  1.11   tsutsui 				 * filesystems properly. On little
    864  1.11   tsutsui 				 * endian machines, we get a bogus
    865  1.11   tsutsui 				 * type name if the namlen matches a
    866  1.11   tsutsui 				 * valid type identifier. We could
    867  1.11   tsutsui 				 * check if we read namlen "0" and
    868  1.11   tsutsui 				 * handle this case specially, if
    869  1.11   tsutsui 				 * there were a pressing need...
    870  1.11   tsutsui 				 */
    871  1.11   tsutsui 				printf("bad dir entry\n");
    872  1.11   tsutsui 				goto out;
    873  1.11   tsutsui 			}
    874  1.20  christos 			lsadd(&names, pattern, dp->e2d_name,
    875  1.29  jakllsch 			    dp->e2d_namlen, fs2h32(dp->e2d_ino), t);
    876  1.11   tsutsui 		}
    877  1.11   tsutsui 		fp->f_seekp += buf_size;
    878  1.11   tsutsui 	}
    879  1.11   tsutsui 
    880  1.20  christos 	lsprint(names);
    881  1.20  christos out:	lsfree(names);
    882  1.11   tsutsui }
    883  1.11   tsutsui #endif
    884  1.11   tsutsui 
    885   1.1   tsutsui /*
    886   1.1   tsutsui  * byte swap functions for big endian machines
    887   1.1   tsutsui  * (ext2fs is always little endian)
    888   1.1   tsutsui  *
    889   1.1   tsutsui  * XXX: We should use src/sys/ufs/ext2fs/ext2fs_bswap.c
    890   1.1   tsutsui  */
    891   1.1   tsutsui 
    892   1.1   tsutsui /* These functions are only needed if native byte order is not big endian */
    893   1.1   tsutsui #if BYTE_ORDER == BIG_ENDIAN
    894   1.1   tsutsui void
    895   1.1   tsutsui e2fs_sb_bswap(struct ext2fs *old, struct ext2fs *new)
    896   1.1   tsutsui {
    897   1.1   tsutsui 
    898   1.1   tsutsui 	/* preserve unused fields */
    899   1.1   tsutsui 	memcpy(new, old, sizeof(struct ext2fs));
    900   1.1   tsutsui 	new->e2fs_icount	=	bswap32(old->e2fs_icount);
    901   1.1   tsutsui 	new->e2fs_bcount	=	bswap32(old->e2fs_bcount);
    902   1.1   tsutsui 	new->e2fs_rbcount	=	bswap32(old->e2fs_rbcount);
    903   1.1   tsutsui 	new->e2fs_fbcount	=	bswap32(old->e2fs_fbcount);
    904   1.1   tsutsui 	new->e2fs_ficount	=	bswap32(old->e2fs_ficount);
    905   1.1   tsutsui 	new->e2fs_first_dblock	=	bswap32(old->e2fs_first_dblock);
    906   1.1   tsutsui 	new->e2fs_log_bsize	=	bswap32(old->e2fs_log_bsize);
    907   1.1   tsutsui 	new->e2fs_fsize		=	bswap32(old->e2fs_fsize);
    908   1.1   tsutsui 	new->e2fs_bpg		=	bswap32(old->e2fs_bpg);
    909   1.1   tsutsui 	new->e2fs_fpg		=	bswap32(old->e2fs_fpg);
    910   1.1   tsutsui 	new->e2fs_ipg		=	bswap32(old->e2fs_ipg);
    911   1.1   tsutsui 	new->e2fs_mtime		=	bswap32(old->e2fs_mtime);
    912   1.1   tsutsui 	new->e2fs_wtime		=	bswap32(old->e2fs_wtime);
    913   1.1   tsutsui 	new->e2fs_mnt_count	=	bswap16(old->e2fs_mnt_count);
    914   1.1   tsutsui 	new->e2fs_max_mnt_count	=	bswap16(old->e2fs_max_mnt_count);
    915   1.1   tsutsui 	new->e2fs_magic		=	bswap16(old->e2fs_magic);
    916   1.1   tsutsui 	new->e2fs_state		=	bswap16(old->e2fs_state);
    917   1.1   tsutsui 	new->e2fs_beh		=	bswap16(old->e2fs_beh);
    918   1.1   tsutsui 	new->e2fs_minrev	=	bswap16(old->e2fs_minrev);
    919   1.1   tsutsui 	new->e2fs_lastfsck	=	bswap32(old->e2fs_lastfsck);
    920   1.1   tsutsui 	new->e2fs_fsckintv	=	bswap32(old->e2fs_fsckintv);
    921   1.1   tsutsui 	new->e2fs_creator	=	bswap32(old->e2fs_creator);
    922   1.1   tsutsui 	new->e2fs_rev		=	bswap32(old->e2fs_rev);
    923   1.1   tsutsui 	new->e2fs_ruid		=	bswap16(old->e2fs_ruid);
    924   1.1   tsutsui 	new->e2fs_rgid		=	bswap16(old->e2fs_rgid);
    925   1.1   tsutsui 	new->e2fs_first_ino	=	bswap32(old->e2fs_first_ino);
    926   1.1   tsutsui 	new->e2fs_inode_size	=	bswap16(old->e2fs_inode_size);
    927   1.1   tsutsui 	new->e2fs_block_group_nr =	bswap16(old->e2fs_block_group_nr);
    928   1.1   tsutsui 	new->e2fs_features_compat =	bswap32(old->e2fs_features_compat);
    929   1.1   tsutsui 	new->e2fs_features_incompat =	bswap32(old->e2fs_features_incompat);
    930   1.1   tsutsui 	new->e2fs_features_rocompat =	bswap32(old->e2fs_features_rocompat);
    931   1.1   tsutsui 	new->e2fs_algo		=	bswap32(old->e2fs_algo);
    932   1.1   tsutsui 	new->e2fs_reserved_ngdb	=	bswap16(old->e2fs_reserved_ngdb);
    933   1.1   tsutsui }
    934   1.1   tsutsui 
    935  1.23    nonaka void e2fs_i_bswap(struct ext2fs_dinode *old, struct ext2fs_dinode *new,
    936  1.23    nonaka     size_t isize)
    937   1.1   tsutsui {
    938  1.23    nonaka 	/* preserve non-swapped and unused fields */
    939  1.23    nonaka 	memcpy(new, old, isize);
    940   1.1   tsutsui 
    941  1.23    nonaka 	/* swap what needs to be swapped */
    942   1.1   tsutsui 	new->e2di_mode		=	bswap16(old->e2di_mode);
    943   1.1   tsutsui 	new->e2di_uid		=	bswap16(old->e2di_uid);
    944   1.1   tsutsui 	new->e2di_gid		=	bswap16(old->e2di_gid);
    945   1.1   tsutsui 	new->e2di_nlink		=	bswap16(old->e2di_nlink);
    946   1.1   tsutsui 	new->e2di_size		=	bswap32(old->e2di_size);
    947   1.1   tsutsui 	new->e2di_atime		=	bswap32(old->e2di_atime);
    948   1.1   tsutsui 	new->e2di_ctime		=	bswap32(old->e2di_ctime);
    949   1.1   tsutsui 	new->e2di_mtime		=	bswap32(old->e2di_mtime);
    950   1.1   tsutsui 	new->e2di_dtime		=	bswap32(old->e2di_dtime);
    951   1.1   tsutsui 	new->e2di_nblock	=	bswap32(old->e2di_nblock);
    952   1.1   tsutsui 	new->e2di_flags		=	bswap32(old->e2di_flags);
    953  1.23    nonaka 	new->e2di_version	=	bswap32(old->e2di_version);
    954   1.1   tsutsui 	new->e2di_gen		=	bswap32(old->e2di_gen);
    955   1.1   tsutsui 	new->e2di_facl		=	bswap32(old->e2di_facl);
    956  1.24       rjs 	new->e2di_size_high	=	bswap32(old->e2di_size_high);
    957  1.23    nonaka 	new->e2di_nblock_high	=	bswap16(old->e2di_nblock_high);
    958  1.23    nonaka 	new->e2di_facl_high	=	bswap16(old->e2di_facl_high);
    959  1.23    nonaka 	new->e2di_uid_high	=	bswap16(old->e2di_uid_high);
    960  1.23    nonaka 	new->e2di_gid_high	=	bswap16(old->e2di_gid_high);
    961  1.23    nonaka 	new->e2di_checksum_low  = 	bswap16(old->e2di_checksum_low);
    962  1.23    nonaka 
    963  1.23    nonaka 	/*
    964  1.23    nonaka 	 * Following fields are only supported for inode sizes bigger
    965  1.23    nonaka 	 * than the old ext2 one
    966  1.23    nonaka 	 */
    967  1.23    nonaka 	if (isize == EXT2_REV0_DINODE_SIZE)
    968  1.23    nonaka 		return;
    969  1.23    nonaka 
    970  1.23    nonaka 	new->e2di_extra_isize   = bswap16(old->e2di_extra_isize);
    971  1.23    nonaka 	new->e2di_checksum_high = bswap16(old->e2di_checksum_high);
    972  1.23    nonaka 
    973  1.23    nonaka 	/* Following fields are ext4, might not be actually present */
    974  1.23    nonaka 	if (EXT2_DINODE_FITS(new, e2di_ctime_extra, isize))
    975  1.23    nonaka 		new->e2di_ctime_extra   = bswap32(old->e2di_ctime_extra);
    976  1.23    nonaka 	if (EXT2_DINODE_FITS(new, e2di_mtime_extra, isize))
    977  1.23    nonaka 		new->e2di_mtime_extra	= bswap32(old->e2di_mtime_extra);
    978  1.23    nonaka 	if (EXT2_DINODE_FITS(new, e2di_atime_extra, isize))
    979  1.23    nonaka 		new->e2di_atime_extra	= bswap32(old->e2di_atime_extra);
    980  1.23    nonaka 	if (EXT2_DINODE_FITS(new, e2di_crtime, isize))
    981  1.23    nonaka 		new->e2di_crtime	= bswap32(old->e2di_crtime);
    982  1.23    nonaka 	if (EXT2_DINODE_FITS(new, e2di_crtime_extra, isize))
    983  1.23    nonaka 		new->e2di_crtime_extra	= bswap32(old->e2di_crtime_extra);
    984  1.23    nonaka 	if (EXT2_DINODE_FITS(new, e2di_version_high, isize))
    985  1.23    nonaka 		new->e2di_version_high	= bswap32(old->e2di_version_high);
    986  1.23    nonaka 	if (EXT2_DINODE_FITS(new, e2di_projid, isize))
    987  1.23    nonaka 		new->e2di_projid	= bswap32(old->e2di_projid);
    988   1.1   tsutsui }
    989   1.1   tsutsui #endif
    990   1.1   tsutsui 
    991   1.1   tsutsui #ifdef EXT2FS_DEBUG
    992   1.1   tsutsui void
    993   1.1   tsutsui dump_sblock(struct m_ext2fs *fs)
    994   1.1   tsutsui {
    995   1.1   tsutsui 
    996   1.1   tsutsui 	printf("fs->e2fs.e2fs_bcount = %u\n", fs->e2fs.e2fs_bcount);
    997   1.1   tsutsui 	printf("fs->e2fs.e2fs_first_dblock = %u\n", fs->e2fs.e2fs_first_dblock);
    998   1.1   tsutsui 	printf("fs->e2fs.e2fs_log_bsize = %u\n", fs->e2fs.e2fs_log_bsize);
    999   1.1   tsutsui 	printf("fs->e2fs.e2fs_bpg = %u\n", fs->e2fs.e2fs_bpg);
   1000   1.1   tsutsui 	printf("fs->e2fs.e2fs_ipg = %u\n", fs->e2fs.e2fs_ipg);
   1001  1.27  christos 	printf("fs->e2fs.e2fs_magic = 0x%x\n", fs->e2fs.e2fs_magic);
   1002   1.1   tsutsui 	printf("fs->e2fs.e2fs_rev = %u\n", fs->e2fs.e2fs_rev);
   1003   1.1   tsutsui 
   1004   1.1   tsutsui 	if (fs->e2fs.e2fs_rev == E2FS_REV1) {
   1005   1.1   tsutsui 		printf("fs->e2fs.e2fs_first_ino = %u\n",
   1006   1.1   tsutsui 		    fs->e2fs.e2fs_first_ino);
   1007   1.1   tsutsui 		printf("fs->e2fs.e2fs_inode_size = %u\n",
   1008   1.1   tsutsui 		    fs->e2fs.e2fs_inode_size);
   1009   1.1   tsutsui 		printf("fs->e2fs.e2fs_features_compat = %u\n",
   1010   1.1   tsutsui 		    fs->e2fs.e2fs_features_compat);
   1011   1.1   tsutsui 		printf("fs->e2fs.e2fs_features_incompat = %u\n",
   1012   1.1   tsutsui 		    fs->e2fs.e2fs_features_incompat);
   1013   1.1   tsutsui 		printf("fs->e2fs.e2fs_features_rocompat = %u\n",
   1014   1.1   tsutsui 		    fs->e2fs.e2fs_features_rocompat);
   1015   1.1   tsutsui 		printf("fs->e2fs.e2fs_reserved_ngdb = %u\n",
   1016   1.1   tsutsui 		    fs->e2fs.e2fs_reserved_ngdb);
   1017   1.1   tsutsui 	}
   1018   1.1   tsutsui 
   1019   1.1   tsutsui 	printf("fs->e2fs_bsize = %u\n", fs->e2fs_bsize);
   1020   1.1   tsutsui 	printf("fs->e2fs_fsbtodb = %u\n", fs->e2fs_fsbtodb);
   1021   1.1   tsutsui 	printf("fs->e2fs_ncg = %u\n", fs->e2fs_ncg);
   1022   1.1   tsutsui 	printf("fs->e2fs_ngdb = %u\n", fs->e2fs_ngdb);
   1023   1.1   tsutsui 	printf("fs->e2fs_ipb = %u\n", fs->e2fs_ipb);
   1024   1.1   tsutsui 	printf("fs->e2fs_itpg = %u\n", fs->e2fs_itpg);
   1025   1.1   tsutsui }
   1026   1.1   tsutsui #endif
   1027