1*0a6a1f1dSLionel Sambuc /* $NetBSD: ext2fs.c,v 1.20 2014/03/20 03:13:18 christos Exp $ */
258a2b000SEvgeniy Ivanov
358a2b000SEvgeniy Ivanov /*
458a2b000SEvgeniy Ivanov * Copyright (c) 1997 Manuel Bouyer.
558a2b000SEvgeniy Ivanov *
658a2b000SEvgeniy Ivanov * Redistribution and use in source and binary forms, with or without
758a2b000SEvgeniy Ivanov * modification, are permitted provided that the following conditions
858a2b000SEvgeniy Ivanov * are met:
958a2b000SEvgeniy Ivanov * 1. Redistributions of source code must retain the above copyright
1058a2b000SEvgeniy Ivanov * notice, this list of conditions and the following disclaimer.
1158a2b000SEvgeniy Ivanov * 2. Redistributions in binary form must reproduce the above copyright
1258a2b000SEvgeniy Ivanov * notice, this list of conditions and the following disclaimer in the
1358a2b000SEvgeniy Ivanov * documentation and/or other materials provided with the distribution.
1458a2b000SEvgeniy Ivanov *
1558a2b000SEvgeniy Ivanov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1658a2b000SEvgeniy Ivanov * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1758a2b000SEvgeniy Ivanov * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1858a2b000SEvgeniy Ivanov * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1958a2b000SEvgeniy Ivanov * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2058a2b000SEvgeniy Ivanov * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2158a2b000SEvgeniy Ivanov * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2258a2b000SEvgeniy Ivanov * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2358a2b000SEvgeniy Ivanov * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2458a2b000SEvgeniy Ivanov * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2558a2b000SEvgeniy Ivanov */
2658a2b000SEvgeniy Ivanov
2758a2b000SEvgeniy Ivanov /*-
2858a2b000SEvgeniy Ivanov * Copyright (c) 1993
2958a2b000SEvgeniy Ivanov * The Regents of the University of California. All rights reserved.
3058a2b000SEvgeniy Ivanov *
3158a2b000SEvgeniy Ivanov * This code is derived from software contributed to Berkeley by
3258a2b000SEvgeniy Ivanov * The Mach Operating System project at Carnegie-Mellon University.
3358a2b000SEvgeniy Ivanov *
3458a2b000SEvgeniy Ivanov * Redistribution and use in source and binary forms, with or without
3558a2b000SEvgeniy Ivanov * modification, are permitted provided that the following conditions
3658a2b000SEvgeniy Ivanov * are met:
3758a2b000SEvgeniy Ivanov * 1. Redistributions of source code must retain the above copyright
3858a2b000SEvgeniy Ivanov * notice, this list of conditions and the following disclaimer.
3958a2b000SEvgeniy Ivanov * 2. Redistributions in binary form must reproduce the above copyright
4058a2b000SEvgeniy Ivanov * notice, this list of conditions and the following disclaimer in the
4158a2b000SEvgeniy Ivanov * documentation and/or other materials provided with the distribution.
4258a2b000SEvgeniy Ivanov * 3. Neither the name of the University nor the names of its contributors
4358a2b000SEvgeniy Ivanov * may be used to endorse or promote products derived from this software
4458a2b000SEvgeniy Ivanov * without specific prior written permission.
4558a2b000SEvgeniy Ivanov *
4658a2b000SEvgeniy Ivanov * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
4758a2b000SEvgeniy Ivanov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4858a2b000SEvgeniy Ivanov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4958a2b000SEvgeniy Ivanov * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
5058a2b000SEvgeniy Ivanov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5158a2b000SEvgeniy Ivanov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5258a2b000SEvgeniy Ivanov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5358a2b000SEvgeniy Ivanov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5458a2b000SEvgeniy Ivanov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5558a2b000SEvgeniy Ivanov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5658a2b000SEvgeniy Ivanov * SUCH DAMAGE.
5758a2b000SEvgeniy Ivanov *
5858a2b000SEvgeniy Ivanov *
5958a2b000SEvgeniy Ivanov * Copyright (c) 1990, 1991 Carnegie Mellon University
6058a2b000SEvgeniy Ivanov * All Rights Reserved.
6158a2b000SEvgeniy Ivanov *
6258a2b000SEvgeniy Ivanov * Author: David Golub
6358a2b000SEvgeniy Ivanov *
6458a2b000SEvgeniy Ivanov * Permission to use, copy, modify and distribute this software and its
6558a2b000SEvgeniy Ivanov * documentation is hereby granted, provided that both the copyright
6658a2b000SEvgeniy Ivanov * notice and this permission notice appear in all copies of the
6758a2b000SEvgeniy Ivanov * software, derivative works or modified versions, and any portions
6858a2b000SEvgeniy Ivanov * thereof, and that both notices appear in supporting documentation.
6958a2b000SEvgeniy Ivanov *
7058a2b000SEvgeniy Ivanov * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
7158a2b000SEvgeniy Ivanov * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
7258a2b000SEvgeniy Ivanov * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
7358a2b000SEvgeniy Ivanov *
7458a2b000SEvgeniy Ivanov * Carnegie Mellon requests users of this software to return to
7558a2b000SEvgeniy Ivanov *
7658a2b000SEvgeniy Ivanov * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
7758a2b000SEvgeniy Ivanov * School of Computer Science
7858a2b000SEvgeniy Ivanov * Carnegie Mellon University
7958a2b000SEvgeniy Ivanov * Pittsburgh PA 15213-3890
8058a2b000SEvgeniy Ivanov *
8158a2b000SEvgeniy Ivanov * any improvements or extensions that they make and grant Carnegie the
8258a2b000SEvgeniy Ivanov * rights to redistribute these changes.
8358a2b000SEvgeniy Ivanov */
8458a2b000SEvgeniy Ivanov
8558a2b000SEvgeniy Ivanov /*
8658a2b000SEvgeniy Ivanov * Stand-alone file reading package for Ext2 file system.
8758a2b000SEvgeniy Ivanov */
8858a2b000SEvgeniy Ivanov
8958a2b000SEvgeniy Ivanov /* #define EXT2FS_DEBUG */
9058a2b000SEvgeniy Ivanov
9158a2b000SEvgeniy Ivanov #include <sys/param.h>
9258a2b000SEvgeniy Ivanov #include <sys/time.h>
9358a2b000SEvgeniy Ivanov #include <ufs/ext2fs/ext2fs_dinode.h>
9458a2b000SEvgeniy Ivanov #include <ufs/ext2fs/ext2fs_dir.h>
9558a2b000SEvgeniy Ivanov #include <ufs/ext2fs/ext2fs.h>
9658a2b000SEvgeniy Ivanov #ifdef _STANDALONE
9758a2b000SEvgeniy Ivanov #include <lib/libkern/libkern.h>
9858a2b000SEvgeniy Ivanov #else
9958a2b000SEvgeniy Ivanov #include <string.h>
10058a2b000SEvgeniy Ivanov #endif
10158a2b000SEvgeniy Ivanov
10258a2b000SEvgeniy Ivanov #include "stand.h"
10358a2b000SEvgeniy Ivanov #include "ext2fs.h"
10458a2b000SEvgeniy Ivanov
10558a2b000SEvgeniy Ivanov #if defined(LIBSA_FS_SINGLECOMPONENT) && !defined(LIBSA_NO_FS_SYMLINK)
10658a2b000SEvgeniy Ivanov #define LIBSA_NO_FS_SYMLINK
10758a2b000SEvgeniy Ivanov #endif
10858a2b000SEvgeniy Ivanov
10958a2b000SEvgeniy Ivanov #if defined(LIBSA_NO_TWIDDLE)
11058a2b000SEvgeniy Ivanov #define twiddle()
11158a2b000SEvgeniy Ivanov #endif
11258a2b000SEvgeniy Ivanov
11358a2b000SEvgeniy Ivanov #ifndef indp_t
11458a2b000SEvgeniy Ivanov #define indp_t int32_t
11558a2b000SEvgeniy Ivanov #endif
11658a2b000SEvgeniy Ivanov typedef uint32_t ino32_t;
11758a2b000SEvgeniy Ivanov #ifndef FSBTODB
11884d9c625SLionel Sambuc #define FSBTODB(fs, indp) EXT2_FSBTODB(fs, indp)
11958a2b000SEvgeniy Ivanov #endif
12058a2b000SEvgeniy Ivanov
12158a2b000SEvgeniy Ivanov /*
12258a2b000SEvgeniy Ivanov * To avoid having a lot of filesystem-block sized buffers lurking (which
12358a2b000SEvgeniy Ivanov * could be 32k) we only keep a few entries of the indirect block map.
12458a2b000SEvgeniy Ivanov * With 8k blocks, 2^8 blocks is ~500k so we reread the indirect block
12558a2b000SEvgeniy Ivanov * ~13 times pulling in a 6M kernel.
12658a2b000SEvgeniy Ivanov * The cache size must be smaller than the smallest filesystem block,
12758a2b000SEvgeniy Ivanov * so LN2_IND_CACHE_SZ <= 9 (UFS2 and 4k blocks).
12858a2b000SEvgeniy Ivanov */
12958a2b000SEvgeniy Ivanov #define LN2_IND_CACHE_SZ 6
13058a2b000SEvgeniy Ivanov #define IND_CACHE_SZ (1 << LN2_IND_CACHE_SZ)
13158a2b000SEvgeniy Ivanov #define IND_CACHE_MASK (IND_CACHE_SZ - 1)
13258a2b000SEvgeniy Ivanov
13358a2b000SEvgeniy Ivanov /*
13458a2b000SEvgeniy Ivanov * In-core open file.
13558a2b000SEvgeniy Ivanov */
13658a2b000SEvgeniy Ivanov struct file {
13758a2b000SEvgeniy Ivanov off_t f_seekp; /* seek pointer */
13858a2b000SEvgeniy Ivanov struct m_ext2fs *f_fs; /* pointer to super-block */
13958a2b000SEvgeniy Ivanov struct ext2fs_dinode f_di; /* copy of on-disk inode */
14058a2b000SEvgeniy Ivanov uint f_nishift; /* for blocks in indirect block */
14158a2b000SEvgeniy Ivanov indp_t f_ind_cache_block;
14258a2b000SEvgeniy Ivanov indp_t f_ind_cache[IND_CACHE_SZ];
14358a2b000SEvgeniy Ivanov
14458a2b000SEvgeniy Ivanov char *f_buf; /* buffer for data block */
14558a2b000SEvgeniy Ivanov size_t f_buf_size; /* size of data block */
14658a2b000SEvgeniy Ivanov daddr_t f_buf_blkno; /* block number of data block */
14758a2b000SEvgeniy Ivanov };
14858a2b000SEvgeniy Ivanov
14958a2b000SEvgeniy Ivanov
15058a2b000SEvgeniy Ivanov static int read_inode(ino32_t, struct open_file *);
15158a2b000SEvgeniy Ivanov static int block_map(struct open_file *, indp_t, indp_t *);
15258a2b000SEvgeniy Ivanov static int buf_read_file(struct open_file *, char **, size_t *);
15358a2b000SEvgeniy Ivanov static int search_directory(const char *, int, struct open_file *, ino32_t *);
15458a2b000SEvgeniy Ivanov static int read_sblock(struct open_file *, struct m_ext2fs *);
15558a2b000SEvgeniy Ivanov static int read_gdblock(struct open_file *, struct m_ext2fs *);
15658a2b000SEvgeniy Ivanov #ifdef EXT2FS_DEBUG
15758a2b000SEvgeniy Ivanov static void dump_sblock(struct m_ext2fs *);
15858a2b000SEvgeniy Ivanov #endif
15958a2b000SEvgeniy Ivanov
16058a2b000SEvgeniy Ivanov /*
16158a2b000SEvgeniy Ivanov * Read a new inode into a file structure.
16258a2b000SEvgeniy Ivanov */
16358a2b000SEvgeniy Ivanov static int
read_inode(ino32_t inumber,struct open_file * f)16458a2b000SEvgeniy Ivanov read_inode(ino32_t inumber, struct open_file *f)
16558a2b000SEvgeniy Ivanov {
16658a2b000SEvgeniy Ivanov struct file *fp = (struct file *)f->f_fsdata;
16758a2b000SEvgeniy Ivanov struct m_ext2fs *fs = fp->f_fs;
16858a2b000SEvgeniy Ivanov char *buf;
16958a2b000SEvgeniy Ivanov size_t rsize;
17058a2b000SEvgeniy Ivanov int rc;
17158a2b000SEvgeniy Ivanov daddr_t inode_sector;
17258a2b000SEvgeniy Ivanov struct ext2fs_dinode *dip;
17358a2b000SEvgeniy Ivanov
17458a2b000SEvgeniy Ivanov inode_sector = FSBTODB(fs, ino_to_fsba(fs, inumber));
17558a2b000SEvgeniy Ivanov
17658a2b000SEvgeniy Ivanov /*
17758a2b000SEvgeniy Ivanov * Read inode and save it.
17858a2b000SEvgeniy Ivanov */
17958a2b000SEvgeniy Ivanov buf = fp->f_buf;
18058a2b000SEvgeniy Ivanov twiddle();
18158a2b000SEvgeniy Ivanov rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
18258a2b000SEvgeniy Ivanov inode_sector, fs->e2fs_bsize, buf, &rsize);
18358a2b000SEvgeniy Ivanov if (rc)
18458a2b000SEvgeniy Ivanov return rc;
18558a2b000SEvgeniy Ivanov if (rsize != fs->e2fs_bsize)
18658a2b000SEvgeniy Ivanov return EIO;
18758a2b000SEvgeniy Ivanov
18858a2b000SEvgeniy Ivanov dip = (struct ext2fs_dinode *)(buf +
18958a2b000SEvgeniy Ivanov EXT2_DINODE_SIZE(fs) * ino_to_fsbo(fs, inumber));
19058a2b000SEvgeniy Ivanov e2fs_iload(dip, &fp->f_di);
19158a2b000SEvgeniy Ivanov
19258a2b000SEvgeniy Ivanov /*
19358a2b000SEvgeniy Ivanov * Clear out the old buffers
19458a2b000SEvgeniy Ivanov */
19558a2b000SEvgeniy Ivanov fp->f_ind_cache_block = ~0;
19658a2b000SEvgeniy Ivanov fp->f_buf_blkno = -1;
19758a2b000SEvgeniy Ivanov return rc;
19858a2b000SEvgeniy Ivanov }
19958a2b000SEvgeniy Ivanov
20058a2b000SEvgeniy Ivanov /*
20158a2b000SEvgeniy Ivanov * Given an offset in a file, find the disk block number that
20258a2b000SEvgeniy Ivanov * contains that block.
20358a2b000SEvgeniy Ivanov */
20458a2b000SEvgeniy Ivanov static int
block_map(struct open_file * f,indp_t file_block,indp_t * disk_block_p)20558a2b000SEvgeniy Ivanov block_map(struct open_file *f, indp_t file_block, indp_t *disk_block_p)
20658a2b000SEvgeniy Ivanov {
20758a2b000SEvgeniy Ivanov struct file *fp = (struct file *)f->f_fsdata;
20858a2b000SEvgeniy Ivanov struct m_ext2fs *fs = fp->f_fs;
20958a2b000SEvgeniy Ivanov uint level;
21058a2b000SEvgeniy Ivanov indp_t ind_cache;
21158a2b000SEvgeniy Ivanov indp_t ind_block_num;
21258a2b000SEvgeniy Ivanov size_t rsize;
21358a2b000SEvgeniy Ivanov int rc;
21458a2b000SEvgeniy Ivanov indp_t *buf = (void *)fp->f_buf;
21558a2b000SEvgeniy Ivanov
21658a2b000SEvgeniy Ivanov /*
21758a2b000SEvgeniy Ivanov * Index structure of an inode:
21858a2b000SEvgeniy Ivanov *
21984d9c625SLionel Sambuc * e2di_blocks[0..EXT2FS_NDADDR-1]
22058a2b000SEvgeniy Ivanov * hold block numbers for blocks
22184d9c625SLionel Sambuc * 0..EXT2FS_NDADDR-1
22258a2b000SEvgeniy Ivanov *
22384d9c625SLionel Sambuc * e2di_blocks[EXT2FS_NDADDR+0]
22484d9c625SLionel Sambuc * block EXT2FS_NDADDR+0 is the single indirect block
22558a2b000SEvgeniy Ivanov * holds block numbers for blocks
22684d9c625SLionel Sambuc * EXT2FS_NDADDR .. EXT2FS_NDADDR + EXT2_NINDIR(fs)-1
22758a2b000SEvgeniy Ivanov *
22884d9c625SLionel Sambuc * e2di_blocks[EXT2FS_NDADDR+1]
22984d9c625SLionel Sambuc * block EXT2FS_NDADDR+1 is the double indirect block
23058a2b000SEvgeniy Ivanov * holds block numbers for INDEX blocks for blocks
23184d9c625SLionel Sambuc * EXT2FS_NDADDR + EXT2_NINDIR(fs) ..
23284d9c625SLionel Sambuc * EXT2FS_NDADDR + EXT2_NINDIR(fs) + EXT2_NINDIR(fs)**2 - 1
23358a2b000SEvgeniy Ivanov *
23484d9c625SLionel Sambuc * e2di_blocks[EXT2FS_NDADDR+2]
23584d9c625SLionel Sambuc * block EXT2FS_NDADDR+2 is the triple indirect block
23658a2b000SEvgeniy Ivanov * holds block numbers for double-indirect
23758a2b000SEvgeniy Ivanov * blocks for blocks
23884d9c625SLionel Sambuc * EXT2FS_NDADDR + EXT2_NINDIR(fs) + EXT2_NINDIR(fs)**2 ..
23984d9c625SLionel Sambuc * EXT2FS_NDADDR + EXT2_NINDIR(fs) + EXT2_NINDIR(fs)**2
24084d9c625SLionel Sambuc * + EXT2_NINDIR(fs)**3 - 1
24158a2b000SEvgeniy Ivanov */
24258a2b000SEvgeniy Ivanov
24384d9c625SLionel Sambuc if (file_block < EXT2FS_NDADDR) {
24458a2b000SEvgeniy Ivanov /* Direct block. */
24558a2b000SEvgeniy Ivanov *disk_block_p = fs2h32(fp->f_di.e2di_blocks[file_block]);
24658a2b000SEvgeniy Ivanov return 0;
24758a2b000SEvgeniy Ivanov }
24858a2b000SEvgeniy Ivanov
24984d9c625SLionel Sambuc file_block -= EXT2FS_NDADDR;
25058a2b000SEvgeniy Ivanov
25158a2b000SEvgeniy Ivanov ind_cache = file_block >> LN2_IND_CACHE_SZ;
25258a2b000SEvgeniy Ivanov if (ind_cache == fp->f_ind_cache_block) {
25358a2b000SEvgeniy Ivanov *disk_block_p =
25458a2b000SEvgeniy Ivanov fs2h32(fp->f_ind_cache[file_block & IND_CACHE_MASK]);
25558a2b000SEvgeniy Ivanov return 0;
25658a2b000SEvgeniy Ivanov }
25758a2b000SEvgeniy Ivanov
25858a2b000SEvgeniy Ivanov for (level = 0;;) {
25958a2b000SEvgeniy Ivanov level += fp->f_nishift;
26058a2b000SEvgeniy Ivanov if (file_block < (indp_t)1 << level)
26158a2b000SEvgeniy Ivanov break;
26284d9c625SLionel Sambuc if (level > EXT2FS_NIADDR * fp->f_nishift)
26358a2b000SEvgeniy Ivanov /* Block number too high */
26458a2b000SEvgeniy Ivanov return EFBIG;
26558a2b000SEvgeniy Ivanov file_block -= (indp_t)1 << level;
26658a2b000SEvgeniy Ivanov }
26758a2b000SEvgeniy Ivanov
26858a2b000SEvgeniy Ivanov ind_block_num =
26984d9c625SLionel Sambuc fs2h32(fp->f_di.e2di_blocks[EXT2FS_NDADDR +
27084d9c625SLionel Sambuc (level / fp->f_nishift - 1)]);
27158a2b000SEvgeniy Ivanov
27258a2b000SEvgeniy Ivanov for (;;) {
27358a2b000SEvgeniy Ivanov level -= fp->f_nishift;
27458a2b000SEvgeniy Ivanov if (ind_block_num == 0) {
27558a2b000SEvgeniy Ivanov *disk_block_p = 0; /* missing */
27658a2b000SEvgeniy Ivanov return 0;
27758a2b000SEvgeniy Ivanov }
27858a2b000SEvgeniy Ivanov
27958a2b000SEvgeniy Ivanov twiddle();
28058a2b000SEvgeniy Ivanov /*
28158a2b000SEvgeniy Ivanov * If we were feeling brave, we could work out the number
28258a2b000SEvgeniy Ivanov * of the disk sector and read a single disk sector instead
28358a2b000SEvgeniy Ivanov * of a filesystem block.
28458a2b000SEvgeniy Ivanov * However we don't do this very often anyway...
28558a2b000SEvgeniy Ivanov */
28658a2b000SEvgeniy Ivanov rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
28758a2b000SEvgeniy Ivanov FSBTODB(fp->f_fs, ind_block_num), fs->e2fs_bsize,
28858a2b000SEvgeniy Ivanov buf, &rsize);
28958a2b000SEvgeniy Ivanov if (rc)
29058a2b000SEvgeniy Ivanov return rc;
29158a2b000SEvgeniy Ivanov if (rsize != fs->e2fs_bsize)
29258a2b000SEvgeniy Ivanov return EIO;
29358a2b000SEvgeniy Ivanov ind_block_num = fs2h32(buf[file_block >> level]);
29458a2b000SEvgeniy Ivanov if (level == 0)
29558a2b000SEvgeniy Ivanov break;
29658a2b000SEvgeniy Ivanov file_block &= (1 << level) - 1;
29758a2b000SEvgeniy Ivanov }
29858a2b000SEvgeniy Ivanov
29958a2b000SEvgeniy Ivanov /* Save the part of the block that contains this sector */
30058a2b000SEvgeniy Ivanov memcpy(fp->f_ind_cache, &buf[file_block & ~IND_CACHE_MASK],
30158a2b000SEvgeniy Ivanov IND_CACHE_SZ * sizeof fp->f_ind_cache[0]);
30258a2b000SEvgeniy Ivanov fp->f_ind_cache_block = ind_cache;
30358a2b000SEvgeniy Ivanov
30458a2b000SEvgeniy Ivanov *disk_block_p = ind_block_num;
30558a2b000SEvgeniy Ivanov
30658a2b000SEvgeniy Ivanov return 0;
30758a2b000SEvgeniy Ivanov }
30858a2b000SEvgeniy Ivanov
30958a2b000SEvgeniy Ivanov /*
31058a2b000SEvgeniy Ivanov * Read a portion of a file into an internal buffer.
31158a2b000SEvgeniy Ivanov * Return the location in the buffer and the amount in the buffer.
31258a2b000SEvgeniy Ivanov */
31358a2b000SEvgeniy Ivanov static int
buf_read_file(struct open_file * f,char ** buf_p,size_t * size_p)31458a2b000SEvgeniy Ivanov buf_read_file(struct open_file *f, char **buf_p, size_t *size_p)
31558a2b000SEvgeniy Ivanov {
31658a2b000SEvgeniy Ivanov struct file *fp = (struct file *)f->f_fsdata;
31758a2b000SEvgeniy Ivanov struct m_ext2fs *fs = fp->f_fs;
31858a2b000SEvgeniy Ivanov long off;
31958a2b000SEvgeniy Ivanov indp_t file_block;
32084d9c625SLionel Sambuc indp_t disk_block = 0; /* XXX: gcc */
32158a2b000SEvgeniy Ivanov size_t block_size;
32258a2b000SEvgeniy Ivanov int rc;
32358a2b000SEvgeniy Ivanov
32484d9c625SLionel Sambuc off = ext2_blkoff(fs, fp->f_seekp);
32584d9c625SLionel Sambuc file_block = ext2_lblkno(fs, fp->f_seekp);
32658a2b000SEvgeniy Ivanov block_size = fs->e2fs_bsize; /* no fragment */
32758a2b000SEvgeniy Ivanov
32858a2b000SEvgeniy Ivanov if (file_block != fp->f_buf_blkno) {
32958a2b000SEvgeniy Ivanov rc = block_map(f, file_block, &disk_block);
33058a2b000SEvgeniy Ivanov if (rc)
33158a2b000SEvgeniy Ivanov return rc;
33258a2b000SEvgeniy Ivanov
33358a2b000SEvgeniy Ivanov if (disk_block == 0) {
33458a2b000SEvgeniy Ivanov memset(fp->f_buf, 0, block_size);
33558a2b000SEvgeniy Ivanov fp->f_buf_size = block_size;
33658a2b000SEvgeniy Ivanov } else {
33758a2b000SEvgeniy Ivanov twiddle();
33858a2b000SEvgeniy Ivanov rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
33958a2b000SEvgeniy Ivanov FSBTODB(fs, disk_block),
34058a2b000SEvgeniy Ivanov block_size, fp->f_buf, &fp->f_buf_size);
34158a2b000SEvgeniy Ivanov if (rc)
34258a2b000SEvgeniy Ivanov return rc;
34358a2b000SEvgeniy Ivanov }
34458a2b000SEvgeniy Ivanov
34558a2b000SEvgeniy Ivanov fp->f_buf_blkno = file_block;
34658a2b000SEvgeniy Ivanov }
34758a2b000SEvgeniy Ivanov
34858a2b000SEvgeniy Ivanov /*
34958a2b000SEvgeniy Ivanov * Return address of byte in buffer corresponding to
35058a2b000SEvgeniy Ivanov * offset, and size of remainder of buffer after that
35158a2b000SEvgeniy Ivanov * byte.
35258a2b000SEvgeniy Ivanov */
35358a2b000SEvgeniy Ivanov *buf_p = fp->f_buf + off;
35458a2b000SEvgeniy Ivanov *size_p = block_size - off;
35558a2b000SEvgeniy Ivanov
35658a2b000SEvgeniy Ivanov /*
35758a2b000SEvgeniy Ivanov * But truncate buffer at end of file.
35858a2b000SEvgeniy Ivanov */
35958a2b000SEvgeniy Ivanov /* XXX should handle LARGEFILE */
36058a2b000SEvgeniy Ivanov if (*size_p > fp->f_di.e2di_size - fp->f_seekp)
36158a2b000SEvgeniy Ivanov *size_p = fp->f_di.e2di_size - fp->f_seekp;
36258a2b000SEvgeniy Ivanov
36358a2b000SEvgeniy Ivanov return 0;
36458a2b000SEvgeniy Ivanov }
36558a2b000SEvgeniy Ivanov
36658a2b000SEvgeniy Ivanov /*
36758a2b000SEvgeniy Ivanov * Search a directory for a name and return its
36858a2b000SEvgeniy Ivanov * inode number.
36958a2b000SEvgeniy Ivanov */
37058a2b000SEvgeniy Ivanov static int
search_directory(const char * name,int length,struct open_file * f,ino32_t * inumber_p)37158a2b000SEvgeniy Ivanov search_directory(const char *name, int length, struct open_file *f,
37258a2b000SEvgeniy Ivanov ino32_t *inumber_p)
37358a2b000SEvgeniy Ivanov {
37458a2b000SEvgeniy Ivanov struct file *fp = (struct file *)f->f_fsdata;
37558a2b000SEvgeniy Ivanov struct ext2fs_direct *dp;
37658a2b000SEvgeniy Ivanov struct ext2fs_direct *edp;
37758a2b000SEvgeniy Ivanov char *buf;
37858a2b000SEvgeniy Ivanov size_t buf_size;
37958a2b000SEvgeniy Ivanov int namlen;
38058a2b000SEvgeniy Ivanov int rc;
38158a2b000SEvgeniy Ivanov
38258a2b000SEvgeniy Ivanov fp->f_seekp = 0;
38358a2b000SEvgeniy Ivanov /* XXX should handle LARGEFILE */
38458a2b000SEvgeniy Ivanov while (fp->f_seekp < (off_t)fp->f_di.e2di_size) {
38558a2b000SEvgeniy Ivanov rc = buf_read_file(f, &buf, &buf_size);
38658a2b000SEvgeniy Ivanov if (rc)
38758a2b000SEvgeniy Ivanov return rc;
38858a2b000SEvgeniy Ivanov
38958a2b000SEvgeniy Ivanov dp = (struct ext2fs_direct *)buf;
39058a2b000SEvgeniy Ivanov edp = (struct ext2fs_direct *)(buf + buf_size);
39158a2b000SEvgeniy Ivanov for (; dp < edp;
39258a2b000SEvgeniy Ivanov dp = (void *)((char *)dp + fs2h16(dp->e2d_reclen))) {
39358a2b000SEvgeniy Ivanov if (fs2h16(dp->e2d_reclen) <= 0)
39458a2b000SEvgeniy Ivanov break;
39558a2b000SEvgeniy Ivanov if (fs2h32(dp->e2d_ino) == (ino32_t)0)
39658a2b000SEvgeniy Ivanov continue;
39758a2b000SEvgeniy Ivanov namlen = dp->e2d_namlen;
39858a2b000SEvgeniy Ivanov if (namlen == length &&
39958a2b000SEvgeniy Ivanov !memcmp(name, dp->e2d_name, length)) {
40058a2b000SEvgeniy Ivanov /* found entry */
40158a2b000SEvgeniy Ivanov *inumber_p = fs2h32(dp->e2d_ino);
40258a2b000SEvgeniy Ivanov return 0;
40358a2b000SEvgeniy Ivanov }
40458a2b000SEvgeniy Ivanov }
40558a2b000SEvgeniy Ivanov fp->f_seekp += buf_size;
40658a2b000SEvgeniy Ivanov }
40758a2b000SEvgeniy Ivanov return ENOENT;
40858a2b000SEvgeniy Ivanov }
40958a2b000SEvgeniy Ivanov
41058a2b000SEvgeniy Ivanov int
read_sblock(struct open_file * f,struct m_ext2fs * fs)41158a2b000SEvgeniy Ivanov read_sblock(struct open_file *f, struct m_ext2fs *fs)
41258a2b000SEvgeniy Ivanov {
41358a2b000SEvgeniy Ivanov static uint8_t sbbuf[SBSIZE];
41458a2b000SEvgeniy Ivanov struct ext2fs ext2fs;
41558a2b000SEvgeniy Ivanov size_t buf_size;
41658a2b000SEvgeniy Ivanov int rc;
41758a2b000SEvgeniy Ivanov
41858a2b000SEvgeniy Ivanov rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
41958a2b000SEvgeniy Ivanov SBOFF / DEV_BSIZE, SBSIZE, sbbuf, &buf_size);
42058a2b000SEvgeniy Ivanov if (rc)
42158a2b000SEvgeniy Ivanov return rc;
42258a2b000SEvgeniy Ivanov
42358a2b000SEvgeniy Ivanov if (buf_size != SBSIZE)
42458a2b000SEvgeniy Ivanov return EIO;
42558a2b000SEvgeniy Ivanov
42658a2b000SEvgeniy Ivanov e2fs_sbload((void *)sbbuf, &ext2fs);
42758a2b000SEvgeniy Ivanov if (ext2fs.e2fs_magic != E2FS_MAGIC)
42858a2b000SEvgeniy Ivanov return EINVAL;
42958a2b000SEvgeniy Ivanov if (ext2fs.e2fs_rev > E2FS_REV1 ||
43058a2b000SEvgeniy Ivanov (ext2fs.e2fs_rev == E2FS_REV1 &&
43158a2b000SEvgeniy Ivanov (ext2fs.e2fs_first_ino != EXT2_FIRSTINO ||
43258a2b000SEvgeniy Ivanov (ext2fs.e2fs_inode_size != 128 && ext2fs.e2fs_inode_size != 256) ||
43358a2b000SEvgeniy Ivanov ext2fs.e2fs_features_incompat & ~EXT2F_INCOMPAT_SUPP))) {
43458a2b000SEvgeniy Ivanov return ENODEV;
43558a2b000SEvgeniy Ivanov }
43658a2b000SEvgeniy Ivanov
43758a2b000SEvgeniy Ivanov e2fs_sbload((void *)sbbuf, &fs->e2fs);
43858a2b000SEvgeniy Ivanov /* compute in-memory m_ext2fs values */
43958a2b000SEvgeniy Ivanov fs->e2fs_ncg =
44058a2b000SEvgeniy Ivanov howmany(fs->e2fs.e2fs_bcount - fs->e2fs.e2fs_first_dblock,
44158a2b000SEvgeniy Ivanov fs->e2fs.e2fs_bpg);
44258a2b000SEvgeniy Ivanov /* XXX assume hw bsize = 512 */
44358a2b000SEvgeniy Ivanov fs->e2fs_fsbtodb = fs->e2fs.e2fs_log_bsize + 1;
44458a2b000SEvgeniy Ivanov fs->e2fs_bsize = MINBSIZE << fs->e2fs.e2fs_log_bsize;
44558a2b000SEvgeniy Ivanov fs->e2fs_bshift = LOG_MINBSIZE + fs->e2fs.e2fs_log_bsize;
44658a2b000SEvgeniy Ivanov fs->e2fs_qbmask = fs->e2fs_bsize - 1;
44758a2b000SEvgeniy Ivanov fs->e2fs_bmask = ~fs->e2fs_qbmask;
44858a2b000SEvgeniy Ivanov fs->e2fs_ngdb =
44958a2b000SEvgeniy Ivanov howmany(fs->e2fs_ncg, fs->e2fs_bsize / sizeof(struct ext2_gd));
45058a2b000SEvgeniy Ivanov fs->e2fs_ipb = fs->e2fs_bsize / ext2fs.e2fs_inode_size;
45158a2b000SEvgeniy Ivanov fs->e2fs_itpg = fs->e2fs.e2fs_ipg / fs->e2fs_ipb;
45258a2b000SEvgeniy Ivanov
45358a2b000SEvgeniy Ivanov return 0;
45458a2b000SEvgeniy Ivanov }
45558a2b000SEvgeniy Ivanov
45658a2b000SEvgeniy Ivanov int
read_gdblock(struct open_file * f,struct m_ext2fs * fs)45758a2b000SEvgeniy Ivanov read_gdblock(struct open_file *f, struct m_ext2fs *fs)
45858a2b000SEvgeniy Ivanov {
45958a2b000SEvgeniy Ivanov struct file *fp = (struct file *)f->f_fsdata;
46058a2b000SEvgeniy Ivanov size_t rsize;
46158a2b000SEvgeniy Ivanov uint gdpb;
46258a2b000SEvgeniy Ivanov int i, rc;
46358a2b000SEvgeniy Ivanov
46458a2b000SEvgeniy Ivanov gdpb = fs->e2fs_bsize / sizeof(struct ext2_gd);
46558a2b000SEvgeniy Ivanov
46658a2b000SEvgeniy Ivanov for (i = 0; i < fs->e2fs_ngdb; i++) {
46758a2b000SEvgeniy Ivanov rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
46858a2b000SEvgeniy Ivanov FSBTODB(fs, fs->e2fs.e2fs_first_dblock +
46958a2b000SEvgeniy Ivanov 1 /* superblock */ + i),
47058a2b000SEvgeniy Ivanov fs->e2fs_bsize, fp->f_buf, &rsize);
47158a2b000SEvgeniy Ivanov if (rc)
47258a2b000SEvgeniy Ivanov return rc;
47358a2b000SEvgeniy Ivanov if (rsize != fs->e2fs_bsize)
47458a2b000SEvgeniy Ivanov return EIO;
47558a2b000SEvgeniy Ivanov
47658a2b000SEvgeniy Ivanov e2fs_cgload((struct ext2_gd *)fp->f_buf,
47758a2b000SEvgeniy Ivanov &fs->e2fs_gd[i * gdpb],
47858a2b000SEvgeniy Ivanov (i == (fs->e2fs_ngdb - 1)) ?
47958a2b000SEvgeniy Ivanov (fs->e2fs_ncg - gdpb * i) * sizeof(struct ext2_gd):
48058a2b000SEvgeniy Ivanov fs->e2fs_bsize);
48158a2b000SEvgeniy Ivanov }
48258a2b000SEvgeniy Ivanov
48358a2b000SEvgeniy Ivanov return 0;
48458a2b000SEvgeniy Ivanov }
48558a2b000SEvgeniy Ivanov
48658a2b000SEvgeniy Ivanov
48758a2b000SEvgeniy Ivanov /*
48858a2b000SEvgeniy Ivanov * Open a file.
48958a2b000SEvgeniy Ivanov */
49058a2b000SEvgeniy Ivanov __compactcall int
ext2fs_open(const char * path,struct open_file * f)49158a2b000SEvgeniy Ivanov ext2fs_open(const char *path, struct open_file *f)
49258a2b000SEvgeniy Ivanov {
49358a2b000SEvgeniy Ivanov #ifndef LIBSA_FS_SINGLECOMPONENT
49458a2b000SEvgeniy Ivanov const char *cp, *ncp;
49558a2b000SEvgeniy Ivanov int c;
49658a2b000SEvgeniy Ivanov #endif
49758a2b000SEvgeniy Ivanov ino32_t inumber;
49858a2b000SEvgeniy Ivanov struct file *fp;
49958a2b000SEvgeniy Ivanov struct m_ext2fs *fs;
50058a2b000SEvgeniy Ivanov int rc;
50158a2b000SEvgeniy Ivanov #ifndef LIBSA_NO_FS_SYMLINK
50258a2b000SEvgeniy Ivanov ino32_t parent_inumber;
50358a2b000SEvgeniy Ivanov int nlinks = 0;
50458a2b000SEvgeniy Ivanov char namebuf[MAXPATHLEN+1];
50558a2b000SEvgeniy Ivanov char *buf;
50658a2b000SEvgeniy Ivanov #endif
50758a2b000SEvgeniy Ivanov
50858a2b000SEvgeniy Ivanov /* allocate file system specific data structure */
50958a2b000SEvgeniy Ivanov fp = alloc(sizeof(struct file));
51058a2b000SEvgeniy Ivanov memset(fp, 0, sizeof(struct file));
51158a2b000SEvgeniy Ivanov f->f_fsdata = (void *)fp;
51258a2b000SEvgeniy Ivanov
51358a2b000SEvgeniy Ivanov /* allocate space and read super block */
51458a2b000SEvgeniy Ivanov fs = alloc(sizeof(*fs));
51558a2b000SEvgeniy Ivanov memset(fs, 0, sizeof(*fs));
51658a2b000SEvgeniy Ivanov fp->f_fs = fs;
51758a2b000SEvgeniy Ivanov twiddle();
51858a2b000SEvgeniy Ivanov
51958a2b000SEvgeniy Ivanov rc = read_sblock(f, fs);
52058a2b000SEvgeniy Ivanov if (rc)
52158a2b000SEvgeniy Ivanov goto out;
52258a2b000SEvgeniy Ivanov
52358a2b000SEvgeniy Ivanov #ifdef EXT2FS_DEBUG
52458a2b000SEvgeniy Ivanov dump_sblock(fs);
52558a2b000SEvgeniy Ivanov #endif
52658a2b000SEvgeniy Ivanov
52758a2b000SEvgeniy Ivanov /* alloc a block sized buffer used for all fs transfers */
52858a2b000SEvgeniy Ivanov fp->f_buf = alloc(fs->e2fs_bsize);
52958a2b000SEvgeniy Ivanov
53058a2b000SEvgeniy Ivanov /* read group descriptor blocks */
53158a2b000SEvgeniy Ivanov fs->e2fs_gd = alloc(sizeof(struct ext2_gd) * fs->e2fs_ncg);
53258a2b000SEvgeniy Ivanov rc = read_gdblock(f, fs);
53358a2b000SEvgeniy Ivanov if (rc)
53458a2b000SEvgeniy Ivanov goto out;
53558a2b000SEvgeniy Ivanov
53658a2b000SEvgeniy Ivanov /*
53758a2b000SEvgeniy Ivanov * Calculate indirect block levels.
53858a2b000SEvgeniy Ivanov */
53958a2b000SEvgeniy Ivanov {
54058a2b000SEvgeniy Ivanov indp_t mult;
54158a2b000SEvgeniy Ivanov int ln2;
54258a2b000SEvgeniy Ivanov
54358a2b000SEvgeniy Ivanov /*
54458a2b000SEvgeniy Ivanov * We note that the number of indirect blocks is always
54558a2b000SEvgeniy Ivanov * a power of 2. This lets us use shifts and masks instead
54658a2b000SEvgeniy Ivanov * of divide and remainder and avoinds pulling in the
54758a2b000SEvgeniy Ivanov * 64bit division routine into the boot code.
54858a2b000SEvgeniy Ivanov */
54984d9c625SLionel Sambuc mult = EXT2_NINDIR(fs);
55058a2b000SEvgeniy Ivanov #ifdef DEBUG
55158a2b000SEvgeniy Ivanov if (!powerof2(mult)) {
55258a2b000SEvgeniy Ivanov /* Hummm was't a power of 2 */
55358a2b000SEvgeniy Ivanov rc = EINVAL;
55458a2b000SEvgeniy Ivanov goto out;
55558a2b000SEvgeniy Ivanov }
55658a2b000SEvgeniy Ivanov #endif
55758a2b000SEvgeniy Ivanov for (ln2 = 0; mult != 1; ln2++)
55858a2b000SEvgeniy Ivanov mult >>= 1;
55958a2b000SEvgeniy Ivanov
56058a2b000SEvgeniy Ivanov fp->f_nishift = ln2;
56158a2b000SEvgeniy Ivanov }
56258a2b000SEvgeniy Ivanov
56358a2b000SEvgeniy Ivanov inumber = EXT2_ROOTINO;
56458a2b000SEvgeniy Ivanov if ((rc = read_inode(inumber, f)) != 0)
56558a2b000SEvgeniy Ivanov goto out;
56658a2b000SEvgeniy Ivanov
56758a2b000SEvgeniy Ivanov #ifndef LIBSA_FS_SINGLECOMPONENT
56858a2b000SEvgeniy Ivanov cp = path;
56958a2b000SEvgeniy Ivanov while (*cp) {
57058a2b000SEvgeniy Ivanov
57158a2b000SEvgeniy Ivanov /*
57258a2b000SEvgeniy Ivanov * Remove extra separators
57358a2b000SEvgeniy Ivanov */
57458a2b000SEvgeniy Ivanov while (*cp == '/')
57558a2b000SEvgeniy Ivanov cp++;
57658a2b000SEvgeniy Ivanov if (*cp == '\0')
57758a2b000SEvgeniy Ivanov break;
57858a2b000SEvgeniy Ivanov
57958a2b000SEvgeniy Ivanov /*
58058a2b000SEvgeniy Ivanov * Check that current node is a directory.
58158a2b000SEvgeniy Ivanov */
58258a2b000SEvgeniy Ivanov if ((fp->f_di.e2di_mode & EXT2_IFMT) != EXT2_IFDIR) {
58358a2b000SEvgeniy Ivanov rc = ENOTDIR;
58458a2b000SEvgeniy Ivanov goto out;
58558a2b000SEvgeniy Ivanov }
58658a2b000SEvgeniy Ivanov
58758a2b000SEvgeniy Ivanov /*
58858a2b000SEvgeniy Ivanov * Get next component of path name.
58958a2b000SEvgeniy Ivanov */
59058a2b000SEvgeniy Ivanov ncp = cp;
59158a2b000SEvgeniy Ivanov while ((c = *cp) != '\0' && c != '/')
59258a2b000SEvgeniy Ivanov cp++;
59358a2b000SEvgeniy Ivanov
59458a2b000SEvgeniy Ivanov /*
59558a2b000SEvgeniy Ivanov * Look up component in current directory.
59658a2b000SEvgeniy Ivanov * Save directory inumber in case we find a
59758a2b000SEvgeniy Ivanov * symbolic link.
59858a2b000SEvgeniy Ivanov */
59958a2b000SEvgeniy Ivanov #ifndef LIBSA_NO_FS_SYMLINK
60058a2b000SEvgeniy Ivanov parent_inumber = inumber;
60158a2b000SEvgeniy Ivanov #endif
60258a2b000SEvgeniy Ivanov rc = search_directory(ncp, cp - ncp, f, &inumber);
60358a2b000SEvgeniy Ivanov if (rc)
60458a2b000SEvgeniy Ivanov goto out;
60558a2b000SEvgeniy Ivanov
60658a2b000SEvgeniy Ivanov /*
60758a2b000SEvgeniy Ivanov * Open next component.
60858a2b000SEvgeniy Ivanov */
60958a2b000SEvgeniy Ivanov if ((rc = read_inode(inumber, f)) != 0)
61058a2b000SEvgeniy Ivanov goto out;
61158a2b000SEvgeniy Ivanov
61258a2b000SEvgeniy Ivanov #ifndef LIBSA_NO_FS_SYMLINK
61358a2b000SEvgeniy Ivanov /*
61458a2b000SEvgeniy Ivanov * Check for symbolic link.
61558a2b000SEvgeniy Ivanov */
61658a2b000SEvgeniy Ivanov if ((fp->f_di.e2di_mode & EXT2_IFMT) == EXT2_IFLNK) {
61758a2b000SEvgeniy Ivanov /* XXX should handle LARGEFILE */
61858a2b000SEvgeniy Ivanov int link_len = fp->f_di.e2di_size;
61958a2b000SEvgeniy Ivanov int len;
62058a2b000SEvgeniy Ivanov
62158a2b000SEvgeniy Ivanov len = strlen(cp);
62258a2b000SEvgeniy Ivanov
62358a2b000SEvgeniy Ivanov if (link_len + len > MAXPATHLEN ||
62458a2b000SEvgeniy Ivanov ++nlinks > MAXSYMLINKS) {
62558a2b000SEvgeniy Ivanov rc = ENOENT;
62658a2b000SEvgeniy Ivanov goto out;
62758a2b000SEvgeniy Ivanov }
62858a2b000SEvgeniy Ivanov
62958a2b000SEvgeniy Ivanov memmove(&namebuf[link_len], cp, len + 1);
63058a2b000SEvgeniy Ivanov
63158a2b000SEvgeniy Ivanov if (link_len < EXT2_MAXSYMLINKLEN) {
63258a2b000SEvgeniy Ivanov memcpy(namebuf, fp->f_di.e2di_blocks, link_len);
63358a2b000SEvgeniy Ivanov } else {
63458a2b000SEvgeniy Ivanov /*
63558a2b000SEvgeniy Ivanov * Read file for symbolic link
63658a2b000SEvgeniy Ivanov */
63758a2b000SEvgeniy Ivanov size_t buf_size;
63858a2b000SEvgeniy Ivanov indp_t disk_block;
63958a2b000SEvgeniy Ivanov
64058a2b000SEvgeniy Ivanov buf = fp->f_buf;
64158a2b000SEvgeniy Ivanov rc = block_map(f, (indp_t)0, &disk_block);
64258a2b000SEvgeniy Ivanov if (rc)
64358a2b000SEvgeniy Ivanov goto out;
64458a2b000SEvgeniy Ivanov
64558a2b000SEvgeniy Ivanov twiddle();
64658a2b000SEvgeniy Ivanov rc = DEV_STRATEGY(f->f_dev)(f->f_devdata,
64758a2b000SEvgeniy Ivanov F_READ, FSBTODB(fs, disk_block),
64858a2b000SEvgeniy Ivanov fs->e2fs_bsize, buf, &buf_size);
64958a2b000SEvgeniy Ivanov if (rc)
65058a2b000SEvgeniy Ivanov goto out;
65158a2b000SEvgeniy Ivanov
65258a2b000SEvgeniy Ivanov memcpy(namebuf, buf, link_len);
65358a2b000SEvgeniy Ivanov }
65458a2b000SEvgeniy Ivanov
65558a2b000SEvgeniy Ivanov /*
65658a2b000SEvgeniy Ivanov * If relative pathname, restart at parent directory.
65758a2b000SEvgeniy Ivanov * If absolute pathname, restart at root.
65858a2b000SEvgeniy Ivanov */
65958a2b000SEvgeniy Ivanov cp = namebuf;
66058a2b000SEvgeniy Ivanov if (*cp != '/')
66158a2b000SEvgeniy Ivanov inumber = parent_inumber;
66258a2b000SEvgeniy Ivanov else
66358a2b000SEvgeniy Ivanov inumber = (ino32_t)EXT2_ROOTINO;
66458a2b000SEvgeniy Ivanov
66558a2b000SEvgeniy Ivanov if ((rc = read_inode(inumber, f)) != 0)
66658a2b000SEvgeniy Ivanov goto out;
66758a2b000SEvgeniy Ivanov }
66858a2b000SEvgeniy Ivanov #endif /* !LIBSA_NO_FS_SYMLINK */
66958a2b000SEvgeniy Ivanov }
67058a2b000SEvgeniy Ivanov
67158a2b000SEvgeniy Ivanov /*
67258a2b000SEvgeniy Ivanov * Found terminal component.
67358a2b000SEvgeniy Ivanov */
67458a2b000SEvgeniy Ivanov rc = 0;
67558a2b000SEvgeniy Ivanov
67658a2b000SEvgeniy Ivanov #else /* !LIBSA_FS_SINGLECOMPONENT */
67758a2b000SEvgeniy Ivanov
67858a2b000SEvgeniy Ivanov /* look up component in the current (root) directory */
67958a2b000SEvgeniy Ivanov rc = search_directory(path, strlen(path), f, &inumber);
68058a2b000SEvgeniy Ivanov if (rc)
68158a2b000SEvgeniy Ivanov goto out;
68258a2b000SEvgeniy Ivanov
68358a2b000SEvgeniy Ivanov /* open it */
68458a2b000SEvgeniy Ivanov rc = read_inode(inumber, f);
68558a2b000SEvgeniy Ivanov
68658a2b000SEvgeniy Ivanov #endif /* !LIBSA_FS_SINGLECOMPONENT */
68758a2b000SEvgeniy Ivanov
68858a2b000SEvgeniy Ivanov fp->f_seekp = 0; /* reset seek pointer */
68958a2b000SEvgeniy Ivanov
69058a2b000SEvgeniy Ivanov out:
69158a2b000SEvgeniy Ivanov if (rc)
69258a2b000SEvgeniy Ivanov ext2fs_close(f);
693*0a6a1f1dSLionel Sambuc else
69458a2b000SEvgeniy Ivanov fsmod = "ext2fs";
69558a2b000SEvgeniy Ivanov return rc;
69658a2b000SEvgeniy Ivanov }
69758a2b000SEvgeniy Ivanov
69858a2b000SEvgeniy Ivanov __compactcall int
ext2fs_close(struct open_file * f)69958a2b000SEvgeniy Ivanov ext2fs_close(struct open_file *f)
70058a2b000SEvgeniy Ivanov {
70158a2b000SEvgeniy Ivanov struct file *fp = (struct file *)f->f_fsdata;
70258a2b000SEvgeniy Ivanov
70358a2b000SEvgeniy Ivanov f->f_fsdata = NULL;
70458a2b000SEvgeniy Ivanov if (fp == NULL)
70558a2b000SEvgeniy Ivanov return 0;
70658a2b000SEvgeniy Ivanov
70758a2b000SEvgeniy Ivanov if (fp->f_fs->e2fs_gd)
70858a2b000SEvgeniy Ivanov dealloc(fp->f_fs->e2fs_gd,
70958a2b000SEvgeniy Ivanov sizeof(struct ext2_gd) * fp->f_fs->e2fs_ncg);
71058a2b000SEvgeniy Ivanov if (fp->f_buf)
71158a2b000SEvgeniy Ivanov dealloc(fp->f_buf, fp->f_fs->e2fs_bsize);
71258a2b000SEvgeniy Ivanov dealloc(fp->f_fs, sizeof(*fp->f_fs));
71358a2b000SEvgeniy Ivanov dealloc(fp, sizeof(struct file));
71458a2b000SEvgeniy Ivanov return 0;
71558a2b000SEvgeniy Ivanov }
71658a2b000SEvgeniy Ivanov
71758a2b000SEvgeniy Ivanov /*
71858a2b000SEvgeniy Ivanov * Copy a portion of a file into kernel memory.
71958a2b000SEvgeniy Ivanov * Cross block boundaries when necessary.
72058a2b000SEvgeniy Ivanov */
72158a2b000SEvgeniy Ivanov __compactcall int
ext2fs_read(struct open_file * f,void * start,size_t size,size_t * resid)72258a2b000SEvgeniy Ivanov ext2fs_read(struct open_file *f, void *start, size_t size, size_t *resid)
72358a2b000SEvgeniy Ivanov {
72458a2b000SEvgeniy Ivanov struct file *fp = (struct file *)f->f_fsdata;
72558a2b000SEvgeniy Ivanov size_t csize;
72658a2b000SEvgeniy Ivanov char *buf;
72758a2b000SEvgeniy Ivanov size_t buf_size;
72858a2b000SEvgeniy Ivanov int rc = 0;
72958a2b000SEvgeniy Ivanov char *addr = start;
73058a2b000SEvgeniy Ivanov
73158a2b000SEvgeniy Ivanov while (size != 0) {
73258a2b000SEvgeniy Ivanov /* XXX should handle LARGEFILE */
73358a2b000SEvgeniy Ivanov if (fp->f_seekp >= (off_t)fp->f_di.e2di_size)
73458a2b000SEvgeniy Ivanov break;
73558a2b000SEvgeniy Ivanov
73658a2b000SEvgeniy Ivanov rc = buf_read_file(f, &buf, &buf_size);
73758a2b000SEvgeniy Ivanov if (rc)
73858a2b000SEvgeniy Ivanov break;
73958a2b000SEvgeniy Ivanov
74058a2b000SEvgeniy Ivanov csize = size;
74158a2b000SEvgeniy Ivanov if (csize > buf_size)
74258a2b000SEvgeniy Ivanov csize = buf_size;
74358a2b000SEvgeniy Ivanov
74458a2b000SEvgeniy Ivanov memcpy(addr, buf, csize);
74558a2b000SEvgeniy Ivanov
74658a2b000SEvgeniy Ivanov fp->f_seekp += csize;
74758a2b000SEvgeniy Ivanov addr += csize;
74858a2b000SEvgeniy Ivanov size -= csize;
74958a2b000SEvgeniy Ivanov }
75058a2b000SEvgeniy Ivanov if (resid)
75158a2b000SEvgeniy Ivanov *resid = size;
75258a2b000SEvgeniy Ivanov return rc;
75358a2b000SEvgeniy Ivanov }
75458a2b000SEvgeniy Ivanov
75558a2b000SEvgeniy Ivanov /*
75658a2b000SEvgeniy Ivanov * Not implemented.
75758a2b000SEvgeniy Ivanov */
75858a2b000SEvgeniy Ivanov #ifndef LIBSA_NO_FS_WRITE
75958a2b000SEvgeniy Ivanov __compactcall int
ext2fs_write(struct open_file * f,void * start,size_t size,size_t * resid)76058a2b000SEvgeniy Ivanov ext2fs_write(struct open_file *f, void *start, size_t size, size_t *resid)
76158a2b000SEvgeniy Ivanov {
76258a2b000SEvgeniy Ivanov
76358a2b000SEvgeniy Ivanov return EROFS;
76458a2b000SEvgeniy Ivanov }
76558a2b000SEvgeniy Ivanov #endif /* !LIBSA_NO_FS_WRITE */
76658a2b000SEvgeniy Ivanov
76758a2b000SEvgeniy Ivanov #ifndef LIBSA_NO_FS_SEEK
76858a2b000SEvgeniy Ivanov __compactcall off_t
ext2fs_seek(struct open_file * f,off_t offset,int where)76958a2b000SEvgeniy Ivanov ext2fs_seek(struct open_file *f, off_t offset, int where)
77058a2b000SEvgeniy Ivanov {
77158a2b000SEvgeniy Ivanov struct file *fp = (struct file *)f->f_fsdata;
77258a2b000SEvgeniy Ivanov
77358a2b000SEvgeniy Ivanov switch (where) {
77458a2b000SEvgeniy Ivanov case SEEK_SET:
77558a2b000SEvgeniy Ivanov fp->f_seekp = offset;
77658a2b000SEvgeniy Ivanov break;
77758a2b000SEvgeniy Ivanov case SEEK_CUR:
77858a2b000SEvgeniy Ivanov fp->f_seekp += offset;
77958a2b000SEvgeniy Ivanov break;
78058a2b000SEvgeniy Ivanov case SEEK_END:
78158a2b000SEvgeniy Ivanov /* XXX should handle LARGEFILE */
78258a2b000SEvgeniy Ivanov fp->f_seekp = fp->f_di.e2di_size - offset;
78358a2b000SEvgeniy Ivanov break;
78458a2b000SEvgeniy Ivanov default:
78558a2b000SEvgeniy Ivanov return -1;
78658a2b000SEvgeniy Ivanov }
78758a2b000SEvgeniy Ivanov return fp->f_seekp;
78858a2b000SEvgeniy Ivanov }
78958a2b000SEvgeniy Ivanov #endif /* !LIBSA_NO_FS_SEEK */
79058a2b000SEvgeniy Ivanov
79158a2b000SEvgeniy Ivanov __compactcall int
ext2fs_stat(struct open_file * f,struct stat * sb)79258a2b000SEvgeniy Ivanov ext2fs_stat(struct open_file *f, struct stat *sb)
79358a2b000SEvgeniy Ivanov {
79458a2b000SEvgeniy Ivanov struct file *fp = (struct file *)f->f_fsdata;
79558a2b000SEvgeniy Ivanov
79658a2b000SEvgeniy Ivanov /* only important stuff */
79758a2b000SEvgeniy Ivanov memset(sb, 0, sizeof *sb);
79858a2b000SEvgeniy Ivanov sb->st_mode = fp->f_di.e2di_mode;
79958a2b000SEvgeniy Ivanov sb->st_uid = fp->f_di.e2di_uid;
80058a2b000SEvgeniy Ivanov sb->st_gid = fp->f_di.e2di_gid;
80158a2b000SEvgeniy Ivanov /* XXX should handle LARGEFILE */
80258a2b000SEvgeniy Ivanov sb->st_size = fp->f_di.e2di_size;
80358a2b000SEvgeniy Ivanov return 0;
80458a2b000SEvgeniy Ivanov }
80558a2b000SEvgeniy Ivanov
80658a2b000SEvgeniy Ivanov #if defined(LIBSA_ENABLE_LS_OP)
807*0a6a1f1dSLionel Sambuc
808*0a6a1f1dSLionel Sambuc #include "ls.h"
809*0a6a1f1dSLionel Sambuc
810*0a6a1f1dSLionel Sambuc static const char *const typestr[] = {
811*0a6a1f1dSLionel Sambuc "unknown",
812*0a6a1f1dSLionel Sambuc "REG",
813*0a6a1f1dSLionel Sambuc "DIR",
814*0a6a1f1dSLionel Sambuc "CHR",
815*0a6a1f1dSLionel Sambuc "BLK",
816*0a6a1f1dSLionel Sambuc "FIFO",
817*0a6a1f1dSLionel Sambuc "SOCK",
818*0a6a1f1dSLionel Sambuc "LNK"
819*0a6a1f1dSLionel Sambuc };
820*0a6a1f1dSLionel Sambuc
82158a2b000SEvgeniy Ivanov __compactcall void
ext2fs_ls(struct open_file * f,const char * pattern)822*0a6a1f1dSLionel Sambuc ext2fs_ls(struct open_file *f, const char *pattern)
82358a2b000SEvgeniy Ivanov {
82458a2b000SEvgeniy Ivanov struct file *fp = (struct file *)f->f_fsdata;
82558a2b000SEvgeniy Ivanov size_t block_size = fp->f_fs->e2fs_bsize;
82658a2b000SEvgeniy Ivanov char *buf;
82758a2b000SEvgeniy Ivanov size_t buf_size;
828*0a6a1f1dSLionel Sambuc lsentry_t *names = NULL;
82958a2b000SEvgeniy Ivanov
83058a2b000SEvgeniy Ivanov fp->f_seekp = 0;
83158a2b000SEvgeniy Ivanov while (fp->f_seekp < (off_t)fp->f_di.e2di_size) {
83258a2b000SEvgeniy Ivanov struct ext2fs_direct *dp, *edp;
83358a2b000SEvgeniy Ivanov int rc = buf_read_file(f, &buf, &buf_size);
83458a2b000SEvgeniy Ivanov if (rc)
83558a2b000SEvgeniy Ivanov goto out;
83658a2b000SEvgeniy Ivanov if (buf_size != block_size || buf_size == 0)
83758a2b000SEvgeniy Ivanov goto out;
83858a2b000SEvgeniy Ivanov
83958a2b000SEvgeniy Ivanov dp = (struct ext2fs_direct *)buf;
84058a2b000SEvgeniy Ivanov edp = (struct ext2fs_direct *)(buf + buf_size);
84158a2b000SEvgeniy Ivanov
84258a2b000SEvgeniy Ivanov for (; dp < edp;
84358a2b000SEvgeniy Ivanov dp = (void *)((char *)dp + fs2h16(dp->e2d_reclen))) {
84458a2b000SEvgeniy Ivanov const char *t;
84558a2b000SEvgeniy Ivanov
84658a2b000SEvgeniy Ivanov if (fs2h16(dp->e2d_reclen) <= 0)
84758a2b000SEvgeniy Ivanov goto out;
84858a2b000SEvgeniy Ivanov
84958a2b000SEvgeniy Ivanov if (fs2h32(dp->e2d_ino) == 0)
85058a2b000SEvgeniy Ivanov continue;
85158a2b000SEvgeniy Ivanov
85258a2b000SEvgeniy Ivanov if (dp->e2d_type >= NELEM(typestr) ||
85358a2b000SEvgeniy Ivanov !(t = typestr[dp->e2d_type])) {
85458a2b000SEvgeniy Ivanov /*
85558a2b000SEvgeniy Ivanov * This does not handle "old"
85658a2b000SEvgeniy Ivanov * filesystems properly. On little
85758a2b000SEvgeniy Ivanov * endian machines, we get a bogus
85858a2b000SEvgeniy Ivanov * type name if the namlen matches a
85958a2b000SEvgeniy Ivanov * valid type identifier. We could
86058a2b000SEvgeniy Ivanov * check if we read namlen "0" and
86158a2b000SEvgeniy Ivanov * handle this case specially, if
86258a2b000SEvgeniy Ivanov * there were a pressing need...
86358a2b000SEvgeniy Ivanov */
86458a2b000SEvgeniy Ivanov printf("bad dir entry\n");
86558a2b000SEvgeniy Ivanov goto out;
86658a2b000SEvgeniy Ivanov }
867*0a6a1f1dSLionel Sambuc lsadd(&names, pattern, dp->e2d_name,
868*0a6a1f1dSLionel Sambuc strlen(dp->e2d_name), fs2h32(dp->e2d_ino), t);
86958a2b000SEvgeniy Ivanov }
87058a2b000SEvgeniy Ivanov fp->f_seekp += buf_size;
87158a2b000SEvgeniy Ivanov }
87258a2b000SEvgeniy Ivanov
873*0a6a1f1dSLionel Sambuc lsprint(names);
874*0a6a1f1dSLionel Sambuc out: lsfree(names);
87558a2b000SEvgeniy Ivanov }
876*0a6a1f1dSLionel Sambuc
877*0a6a1f1dSLionel Sambuc #if defined(__minix) && defined(LIBSA_ENABLE_LOAD_MODS_OP)
878*0a6a1f1dSLionel Sambuc __compactcall void
ext2fs_load_mods(struct open_file * f,const char * pattern,void (* funcp)(char *),char * path)879*0a6a1f1dSLionel Sambuc ext2fs_load_mods(struct open_file *f, const char *pattern,
880*0a6a1f1dSLionel Sambuc void (*funcp)(char *), char *path)
881*0a6a1f1dSLionel Sambuc {
882*0a6a1f1dSLionel Sambuc load_modsunsup("extfs");
88358a2b000SEvgeniy Ivanov }
884*0a6a1f1dSLionel Sambuc #endif /* defined(__minix) && defined(LIBSA_ENABLE_LOAD_MODS_OP) */
88558a2b000SEvgeniy Ivanov #endif
88658a2b000SEvgeniy Ivanov
88758a2b000SEvgeniy Ivanov /*
88858a2b000SEvgeniy Ivanov * byte swap functions for big endian machines
88958a2b000SEvgeniy Ivanov * (ext2fs is always little endian)
89058a2b000SEvgeniy Ivanov *
89158a2b000SEvgeniy Ivanov * XXX: We should use src/sys/ufs/ext2fs/ext2fs_bswap.c
89258a2b000SEvgeniy Ivanov */
89358a2b000SEvgeniy Ivanov
89458a2b000SEvgeniy Ivanov /* These functions are only needed if native byte order is not big endian */
89558a2b000SEvgeniy Ivanov #if BYTE_ORDER == BIG_ENDIAN
89658a2b000SEvgeniy Ivanov void
e2fs_sb_bswap(struct ext2fs * old,struct ext2fs * new)89758a2b000SEvgeniy Ivanov e2fs_sb_bswap(struct ext2fs *old, struct ext2fs *new)
89858a2b000SEvgeniy Ivanov {
89958a2b000SEvgeniy Ivanov
90058a2b000SEvgeniy Ivanov /* preserve unused fields */
90158a2b000SEvgeniy Ivanov memcpy(new, old, sizeof(struct ext2fs));
90258a2b000SEvgeniy Ivanov new->e2fs_icount = bswap32(old->e2fs_icount);
90358a2b000SEvgeniy Ivanov new->e2fs_bcount = bswap32(old->e2fs_bcount);
90458a2b000SEvgeniy Ivanov new->e2fs_rbcount = bswap32(old->e2fs_rbcount);
90558a2b000SEvgeniy Ivanov new->e2fs_fbcount = bswap32(old->e2fs_fbcount);
90658a2b000SEvgeniy Ivanov new->e2fs_ficount = bswap32(old->e2fs_ficount);
90758a2b000SEvgeniy Ivanov new->e2fs_first_dblock = bswap32(old->e2fs_first_dblock);
90858a2b000SEvgeniy Ivanov new->e2fs_log_bsize = bswap32(old->e2fs_log_bsize);
90958a2b000SEvgeniy Ivanov new->e2fs_fsize = bswap32(old->e2fs_fsize);
91058a2b000SEvgeniy Ivanov new->e2fs_bpg = bswap32(old->e2fs_bpg);
91158a2b000SEvgeniy Ivanov new->e2fs_fpg = bswap32(old->e2fs_fpg);
91258a2b000SEvgeniy Ivanov new->e2fs_ipg = bswap32(old->e2fs_ipg);
91358a2b000SEvgeniy Ivanov new->e2fs_mtime = bswap32(old->e2fs_mtime);
91458a2b000SEvgeniy Ivanov new->e2fs_wtime = bswap32(old->e2fs_wtime);
91558a2b000SEvgeniy Ivanov new->e2fs_mnt_count = bswap16(old->e2fs_mnt_count);
91658a2b000SEvgeniy Ivanov new->e2fs_max_mnt_count = bswap16(old->e2fs_max_mnt_count);
91758a2b000SEvgeniy Ivanov new->e2fs_magic = bswap16(old->e2fs_magic);
91858a2b000SEvgeniy Ivanov new->e2fs_state = bswap16(old->e2fs_state);
91958a2b000SEvgeniy Ivanov new->e2fs_beh = bswap16(old->e2fs_beh);
92058a2b000SEvgeniy Ivanov new->e2fs_minrev = bswap16(old->e2fs_minrev);
92158a2b000SEvgeniy Ivanov new->e2fs_lastfsck = bswap32(old->e2fs_lastfsck);
92258a2b000SEvgeniy Ivanov new->e2fs_fsckintv = bswap32(old->e2fs_fsckintv);
92358a2b000SEvgeniy Ivanov new->e2fs_creator = bswap32(old->e2fs_creator);
92458a2b000SEvgeniy Ivanov new->e2fs_rev = bswap32(old->e2fs_rev);
92558a2b000SEvgeniy Ivanov new->e2fs_ruid = bswap16(old->e2fs_ruid);
92658a2b000SEvgeniy Ivanov new->e2fs_rgid = bswap16(old->e2fs_rgid);
92758a2b000SEvgeniy Ivanov new->e2fs_first_ino = bswap32(old->e2fs_first_ino);
92858a2b000SEvgeniy Ivanov new->e2fs_inode_size = bswap16(old->e2fs_inode_size);
92958a2b000SEvgeniy Ivanov new->e2fs_block_group_nr = bswap16(old->e2fs_block_group_nr);
93058a2b000SEvgeniy Ivanov new->e2fs_features_compat = bswap32(old->e2fs_features_compat);
93158a2b000SEvgeniy Ivanov new->e2fs_features_incompat = bswap32(old->e2fs_features_incompat);
93258a2b000SEvgeniy Ivanov new->e2fs_features_rocompat = bswap32(old->e2fs_features_rocompat);
93358a2b000SEvgeniy Ivanov new->e2fs_algo = bswap32(old->e2fs_algo);
93458a2b000SEvgeniy Ivanov new->e2fs_reserved_ngdb = bswap16(old->e2fs_reserved_ngdb);
93558a2b000SEvgeniy Ivanov }
93658a2b000SEvgeniy Ivanov
e2fs_cg_bswap(struct ext2_gd * old,struct ext2_gd * new,int size)93758a2b000SEvgeniy Ivanov void e2fs_cg_bswap(struct ext2_gd *old, struct ext2_gd *new, int size)
93858a2b000SEvgeniy Ivanov {
93958a2b000SEvgeniy Ivanov int i;
94058a2b000SEvgeniy Ivanov
94158a2b000SEvgeniy Ivanov for (i = 0; i < (size / sizeof(struct ext2_gd)); i++) {
94258a2b000SEvgeniy Ivanov new[i].ext2bgd_b_bitmap = bswap32(old[i].ext2bgd_b_bitmap);
94358a2b000SEvgeniy Ivanov new[i].ext2bgd_i_bitmap = bswap32(old[i].ext2bgd_i_bitmap);
94458a2b000SEvgeniy Ivanov new[i].ext2bgd_i_tables = bswap32(old[i].ext2bgd_i_tables);
94558a2b000SEvgeniy Ivanov new[i].ext2bgd_nbfree = bswap16(old[i].ext2bgd_nbfree);
94658a2b000SEvgeniy Ivanov new[i].ext2bgd_nifree = bswap16(old[i].ext2bgd_nifree);
94758a2b000SEvgeniy Ivanov new[i].ext2bgd_ndirs = bswap16(old[i].ext2bgd_ndirs);
94858a2b000SEvgeniy Ivanov }
94958a2b000SEvgeniy Ivanov }
95058a2b000SEvgeniy Ivanov
e2fs_i_bswap(struct ext2fs_dinode * old,struct ext2fs_dinode * new)95158a2b000SEvgeniy Ivanov void e2fs_i_bswap(struct ext2fs_dinode *old, struct ext2fs_dinode *new)
95258a2b000SEvgeniy Ivanov {
95358a2b000SEvgeniy Ivanov
95458a2b000SEvgeniy Ivanov new->e2di_mode = bswap16(old->e2di_mode);
95558a2b000SEvgeniy Ivanov new->e2di_uid = bswap16(old->e2di_uid);
95658a2b000SEvgeniy Ivanov new->e2di_gid = bswap16(old->e2di_gid);
95758a2b000SEvgeniy Ivanov new->e2di_nlink = bswap16(old->e2di_nlink);
95858a2b000SEvgeniy Ivanov new->e2di_size = bswap32(old->e2di_size);
95958a2b000SEvgeniy Ivanov new->e2di_atime = bswap32(old->e2di_atime);
96058a2b000SEvgeniy Ivanov new->e2di_ctime = bswap32(old->e2di_ctime);
96158a2b000SEvgeniy Ivanov new->e2di_mtime = bswap32(old->e2di_mtime);
96258a2b000SEvgeniy Ivanov new->e2di_dtime = bswap32(old->e2di_dtime);
96358a2b000SEvgeniy Ivanov new->e2di_nblock = bswap32(old->e2di_nblock);
96458a2b000SEvgeniy Ivanov new->e2di_flags = bswap32(old->e2di_flags);
96558a2b000SEvgeniy Ivanov new->e2di_gen = bswap32(old->e2di_gen);
96658a2b000SEvgeniy Ivanov new->e2di_facl = bswap32(old->e2di_facl);
96758a2b000SEvgeniy Ivanov new->e2di_dacl = bswap32(old->e2di_dacl);
96858a2b000SEvgeniy Ivanov new->e2di_faddr = bswap32(old->e2di_faddr);
96958a2b000SEvgeniy Ivanov memcpy(&new->e2di_blocks[0], &old->e2di_blocks[0],
97084d9c625SLionel Sambuc (EXT2FS_NDADDR + EXT2FS_NIADDR) * sizeof(uint32_t));
97158a2b000SEvgeniy Ivanov }
97258a2b000SEvgeniy Ivanov #endif
97358a2b000SEvgeniy Ivanov
97458a2b000SEvgeniy Ivanov #ifdef EXT2FS_DEBUG
97558a2b000SEvgeniy Ivanov void
dump_sblock(struct m_ext2fs * fs)97658a2b000SEvgeniy Ivanov dump_sblock(struct m_ext2fs *fs)
97758a2b000SEvgeniy Ivanov {
97858a2b000SEvgeniy Ivanov
97958a2b000SEvgeniy Ivanov printf("fs->e2fs.e2fs_bcount = %u\n", fs->e2fs.e2fs_bcount);
98058a2b000SEvgeniy Ivanov printf("fs->e2fs.e2fs_first_dblock = %u\n", fs->e2fs.e2fs_first_dblock);
98158a2b000SEvgeniy Ivanov printf("fs->e2fs.e2fs_log_bsize = %u\n", fs->e2fs.e2fs_log_bsize);
98258a2b000SEvgeniy Ivanov printf("fs->e2fs.e2fs_bpg = %u\n", fs->e2fs.e2fs_bpg);
98358a2b000SEvgeniy Ivanov printf("fs->e2fs.e2fs_ipg = %u\n", fs->e2fs.e2fs_ipg);
98458a2b000SEvgeniy Ivanov printf("fs->e2fs.e2fs_magic = 0x%x\n", fs->e2fs.e2fs_magic);
98558a2b000SEvgeniy Ivanov printf("fs->e2fs.e2fs_rev = %u\n", fs->e2fs.e2fs_rev);
98658a2b000SEvgeniy Ivanov
98758a2b000SEvgeniy Ivanov if (fs->e2fs.e2fs_rev == E2FS_REV1) {
98858a2b000SEvgeniy Ivanov printf("fs->e2fs.e2fs_first_ino = %u\n",
98958a2b000SEvgeniy Ivanov fs->e2fs.e2fs_first_ino);
99058a2b000SEvgeniy Ivanov printf("fs->e2fs.e2fs_inode_size = %u\n",
99158a2b000SEvgeniy Ivanov fs->e2fs.e2fs_inode_size);
99258a2b000SEvgeniy Ivanov printf("fs->e2fs.e2fs_features_compat = %u\n",
99358a2b000SEvgeniy Ivanov fs->e2fs.e2fs_features_compat);
99458a2b000SEvgeniy Ivanov printf("fs->e2fs.e2fs_features_incompat = %u\n",
99558a2b000SEvgeniy Ivanov fs->e2fs.e2fs_features_incompat);
99658a2b000SEvgeniy Ivanov printf("fs->e2fs.e2fs_features_rocompat = %u\n",
99758a2b000SEvgeniy Ivanov fs->e2fs.e2fs_features_rocompat);
99858a2b000SEvgeniy Ivanov printf("fs->e2fs.e2fs_reserved_ngdb = %u\n",
99958a2b000SEvgeniy Ivanov fs->e2fs.e2fs_reserved_ngdb);
100058a2b000SEvgeniy Ivanov }
100158a2b000SEvgeniy Ivanov
100258a2b000SEvgeniy Ivanov printf("fs->e2fs_bsize = %u\n", fs->e2fs_bsize);
100358a2b000SEvgeniy Ivanov printf("fs->e2fs_fsbtodb = %u\n", fs->e2fs_fsbtodb);
100458a2b000SEvgeniy Ivanov printf("fs->e2fs_ncg = %u\n", fs->e2fs_ncg);
100558a2b000SEvgeniy Ivanov printf("fs->e2fs_ngdb = %u\n", fs->e2fs_ngdb);
100658a2b000SEvgeniy Ivanov printf("fs->e2fs_ipb = %u\n", fs->e2fs_ipb);
100758a2b000SEvgeniy Ivanov printf("fs->e2fs_itpg = %u\n", fs->e2fs_itpg);
100858a2b000SEvgeniy Ivanov }
100958a2b000SEvgeniy Ivanov #endif
1010