summaryrefslogtreecommitdiff
path: root/core/fs/ext2/bmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'core/fs/ext2/bmap.c')
-rw-r--r--core/fs/ext2/bmap.c185
1 files changed, 185 insertions, 0 deletions
diff --git a/core/fs/ext2/bmap.c b/core/fs/ext2/bmap.c
new file mode 100644
index 00000000..e4698d0c
--- /dev/null
+++ b/core/fs/ext2/bmap.c
@@ -0,0 +1,185 @@
+/*
+ * 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 <fs.h>
+#include <disk.h>
+#include <cache.h>
+#include "ext2_fs.h"
+
+
+static struct ext4_extent_header *
+ext4_find_leaf(struct fs_info *fs, struct ext4_extent_header *eh, block_t block)
+{
+ struct ext4_extent_idx *index;
+ struct cache_struct *cs;
+ 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;
+ cs = get_cache_block(fs->fs_dev, blk);
+ eh = (struct ext4_extent_header *)cs->data;
+ }
+}
+
+/* handle the ext4 extents to get the phsical block number */
+static uint64_t bmap_extent(struct fs_info *fs,
+ struct inode *inode,
+ uint32_t block)
+{
+ struct ext4_extent_header *leaf;
+ struct ext4_extent *ext;
+ int i;
+ block_t start;
+
+ leaf = ext4_find_leaf(fs, (struct ext4_extent_header *)inode->pvt, 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 = ext[i].ee_start_hi;
+ start = (start << 32) + ext[i].ee_start_lo;
+
+ return start + block;
+}
+
+
+/*
+ * handle the traditional block map, like indirect, double indirect
+ * and triple indirect
+ */
+static unsigned int bmap_traditional(struct fs_info *fs,
+ struct inode *inode,
+ uint32_t block)
+{
+ int addr_per_block = BLOCK_SIZE(fs) >> 2;
+ uint32_t direct_blocks = EXT2_NDIR_BLOCKS,
+ indirect_blocks = addr_per_block,
+ double_blocks = addr_per_block * addr_per_block,
+ triple_blocks = double_blocks * addr_per_block;
+ struct cache_struct *cs;
+
+ /* direct blocks */
+ if (block < direct_blocks)
+ return ((uint32_t *)inode->pvt)[block];
+
+ /* indirect blocks */
+ block -= direct_blocks;
+ if (block < indirect_blocks) {
+ block_t ind_block = ((uint32_t *)inode->pvt)[EXT2_IND_BLOCK];
+
+ if (!ind_block)
+ return 0;
+ cs = get_cache_block(fs->fs_dev, ind_block);
+
+ return ((uint32_t *)cs->data)[block];
+ }
+
+
+ /* double indirect blocks */
+ block -= indirect_blocks;
+ if (block < double_blocks) {
+ block_t dou_block = ((uint32_t *)inode->pvt)[EXT2_DIND_BLOCK];
+
+ if (!dou_block)
+ return 0;
+ cs = get_cache_block(fs->fs_dev, dou_block);
+
+ dou_block = ((uint32_t *)cs->data)[block / indirect_blocks];
+ if (!dou_block)
+ return 0;
+ cs = get_cache_block(fs->fs_dev, dou_block);
+
+ return ((uint32_t *)cs->data)[block % addr_per_block];
+ }
+
+
+ /* triple indirect block */
+ block -= double_blocks;
+ if (block < triple_blocks) {
+ block_t tri_block = ((uint32_t *)inode->pvt)[EXT2_TIND_BLOCK];
+
+ if (!tri_block)
+ return 0;
+ cs = get_cache_block(fs->fs_dev, tri_block);
+
+ tri_block = ((uint32_t *)cs->data)[block / double_blocks];
+ if (!tri_block)
+ return 0;
+ cs = get_cache_block(fs->fs_dev, tri_block);
+
+ tri_block = (block / addr_per_block) % addr_per_block;
+ tri_block = ((uint32_t *)cs->data)[tri_block];
+ if (!tri_block)
+ return 0;
+ cs = get_cache_block(fs->fs_dev, tri_block);
+
+ return ((uint32_t *)cs->data)[block % addr_per_block];
+ }
+
+
+ /* File too big, can not handle */
+ printf("ERROR, file too big\n");
+ 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 blcok needed to be maped.
+ * @retrun: the physic block number.
+ *
+ */
+block_t bmap(struct fs_info *fs, struct inode * inode, int block)
+{
+ block_t ret;
+
+ if (block < 0)
+ return 0;
+
+ if (inode->flags & EXT4_EXTENTS_FLAG)
+ ret = bmap_extent(fs, inode, block);
+ else
+ ret = bmap_traditional(fs, inode, block);
+
+ return ret;
+}