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