aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChen Baozi <baozich@gmail.com>2012-08-15 17:32:40 +0800
committerPaulo Alcantara <pcacjr@zytor.com>2012-09-02 19:12:47 -0300
commit4db137eaa7ac68966660f6fbf4dc13a2244bf8b2 (patch)
treec9c908d8633f8086f4ef19a307cd3d8fe6dce18e
parent7807be97f3df9f039592908140b97c12e3f30ede (diff)
downloadsyslinux-4db137eaa7ac68966660f6fbf4dc13a2244bf8b2.tar.gz
syslinux-4db137eaa7ac68966660f6fbf4dc13a2244bf8b2.tar.xz
syslinux-4db137eaa7ac68966660f6fbf4dc13a2244bf8b2.zip
xfs: Add full B+tree search support in xfs_dir2_node_find_entry()
According to the manual, the difference between B+tree directory and node directory is that the node/leaf trees can be more than one level deep in the B+tree format. That is to say we do not need to reimplemented a completely new function in B+tree case. What we've done here is to modify xfs_dir2_node_find_entry() to support searching in a B+tree more than one level. Signed-off-by: Chen Baozi <baozich@gmail.com> Signed-off-by: Paulo Alcantara <pcacjr@zytor.com>
-rw-r--r--core/fs/xfs/xfs_dir2.c108
1 files changed, 54 insertions, 54 deletions
diff --git a/core/fs/xfs/xfs_dir2.c b/core/fs/xfs/xfs_dir2.c
index 30db8cca..e6ae92f9 100644
--- a/core/fs/xfs/xfs_dir2.c
+++ b/core/fs/xfs/xfs_dir2.c
@@ -493,68 +493,73 @@ struct inode *xfs_dir2_node_find_entry(const char *dname, struct inode *parent,
} while (irec.br_startoff <
xfs_dir2_byte_to_db(parent->fs, XFS_DIR2_LEAF_OFFSET));
+ hashwant = xfs_dir2_da_hashname((uint8_t *)dname, strlen(dname));
+
fsblkno = fsblock_to_bytes(parent->fs, irec.br_startblock) >>
BLOCK_SHIFT(parent->fs);
-
node = (xfs_da_intnode_t *)xfs_dir2_get_dirblks(parent->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;
}
- if (!node->hdr.count)
- goto out;
-
- hashwant = xfs_dir2_da_hashname((uint8_t *)dname, strlen(dname));
+ do {
+ if (!node->hdr.count)
+ goto out;
+
+ /* Given a hash to lookup, you read the node's btree array and first
+ * "hashval" in the array that exceeds the given hash and it can then
+ * be found in the block pointed by the "before" value.
+ */
+ max = be16_to_cpu(node->hdr.count);
+
+ probe = span = max/2;
+ for (btree = &node->btree[probe];
+ span > 4; btree = &node->btree[probe]) {
+ span /= 2;
+ hash = be32_to_cpu(btree->hashval);
+ if (hash < hashwant)
+ probe += span;
+ else if (hash > hashwant)
+ probe -= span;
+ else
+ break;
+ }
- /* Given a hash to lookup, you read the node's btree array and first
- * "hashval" in the array that exceeds the given hash and it can then
- * be found in the block pointed by the "before" value.
- */
- max = be16_to_cpu(node->hdr.count);
+ while ((probe > 0) && (be32_to_cpu(btree->hashval) >= hashwant)) {
+ btree--;
+ probe--;
+ }
+ while ((probe < max) && (be32_to_cpu(btree->hashval) < hashwant)) {
+ btree++;
+ probe++;
+ }
- probe = span = max/2;
- for (btree = &node->btree[probe]; span > 4; btree = &node->btree[probe]) {
- span /= 2;
- hash = be32_to_cpu(btree->hashval);
- if (hash < hashwant)
- probe += span;
- else if (hash > hashwant)
- probe -= span;
+ if (probe == max)
+ fsblkno = be32_to_cpu(node->btree[max-1].before);
else
- break;
- }
-
- while ((probe > 0) && (be32_to_cpu(btree->hashval) >= hashwant)) {
- btree--;
- probe--;
- }
- while ((probe < max) && (be32_to_cpu(btree->hashval) < hashwant)) {
- btree++;
- probe++;
- }
-
- if (probe == max)
- fsblkno = be32_to_cpu(node->btree[max-1].before);
- else
- fsblkno = be32_to_cpu(node->btree[probe].before);
-
- 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;
- }
+ fsblkno = be32_to_cpu(node->btree[probe].before);
+
+ 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 right rec!");
+ goto out;
+ }
+ free(node);
+ node = (xfs_da_intnode_t *)xfs_dir2_get_dirblks(parent->fs,
+ fsblkno, 1);
+ } while(be16_to_cpu(node->hdr.info.magic) == XFS_DA_NODE_MAGIC);
- leaf = (xfs_dir2_leaf_t*)xfs_dir2_get_dirblks(parent->fs, fsblkno, 1);
+ leaf = (xfs_dir2_leaf_t*)node;
if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAFN_MAGIC) {
xfs_error("Leaf's magic number does not match!");
- goto out1;
+ goto out;
}
if (!leaf->hdr.count)
- goto out1;
+ goto out;
for (lep = leaf->ents, low = 0, high = be16_to_cpu(leaf->hdr.count) - 1;
low <= high; ) {
@@ -571,7 +576,7 @@ struct inode *xfs_dir2_node_find_entry(const char *dname, struct inode *parent,
* entry we're looking for and there is nothing to do anymore.
*/
if (hash != hashwant)
- goto out1;
+ goto out;
while (mid > 0 && be32_to_cpu(lep[mid - 1].hashval) == hashwant)
mid--;
@@ -593,14 +598,14 @@ struct inode *xfs_dir2_node_find_entry(const char *dname, struct inode *parent,
newdb, &error);
if (error) {
xfs_error("Cannot find data block!");
- goto out1;
+ goto out;
}
buf = xfs_dir2_get_dirblks(parent->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;
+ goto out1;
}
curdb = newdb;
}
@@ -617,11 +622,8 @@ struct inode *xfs_dir2_node_find_entry(const char *dname, struct inode *parent,
free(name);
}
-out2:
- free(buf);
-
out1:
- free(leaf);
+ free(buf);
out:
free(node);
@@ -655,7 +657,6 @@ found:
xfs_debug("entry inode's number %lu", ino);
free(buf);
- free(leaf);
free(node);
return ip;
@@ -663,7 +664,6 @@ found:
failed:
free(ip);
free(buf);
- free(leaf);
free(node);
return NULL;