aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaulo Alcantara <pcacjr@zytor.com>2012-07-29 17:31:48 -0300
committerPaulo Alcantara <pcacjr@zytor.com>2012-07-29 17:31:48 -0300
commit9dda198676c8444b2d3a82dd167d1d81f46c284e (patch)
treef501914ea110dff4ce87299ea3acd1beedfcb08f
parent7997877811d9ce99efed65604bba2bae91332c79 (diff)
downloadsyslinux-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.c3
-rw-r--r--core/fs/xfs/xfs.h2
-rw-r--r--core/fs/xfs/xfs_dir2.c18
-rw-r--r--core/fs/xfs/xfs_dir2.h3
-rw-r--r--core/fs/xfs/xfs_readdir.c125
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;
}