Home | History | Annotate | Line # | Download | only in libsa
ext2fs.c revision 1.18
      1  1.18  dholland /*	$NetBSD: ext2fs.c,v 1.18 2013/06/23 07:28:36 dholland 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 #if defined(LIBSA_ENABLE_LS_OP)
    150  1.11   tsutsui 
    151  1.11   tsutsui #define NELEM(x) (sizeof (x) / sizeof(*x))
    152  1.11   tsutsui 
    153  1.11   tsutsui typedef struct entry_t entry_t;
    154  1.11   tsutsui struct entry_t {
    155  1.11   tsutsui 	entry_t	*e_next;
    156  1.11   tsutsui 	ino32_t	e_ino;
    157  1.11   tsutsui 	uint8_t	e_type;
    158  1.11   tsutsui 	char	e_name[1];
    159  1.11   tsutsui };
    160  1.11   tsutsui 
    161  1.11   tsutsui static const char    *const typestr[] = {
    162  1.11   tsutsui 	"unknown",
    163  1.11   tsutsui 	"REG",
    164  1.11   tsutsui 	"DIR",
    165  1.11   tsutsui 	"CHR",
    166  1.11   tsutsui 	"BLK",
    167  1.11   tsutsui 	"FIFO",
    168  1.11   tsutsui 	"SOCK",
    169  1.11   tsutsui 	"LNK"
    170  1.11   tsutsui };
    171  1.11   tsutsui 
    172  1.11   tsutsui #endif /* LIBSA_ENABLE_LS_OP */
    173  1.11   tsutsui 
    174   1.1   tsutsui static int read_inode(ino32_t, struct open_file *);
    175   1.1   tsutsui static int block_map(struct open_file *, indp_t, indp_t *);
    176   1.1   tsutsui static int buf_read_file(struct open_file *, char **, size_t *);
    177   1.1   tsutsui static int search_directory(const char *, int, struct open_file *, ino32_t *);
    178   1.1   tsutsui static int read_sblock(struct open_file *, struct m_ext2fs *);
    179   1.1   tsutsui static int read_gdblock(struct open_file *, struct m_ext2fs *);
    180   1.1   tsutsui #ifdef EXT2FS_DEBUG
    181   1.1   tsutsui static void dump_sblock(struct m_ext2fs *);
    182   1.1   tsutsui #endif
    183   1.1   tsutsui 
    184   1.1   tsutsui /*
    185   1.1   tsutsui  * Read a new inode into a file structure.
    186   1.1   tsutsui  */
    187   1.1   tsutsui static int
    188   1.1   tsutsui read_inode(ino32_t inumber, struct open_file *f)
    189   1.1   tsutsui {
    190   1.1   tsutsui 	struct file *fp = (struct file *)f->f_fsdata;
    191   1.1   tsutsui 	struct m_ext2fs *fs = fp->f_fs;
    192   1.1   tsutsui 	char *buf;
    193   1.1   tsutsui 	size_t rsize;
    194   1.1   tsutsui 	int rc;
    195   1.1   tsutsui 	daddr_t inode_sector;
    196   1.1   tsutsui 	struct ext2fs_dinode *dip;
    197   1.1   tsutsui 
    198   1.1   tsutsui 	inode_sector = FSBTODB(fs, ino_to_fsba(fs, inumber));
    199   1.1   tsutsui 
    200   1.1   tsutsui 	/*
    201   1.1   tsutsui 	 * Read inode and save it.
    202   1.1   tsutsui 	 */
    203   1.1   tsutsui 	buf = fp->f_buf;
    204   1.1   tsutsui 	twiddle();
    205   1.1   tsutsui 	rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
    206   1.1   tsutsui 	    inode_sector, fs->e2fs_bsize, buf, &rsize);
    207   1.1   tsutsui 	if (rc)
    208   1.1   tsutsui 		return rc;
    209   1.1   tsutsui 	if (rsize != fs->e2fs_bsize)
    210   1.1   tsutsui 		return EIO;
    211   1.1   tsutsui 
    212   1.7   tsutsui 	dip = (struct ext2fs_dinode *)(buf +
    213   1.7   tsutsui 	    EXT2_DINODE_SIZE(fs) * ino_to_fsbo(fs, inumber));
    214   1.7   tsutsui 	e2fs_iload(dip, &fp->f_di);
    215   1.1   tsutsui 
    216   1.1   tsutsui 	/*
    217   1.1   tsutsui 	 * Clear out the old buffers
    218   1.1   tsutsui 	 */
    219   1.1   tsutsui 	fp->f_ind_cache_block = ~0;
    220   1.1   tsutsui 	fp->f_buf_blkno = -1;
    221   1.1   tsutsui 	return rc;
    222   1.1   tsutsui }
    223   1.1   tsutsui 
    224   1.1   tsutsui /*
    225   1.1   tsutsui  * Given an offset in a file, find the disk block number that
    226   1.1   tsutsui  * contains that block.
    227   1.1   tsutsui  */
    228   1.1   tsutsui static int
    229   1.1   tsutsui block_map(struct open_file *f, indp_t file_block, indp_t *disk_block_p)
    230   1.1   tsutsui {
    231   1.1   tsutsui 	struct file *fp = (struct file *)f->f_fsdata;
    232   1.1   tsutsui 	struct m_ext2fs *fs = fp->f_fs;
    233   1.1   tsutsui 	uint level;
    234   1.1   tsutsui 	indp_t ind_cache;
    235   1.1   tsutsui 	indp_t ind_block_num;
    236   1.1   tsutsui 	size_t rsize;
    237   1.1   tsutsui 	int rc;
    238   1.1   tsutsui 	indp_t *buf = (void *)fp->f_buf;
    239   1.1   tsutsui 
    240   1.1   tsutsui 	/*
    241   1.1   tsutsui 	 * Index structure of an inode:
    242   1.1   tsutsui 	 *
    243  1.14  dholland 	 * e2di_blocks[0..EXT2FS_NDADDR-1]
    244  1.15   tsutsui 	 *		hold block numbers for blocks
    245  1.15   tsutsui 	 *		0..EXT2FS_NDADDR-1
    246   1.1   tsutsui 	 *
    247  1.14  dholland 	 * e2di_blocks[EXT2FS_NDADDR+0]
    248  1.15   tsutsui 	 *		block EXT2FS_NDADDR+0 is the single indirect block
    249  1.15   tsutsui 	 *		holds block numbers for blocks
    250  1.16  dholland 	 *		EXT2FS_NDADDR .. EXT2FS_NDADDR + EXT2_NINDIR(fs)-1
    251   1.1   tsutsui 	 *
    252  1.14  dholland 	 * e2di_blocks[EXT2FS_NDADDR+1]
    253  1.15   tsutsui 	 *		block EXT2FS_NDADDR+1 is the double indirect block
    254  1.15   tsutsui 	 *		holds block numbers for INDEX blocks for blocks
    255  1.16  dholland 	 *		EXT2FS_NDADDR + EXT2_NINDIR(fs) ..
    256  1.16  dholland 	 *		EXT2FS_NDADDR + EXT2_NINDIR(fs) + EXT2_NINDIR(fs)**2 - 1
    257   1.1   tsutsui 	 *
    258  1.14  dholland 	 * e2di_blocks[EXT2FS_NDADDR+2]
    259  1.15   tsutsui 	 *		block EXT2FS_NDADDR+2 is the triple indirect block
    260  1.15   tsutsui 	 *		holds block numbers for	double-indirect
    261  1.15   tsutsui 	 *		blocks for blocks
    262  1.16  dholland 	 *		EXT2FS_NDADDR + EXT2_NINDIR(fs) + EXT2_NINDIR(fs)**2 ..
    263  1.16  dholland 	 *		EXT2FS_NDADDR + EXT2_NINDIR(fs) + EXT2_NINDIR(fs)**2
    264  1.16  dholland 	 *			+ EXT2_NINDIR(fs)**3 - 1
    265   1.1   tsutsui 	 */
    266   1.1   tsutsui 
    267  1.14  dholland 	if (file_block < EXT2FS_NDADDR) {
    268   1.1   tsutsui 		/* Direct block. */
    269   1.1   tsutsui 		*disk_block_p = fs2h32(fp->f_di.e2di_blocks[file_block]);
    270   1.1   tsutsui 		return 0;
    271   1.1   tsutsui 	}
    272   1.1   tsutsui 
    273  1.14  dholland 	file_block -= EXT2FS_NDADDR;
    274   1.1   tsutsui 
    275   1.1   tsutsui 	ind_cache = file_block >> LN2_IND_CACHE_SZ;
    276   1.1   tsutsui 	if (ind_cache == fp->f_ind_cache_block) {
    277   1.2   tsutsui 		*disk_block_p =
    278   1.2   tsutsui 		    fs2h32(fp->f_ind_cache[file_block & IND_CACHE_MASK]);
    279   1.1   tsutsui 		return 0;
    280   1.1   tsutsui 	}
    281   1.1   tsutsui 
    282   1.1   tsutsui 	for (level = 0;;) {
    283   1.1   tsutsui 		level += fp->f_nishift;
    284   1.1   tsutsui 		if (file_block < (indp_t)1 << level)
    285   1.1   tsutsui 			break;
    286  1.14  dholland 		if (level > EXT2FS_NIADDR * fp->f_nishift)
    287   1.1   tsutsui 			/* Block number too high */
    288   1.1   tsutsui 			return EFBIG;
    289   1.1   tsutsui 		file_block -= (indp_t)1 << level;
    290   1.1   tsutsui 	}
    291   1.1   tsutsui 
    292   1.1   tsutsui 	ind_block_num =
    293  1.15   tsutsui 	    fs2h32(fp->f_di.e2di_blocks[EXT2FS_NDADDR +
    294  1.15   tsutsui 	    (level / fp->f_nishift - 1)]);
    295   1.1   tsutsui 
    296   1.1   tsutsui 	for (;;) {
    297   1.1   tsutsui 		level -= fp->f_nishift;
    298   1.1   tsutsui 		if (ind_block_num == 0) {
    299   1.1   tsutsui 			*disk_block_p = 0;	/* missing */
    300   1.1   tsutsui 			return 0;
    301   1.1   tsutsui 		}
    302   1.1   tsutsui 
    303   1.1   tsutsui 		twiddle();
    304   1.1   tsutsui 		/*
    305   1.1   tsutsui 		 * If we were feeling brave, we could work out the number
    306   1.1   tsutsui 		 * of the disk sector and read a single disk sector instead
    307   1.1   tsutsui 		 * of a filesystem block.
    308   1.1   tsutsui 		 * However we don't do this very often anyway...
    309   1.1   tsutsui 		 */
    310   1.1   tsutsui 		rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
    311   1.1   tsutsui 			FSBTODB(fp->f_fs, ind_block_num), fs->e2fs_bsize,
    312   1.1   tsutsui 			buf, &rsize);
    313   1.1   tsutsui 		if (rc)
    314   1.1   tsutsui 			return rc;
    315   1.1   tsutsui 		if (rsize != fs->e2fs_bsize)
    316   1.1   tsutsui 			return EIO;
    317   1.2   tsutsui 		ind_block_num = fs2h32(buf[file_block >> level]);
    318   1.1   tsutsui 		if (level == 0)
    319   1.1   tsutsui 			break;
    320   1.1   tsutsui 		file_block &= (1 << level) - 1;
    321   1.1   tsutsui 	}
    322   1.1   tsutsui 
    323   1.1   tsutsui 	/* Save the part of the block that contains this sector */
    324   1.1   tsutsui 	memcpy(fp->f_ind_cache, &buf[file_block & ~IND_CACHE_MASK],
    325   1.1   tsutsui 	    IND_CACHE_SZ * sizeof fp->f_ind_cache[0]);
    326   1.1   tsutsui 	fp->f_ind_cache_block = ind_cache;
    327   1.1   tsutsui 
    328   1.1   tsutsui 	*disk_block_p = ind_block_num;
    329   1.1   tsutsui 
    330   1.1   tsutsui 	return 0;
    331   1.1   tsutsui }
    332   1.1   tsutsui 
    333   1.1   tsutsui /*
    334   1.1   tsutsui  * Read a portion of a file into an internal buffer.
    335   1.1   tsutsui  * Return the location in the buffer and the amount in the buffer.
    336   1.1   tsutsui  */
    337   1.1   tsutsui static int
    338   1.1   tsutsui buf_read_file(struct open_file *f, char **buf_p, size_t *size_p)
    339   1.1   tsutsui {
    340   1.1   tsutsui 	struct file *fp = (struct file *)f->f_fsdata;
    341   1.1   tsutsui 	struct m_ext2fs *fs = fp->f_fs;
    342   1.1   tsutsui 	long off;
    343   1.1   tsutsui 	indp_t file_block;
    344   1.1   tsutsui 	indp_t disk_block;
    345   1.1   tsutsui 	size_t block_size;
    346   1.1   tsutsui 	int rc;
    347   1.1   tsutsui 
    348  1.16  dholland 	off = ext2_blkoff(fs, fp->f_seekp);
    349  1.18  dholland 	file_block = ext2_lblkno(fs, fp->f_seekp);
    350   1.1   tsutsui 	block_size = fs->e2fs_bsize;	/* no fragment */
    351   1.1   tsutsui 
    352   1.1   tsutsui 	if (file_block != fp->f_buf_blkno) {
    353   1.1   tsutsui 		rc = block_map(f, file_block, &disk_block);
    354   1.1   tsutsui 		if (rc)
    355   1.1   tsutsui 			return rc;
    356   1.1   tsutsui 
    357   1.1   tsutsui 		if (disk_block == 0) {
    358   1.1   tsutsui 			memset(fp->f_buf, 0, block_size);
    359   1.1   tsutsui 			fp->f_buf_size = block_size;
    360   1.1   tsutsui 		} else {
    361   1.1   tsutsui 			twiddle();
    362   1.1   tsutsui 			rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
    363   1.1   tsutsui 				FSBTODB(fs, disk_block),
    364   1.1   tsutsui 				block_size, fp->f_buf, &fp->f_buf_size);
    365   1.1   tsutsui 			if (rc)
    366   1.1   tsutsui 				return rc;
    367   1.1   tsutsui 		}
    368   1.1   tsutsui 
    369   1.1   tsutsui 		fp->f_buf_blkno = file_block;
    370   1.1   tsutsui 	}
    371   1.1   tsutsui 
    372   1.1   tsutsui 	/*
    373   1.1   tsutsui 	 * Return address of byte in buffer corresponding to
    374   1.1   tsutsui 	 * offset, and size of remainder of buffer after that
    375   1.1   tsutsui 	 * byte.
    376   1.1   tsutsui 	 */
    377   1.1   tsutsui 	*buf_p = fp->f_buf + off;
    378   1.1   tsutsui 	*size_p = block_size - off;
    379   1.1   tsutsui 
    380   1.1   tsutsui 	/*
    381   1.1   tsutsui 	 * But truncate buffer at end of file.
    382   1.1   tsutsui 	 */
    383   1.1   tsutsui 	/* XXX should handle LARGEFILE */
    384   1.1   tsutsui 	if (*size_p > fp->f_di.e2di_size - fp->f_seekp)
    385   1.1   tsutsui 		*size_p = fp->f_di.e2di_size - fp->f_seekp;
    386   1.1   tsutsui 
    387   1.1   tsutsui 	return 0;
    388   1.1   tsutsui }
    389   1.1   tsutsui 
    390   1.1   tsutsui /*
    391   1.1   tsutsui  * Search a directory for a name and return its
    392   1.1   tsutsui  * inode number.
    393   1.1   tsutsui  */
    394   1.1   tsutsui static int
    395   1.1   tsutsui search_directory(const char *name, int length, struct open_file *f,
    396   1.1   tsutsui 	ino32_t *inumber_p)
    397   1.1   tsutsui {
    398   1.1   tsutsui 	struct file *fp = (struct file *)f->f_fsdata;
    399   1.1   tsutsui 	struct ext2fs_direct *dp;
    400   1.1   tsutsui 	struct ext2fs_direct *edp;
    401   1.1   tsutsui 	char *buf;
    402   1.1   tsutsui 	size_t buf_size;
    403   1.1   tsutsui 	int namlen;
    404   1.1   tsutsui 	int rc;
    405   1.1   tsutsui 
    406   1.1   tsutsui 	fp->f_seekp = 0;
    407   1.1   tsutsui 	/* XXX should handle LARGEFILE */
    408   1.1   tsutsui 	while (fp->f_seekp < (off_t)fp->f_di.e2di_size) {
    409   1.1   tsutsui 		rc = buf_read_file(f, &buf, &buf_size);
    410   1.1   tsutsui 		if (rc)
    411   1.1   tsutsui 			return rc;
    412   1.1   tsutsui 
    413   1.1   tsutsui 		dp = (struct ext2fs_direct *)buf;
    414   1.1   tsutsui 		edp = (struct ext2fs_direct *)(buf + buf_size);
    415   1.1   tsutsui 		for (; dp < edp;
    416   1.1   tsutsui 		    dp = (void *)((char *)dp + fs2h16(dp->e2d_reclen))) {
    417   1.1   tsutsui 			if (fs2h16(dp->e2d_reclen) <= 0)
    418   1.1   tsutsui 				break;
    419   1.1   tsutsui 			if (fs2h32(dp->e2d_ino) == (ino32_t)0)
    420   1.1   tsutsui 				continue;
    421   1.1   tsutsui 			namlen = dp->e2d_namlen;
    422   1.1   tsutsui 			if (namlen == length &&
    423   1.1   tsutsui 			    !memcmp(name, dp->e2d_name, length)) {
    424   1.1   tsutsui 				/* found entry */
    425   1.1   tsutsui 				*inumber_p = fs2h32(dp->e2d_ino);
    426   1.1   tsutsui 				return 0;
    427   1.1   tsutsui 			}
    428   1.1   tsutsui 		}
    429   1.1   tsutsui 		fp->f_seekp += buf_size;
    430   1.1   tsutsui 	}
    431   1.1   tsutsui 	return ENOENT;
    432   1.1   tsutsui }
    433   1.1   tsutsui 
    434   1.1   tsutsui int
    435   1.1   tsutsui read_sblock(struct open_file *f, struct m_ext2fs *fs)
    436   1.1   tsutsui {
    437   1.1   tsutsui 	static uint8_t sbbuf[SBSIZE];
    438   1.1   tsutsui 	struct ext2fs ext2fs;
    439   1.1   tsutsui 	size_t buf_size;
    440   1.1   tsutsui 	int rc;
    441   1.1   tsutsui 
    442   1.1   tsutsui 	rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
    443   1.1   tsutsui 	    SBOFF / DEV_BSIZE, SBSIZE, sbbuf, &buf_size);
    444   1.1   tsutsui 	if (rc)
    445   1.1   tsutsui 		return rc;
    446   1.1   tsutsui 
    447   1.1   tsutsui 	if (buf_size != SBSIZE)
    448   1.1   tsutsui 		return EIO;
    449   1.1   tsutsui 
    450   1.1   tsutsui 	e2fs_sbload((void *)sbbuf, &ext2fs);
    451   1.1   tsutsui 	if (ext2fs.e2fs_magic != E2FS_MAGIC)
    452   1.1   tsutsui 		return EINVAL;
    453   1.1   tsutsui 	if (ext2fs.e2fs_rev > E2FS_REV1 ||
    454   1.1   tsutsui 	    (ext2fs.e2fs_rev == E2FS_REV1 &&
    455   1.1   tsutsui 	     (ext2fs.e2fs_first_ino != EXT2_FIRSTINO ||
    456   1.6  christos 	     (ext2fs.e2fs_inode_size != 128 && ext2fs.e2fs_inode_size != 256) ||
    457   1.1   tsutsui 	      ext2fs.e2fs_features_incompat & ~EXT2F_INCOMPAT_SUPP))) {
    458   1.1   tsutsui 		return ENODEV;
    459   1.1   tsutsui 	}
    460   1.1   tsutsui 
    461   1.1   tsutsui 	e2fs_sbload((void *)sbbuf, &fs->e2fs);
    462   1.1   tsutsui 	/* compute in-memory m_ext2fs values */
    463   1.1   tsutsui 	fs->e2fs_ncg =
    464   1.1   tsutsui 	    howmany(fs->e2fs.e2fs_bcount - fs->e2fs.e2fs_first_dblock,
    465   1.1   tsutsui 	    fs->e2fs.e2fs_bpg);
    466   1.1   tsutsui 	/* XXX assume hw bsize = 512 */
    467   1.1   tsutsui 	fs->e2fs_fsbtodb = fs->e2fs.e2fs_log_bsize + 1;
    468   1.1   tsutsui 	fs->e2fs_bsize = MINBSIZE << fs->e2fs.e2fs_log_bsize;
    469   1.1   tsutsui 	fs->e2fs_bshift = LOG_MINBSIZE + fs->e2fs.e2fs_log_bsize;
    470   1.1   tsutsui 	fs->e2fs_qbmask = fs->e2fs_bsize - 1;
    471   1.1   tsutsui 	fs->e2fs_bmask = ~fs->e2fs_qbmask;
    472   1.1   tsutsui 	fs->e2fs_ngdb =
    473   1.1   tsutsui 	    howmany(fs->e2fs_ncg, fs->e2fs_bsize / sizeof(struct ext2_gd));
    474   1.6  christos 	fs->e2fs_ipb = fs->e2fs_bsize / ext2fs.e2fs_inode_size;
    475   1.1   tsutsui 	fs->e2fs_itpg = fs->e2fs.e2fs_ipg / fs->e2fs_ipb;
    476   1.1   tsutsui 
    477   1.1   tsutsui 	return 0;
    478   1.1   tsutsui }
    479   1.1   tsutsui 
    480   1.1   tsutsui int
    481   1.1   tsutsui read_gdblock(struct open_file *f, struct m_ext2fs *fs)
    482   1.1   tsutsui {
    483   1.1   tsutsui 	struct file *fp = (struct file *)f->f_fsdata;
    484   1.1   tsutsui 	size_t rsize;
    485   1.1   tsutsui 	uint gdpb;
    486   1.1   tsutsui 	int i, rc;
    487   1.1   tsutsui 
    488   1.1   tsutsui 	gdpb = fs->e2fs_bsize / sizeof(struct ext2_gd);
    489   1.1   tsutsui 
    490   1.1   tsutsui 	for (i = 0; i < fs->e2fs_ngdb; i++) {
    491   1.1   tsutsui 		rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
    492   1.1   tsutsui 		    FSBTODB(fs, fs->e2fs.e2fs_first_dblock +
    493   1.1   tsutsui 		    1 /* superblock */ + i),
    494   1.1   tsutsui 		    fs->e2fs_bsize, fp->f_buf, &rsize);
    495   1.1   tsutsui 		if (rc)
    496   1.1   tsutsui 			return rc;
    497   1.1   tsutsui 		if (rsize != fs->e2fs_bsize)
    498   1.1   tsutsui 			return EIO;
    499   1.1   tsutsui 
    500   1.1   tsutsui 		e2fs_cgload((struct ext2_gd *)fp->f_buf,
    501   1.1   tsutsui 		    &fs->e2fs_gd[i * gdpb],
    502   1.1   tsutsui 		    (i == (fs->e2fs_ngdb - 1)) ?
    503   1.1   tsutsui 		    (fs->e2fs_ncg - gdpb * i) * sizeof(struct ext2_gd):
    504   1.1   tsutsui 		    fs->e2fs_bsize);
    505   1.1   tsutsui 	}
    506   1.1   tsutsui 
    507   1.1   tsutsui 	return 0;
    508   1.1   tsutsui }
    509   1.1   tsutsui 
    510   1.1   tsutsui 
    511   1.1   tsutsui /*
    512   1.1   tsutsui  * Open a file.
    513   1.1   tsutsui  */
    514  1.10     joerg __compactcall int
    515   1.1   tsutsui ext2fs_open(const char *path, struct open_file *f)
    516   1.1   tsutsui {
    517   1.1   tsutsui #ifndef LIBSA_FS_SINGLECOMPONENT
    518   1.1   tsutsui 	const char *cp, *ncp;
    519   1.1   tsutsui 	int c;
    520   1.1   tsutsui #endif
    521   1.1   tsutsui 	ino32_t inumber;
    522   1.1   tsutsui 	struct file *fp;
    523   1.1   tsutsui 	struct m_ext2fs *fs;
    524   1.1   tsutsui 	int rc;
    525   1.1   tsutsui #ifndef LIBSA_NO_FS_SYMLINK
    526   1.1   tsutsui 	ino32_t parent_inumber;
    527   1.1   tsutsui 	int nlinks = 0;
    528   1.1   tsutsui 	char namebuf[MAXPATHLEN+1];
    529   1.1   tsutsui 	char *buf;
    530   1.1   tsutsui #endif
    531   1.1   tsutsui 
    532   1.1   tsutsui 	/* allocate file system specific data structure */
    533   1.1   tsutsui 	fp = alloc(sizeof(struct file));
    534   1.1   tsutsui 	memset(fp, 0, sizeof(struct file));
    535   1.1   tsutsui 	f->f_fsdata = (void *)fp;
    536   1.1   tsutsui 
    537   1.1   tsutsui 	/* allocate space and read super block */
    538   1.3   tsutsui 	fs = alloc(sizeof(*fs));
    539   1.9  jakllsch 	memset(fs, 0, sizeof(*fs));
    540   1.1   tsutsui 	fp->f_fs = fs;
    541   1.1   tsutsui 	twiddle();
    542   1.1   tsutsui 
    543   1.1   tsutsui 	rc = read_sblock(f, fs);
    544   1.1   tsutsui 	if (rc)
    545   1.1   tsutsui 		goto out;
    546   1.1   tsutsui 
    547   1.1   tsutsui #ifdef EXT2FS_DEBUG
    548   1.1   tsutsui 	dump_sblock(fs);
    549   1.1   tsutsui #endif
    550   1.1   tsutsui 
    551   1.1   tsutsui 	/* alloc a block sized buffer used for all fs transfers */
    552   1.1   tsutsui 	fp->f_buf = alloc(fs->e2fs_bsize);
    553   1.1   tsutsui 
    554   1.1   tsutsui 	/* read group descriptor blocks */
    555   1.1   tsutsui 	fs->e2fs_gd = alloc(sizeof(struct ext2_gd) * fs->e2fs_ncg);
    556   1.1   tsutsui 	rc = read_gdblock(f, fs);
    557   1.1   tsutsui 	if (rc)
    558   1.1   tsutsui 		goto out;
    559   1.1   tsutsui 
    560   1.1   tsutsui 	/*
    561   1.1   tsutsui 	 * Calculate indirect block levels.
    562   1.1   tsutsui 	 */
    563   1.1   tsutsui 	{
    564   1.1   tsutsui 		indp_t mult;
    565   1.1   tsutsui 		int ln2;
    566   1.1   tsutsui 
    567   1.1   tsutsui 		/*
    568   1.1   tsutsui 		 * We note that the number of indirect blocks is always
    569   1.1   tsutsui 		 * a power of 2.  This lets us use shifts and masks instead
    570   1.1   tsutsui 		 * of divide and remainder and avoinds pulling in the
    571   1.1   tsutsui 		 * 64bit division routine into the boot code.
    572   1.1   tsutsui 		 */
    573  1.16  dholland 		mult = EXT2_NINDIR(fs);
    574   1.1   tsutsui #ifdef DEBUG
    575   1.1   tsutsui 		if (!powerof2(mult)) {
    576   1.1   tsutsui 			/* Hummm was't a power of 2 */
    577   1.1   tsutsui 			rc = EINVAL;
    578   1.1   tsutsui 			goto out;
    579   1.1   tsutsui 		}
    580   1.1   tsutsui #endif
    581   1.1   tsutsui 		for (ln2 = 0; mult != 1; ln2++)
    582   1.1   tsutsui 			mult >>= 1;
    583   1.1   tsutsui 
    584   1.1   tsutsui 		fp->f_nishift = ln2;
    585   1.1   tsutsui 	}
    586   1.1   tsutsui 
    587   1.1   tsutsui 	inumber = EXT2_ROOTINO;
    588   1.1   tsutsui 	if ((rc = read_inode(inumber, f)) != 0)
    589   1.1   tsutsui 		goto out;
    590   1.1   tsutsui 
    591   1.1   tsutsui #ifndef LIBSA_FS_SINGLECOMPONENT
    592   1.1   tsutsui 	cp = path;
    593   1.1   tsutsui 	while (*cp) {
    594   1.1   tsutsui 
    595   1.1   tsutsui 		/*
    596   1.1   tsutsui 		 * Remove extra separators
    597   1.1   tsutsui 		 */
    598   1.1   tsutsui 		while (*cp == '/')
    599   1.1   tsutsui 			cp++;
    600   1.1   tsutsui 		if (*cp == '\0')
    601   1.1   tsutsui 			break;
    602   1.1   tsutsui 
    603   1.1   tsutsui 		/*
    604   1.1   tsutsui 		 * Check that current node is a directory.
    605   1.1   tsutsui 		 */
    606   1.1   tsutsui 		if ((fp->f_di.e2di_mode & EXT2_IFMT) != EXT2_IFDIR) {
    607   1.1   tsutsui 			rc = ENOTDIR;
    608   1.1   tsutsui 			goto out;
    609   1.1   tsutsui 		}
    610   1.1   tsutsui 
    611   1.1   tsutsui 		/*
    612   1.1   tsutsui 		 * Get next component of path name.
    613   1.1   tsutsui 		 */
    614   1.1   tsutsui 		ncp = cp;
    615   1.1   tsutsui 		while ((c = *cp) != '\0' && c != '/')
    616   1.1   tsutsui 			cp++;
    617   1.1   tsutsui 
    618   1.1   tsutsui 		/*
    619   1.1   tsutsui 		 * Look up component in current directory.
    620   1.1   tsutsui 		 * Save directory inumber in case we find a
    621   1.1   tsutsui 		 * symbolic link.
    622   1.1   tsutsui 		 */
    623   1.1   tsutsui #ifndef LIBSA_NO_FS_SYMLINK
    624   1.1   tsutsui 		parent_inumber = inumber;
    625   1.1   tsutsui #endif
    626   1.1   tsutsui 		rc = search_directory(ncp, cp - ncp, f, &inumber);
    627   1.1   tsutsui 		if (rc)
    628   1.1   tsutsui 			goto out;
    629   1.1   tsutsui 
    630   1.1   tsutsui 		/*
    631   1.1   tsutsui 		 * Open next component.
    632   1.1   tsutsui 		 */
    633   1.1   tsutsui 		if ((rc = read_inode(inumber, f)) != 0)
    634   1.1   tsutsui 			goto out;
    635   1.1   tsutsui 
    636   1.1   tsutsui #ifndef LIBSA_NO_FS_SYMLINK
    637   1.1   tsutsui 		/*
    638   1.1   tsutsui 		 * Check for symbolic link.
    639   1.1   tsutsui 		 */
    640   1.1   tsutsui 		if ((fp->f_di.e2di_mode & EXT2_IFMT) == EXT2_IFLNK) {
    641   1.1   tsutsui 			/* XXX should handle LARGEFILE */
    642   1.1   tsutsui 			int link_len = fp->f_di.e2di_size;
    643   1.1   tsutsui 			int len;
    644   1.1   tsutsui 
    645   1.1   tsutsui 			len = strlen(cp);
    646   1.1   tsutsui 
    647   1.1   tsutsui 			if (link_len + len > MAXPATHLEN ||
    648   1.1   tsutsui 			    ++nlinks > MAXSYMLINKS) {
    649   1.1   tsutsui 				rc = ENOENT;
    650   1.1   tsutsui 				goto out;
    651   1.1   tsutsui 			}
    652   1.1   tsutsui 
    653   1.1   tsutsui 			memmove(&namebuf[link_len], cp, len + 1);
    654   1.1   tsutsui 
    655   1.1   tsutsui 			if (link_len < EXT2_MAXSYMLINKLEN) {
    656   1.1   tsutsui 				memcpy(namebuf, fp->f_di.e2di_blocks, link_len);
    657   1.1   tsutsui 			} else {
    658   1.1   tsutsui 				/*
    659   1.1   tsutsui 				 * Read file for symbolic link
    660   1.1   tsutsui 				 */
    661   1.1   tsutsui 				size_t buf_size;
    662   1.1   tsutsui 				indp_t	disk_block;
    663   1.1   tsutsui 
    664   1.1   tsutsui 				buf = fp->f_buf;
    665   1.1   tsutsui 				rc = block_map(f, (indp_t)0, &disk_block);
    666   1.1   tsutsui 				if (rc)
    667   1.1   tsutsui 					goto out;
    668   1.1   tsutsui 
    669   1.1   tsutsui 				twiddle();
    670   1.1   tsutsui 				rc = DEV_STRATEGY(f->f_dev)(f->f_devdata,
    671   1.1   tsutsui 					F_READ, FSBTODB(fs, disk_block),
    672   1.1   tsutsui 					fs->e2fs_bsize, buf, &buf_size);
    673   1.1   tsutsui 				if (rc)
    674   1.1   tsutsui 					goto out;
    675   1.1   tsutsui 
    676   1.1   tsutsui 				memcpy(namebuf, buf, link_len);
    677   1.1   tsutsui 			}
    678   1.1   tsutsui 
    679   1.1   tsutsui 			/*
    680   1.1   tsutsui 			 * If relative pathname, restart at parent directory.
    681   1.1   tsutsui 			 * If absolute pathname, restart at root.
    682   1.1   tsutsui 			 */
    683   1.1   tsutsui 			cp = namebuf;
    684   1.1   tsutsui 			if (*cp != '/')
    685   1.1   tsutsui 				inumber = parent_inumber;
    686   1.1   tsutsui 			else
    687   1.1   tsutsui 				inumber = (ino32_t)EXT2_ROOTINO;
    688   1.1   tsutsui 
    689   1.1   tsutsui 			if ((rc = read_inode(inumber, f)) != 0)
    690   1.1   tsutsui 				goto out;
    691   1.1   tsutsui 		}
    692   1.1   tsutsui #endif	/* !LIBSA_NO_FS_SYMLINK */
    693   1.1   tsutsui 	}
    694   1.1   tsutsui 
    695   1.1   tsutsui 	/*
    696   1.1   tsutsui 	 * Found terminal component.
    697   1.1   tsutsui 	 */
    698   1.1   tsutsui 	rc = 0;
    699   1.1   tsutsui 
    700   1.1   tsutsui #else /* !LIBSA_FS_SINGLECOMPONENT */
    701   1.1   tsutsui 
    702   1.1   tsutsui 	/* look up component in the current (root) directory */
    703   1.1   tsutsui 	rc = search_directory(path, strlen(path), f, &inumber);
    704   1.1   tsutsui 	if (rc)
    705   1.1   tsutsui 		goto out;
    706   1.1   tsutsui 
    707   1.1   tsutsui 	/* open it */
    708   1.1   tsutsui 	rc = read_inode(inumber, f);
    709   1.1   tsutsui 
    710   1.1   tsutsui #endif /* !LIBSA_FS_SINGLECOMPONENT */
    711   1.1   tsutsui 
    712   1.1   tsutsui 	fp->f_seekp = 0;		/* reset seek pointer */
    713   1.1   tsutsui 
    714   1.1   tsutsui out:
    715   1.1   tsutsui 	if (rc)
    716   1.1   tsutsui 		ext2fs_close(f);
    717  1.13       dsl 	else
    718   1.5        ad 		fsmod = "ext2fs";
    719   1.1   tsutsui 	return rc;
    720   1.1   tsutsui }
    721   1.1   tsutsui 
    722  1.10     joerg __compactcall int
    723   1.1   tsutsui ext2fs_close(struct open_file *f)
    724   1.1   tsutsui {
    725   1.1   tsutsui 	struct file *fp = (struct file *)f->f_fsdata;
    726   1.1   tsutsui 
    727   1.1   tsutsui 	f->f_fsdata = NULL;
    728   1.1   tsutsui 	if (fp == NULL)
    729   1.1   tsutsui 		return 0;
    730   1.1   tsutsui 
    731   1.4   tsutsui 	if (fp->f_fs->e2fs_gd)
    732   1.4   tsutsui 		dealloc(fp->f_fs->e2fs_gd,
    733   1.4   tsutsui 		    sizeof(struct ext2_gd) * fp->f_fs->e2fs_ncg);
    734   1.1   tsutsui 	if (fp->f_buf)
    735   1.1   tsutsui 		dealloc(fp->f_buf, fp->f_fs->e2fs_bsize);
    736   1.4   tsutsui 	dealloc(fp->f_fs, sizeof(*fp->f_fs));
    737   1.1   tsutsui 	dealloc(fp, sizeof(struct file));
    738   1.1   tsutsui 	return 0;
    739   1.1   tsutsui }
    740   1.1   tsutsui 
    741   1.1   tsutsui /*
    742   1.1   tsutsui  * Copy a portion of a file into kernel memory.
    743   1.1   tsutsui  * Cross block boundaries when necessary.
    744   1.1   tsutsui  */
    745  1.10     joerg __compactcall int
    746   1.1   tsutsui ext2fs_read(struct open_file *f, void *start, size_t size, size_t *resid)
    747   1.1   tsutsui {
    748   1.1   tsutsui 	struct file *fp = (struct file *)f->f_fsdata;
    749   1.1   tsutsui 	size_t csize;
    750   1.1   tsutsui 	char *buf;
    751   1.1   tsutsui 	size_t buf_size;
    752   1.1   tsutsui 	int rc = 0;
    753   1.1   tsutsui 	char *addr = start;
    754   1.1   tsutsui 
    755   1.1   tsutsui 	while (size != 0) {
    756   1.1   tsutsui 		/* XXX should handle LARGEFILE */
    757   1.1   tsutsui 		if (fp->f_seekp >= (off_t)fp->f_di.e2di_size)
    758   1.1   tsutsui 			break;
    759   1.1   tsutsui 
    760   1.1   tsutsui 		rc = buf_read_file(f, &buf, &buf_size);
    761   1.1   tsutsui 		if (rc)
    762   1.1   tsutsui 			break;
    763   1.1   tsutsui 
    764   1.1   tsutsui 		csize = size;
    765   1.1   tsutsui 		if (csize > buf_size)
    766   1.1   tsutsui 			csize = buf_size;
    767   1.1   tsutsui 
    768   1.1   tsutsui 		memcpy(addr, buf, csize);
    769   1.1   tsutsui 
    770   1.1   tsutsui 		fp->f_seekp += csize;
    771   1.1   tsutsui 		addr += csize;
    772   1.1   tsutsui 		size -= csize;
    773   1.1   tsutsui 	}
    774   1.1   tsutsui 	if (resid)
    775   1.1   tsutsui 		*resid = size;
    776   1.1   tsutsui 	return rc;
    777   1.1   tsutsui }
    778   1.1   tsutsui 
    779   1.1   tsutsui /*
    780   1.1   tsutsui  * Not implemented.
    781   1.1   tsutsui  */
    782   1.1   tsutsui #ifndef LIBSA_NO_FS_WRITE
    783  1.10     joerg __compactcall int
    784   1.1   tsutsui ext2fs_write(struct open_file *f, void *start, size_t size, size_t *resid)
    785   1.1   tsutsui {
    786   1.1   tsutsui 
    787   1.1   tsutsui 	return EROFS;
    788   1.1   tsutsui }
    789   1.1   tsutsui #endif /* !LIBSA_NO_FS_WRITE */
    790   1.1   tsutsui 
    791   1.1   tsutsui #ifndef LIBSA_NO_FS_SEEK
    792  1.10     joerg __compactcall off_t
    793   1.1   tsutsui ext2fs_seek(struct open_file *f, off_t offset, int where)
    794   1.1   tsutsui {
    795   1.1   tsutsui 	struct file *fp = (struct file *)f->f_fsdata;
    796   1.1   tsutsui 
    797   1.1   tsutsui 	switch (where) {
    798   1.1   tsutsui 	case SEEK_SET:
    799   1.1   tsutsui 		fp->f_seekp = offset;
    800   1.1   tsutsui 		break;
    801   1.1   tsutsui 	case SEEK_CUR:
    802   1.1   tsutsui 		fp->f_seekp += offset;
    803   1.1   tsutsui 		break;
    804   1.1   tsutsui 	case SEEK_END:
    805   1.1   tsutsui 		/* XXX should handle LARGEFILE */
    806   1.1   tsutsui 		fp->f_seekp = fp->f_di.e2di_size - offset;
    807   1.1   tsutsui 		break;
    808   1.1   tsutsui 	default:
    809   1.1   tsutsui 		return -1;
    810   1.1   tsutsui 	}
    811   1.1   tsutsui 	return fp->f_seekp;
    812   1.1   tsutsui }
    813   1.1   tsutsui #endif /* !LIBSA_NO_FS_SEEK */
    814   1.1   tsutsui 
    815  1.10     joerg __compactcall int
    816   1.1   tsutsui ext2fs_stat(struct open_file *f, struct stat *sb)
    817   1.1   tsutsui {
    818   1.1   tsutsui 	struct file *fp = (struct file *)f->f_fsdata;
    819   1.1   tsutsui 
    820   1.1   tsutsui 	/* only important stuff */
    821   1.1   tsutsui 	memset(sb, 0, sizeof *sb);
    822   1.1   tsutsui 	sb->st_mode = fp->f_di.e2di_mode;
    823   1.1   tsutsui 	sb->st_uid = fp->f_di.e2di_uid;
    824   1.1   tsutsui 	sb->st_gid = fp->f_di.e2di_gid;
    825   1.1   tsutsui 	/* XXX should handle LARGEFILE */
    826   1.1   tsutsui 	sb->st_size = fp->f_di.e2di_size;
    827   1.1   tsutsui 	return 0;
    828   1.1   tsutsui }
    829   1.1   tsutsui 
    830  1.11   tsutsui #if defined(LIBSA_ENABLE_LS_OP)
    831  1.11   tsutsui __compactcall void
    832  1.11   tsutsui ext2fs_ls(struct open_file *f, const char *pattern)
    833  1.11   tsutsui {
    834  1.11   tsutsui 	struct file *fp = (struct file *)f->f_fsdata;
    835  1.11   tsutsui 	size_t block_size = fp->f_fs->e2fs_bsize;
    836  1.11   tsutsui 	char *buf;
    837  1.11   tsutsui 	size_t buf_size;
    838  1.11   tsutsui 	entry_t	*names = 0, *n, **np;
    839  1.11   tsutsui 
    840  1.11   tsutsui 	fp->f_seekp = 0;
    841  1.11   tsutsui 	while (fp->f_seekp < (off_t)fp->f_di.e2di_size) {
    842  1.11   tsutsui 		struct ext2fs_direct  *dp, *edp;
    843  1.11   tsutsui 		int rc = buf_read_file(f, &buf, &buf_size);
    844  1.11   tsutsui 		if (rc)
    845  1.11   tsutsui 			goto out;
    846  1.11   tsutsui 		if (buf_size != block_size || buf_size == 0)
    847  1.11   tsutsui 			goto out;
    848  1.11   tsutsui 
    849  1.11   tsutsui 		dp = (struct ext2fs_direct *)buf;
    850  1.11   tsutsui 		edp = (struct ext2fs_direct *)(buf + buf_size);
    851  1.11   tsutsui 
    852  1.11   tsutsui 		for (; dp < edp;
    853  1.11   tsutsui 		     dp = (void *)((char *)dp + fs2h16(dp->e2d_reclen))) {
    854  1.11   tsutsui 			const char *t;
    855  1.11   tsutsui 
    856  1.11   tsutsui 			if (fs2h16(dp->e2d_reclen) <= 0)
    857  1.11   tsutsui 				goto out;
    858  1.11   tsutsui 
    859  1.11   tsutsui 			if (fs2h32(dp->e2d_ino) == 0)
    860  1.11   tsutsui 				continue;
    861  1.11   tsutsui 
    862  1.11   tsutsui 			if (dp->e2d_type >= NELEM(typestr) ||
    863  1.11   tsutsui 			    !(t = typestr[dp->e2d_type])) {
    864  1.11   tsutsui 				/*
    865  1.11   tsutsui 				 * This does not handle "old"
    866  1.11   tsutsui 				 * filesystems properly. On little
    867  1.11   tsutsui 				 * endian machines, we get a bogus
    868  1.11   tsutsui 				 * type name if the namlen matches a
    869  1.11   tsutsui 				 * valid type identifier. We could
    870  1.11   tsutsui 				 * check if we read namlen "0" and
    871  1.11   tsutsui 				 * handle this case specially, if
    872  1.11   tsutsui 				 * there were a pressing need...
    873  1.11   tsutsui 				 */
    874  1.11   tsutsui 				printf("bad dir entry\n");
    875  1.11   tsutsui 				goto out;
    876  1.11   tsutsui 			}
    877  1.12  christos 			if (pattern && !fnmatch(dp->e2d_name, pattern))
    878  1.11   tsutsui 				continue;
    879  1.11   tsutsui 			n = alloc(sizeof *n + strlen(dp->e2d_name));
    880  1.11   tsutsui 			if (!n) {
    881  1.11   tsutsui 				printf("%d: %s (%s)\n",
    882  1.11   tsutsui 					fs2h32(dp->e2d_ino), dp->e2d_name, t);
    883  1.11   tsutsui 				continue;
    884  1.11   tsutsui 			}
    885  1.11   tsutsui 			n->e_ino = fs2h32(dp->e2d_ino);
    886  1.11   tsutsui 			n->e_type = dp->e2d_type;
    887  1.11   tsutsui 			strcpy(n->e_name, dp->e2d_name);
    888  1.11   tsutsui 			for (np = &names; *np; np = &(*np)->e_next) {
    889  1.11   tsutsui 				if (strcmp(n->e_name, (*np)->e_name) < 0)
    890  1.11   tsutsui 					break;
    891  1.11   tsutsui 			}
    892  1.11   tsutsui 			n->e_next = *np;
    893  1.11   tsutsui 			*np = n;
    894  1.11   tsutsui 		}
    895  1.11   tsutsui 		fp->f_seekp += buf_size;
    896  1.11   tsutsui 	}
    897  1.11   tsutsui 
    898  1.11   tsutsui 	if (names) {
    899  1.11   tsutsui 		entry_t *p_names = names;
    900  1.11   tsutsui 		do {
    901  1.11   tsutsui 			n = p_names;
    902  1.11   tsutsui 			printf("%d: %s (%s)\n",
    903  1.11   tsutsui 				n->e_ino, n->e_name, typestr[n->e_type]);
    904  1.11   tsutsui 			p_names = n->e_next;
    905  1.11   tsutsui 		} while (p_names);
    906  1.11   tsutsui 	} else {
    907  1.11   tsutsui 		printf("not found\n");
    908  1.11   tsutsui 	}
    909  1.11   tsutsui out:
    910  1.11   tsutsui 	if (names) {
    911  1.11   tsutsui 		do {
    912  1.11   tsutsui 			n = names;
    913  1.11   tsutsui 			names = n->e_next;
    914  1.11   tsutsui 			dealloc(n, 0);
    915  1.11   tsutsui 		} while (names);
    916  1.11   tsutsui 	}
    917  1.11   tsutsui 	return;
    918  1.11   tsutsui }
    919  1.11   tsutsui #endif
    920  1.11   tsutsui 
    921   1.1   tsutsui /*
    922   1.1   tsutsui  * byte swap functions for big endian machines
    923   1.1   tsutsui  * (ext2fs is always little endian)
    924   1.1   tsutsui  *
    925   1.1   tsutsui  * XXX: We should use src/sys/ufs/ext2fs/ext2fs_bswap.c
    926   1.1   tsutsui  */
    927   1.1   tsutsui 
    928   1.1   tsutsui /* These functions are only needed if native byte order is not big endian */
    929   1.1   tsutsui #if BYTE_ORDER == BIG_ENDIAN
    930   1.1   tsutsui void
    931   1.1   tsutsui e2fs_sb_bswap(struct ext2fs *old, struct ext2fs *new)
    932   1.1   tsutsui {
    933   1.1   tsutsui 
    934   1.1   tsutsui 	/* preserve unused fields */
    935   1.1   tsutsui 	memcpy(new, old, sizeof(struct ext2fs));
    936   1.1   tsutsui 	new->e2fs_icount	=	bswap32(old->e2fs_icount);
    937   1.1   tsutsui 	new->e2fs_bcount	=	bswap32(old->e2fs_bcount);
    938   1.1   tsutsui 	new->e2fs_rbcount	=	bswap32(old->e2fs_rbcount);
    939   1.1   tsutsui 	new->e2fs_fbcount	=	bswap32(old->e2fs_fbcount);
    940   1.1   tsutsui 	new->e2fs_ficount	=	bswap32(old->e2fs_ficount);
    941   1.1   tsutsui 	new->e2fs_first_dblock	=	bswap32(old->e2fs_first_dblock);
    942   1.1   tsutsui 	new->e2fs_log_bsize	=	bswap32(old->e2fs_log_bsize);
    943   1.1   tsutsui 	new->e2fs_fsize		=	bswap32(old->e2fs_fsize);
    944   1.1   tsutsui 	new->e2fs_bpg		=	bswap32(old->e2fs_bpg);
    945   1.1   tsutsui 	new->e2fs_fpg		=	bswap32(old->e2fs_fpg);
    946   1.1   tsutsui 	new->e2fs_ipg		=	bswap32(old->e2fs_ipg);
    947   1.1   tsutsui 	new->e2fs_mtime		=	bswap32(old->e2fs_mtime);
    948   1.1   tsutsui 	new->e2fs_wtime		=	bswap32(old->e2fs_wtime);
    949   1.1   tsutsui 	new->e2fs_mnt_count	=	bswap16(old->e2fs_mnt_count);
    950   1.1   tsutsui 	new->e2fs_max_mnt_count	=	bswap16(old->e2fs_max_mnt_count);
    951   1.1   tsutsui 	new->e2fs_magic		=	bswap16(old->e2fs_magic);
    952   1.1   tsutsui 	new->e2fs_state		=	bswap16(old->e2fs_state);
    953   1.1   tsutsui 	new->e2fs_beh		=	bswap16(old->e2fs_beh);
    954   1.1   tsutsui 	new->e2fs_minrev	=	bswap16(old->e2fs_minrev);
    955   1.1   tsutsui 	new->e2fs_lastfsck	=	bswap32(old->e2fs_lastfsck);
    956   1.1   tsutsui 	new->e2fs_fsckintv	=	bswap32(old->e2fs_fsckintv);
    957   1.1   tsutsui 	new->e2fs_creator	=	bswap32(old->e2fs_creator);
    958   1.1   tsutsui 	new->e2fs_rev		=	bswap32(old->e2fs_rev);
    959   1.1   tsutsui 	new->e2fs_ruid		=	bswap16(old->e2fs_ruid);
    960   1.1   tsutsui 	new->e2fs_rgid		=	bswap16(old->e2fs_rgid);
    961   1.1   tsutsui 	new->e2fs_first_ino	=	bswap32(old->e2fs_first_ino);
    962   1.1   tsutsui 	new->e2fs_inode_size	=	bswap16(old->e2fs_inode_size);
    963   1.1   tsutsui 	new->e2fs_block_group_nr =	bswap16(old->e2fs_block_group_nr);
    964   1.1   tsutsui 	new->e2fs_features_compat =	bswap32(old->e2fs_features_compat);
    965   1.1   tsutsui 	new->e2fs_features_incompat =	bswap32(old->e2fs_features_incompat);
    966   1.1   tsutsui 	new->e2fs_features_rocompat =	bswap32(old->e2fs_features_rocompat);
    967   1.1   tsutsui 	new->e2fs_algo		=	bswap32(old->e2fs_algo);
    968   1.1   tsutsui 	new->e2fs_reserved_ngdb	=	bswap16(old->e2fs_reserved_ngdb);
    969   1.1   tsutsui }
    970   1.1   tsutsui 
    971   1.1   tsutsui void e2fs_cg_bswap(struct ext2_gd *old, struct ext2_gd *new, int size)
    972   1.1   tsutsui {
    973   1.1   tsutsui 	int i;
    974   1.1   tsutsui 
    975   1.1   tsutsui 	for (i = 0; i < (size / sizeof(struct ext2_gd)); i++) {
    976   1.1   tsutsui 		new[i].ext2bgd_b_bitmap	= bswap32(old[i].ext2bgd_b_bitmap);
    977   1.1   tsutsui 		new[i].ext2bgd_i_bitmap	= bswap32(old[i].ext2bgd_i_bitmap);
    978   1.1   tsutsui 		new[i].ext2bgd_i_tables	= bswap32(old[i].ext2bgd_i_tables);
    979   1.1   tsutsui 		new[i].ext2bgd_nbfree	= bswap16(old[i].ext2bgd_nbfree);
    980   1.1   tsutsui 		new[i].ext2bgd_nifree	= bswap16(old[i].ext2bgd_nifree);
    981   1.1   tsutsui 		new[i].ext2bgd_ndirs	= bswap16(old[i].ext2bgd_ndirs);
    982   1.1   tsutsui 	}
    983   1.1   tsutsui }
    984   1.1   tsutsui 
    985   1.1   tsutsui void e2fs_i_bswap(struct ext2fs_dinode *old, struct ext2fs_dinode *new)
    986   1.1   tsutsui {
    987   1.1   tsutsui 
    988   1.1   tsutsui 	new->e2di_mode		=	bswap16(old->e2di_mode);
    989   1.1   tsutsui 	new->e2di_uid		=	bswap16(old->e2di_uid);
    990   1.1   tsutsui 	new->e2di_gid		=	bswap16(old->e2di_gid);
    991   1.1   tsutsui 	new->e2di_nlink		=	bswap16(old->e2di_nlink);
    992   1.1   tsutsui 	new->e2di_size		=	bswap32(old->e2di_size);
    993   1.1   tsutsui 	new->e2di_atime		=	bswap32(old->e2di_atime);
    994   1.1   tsutsui 	new->e2di_ctime		=	bswap32(old->e2di_ctime);
    995   1.1   tsutsui 	new->e2di_mtime		=	bswap32(old->e2di_mtime);
    996   1.1   tsutsui 	new->e2di_dtime		=	bswap32(old->e2di_dtime);
    997   1.1   tsutsui 	new->e2di_nblock	=	bswap32(old->e2di_nblock);
    998   1.1   tsutsui 	new->e2di_flags		=	bswap32(old->e2di_flags);
    999   1.1   tsutsui 	new->e2di_gen		=	bswap32(old->e2di_gen);
   1000   1.1   tsutsui 	new->e2di_facl		=	bswap32(old->e2di_facl);
   1001   1.1   tsutsui 	new->e2di_dacl		=	bswap32(old->e2di_dacl);
   1002   1.1   tsutsui 	new->e2di_faddr		=	bswap32(old->e2di_faddr);
   1003   1.1   tsutsui 	memcpy(&new->e2di_blocks[0], &old->e2di_blocks[0],
   1004  1.14  dholland 	    (EXT2FS_NDADDR + EXT2FS_NIADDR) * sizeof(uint32_t));
   1005   1.1   tsutsui }
   1006   1.1   tsutsui #endif
   1007   1.1   tsutsui 
   1008   1.1   tsutsui #ifdef EXT2FS_DEBUG
   1009   1.1   tsutsui void
   1010   1.1   tsutsui dump_sblock(struct m_ext2fs *fs)
   1011   1.1   tsutsui {
   1012   1.1   tsutsui 
   1013   1.1   tsutsui 	printf("fs->e2fs.e2fs_bcount = %u\n", fs->e2fs.e2fs_bcount);
   1014   1.1   tsutsui 	printf("fs->e2fs.e2fs_first_dblock = %u\n", fs->e2fs.e2fs_first_dblock);
   1015   1.1   tsutsui 	printf("fs->e2fs.e2fs_log_bsize = %u\n", fs->e2fs.e2fs_log_bsize);
   1016   1.1   tsutsui 	printf("fs->e2fs.e2fs_bpg = %u\n", fs->e2fs.e2fs_bpg);
   1017   1.1   tsutsui 	printf("fs->e2fs.e2fs_ipg = %u\n", fs->e2fs.e2fs_ipg);
   1018   1.1   tsutsui 	printf("fs->e2fs.e2fs_magic = 0x%x\n", fs->e2fs.e2fs_magic);
   1019   1.1   tsutsui 	printf("fs->e2fs.e2fs_rev = %u\n", fs->e2fs.e2fs_rev);
   1020   1.1   tsutsui 
   1021   1.1   tsutsui 	if (fs->e2fs.e2fs_rev == E2FS_REV1) {
   1022   1.1   tsutsui 		printf("fs->e2fs.e2fs_first_ino = %u\n",
   1023   1.1   tsutsui 		    fs->e2fs.e2fs_first_ino);
   1024   1.1   tsutsui 		printf("fs->e2fs.e2fs_inode_size = %u\n",
   1025   1.1   tsutsui 		    fs->e2fs.e2fs_inode_size);
   1026   1.1   tsutsui 		printf("fs->e2fs.e2fs_features_compat = %u\n",
   1027   1.1   tsutsui 		    fs->e2fs.e2fs_features_compat);
   1028   1.1   tsutsui 		printf("fs->e2fs.e2fs_features_incompat = %u\n",
   1029   1.1   tsutsui 		    fs->e2fs.e2fs_features_incompat);
   1030   1.1   tsutsui 		printf("fs->e2fs.e2fs_features_rocompat = %u\n",
   1031   1.1   tsutsui 		    fs->e2fs.e2fs_features_rocompat);
   1032   1.1   tsutsui 		printf("fs->e2fs.e2fs_reserved_ngdb = %u\n",
   1033   1.1   tsutsui 		    fs->e2fs.e2fs_reserved_ngdb);
   1034   1.1   tsutsui 	}
   1035   1.1   tsutsui 
   1036   1.1   tsutsui 	printf("fs->e2fs_bsize = %u\n", fs->e2fs_bsize);
   1037   1.1   tsutsui 	printf("fs->e2fs_fsbtodb = %u\n", fs->e2fs_fsbtodb);
   1038   1.1   tsutsui 	printf("fs->e2fs_ncg = %u\n", fs->e2fs_ncg);
   1039   1.1   tsutsui 	printf("fs->e2fs_ngdb = %u\n", fs->e2fs_ngdb);
   1040   1.1   tsutsui 	printf("fs->e2fs_ipb = %u\n", fs->e2fs_ipb);
   1041   1.1   tsutsui 	printf("fs->e2fs_itpg = %u\n", fs->e2fs_itpg);
   1042   1.1   tsutsui }
   1043   1.1   tsutsui #endif
   1044