summaryrefslogtreecommitdiffstats
path: root/contrib/syslinux-4.02/core/fs/ext2
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/syslinux-4.02/core/fs/ext2')
-rw-r--r--contrib/syslinux-4.02/core/fs/ext2/bmap.c228
-rw-r--r--contrib/syslinux-4.02/core/fs/ext2/ext2.c335
-rw-r--r--contrib/syslinux-4.02/core/fs/ext2/ext2_fs.h310
3 files changed, 873 insertions, 0 deletions
diff --git a/contrib/syslinux-4.02/core/fs/ext2/bmap.c b/contrib/syslinux-4.02/core/fs/ext2/bmap.c
new file mode 100644
index 0000000..ef2bf64
--- /dev/null
+++ b/contrib/syslinux-4.02/core/fs/ext2/bmap.c
@@ -0,0 +1,228 @@
+/*
+ * The logical block -> physical block routine.
+ *
+ * Copyright (C) 2009 Liu Aleaxander -- All rights reserved. This file
+ * may be redistributed under the terms of the GNU Public License.
+ */
+
+#include <stdio.h>
+#include <dprintf.h>
+#include <fs.h>
+#include <disk.h>
+#include <cache.h>
+#include "ext2_fs.h"
+
+static const struct ext4_extent_header *
+ext4_find_leaf(struct fs_info *fs, const struct ext4_extent_header *eh,
+ block_t block)
+{
+ struct ext4_extent_idx *index;
+ block_t blk;
+ int i;
+
+ while (1) {
+ if (eh->eh_magic != EXT4_EXT_MAGIC)
+ return NULL;
+ if (eh->eh_depth == 0)
+ return eh;
+
+ index = EXT4_FIRST_INDEX(eh);
+ for (i = 0; i < (int)eh->eh_entries; i++) {
+ if (block < index[i].ei_block)
+ break;
+ }
+ if (--i < 0)
+ return NULL;
+
+ blk = index[i].ei_leaf_hi;
+ blk = (blk << 32) + index[i].ei_leaf_lo;
+ eh = get_cache(fs->fs_dev, blk);
+ }
+}
+
+/* handle the ext4 extents to get the phsical block number */
+/* XXX: still need to handle sparse files with extents */
+static block_t
+bmap_extent(struct inode *inode, uint32_t block, size_t *nblocks)
+{
+ struct fs_info *fs = inode->fs;
+ const struct ext4_extent_header *leaf;
+ const struct ext4_extent *ext;
+ int i;
+ block_t start;
+
+ leaf = ext4_find_leaf(fs, &PVT(inode)->i_extent_hdr, block);
+ if (!leaf) {
+ printf("ERROR, extent leaf not found\n");
+ return 0;
+ }
+
+ ext = EXT4_FIRST_EXTENT(leaf);
+ for (i = 0; i < leaf->eh_entries; i++) {
+ if (block < ext[i].ee_block)
+ break;
+ }
+ if (--i < 0) {
+ printf("ERROR, not find the right block\n");
+ return 0;
+ }
+
+ /* got it */
+ block -= ext[i].ee_block;
+ if (block >= ext[i].ee_len)
+ return 0;
+ start = ((block_t)ext[i].ee_start_hi << 32) + ext[i].ee_start_lo;
+
+ if (nblocks)
+ *nblocks = ext[i].ee_len - block;
+
+ return start + block;
+}
+
+/*
+ * Scan forward in a range of blocks to see if they are contiguous,
+ * then return the initial value.
+ */
+static uint32_t
+scan_set_nblocks(const uint32_t *map, unsigned int count, size_t *nblocks)
+{
+ uint32_t blk = *map;
+
+ if (nblocks) {
+ uint32_t skip = blk ? 1 : 0;
+ uint32_t next = blk + skip;
+ size_t cnt = 1;
+
+ while (--count) {
+ map++;
+ if (*map == next) {
+ cnt++;
+ next += skip;
+ } else {
+ break;
+ }
+ }
+
+ *nblocks = cnt;
+ }
+
+ return blk;
+}
+
+/*
+ * The actual indirect block map handling - the block passed in should
+ * be relative to the beginning of the particular block hierarchy.
+ */
+static block_t
+bmap_indirect(struct fs_info *fs, uint32_t start, uint32_t block,
+ int levels, size_t *nblocks)
+{
+ int addr_shift = BLOCK_SHIFT(fs) - 2;
+ uint32_t addr_count = 1 << addr_shift;
+ const uint32_t *blk = NULL;
+ uint32_t index = 0;
+
+ while (levels--) {
+ if (!start) {
+ if (nblocks)
+ *nblocks = addr_count << (levels * addr_shift);
+ return 0;
+ }
+ blk = get_cache(fs->fs_dev, start);
+ index = (block >> (levels * addr_shift)) & (addr_count - 1);
+ start = blk[index];
+ }
+
+ return scan_set_nblocks(blk + index, addr_count - index, nblocks);
+}
+
+/*
+ * Handle the traditional block map, like indirect, double indirect
+ * and triple indirect
+ */
+static block_t
+bmap_traditional(struct inode *inode, block_t block, size_t *nblocks)
+{
+ struct fs_info *fs = inode->fs;
+ const uint32_t addr_per_block = BLOCK_SIZE(fs) >> 2;
+ const int shft_per_block = BLOCK_SHIFT(fs) - 2;
+ const uint32_t direct_blocks = EXT2_NDIR_BLOCKS;
+ const uint32_t indirect_blocks = addr_per_block;
+ const uint32_t double_blocks = addr_per_block << shft_per_block;
+ const uint32_t triple_blocks = double_blocks << shft_per_block;
+
+ /* direct blocks */
+ if (block < direct_blocks)
+ return scan_set_nblocks(&PVT(inode)->i_block[block],
+ direct_blocks - block, nblocks);
+
+ /* indirect blocks */
+ block -= direct_blocks;
+ if (block < indirect_blocks)
+ return bmap_indirect(fs, PVT(inode)->i_block[EXT2_IND_BLOCK],
+ block, 1, nblocks);
+
+ /* double indirect blocks */
+ block -= indirect_blocks;
+ if (block < double_blocks)
+ return bmap_indirect(fs, PVT(inode)->i_block[EXT2_DIND_BLOCK],
+ block, 2, nblocks);
+
+ /* triple indirect block */
+ block -= double_blocks;
+ if (block < triple_blocks)
+ return bmap_indirect(fs, PVT(inode)->i_block[EXT2_TIND_BLOCK],
+ block, 3, nblocks);
+
+ /* This can't happen... */
+ return 0;
+}
+
+
+/**
+ * Map the logical block to physic block where the file data stores.
+ * In EXT4, there are two ways to handle the map process, extents and indirect.
+ * EXT4 uses a inode flag to mark extent file and indirect block file.
+ *
+ * @fs: the fs_info structure.
+ * @inode: the inode structure.
+ * @block: the logical block to be mapped.
+ * @nblocks: optional pointer to number of contiguous blocks (low estimate)
+ * @retrun: the physical block number.
+ *
+ */
+block_t ext2_bmap(struct inode *inode, block_t block, size_t *nblocks)
+{
+ block_t ret;
+
+ if (inode->flags & EXT4_EXTENTS_FLAG)
+ ret = bmap_extent(inode, block, nblocks);
+ else
+ ret = bmap_traditional(inode, block, nblocks);
+
+ return ret;
+}
+
+
+/*
+ * Next extent for getfssec
+ */
+int ext2_next_extent(struct inode *inode, uint32_t lstart)
+{
+ struct fs_info *fs = inode->fs;
+ int blktosec = BLOCK_SHIFT(fs) - SECTOR_SHIFT(fs);
+ int blkmask = (1 << blktosec) - 1;
+ block_t block;
+ size_t nblocks = 0;
+
+ block = ext2_bmap(inode, lstart >> blktosec, &nblocks);
+
+ if (!block)
+ inode->next_extent.pstart = EXTENT_ZERO;
+ else
+ inode->next_extent.pstart =
+ ((sector_t)block << blktosec) | (lstart & blkmask);
+
+ inode->next_extent.len = (nblocks << blktosec) - (lstart & blkmask);
+ return 0;
+}
diff --git a/contrib/syslinux-4.02/core/fs/ext2/ext2.c b/contrib/syslinux-4.02/core/fs/ext2/ext2.c
new file mode 100644
index 0000000..716670c
--- /dev/null
+++ b/contrib/syslinux-4.02/core/fs/ext2/ext2.c
@@ -0,0 +1,335 @@
+#include <dprintf.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/dirent.h>
+#include <minmax.h>
+#include "cache.h"
+#include "core.h"
+#include "disk.h"
+#include "fs.h"
+#include "ext2_fs.h"
+
+/*
+ * Convert an ext2 file type to the global values
+ */
+static enum dirent_type ext2_cvt_type(unsigned int d_file_type)
+{
+ static const enum dirent_type inode_type[] = {
+ DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR,
+ DT_BLK, DT_FIFO, DT_SOCK, DT_LNK,
+ };
+
+ if (d_file_type > sizeof inode_type / sizeof *inode_type)
+ return DT_UNKNOWN;
+ else
+ return inode_type[d_file_type];
+}
+
+/*
+ * get the group's descriptor of group_num
+ */
+static const struct ext2_group_desc *
+ext2_get_group_desc(struct fs_info *fs, uint32_t group_num)
+{
+ struct ext2_sb_info *sbi = EXT2_SB(fs);
+ uint32_t desc_block, desc_index;
+ const struct ext2_group_desc *desc_data_block;
+
+ if (group_num >= sbi->s_groups_count) {
+ printf ("ext2_get_group_desc"
+ "block_group >= groups_count - "
+ "block_group = %d, groups_count = %d",
+ group_num, sbi->s_groups_count);
+
+ return NULL;
+ }
+
+ desc_block = group_num / sbi->s_desc_per_block;
+ desc_index = group_num % sbi->s_desc_per_block;
+
+ desc_block += sbi->s_first_data_block + 1;
+
+ desc_data_block = get_cache(fs->fs_dev, desc_block);
+ return &desc_data_block[desc_index];
+}
+
+/*
+ * Unlike strncmp, ext2_match_entry returns 1 for success, 0 for failure.
+ */
+static inline bool ext2_match_entry(const char *name, size_t len,
+ const struct ext2_dir_entry * de)
+{
+ if (!de->d_inode)
+ return false;
+ if (len != de->d_name_len)
+ return false;
+ return !memcmp(name, de->d_name, len);
+}
+
+
+/*
+ * p is at least 6 bytes before the end of page
+ */
+static inline struct ext2_dir_entry *ext2_next_entry(struct ext2_dir_entry *p)
+{
+ return (struct ext2_dir_entry *)((char*)p + p->d_rec_len);
+}
+
+/*
+ * Map a logical sector and load it into the cache
+ */
+static const void *
+ext2_get_cache(struct inode *inode, block_t lblock)
+{
+ block_t pblock = ext2_bmap(inode, lblock, NULL);
+ return get_cache(inode->fs->fs_dev, pblock);
+}
+
+/*
+ * find a dir entry, return it if found, or return NULL.
+ */
+static const struct ext2_dir_entry *
+ext2_find_entry(struct fs_info *fs, struct inode *inode, const char *dname)
+{
+ block_t index = 0;
+ uint32_t i = 0, offset, maxoffset;
+ const struct ext2_dir_entry *de;
+ const char *data;
+ size_t dname_len = strlen(dname);
+
+ while (i < inode->size) {
+ data = ext2_get_cache(inode, index++);
+ offset = 0;
+ maxoffset = min(BLOCK_SIZE(fs), i-inode->size);
+
+ /* The smallest possible size is 9 bytes */
+ while (offset < maxoffset-8) {
+ de = (const struct ext2_dir_entry *)(data + offset);
+ if (de->d_rec_len > maxoffset - offset)
+ break;
+
+ if (ext2_match_entry(dname, dname_len, de))
+ return de;
+
+ offset += de->d_rec_len;
+ }
+ i += BLOCK_SIZE(fs);
+ }
+
+ return NULL;
+}
+
+static const struct ext2_inode *
+ext2_get_inode(struct fs_info *fs, int inr)
+{
+ const struct ext2_group_desc *desc;
+ const char *data;
+ uint32_t inode_group, inode_offset;
+ uint32_t block_num, block_off;
+
+ inr--;
+ inode_group = inr / EXT2_INODES_PER_GROUP(fs);
+ inode_offset = inr % EXT2_INODES_PER_GROUP(fs);
+ desc = ext2_get_group_desc(fs, inode_group);
+ if (!desc)
+ return NULL;
+
+ block_num = desc->bg_inode_table +
+ inode_offset / EXT2_INODES_PER_BLOCK(fs);
+ block_off = inode_offset % EXT2_INODES_PER_BLOCK(fs);
+
+ data = get_cache(fs->fs_dev, block_num);
+
+ return (const struct ext2_inode *)
+ (data + block_off * EXT2_SB(fs)->s_inode_size);
+}
+
+static void fill_inode(struct inode *inode, const struct ext2_inode *e_inode)
+{
+ inode->mode = IFTODT(e_inode->i_mode);
+ inode->size = e_inode->i_size;
+ inode->atime = e_inode->i_atime;
+ inode->ctime = e_inode->i_ctime;
+ inode->mtime = e_inode->i_mtime;
+ inode->dtime = e_inode->i_dtime;
+ inode->blocks = e_inode->i_blocks;
+ inode->flags = e_inode->i_flags;
+ inode->file_acl = e_inode->i_file_acl;
+ memcpy(PVT(inode)->i_block, e_inode->i_block, sizeof PVT(inode)->i_block);
+}
+
+static struct inode *ext2_iget_by_inr(struct fs_info *fs, uint32_t inr)
+{
+ const struct ext2_inode *e_inode;
+ struct inode *inode;
+
+ e_inode = ext2_get_inode(fs, inr);
+ if (!(inode = alloc_inode(fs, inr, sizeof(struct ext2_pvt_inode))))
+ return NULL;
+ fill_inode(inode, e_inode);
+
+ return inode;
+}
+
+static struct inode *ext2_iget_root(struct fs_info *fs)
+{
+ return ext2_iget_by_inr(fs, EXT2_ROOT_INO);
+}
+
+static struct inode *ext2_iget(const char *dname, struct inode *parent)
+{
+ const struct ext2_dir_entry *de;
+ struct fs_info *fs = parent->fs;
+
+ de = ext2_find_entry(fs, parent, dname);
+ if (!de)
+ return NULL;
+
+ return ext2_iget_by_inr(fs, de->d_inode);
+}
+
+/*
+ * Read the entire contents of an inode into a memory buffer
+ */
+static int cache_get_file(struct inode *inode, void *buf, size_t bytes)
+{
+ struct fs_info *fs = inode->fs;
+ size_t block_size = BLOCK_SIZE(fs);
+ uint32_t index = 0; /* Logical block number */
+ size_t chunk;
+ const char *data;
+ char *p = buf;
+
+ if (inode->size > bytes)
+ bytes = inode->size;
+
+ while (bytes) {
+ chunk = min(bytes, block_size);
+ data = ext2_get_cache(inode, index++);
+ memcpy(p, data, chunk);
+
+ bytes -= chunk;
+ p += chunk;
+ }
+
+ return 0;
+}
+
+static int ext2_readlink(struct inode *inode, char *buf)
+{
+ struct fs_info *fs = inode->fs;
+ int sec_per_block = 1 << (fs->block_shift - fs->sector_shift);
+ bool fast_symlink;
+
+ if (inode->size > BLOCK_SIZE(fs))
+ return -1; /* Error! */
+
+ fast_symlink = (inode->file_acl ? sec_per_block : 0) == inode->blocks;
+ if (fast_symlink)
+ memcpy(buf, PVT(inode)->i_block, inode->size);
+ else
+ cache_get_file(inode, buf, inode->size);
+
+ return inode->size;
+}
+
+/*
+ * Read one directory entry at a time
+ */
+static int ext2_readdir(struct file *file, struct dirent *dirent)
+{
+ struct fs_info *fs = file->fs;
+ struct inode *inode = file->inode;
+ const struct ext2_dir_entry *de;
+ const char *data;
+ block_t index = file->offset >> fs->block_shift;
+
+ if (file->offset >= inode->size)
+ return -1; /* End of file */
+
+ data = ext2_get_cache(inode, index);
+ de = (const struct ext2_dir_entry *)
+ (data + (file->offset & (BLOCK_SIZE(fs) - 1)));
+
+ dirent->d_ino = de->d_inode;
+ dirent->d_off = file->offset;
+ dirent->d_reclen = offsetof(struct dirent, d_name) + de->d_name_len + 1;
+ dirent->d_type = ext2_cvt_type(de->d_file_type);
+ memcpy(dirent->d_name, de->d_name, de->d_name_len);
+ dirent->d_name[de->d_name_len] = '\0';
+
+ file->offset += de->d_rec_len; /* Update for next reading */
+
+ return 0;
+}
+
+/*
+ * init. the fs meta data, return the block size bits.
+ */
+static int ext2_fs_init(struct fs_info *fs)
+{
+ struct disk *disk = fs->fs_dev->disk;
+ struct ext2_sb_info *sbi;
+ struct ext2_super_block sb;
+ struct cache *cs;
+
+ /* read the super block */
+ disk->rdwr_sectors(disk, &sb, 2, 2, 0);
+
+ /* check if it is ext2, since we also support btrfs now */
+ if (sb.s_magic != EXT2_SUPER_MAGIC)
+ return -1;
+
+ sbi = malloc(sizeof(*sbi));
+ if (!sbi) {
+ malloc_error("ext2_sb_info structure");
+ return -1;
+ }
+ fs->fs_info = sbi;
+
+ if (sb.s_magic != EXT2_SUPER_MAGIC) {
+ printf("ext2 mount error: it's not a EXT2/3/4 file system!\n");
+ return 0;
+ }
+
+ fs->sector_shift = disk->sector_shift;
+ fs->block_shift = sb.s_log_block_size + 10;
+ fs->sector_size = 1 << fs->sector_shift;
+ fs->block_size = 1 << fs->block_shift;
+
+ sbi->s_inodes_per_group = sb.s_inodes_per_group;
+ sbi->s_blocks_per_group = sb.s_blocks_per_group;
+ sbi->s_inodes_per_block = BLOCK_SIZE(fs) / sb.s_inode_size;
+ if (sb.s_desc_size < sizeof(struct ext2_group_desc))
+ sb.s_desc_size = sizeof(struct ext2_group_desc);
+ sbi->s_desc_per_block = BLOCK_SIZE(fs) / sb.s_desc_size;
+ sbi->s_groups_count = (sb.s_blocks_count - sb.s_first_data_block
+ + EXT2_BLOCKS_PER_GROUP(fs) - 1)
+ / EXT2_BLOCKS_PER_GROUP(fs);
+ sbi->s_first_data_block = sb.s_first_data_block;
+ sbi->s_inode_size = sb.s_inode_size;
+
+ /* Initialize the cache, and force block zero to all zero */
+ cache_init(fs->fs_dev, fs->block_shift);
+ cs = _get_cache_block(fs->fs_dev, 0);
+ memset(cs->data, 0, fs->block_size);
+ cache_lock_block(cs);
+
+ return fs->block_shift;
+}
+
+const struct fs_ops ext2_fs_ops = {
+ .fs_name = "ext2",
+ .fs_flags = FS_THISIND | FS_USEMEM,
+ .fs_init = ext2_fs_init,
+ .searchdir = NULL,
+ .getfssec = generic_getfssec,
+ .close_file = generic_close_file,
+ .mangle_name = generic_mangle_name,
+ .load_config = generic_load_config,
+ .iget_root = ext2_iget_root,
+ .iget = ext2_iget,
+ .readlink = ext2_readlink,
+ .readdir = ext2_readdir,
+ .next_extent = ext2_next_extent,
+};
diff --git a/contrib/syslinux-4.02/core/fs/ext2/ext2_fs.h b/contrib/syslinux-4.02/core/fs/ext2/ext2_fs.h
new file mode 100644
index 0000000..8adc9bb
--- /dev/null
+++ b/contrib/syslinux-4.02/core/fs/ext2/ext2_fs.h
@@ -0,0 +1,310 @@
+#ifndef __EXT2_FS_H
+#define __EXT2_FS_H
+
+#include <stdint.h>
+
+#define EXT2_SUPER_MAGIC 0xEF53
+
+#define EXT2_GOOD_OLD_REV 0 // The good old (original) format
+#define EXT2_DYNAMIC_REV 1 // V2 format w/ dynamic inode sizes
+#define EXT2_GOOD_OLD_INODE_SIZE 128
+
+// Special inode numbers
+#define EXT2_BAD_INO 1 // Bad blocks inode
+#define EXT2_ROOT_INO 2 // Root inode
+#define EXT2_BOOT_LOADER_INO 5 // Boot loader inode
+#define EXT2_UNDEL_DIR_INO 6 // Undelete directory inode
+#define EXT3_RESIZE_INO 7 // Reserved group descriptors inode
+#define EXT3_JOURNAL_INO 8 // Journal inode
+
+// We're readonly, so we only care about incompat features.
+#define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001
+#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002
+#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004
+#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008
+#define EXT2_FEATURE_INCOMPAT_META_BG 0x0010
+#define EXT2_FEATURE_INCOMPAT_ANY 0xffffffff
+
+#define EXT2_NDIR_BLOCKS 12
+#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS
+#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK+1)
+#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK+1)
+#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK+1)
+
+
+/* for EXT4 extent */
+#define EXT4_EXT_MAGIC 0xf30a
+#define EXT4_EXTENTS_FLAG 0x00080000
+
+/*
+ * File types and file modes
+ */
+#define S_IFDIR 0040000 // Directory
+#define S_IFCHR 0020000 // Character device
+#define S_IFBLK 0060000 // Block device
+#define S_IFREG 0100000 // Regular file
+#define S_IFIFO 0010000 // FIFO
+#define S_IFLNK 0120000 // Symbolic link
+#define S_IFSOCK 0140000 // Socket
+
+#define S_IFSHIFT 12
+
+#define T_IFDIR (S_IFDIR >> S_IFSHIFT)
+#define T_IFCHR (S_IFCHR >> S_IFSHIFT)
+#define T_IFBLK (S_IFBLK >> S_IFSHIFT)
+#define T_IFREG (S_IFREG >> S_IFSHIFT)
+#define T_IFIFO (S_IFIFO >> S_IFSHIFT)
+#define T_IFLNK (S_IFLNK >> S_IFSHIFT)
+#define T_IFSOCK (S_IFSOCK >> S_IFSHIFT)
+
+
+#define ext2_group_desc_lg2size 5
+
+
+
+/*
+ * super block structure:
+ * include/linux/ext2_fs.h
+ */
+struct ext2_super_block {
+ uint32_t s_inodes_count; /* Inodes count */
+ uint32_t s_blocks_count; /* Blocks count */
+ uint32_t s_r_blocks_count; /* Reserved blocks count */
+ uint32_t s_free_blocks_count; /* Free blocks count */
+ uint32_t s_free_inodes_count; /* Free inodes count */
+ uint32_t s_first_data_block; /* First Data Block */
+ uint32_t s_log_block_size; /* Block size */
+ uint32_t s_log_frag_size; /* Fragment size */
+ uint32_t s_blocks_per_group; /* # Blocks per group */
+ uint32_t s_frags_per_group; /* # Fragments per group */
+ uint32_t s_inodes_per_group; /* # Inodes per group */
+ uint32_t s_mtime; /* Mount time */
+ uint32_t s_wtime; /* Write time */
+ uint16_t s_mnt_count; /* Mount count */
+ int16_t s_max_mnt_count; /* Maximal mount count */
+ uint16_t s_magic; /* Magic signature */
+ uint16_t s_state; /* File system state */
+ uint16_t s_errors; /* Behaviour when detecting errors */
+ uint16_t s_minor_rev_level;
+ uint32_t s_lastcheck; /* time of last check */
+ uint32_t s_checkinterval; /* max. time between checks */
+ uint32_t s_creator_os; /* OS */
+ uint32_t s_rev_level; /* Revision level */
+ uint16_t s_def_resuid; /* Default uid for reserved blocks */
+ uint16_t s_def_resgid; /* Default gid for reserved blocks */
+
+ uint32_t s_first_ino; /* First non-reserved inode */
+ uint16_t s_inode_size; /* size of inode structure */
+ uint16_t s_block_group_nr; /* block group # of this superblock */
+ uint32_t s_feature_compat; /* compatible feature set */
+ uint32_t s_feature_incompat; /* incompatible feature set */
+ uint32_t s_feature_ro_compat; /* readonly-compatible feature set */
+ uint8_t s_uuid[16]; /* 128-bit uuid for volume */
+ char s_volume_name[16]; /* volume name */
+ char s_last_mounted[64]; /* directory where last mounted */
+ uint32_t s_algorithm_usage_bitmap; /* For compression */
+ uint8_t s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
+ uint8_t s_prealloc_dir_blocks;
+ uint16_t s_reserved_gdt_blocks; /* Per group desc for online growth */
+ /*
+ * Journaling support valid if EXT4_FEATURE_COMPAT_HAS_JOURNAL set.
+ */
+ uint8_t s_journal_uuid[16]; /* uuid of journal superblock */
+ uint32_t s_journal_inum; /* inode number of journal file */
+ uint32_t s_journal_dev; /* device number of journal file */
+ uint32_t s_last_orphan; /* start of list of inodes to delete */
+ uint32_t s_hash_seed[4]; /* HTREE hash seed */
+ uint8_t s_def_hash_version; /* Default hash version to use */
+ uint8_t s_reserved_char_pad;
+ uint16_t s_desc_size; /* size of group descriptor */
+ uint32_t s_default_mount_opts;
+ uint32_t s_first_meta_bg; /* First metablock block group */
+ uint32_t s_mkfs_time; /* When the filesystem was created */
+ uint32_t s_jnl_blocks[17]; /* Backup of the journal inode */
+ /* 64bit support valid if EXT4_FEATURE_COMPAT_64BIT */
+ uint32_t s_blocks_count_hi; /* Blocks count */
+ uint32_t s_r_blocks_count_hi; /* Reserved blocks count */
+ uint32_t s_free_blocks_count_hi;/* Free blocks count */
+ uint16_t s_min_extra_isize; /* All inodes have at least # bytes */
+ uint16_t s_want_extra_isize; /* New inodes should reserve # bytes */
+ uint32_t s_flags; /* Miscellaneous flags */
+ uint16_t s_raid_stride; /* RAID stride */
+ uint16_t s_mmp_interval; /* # seconds to wait in MMP checking */
+ uint64_t s_mmp_block; /* Block for multi-mount protection */
+ uint32_t s_raid_stripe_width; /* blocks on all data disks (N*stride)*/
+ uint8_t s_log_groups_per_flex; /* FLEX_BG group size */
+ uint8_t s_reserved_char_pad2;
+ uint16_t s_reserved_pad;
+ uint32_t s_reserved[162]; /* Padding to the end of the block */
+};
+
+/*******************************************************************************
+#ifndef DEPEND
+#if ext2_super_block_size != 1024
+#error ext2_super_block definition bogus
+#endif
+#endif
+*******************************************************************************/
+
+/*
+ * ext2 group desc structure:
+ */
+struct ext2_group_desc {
+ uint32_t bg_block_bitmap; /* Blocks bitmap block */
+ uint32_t bg_inode_bitmap; /* Inodes bitmap block */
+ uint32_t bg_inode_table; /* Inodes table block */
+ uint16_t bg_free_blocks_count; /* Free blocks count */
+ uint16_t bg_free_inodes_count; /* Free inodes count */
+ uint16_t bg_used_dirs_count; /* Directories count */
+ uint16_t bg_pad;
+ uint32_t bg_reserved[3];
+};
+
+/*******************************************************************************
+#ifndef DEPEND
+#if ext2_group_desc_size != 32
+#error ext2_group_desc definition bogus
+#endif
+#endif
+*******************************************************************************/
+
+
+/*
+ * ext2 inode structure:
+ */
+struct ext2_inode {
+ uint16_t i_mode; /* File mode */
+ uint16_t i_uid; /* Owner Uid */
+ uint32_t i_size; /* 4: Size in bytes */
+ uint32_t i_atime; /* Access time */
+ uint32_t i_ctime; /* 12: Creation time */
+ uint32_t i_mtime; /* Modification time */
+ uint32_t i_dtime; /* 20: Deletion Time */
+ uint16_t i_gid; /* Group Id */
+ uint16_t i_links_count; /* 24: Links count */
+ uint32_t i_blocks; /* Blocks count */
+ uint32_t i_flags; /* 32: File flags */
+ uint32_t l_i_reserved1;
+ uint32_t i_block[EXT2_N_BLOCKS]; /* 40: Pointers to blocks */
+ uint32_t i_version; /* File version (for NFS) */
+ uint32_t i_file_acl; /* File ACL */
+ uint32_t i_dir_acl; /* Directory ACL */
+ uint32_t i_faddr; /* Fragment address */
+ uint8_t l_i_frag; /* Fragment number */
+ uint8_t l_i_fsize; /* Fragment size */
+ uint16_t i_pad1;
+ uint32_t l_i_reserved2[2];
+};
+
+/*******************************************************************************
+#ifndef DEPEND
+#if ext2_inode_size != 128
+#error ext2_inode definition bogus
+#endif
+#endif
+*******************************************************************************/
+
+
+#define EXT2_NAME_LEN 255
+struct ext2_dir_entry {
+ unsigned int d_inode; /* Inode number */
+ unsigned short d_rec_len; /* Directory entry length */
+ unsigned char d_name_len; /* Name length */
+ unsigned char d_file_type;
+ char d_name[EXT2_NAME_LEN]; /* File name */
+};
+
+/*******************************************************************************
+#define EXT2_DIR_PAD 4
+#define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1)
+#define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \
+ ~EXT2_DIR_ROUND)
+*******************************************************************************/
+
+
+
+
+
+
+/*
+ * This is the extent on-disk structure.
+ * It's used at the bottom of the tree.
+ */
+struct ext4_extent {
+ uint32_t ee_block; /* first logical block extent covers */
+ uint16_t ee_len; /* number of blocks covered by extent */
+ uint16_t ee_start_hi; /* high 16 bits of physical block */
+ uint32_t ee_start_lo; /* low 32 bits of physical block */
+};
+
+/*
+ * This is index on-disk structure.
+ * It's used at all the levels except the bottom.
+ */
+struct ext4_extent_idx {
+ uint32_t ei_block; /* index covers logical blocks from 'block' */
+ uint32_t ei_leaf_lo; /* pointer to the physical block of the next *
+ * level. leaf or next index could be there */
+ uint16_t ei_leaf_hi; /* high 16 bits of physical block */
+ uint16_t ei_unused;
+};
+
+/*
+ * Each block (leaves and indexes), even inode-stored has header.
+ */
+struct ext4_extent_header {
+ uint16_t eh_magic; /* probably will support different formats */
+ uint16_t eh_entries; /* number of valid entries */
+ uint16_t eh_max; /* capacity of store in entries */
+ uint16_t eh_depth; /* has tree real underlying blocks? */
+ uint32_t eh_generation; /* generation of the tree */
+};
+
+
+
+#define EXT4_FIRST_EXTENT(header) ( (struct ext4_extent *)(header + 1) )
+#define EXT4_FIRST_INDEX(header) ( (struct ext4_extent_idx *) (header + 1) )
+
+
+/*
+ * The ext2 super block information in memory
+ */
+struct ext2_sb_info {
+ uint32_t s_inodes_per_block;/* Number of inodes per block */
+ uint32_t s_inodes_per_group;/* Number of inodes in a group */
+ uint32_t s_blocks_per_group;/* Number of blocks in a group */
+ uint32_t s_desc_per_block; /* Number of group descriptors per block */
+ uint32_t s_groups_count; /* Number of groups in the fs */
+ uint32_t s_first_data_block; /* First Data Block */
+ int s_inode_size;
+};
+
+static inline struct ext2_sb_info *EXT2_SB(struct fs_info *fs)
+{
+ return fs->fs_info;
+}
+
+#define EXT2_BLOCKS_PER_GROUP(fs) (EXT2_SB(fs)->s_blocks_per_group)
+#define EXT2_INODES_PER_GROUP(fs) (EXT2_SB(fs)->s_inodes_per_group)
+#define EXT2_INODES_PER_BLOCK(fs) (EXT2_SB(fs)->s_inodes_per_block)
+#define EXT2_DESC_PER_BLOCK(fs) (EXT2_SB(fs)->s_desc_per_block)
+
+/*
+ * ext2 private inode information
+ */
+struct ext2_pvt_inode {
+ union {
+ uint32_t i_block[EXT2_N_BLOCKS];
+ struct ext4_extent_header i_extent_hdr;
+ };
+};
+
+#define PVT(i) ((struct ext2_pvt_inode *)((i)->pvt))
+
+/*
+ * functions
+ */
+block_t ext2_bmap(struct inode *, block_t, size_t *);
+int ext2_next_extent(struct inode *, uint32_t);
+
+#endif /* ext2_fs.h */