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