diff options
author | Paulo Alcantara <pcacjr@zytor.com> | 2012-07-29 17:31:48 -0300 |
---|---|---|
committer | Paulo Alcantara <pcacjr@zytor.com> | 2012-07-29 17:31:48 -0300 |
commit | 9dda198676c8444b2d3a82dd167d1d81f46c284e (patch) | |
tree | f501914ea110dff4ce87299ea3acd1beedfcb08f | |
parent | 7997877811d9ce99efed65604bba2bae91332c79 (diff) | |
download | syslinux-9dda198676c8444b2d3a82dd167d1d81f46c284e.tar.gz syslinux-9dda198676c8444b2d3a82dd167d1d81f46c284e.tar.xz syslinux-9dda198676c8444b2d3a82dd167d1d81f46c284e.zip |
xfs: Implement xfs_readdir_dir2_node() function
Now, xfs_readdir filesystem op will be able to list directory entries
from node directories.
Signed-off-by: Paulo Alcantara <pcacjr@zytor.com>
-rw-r--r-- | core/fs/xfs/xfs.c | 3 | ||||
-rw-r--r-- | core/fs/xfs/xfs.h | 2 | ||||
-rw-r--r-- | core/fs/xfs/xfs_dir2.c | 18 | ||||
-rw-r--r-- | core/fs/xfs/xfs_dir2.h | 3 | ||||
-rw-r--r-- | core/fs/xfs/xfs_readdir.c | 125 |
5 files changed, 139 insertions, 12 deletions
diff --git a/core/fs/xfs/xfs.c b/core/fs/xfs/xfs.c index f4a1fe35..69a57166 100644 --- a/core/fs/xfs/xfs.c +++ b/core/fs/xfs/xfs.c @@ -190,6 +190,9 @@ static struct inode *xfs_iget(const char *dname, struct inode *parent) if (inode->mode == DT_REG) { XFS_PVT(inode)->i_offset = 0; XFS_PVT(inode)->i_cur_extent = 0; + } else if (inode->mode == DT_DIR) { + XFS_PVT(inode)->i_btree_offset = 0; + XFS_PVT(inode)->i_leaf_ent_offset = 0; } return inode; diff --git a/core/fs/xfs/xfs.h b/core/fs/xfs/xfs.h index 3b179cac..21d48290 100644 --- a/core/fs/xfs/xfs.h +++ b/core/fs/xfs/xfs.h @@ -354,6 +354,8 @@ struct xfs_inode { uint64_t i_block_offset; uint64_t i_offset; uint32_t i_cur_extent; + uint32_t i_btree_offset; + uint16_t i_leaf_ent_offset; }; typedef struct { uint8_t i[8]; } __attribute__((__packed__)) xfs_dir2_ino8_t; diff --git a/core/fs/xfs/xfs_dir2.c b/core/fs/xfs/xfs_dir2.c index 67a82c9e..62743496 100644 --- a/core/fs/xfs/xfs_dir2.c +++ b/core/fs/xfs/xfs_dir2.c @@ -74,7 +74,7 @@ uint32_t xfs_dir2_da_hashname(const uint8_t *name, int namelen) } void *xfs_dir2_get_dirblks(struct fs_info *fs, block_t startblock, - xfs_filblks_t c) + xfs_filblks_t c) { int count = c << XFS_INFO(fs)->dirblklog; uint8_t *p; @@ -432,9 +432,9 @@ failed: return ip; } -static block_t get_right_blk(struct fs_info *fs, xfs_dinode_t *core, - uint32_t from, uint32_t to, block_t fsblkno, - int *error) +block_t xfs_dir2_get_right_blk(struct fs_info *fs, xfs_dinode_t *core, + uint32_t from, uint32_t to, block_t fsblkno, + int *error) { uint32_t idx; xfs_bmbt_irec_t irec; @@ -539,9 +539,9 @@ struct inode *xfs_dir2_node_find_entry(const char *dname, struct inode *parent, else fsblkno = be32_to_cpu(node->btree[probe].before); - fsblkno = get_right_blk(parent->fs, core, - node_off + 1, be32_to_cpu(core->di_nextents) - 1, - fsblkno, &error); + fsblkno = xfs_dir2_get_right_blk(parent->fs, core, node_off + 1, + be32_to_cpu(core->di_nextents) - 1, + fsblkno, &error); if (error) { xfs_error("Cannot find leaf rec!"); goto out; @@ -589,8 +589,8 @@ struct inode *xfs_dir2_node_find_entry(const char *dname, struct inode *parent, if (buf) free(buf); - fsblkno = get_right_blk(parent->fs, core, 0, node_off, - newdb, &error); + fsblkno = xfs_dir2_get_right_blk(parent->fs, core, 0, node_off, + newdb, &error); if (error) { xfs_error("Cannot find data rec!"); goto out; diff --git a/core/fs/xfs/xfs_dir2.h b/core/fs/xfs/xfs_dir2.h index 24d01505..c9398332 100644 --- a/core/fs/xfs/xfs_dir2.h +++ b/core/fs/xfs/xfs_dir2.h @@ -27,6 +27,9 @@ char *xfs_dir2_get_entry_name(uint8_t *start, uint8_t *end); void *xfs_dir2_get_dirblks(struct fs_info *fs, block_t startblock, xfs_filblks_t c); uint32_t xfs_dir2_da_hashname(const uint8_t *name, int namelen); +block_t xfs_dir2_get_right_blk(struct fs_info *fs, xfs_dinode_t *core, + uint32_t from, uint32_t to, block_t fsblkno, + int *error); struct inode *xfs_dir2_local_find_entry(const char *dname, struct inode *parent, xfs_dinode_t *core); diff --git a/core/fs/xfs/xfs_readdir.c b/core/fs/xfs/xfs_readdir.c index 4eaeae36..c81c1931 100644 --- a/core/fs/xfs/xfs_readdir.c +++ b/core/fs/xfs/xfs_readdir.c @@ -283,9 +283,128 @@ out: int xfs_readdir_dir2_node(struct file *file, struct dirent *dirent, xfs_dinode_t *core) { - (void)file; - (void)dirent; - (void)core; + struct fs_info *fs = file->fs; + xfs_bmbt_irec_t irec; + uint32_t node_off = 0; + block_t fsblkno; + xfs_da_intnode_t *node = NULL; + struct inode *inode = file->inode; + int error; + xfs_dir2_data_hdr_t *data_hdr; + xfs_dir2_leaf_t *leaf; + xfs_dir2_leaf_entry_t *lep; + unsigned int offset; + xfs_dir2_data_entry_t *dep; + uint8_t *start_name; + uint8_t *end_name; + char *name; + uint32_t db; + uint8_t *buf = NULL; + int retval = 0; + + do { + bmbt_irec_get(&irec, (xfs_bmbt_rec_t *)&core->di_literal_area[0] + + ++node_off); + } while (irec.br_startoff < xfs_dir2_byte_to_db(fs, XFS_DIR2_LEAF_OFFSET)); + + fsblkno = fsblock_to_bytes(fs, irec.br_startblock) >> BLOCK_SHIFT(fs); + + node = (xfs_da_intnode_t *)xfs_dir2_get_dirblks(fs, fsblkno, 1); + if (be16_to_cpu(node->hdr.info.magic) != XFS_DA_NODE_MAGIC) { + xfs_error("Node's magic number does not match!"); + goto out; + } + +try_next_btree: + if (!node->hdr.count || + XFS_PVT(inode)->i_btree_offset >= be16_to_cpu(node->hdr.count)) + goto out; + + fsblkno = be32_to_cpu(node->btree[XFS_PVT(inode)->i_btree_offset].before); + fsblkno = xfs_dir2_get_right_blk(fs, core, node_off + 1, + be32_to_cpu(core->di_nextents) - 1, + fsblkno, &error); + if (error) { + xfs_error("Cannot find leaf rec!"); + goto out; + } + + leaf = (xfs_dir2_leaf_t*)xfs_dir2_get_dirblks(fs, fsblkno, 1); + if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAFN_MAGIC) { + xfs_error("Leaf's magic number does not match!"); + goto out1; + } + + if (!leaf->hdr.count || + XFS_PVT(inode)->i_leaf_ent_offset >= be16_to_cpu(leaf->hdr.count)) { + XFS_PVT(inode)->i_btree_offset++; + XFS_PVT(inode)->i_leaf_ent_offset = 0; + free(leaf); + goto try_next_btree; + } + + lep = &leaf->ents[XFS_PVT(inode)->i_leaf_ent_offset]; + + /* Skip over stale leaf entries */ + for ( ; XFS_PVT(inode)->i_leaf_ent_offset < be16_to_cpu(leaf->hdr.count) && + be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR; + lep++, XFS_PVT(inode)->i_leaf_ent_offset++); + + if (XFS_PVT(inode)->i_leaf_ent_offset == be16_to_cpu(leaf->hdr.count)) { + XFS_PVT(inode)->i_btree_offset++; + XFS_PVT(inode)->i_leaf_ent_offset = 0; + free(leaf); + goto try_next_btree; + } else { + XFS_PVT(inode)->i_leaf_ent_offset++; + } + + db = xfs_dir2_dataptr_to_db(fs, be32_to_cpu(lep->address)); + + fsblkno = xfs_dir2_get_right_blk(fs, core, 0, node_off, db, &error); + if (error) { + xfs_error("Cannot find data rec!"); + goto out1; + } + + buf = xfs_dir2_get_dirblks(fs, fsblkno, 1); + data_hdr = (xfs_dir2_data_hdr_t *)buf; + if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC) { + xfs_error("Leaf directory's data magic No. does not match!"); + goto out2; + } + + offset = xfs_dir2_dataptr_to_off(fs, be32_to_cpu(lep->address)); + + dep = (xfs_dir2_data_entry_t *)((uint8_t *)buf + offset); + + start_name = &dep->name[0]; + end_name = start_name + dep->namelen; + name = xfs_dir2_get_entry_name(start_name, end_name); + + retval = fill_dirent(fs, dirent, 0, be64_to_cpu(dep->inumber), name, + end_name - start_name); + if (retval) + xfs_error("Failed to fill in dirent structure"); + + free(name); + free(buf); + free(leaf); + free(node); + + return retval; + +out2: + free(buf); + +out1: + free(leaf); + +out: + free(node); + + XFS_PVT(inode)->i_btree_offset = 0; + XFS_PVT(inode)->i_leaf_ent_offset = 0; return -1; } |