[syslinux:elflink] xfs: Implement xfs_readdir_dir2_node() function

syslinux-bot for Paulo Alcantara pcacjr at zytor.com
Tue Nov 27 12:57:22 PST 2012


Commit-ID:  9dda198676c8444b2d3a82dd167d1d81f46c284e
Gitweb:     http://www.syslinux.org/commit/9dda198676c8444b2d3a82dd167d1d81f46c284e
Author:     Paulo Alcantara <pcacjr at zytor.com>
AuthorDate: Sun, 29 Jul 2012 17:31:48 -0300
Committer:  Paulo Alcantara <pcacjr at zytor.com>
CommitDate: Sun, 29 Jul 2012 17:31:48 -0300

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 at zytor.com>

---
 core/fs/xfs/xfs.c         |   3 ++
 core/fs/xfs/xfs.h         |   2 +
 core/fs/xfs/xfs_dir2.c    |  18 +++----
 core/fs/xfs/xfs_dir2.h    |   3 ++
 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 f4a1fe3..69a5716 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 3b179ca..21d4829 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 67a82c9..6274349 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 24d0150..c939833 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 4eaeae3..c81c193 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;
 }


More information about the Syslinux-commits mailing list