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