diff options
Diffstat (limited to 'contrib/syslinux-4.02/core/fs/ext2')
-rw-r--r-- | contrib/syslinux-4.02/core/fs/ext2/bmap.c | 228 | ||||
-rw-r--r-- | contrib/syslinux-4.02/core/fs/ext2/ext2.c | 335 | ||||
-rw-r--r-- | contrib/syslinux-4.02/core/fs/ext2/ext2_fs.h | 310 |
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 */ |