aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaulo Alcantara <pcacjr@zytor.com>2012-07-23 17:03:02 -0300
committerPaulo Alcantara <pcacjr@zytor.com>2012-07-24 02:04:49 -0300
commit04236efa820a165b47b203700e5169b8ee901fc4 (patch)
tree4212c872c706f0ffda119c27537a4d5934222819
parent783575baac3bcc3d3f603c35af3c7be4bfe2420a (diff)
downloadsyslinux-04236efa820a165b47b203700e5169b8ee901fc4.tar.gz
syslinux-04236efa820a165b47b203700e5169b8ee901fc4.tar.xz
syslinux-04236efa820a165b47b203700e5169b8ee901fc4.zip
xfs: Implement xfs_dir2_node_find_entry() function
Signed-off-by: Paulo Alcantara <pcacjr@zytor.com>
-rw-r--r--core/fs/xfs/xfs.c241
-rw-r--r--core/fs/xfs/xfs.h15
2 files changed, 252 insertions, 4 deletions
diff --git a/core/fs/xfs/xfs.c b/core/fs/xfs/xfs.c
index 3c0568e5..92063e48 100644
--- a/core/fs/xfs/xfs.c
+++ b/core/fs/xfs/xfs.c
@@ -843,13 +843,245 @@ failed:
return ip;
}
+static block_t get_right_blk(struct fs_info *fs, xfs_dinode_t *core,
+ uint32_t offset)
+{
+ uint32_t cur_extent = 0;
+ block_t blk = 0;
+ xfs_bmbt_irec_t irec;
+
+ /* We ignore the last extent (which is the "freeindex" block) */
+ while (cur_extent < be32_to_cpu(core->di_nextents) - 1) {
+ bmbt_irec_get(&irec, (xfs_bmbt_rec_t *)&core->di_literal_area[0] +
+ cur_extent++);
+
+ if (offset == irec.br_startoff) {
+ blk = irec.br_startblock;
+ break;
+ }
+
+ if (offset <= (irec.br_startoff + irec.br_blockcount) - 1) {
+ blk = irec.br_startblock + ((irec.br_startoff +
+ irec.br_blockcount) - offset);
+ break;
+ }
+ }
+
+ xfs_debug("blk %llu", blk);
+
+ return fsblock_to_bytes(fs, blk) >> BLOCK_SHIFT(fs);
+}
+
static struct inode *xfs_dir2_node_find_entry(const char *dname,
struct inode *parent,
xfs_dinode_t *core)
{
- (void)dname;
- (void)parent;
- (void)core;
+
+ xfs_bmbt_irec_t irec;
+ uint32_t cur_extent;
+ block_t blk;
+ struct fs_info *fs = parent->fs;
+ xfs_da_intnode_t *node = NULL;
+ uint16_t count;
+ xfs_da_node_entry_t *entry;
+ xfs_dir2_leaf_t *leaf = NULL;
+ int low;
+ int high;
+ int mid = 0;
+ uint32_t hash = 0;
+ uint32_t hashwant;
+ block_t dir_blk;
+ xfs_dir2_leaf_entry_t *lep;
+ uint32_t newdb;
+ uint32_t curdb;
+ xfs_dir2_data_entry_t *dep;
+ struct inode *ip;
+ xfs_dir2_data_hdr_t *data_hdr;
+ uint8_t *start_name;
+ uint8_t *end_name;
+ char *name;
+ xfs_intino_t ino;
+ xfs_dinode_t *ncore;
+ uint8_t *buf = NULL;
+
+ cur_extent = 0;
+ do {
+ bmbt_irec_get(&irec, (xfs_bmbt_rec_t *)&core->di_literal_area[0] +
+ cur_extent++);
+ } while (irec.br_startoff != 8388608);
+
+ cur_extent--;
+
+ if (cur_extent >= be32_to_cpu(core->di_nextents))
+ goto out;
+
+ blk = fsblock_to_bytes(fs, irec.br_startblock) >> BLOCK_SHIFT(fs);
+
+ node = (xfs_da_intnode_t *)get_dirblk(fs, blk);
+ if (be16_to_cpu(node->hdr.info.magic) != XFS_DA_NODE_MAGIC) {
+ xfs_error("Leaf block header's magic number does not match!");
+ goto out;
+ }
+
+ for (entry = &node->btree[0], count = 0;
+ count < be16_to_cpu(node->hdr.count); count++, entry++) {
+ mid = 0;
+ hash = 0;
+ curdb = -1;
+ buf = NULL;
+
+ xfs_debug("before %lu", be32_to_cpu(entry->before));
+
+ blk = get_right_blk(fs, core, be32_to_cpu(entry->before));
+
+ xfs_debug("blk %lu", blk);
+
+ leaf = (xfs_dir2_leaf_t *)get_dirblk(fs, blk);
+ if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAFN_MAGIC) {
+ xfs_error("magic does not match!");
+ goto out;
+ }
+
+ if (!leaf->hdr.count) {
+ free(leaf);
+ continue;
+ }
+
+ hashwant = xfs_da_hashname((uint8_t *)dname, strlen(dname));
+ if (hashwant >= be32_to_cpu(entry->hashval))
+ continue;
+
+ /* Binary search */
+ for (lep = leaf->ents, low = 0, high = be16_to_cpu(leaf->hdr.count) - 1;
+ low <= high; ) {
+ mid = (low + high) >> 1;
+
+ if ((hash = be32_to_cpu(lep[mid].hashval)) == hashwant)
+ break;
+ if (hash < hashwant)
+ low = mid + 1;
+ else
+ high = mid - 1;
+ }
+
+ if (hash != hashwant)
+ goto out;
+
+ while (mid > 0 && be32_to_cpu(lep[mid - 1].hashval) == hashwant)
+ mid--;
+
+ xfs_debug("mid %u count %u", mid, be16_to_cpu(leaf->hdr.count));
+ for (lep = &leaf->ents[mid]; mid < be16_to_cpu(leaf->hdr.count) &&
+ be32_to_cpu(lep->hashval) == hashwant;
+ lep++, mid++) {
+ uint32_t offset;
+
+ /* Skip over stale leaf entries. */
+ if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR)
+ continue;
+
+ xfs_debug("hashval 0x%lx", be32_to_cpu(lep->hashval));
+ xfs_debug("address 0x%lx", be32_to_cpu(lep->address));
+
+ newdb = xfs_dir2_dataptr_to_db(fs, be32_to_cpu(lep->address));
+ if (newdb != curdb) {
+ if (buf)
+ free(buf);
+
+ bmbt_irec_get(&irec, ((xfs_bmbt_rec_t *)
+ &core->di_literal_area[0]) + newdb);
+ dir_blk = fsblock_to_bytes(fs, irec.br_startblock) >>
+ BLOCK_SHIFT(fs);
+
+ xfs_debug("startblock %llu", irec.br_startblock);
+
+ buf = get_dirblk(parent->fs, dir_blk);
+ 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 number does not "
+ "match!");
+ xfs_debug("mid %u count %u", mid, be16_to_cpu(leaf->hdr.count));
+ goto buf_free_out;
+ }
+
+ curdb = newdb;
+ }
+
+ 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 = get_entry_name(start_name, end_name);
+
+ if (!strncmp(name, dname, strlen(dname))) {
+ free(name);
+ goto found;
+ }
+
+ free(name);
+ }
+
+ free(leaf);
+ free(buf);
+
+ buf = NULL;
+ }
+
+buf_free_out:
+ free(buf);
+
+out:
+ free(leaf);
+ free(node);
+
+ return NULL;
+
+found:
+ ip = xfs_new_inode(fs);
+
+ ino = be64_to_cpu(dep->inumber);
+
+ xfs_debug("entry inode's number %lu", ino);
+
+ ncore = xfs_get_ino_core(fs, ino);
+ if (!ncore) {
+ xfs_error("Failed to get dinode!");
+ goto bail;
+ }
+
+ fill_xfs_inode_pvt(fs, ip, ino);
+
+ ip->ino = ino;
+ XFS_PVT(ip)->i_ino_blk = ino_to_bytes(fs, ino) >>
+ BLOCK_SHIFT(fs);
+ ip->size = be64_to_cpu(ncore->di_size);
+
+ if (be16_to_cpu(ncore->di_mode) & S_IFDIR) {
+ ip->mode = DT_DIR;
+ xfs_debug("Found a directory inode!");
+ } else if (be16_to_cpu(ncore->di_mode) & S_IFREG) {
+ ip->mode = DT_REG;
+ xfs_debug("Found a file inode!");
+ xfs_debug("inode size %llu", ip->size);
+ }
+
+ xfs_debug("entry inode's number %lu", ino);
+
+ free(node);
+ free(leaf);
+ free(buf);
+
+ return ip;
+
+bail:
+ free(ip);
+ free(node);
+ free(buf);
+ free(leaf);
+
+ return ip;
return NULL;
}
@@ -860,7 +1092,8 @@ static struct inode *xfs_fmt_extents_find_entry(const char *dname,
{
struct inode *inode;
- xfs_debug("ino: %d", parent->ino);
+ xfs_debug("parent ino %llu", parent->ino);
+
if (be32_to_cpu(core->di_nextents) <= 1) {
/* Single-block Directories */
inode = xfs_dir2_block_find_entry(dname, parent, core);
diff --git a/core/fs/xfs/xfs.h b/core/fs/xfs/xfs.h
index a7330c27..fd3a8339 100644
--- a/core/fs/xfs/xfs.h
+++ b/core/fs/xfs/xfs.h
@@ -572,6 +572,21 @@ typedef struct xfs_dir2_leaf {
#define XFS_DIR2_LEAF1_MAGIC 0xd2f1 /* magic number: v2 dirlf single blks */
#define XFS_DIR2_LEAFN_MAGIC 0xd2ff /* magic number: V2 dirlf multi blks */
+typedef struct xfs_da_intnode {
+ struct xfs_da_node_hdr { /* constant-structure header block */
+ xfs_da_blkinfo_t info; /* block type, links, etc. */
+ uint16_t count; /* count of active entries */
+ uint16_t level; /* level above leaves (leaf == 0) */
+ } hdr;
+ struct xfs_da_node_entry {
+ uint32_t hashval; /* hash value for this descendant */
+ uint32_t before; /* Btree block before this key */
+ } btree[1];
+} __attribute__((__packed__)) xfs_da_intnode_t;
+
+typedef struct xfs_da_node_hdr xfs_da_node_hdr_t;
+typedef struct xfs_da_node_entry xfs_da_node_entry_t;
+
static inline bool xfs_is_valid_magicnum(const xfs_sb_t *sb)
{
return sb->sb_magicnum == *(uint32_t *)XFS_SB_MAGIC;