18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * linux/fs/befs/btree.c 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2001-2002 Will Dyson <will_dyson@pobox.com> 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Licensed under the GNU GPL. See the file COPYING for details. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * 2002-02-05: Sergey S. Kostyliov added binary search within 98c2ecf20Sopenharmony_ci * btree nodes. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Many thanks to: 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * Dominic Giampaolo, author of "Practical File System 148c2ecf20Sopenharmony_ci * Design with the Be File System", for such a helpful book. 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * Marcus J. Ranum, author of the b+tree package in 178c2ecf20Sopenharmony_ci * comp.sources.misc volume 10. This code is not copied from that 188c2ecf20Sopenharmony_ci * work, but it is partially based on it. 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * Makoto Kato, author of the original BeFS for linux filesystem 218c2ecf20Sopenharmony_ci * driver. 228c2ecf20Sopenharmony_ci */ 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include <linux/kernel.h> 258c2ecf20Sopenharmony_ci#include <linux/string.h> 268c2ecf20Sopenharmony_ci#include <linux/slab.h> 278c2ecf20Sopenharmony_ci#include <linux/mm.h> 288c2ecf20Sopenharmony_ci#include <linux/buffer_head.h> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#include "befs.h" 318c2ecf20Sopenharmony_ci#include "btree.h" 328c2ecf20Sopenharmony_ci#include "datastream.h" 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* 358c2ecf20Sopenharmony_ci * The btree functions in this file are built on top of the 368c2ecf20Sopenharmony_ci * datastream.c interface, which is in turn built on top of the 378c2ecf20Sopenharmony_ci * io.c interface. 388c2ecf20Sopenharmony_ci */ 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/* Befs B+tree structure: 418c2ecf20Sopenharmony_ci * 428c2ecf20Sopenharmony_ci * The first thing in the tree is the tree superblock. It tells you 438c2ecf20Sopenharmony_ci * all kinds of useful things about the tree, like where the rootnode 448c2ecf20Sopenharmony_ci * is located, and the size of the nodes (always 1024 with current version 458c2ecf20Sopenharmony_ci * of BeOS). 468c2ecf20Sopenharmony_ci * 478c2ecf20Sopenharmony_ci * The rest of the tree consists of a series of nodes. Nodes contain a header 488c2ecf20Sopenharmony_ci * (struct befs_btree_nodehead), the packed key data, an array of shorts 498c2ecf20Sopenharmony_ci * containing the ending offsets for each of the keys, and an array of 508c2ecf20Sopenharmony_ci * befs_off_t values. In interior nodes, the keys are the ending keys for 518c2ecf20Sopenharmony_ci * the childnode they point to, and the values are offsets into the 528c2ecf20Sopenharmony_ci * datastream containing the tree. 538c2ecf20Sopenharmony_ci */ 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci/* Note: 568c2ecf20Sopenharmony_ci * 578c2ecf20Sopenharmony_ci * The book states 2 confusing things about befs b+trees. First, 588c2ecf20Sopenharmony_ci * it states that the overflow field of node headers is used by internal nodes 598c2ecf20Sopenharmony_ci * to point to another node that "effectively continues this one". Here is what 608c2ecf20Sopenharmony_ci * I believe that means. Each key in internal nodes points to another node that 618c2ecf20Sopenharmony_ci * contains key values less than itself. Inspection reveals that the last key 628c2ecf20Sopenharmony_ci * in the internal node is not the last key in the index. Keys that are 638c2ecf20Sopenharmony_ci * greater than the last key in the internal node go into the overflow node. 648c2ecf20Sopenharmony_ci * I imagine there is a performance reason for this. 658c2ecf20Sopenharmony_ci * 668c2ecf20Sopenharmony_ci * Second, it states that the header of a btree node is sufficient to 678c2ecf20Sopenharmony_ci * distinguish internal nodes from leaf nodes. Without saying exactly how. 688c2ecf20Sopenharmony_ci * After figuring out the first, it becomes obvious that internal nodes have 698c2ecf20Sopenharmony_ci * overflow nodes and leafnodes do not. 708c2ecf20Sopenharmony_ci */ 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/* 738c2ecf20Sopenharmony_ci * Currently, this code is only good for directory B+trees. 748c2ecf20Sopenharmony_ci * In order to be used for other BFS indexes, it needs to be extended to handle 758c2ecf20Sopenharmony_ci * duplicate keys and non-string keytypes (int32, int64, float, double). 768c2ecf20Sopenharmony_ci */ 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci/* 798c2ecf20Sopenharmony_ci * In memory structure of each btree node 808c2ecf20Sopenharmony_ci */ 818c2ecf20Sopenharmony_cistruct befs_btree_node { 828c2ecf20Sopenharmony_ci befs_host_btree_nodehead head; /* head of node converted to cpu byteorder */ 838c2ecf20Sopenharmony_ci struct buffer_head *bh; 848c2ecf20Sopenharmony_ci befs_btree_nodehead *od_node; /* on disk node */ 858c2ecf20Sopenharmony_ci}; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci/* local constants */ 888c2ecf20Sopenharmony_cistatic const befs_off_t BEFS_BT_INVAL = 0xffffffffffffffffULL; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci/* local functions */ 918c2ecf20Sopenharmony_cistatic int befs_btree_seekleaf(struct super_block *sb, const befs_data_stream *ds, 928c2ecf20Sopenharmony_ci befs_btree_super * bt_super, 938c2ecf20Sopenharmony_ci struct befs_btree_node *this_node, 948c2ecf20Sopenharmony_ci befs_off_t * node_off); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic int befs_bt_read_super(struct super_block *sb, const befs_data_stream *ds, 978c2ecf20Sopenharmony_ci befs_btree_super * sup); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic int befs_bt_read_node(struct super_block *sb, const befs_data_stream *ds, 1008c2ecf20Sopenharmony_ci struct befs_btree_node *node, 1018c2ecf20Sopenharmony_ci befs_off_t node_off); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic int befs_leafnode(struct befs_btree_node *node); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic fs16 *befs_bt_keylen_index(struct befs_btree_node *node); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic fs64 *befs_bt_valarray(struct befs_btree_node *node); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic char *befs_bt_keydata(struct befs_btree_node *node); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic int befs_find_key(struct super_block *sb, 1128c2ecf20Sopenharmony_ci struct befs_btree_node *node, 1138c2ecf20Sopenharmony_ci const char *findkey, befs_off_t * value); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic char *befs_bt_get_key(struct super_block *sb, 1168c2ecf20Sopenharmony_ci struct befs_btree_node *node, 1178c2ecf20Sopenharmony_ci int index, u16 * keylen); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistatic int befs_compare_strings(const void *key1, int keylen1, 1208c2ecf20Sopenharmony_ci const void *key2, int keylen2); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci/** 1238c2ecf20Sopenharmony_ci * befs_bt_read_super() - read in btree superblock convert to cpu byteorder 1248c2ecf20Sopenharmony_ci * @sb: Filesystem superblock 1258c2ecf20Sopenharmony_ci * @ds: Datastream to read from 1268c2ecf20Sopenharmony_ci * @sup: Buffer in which to place the btree superblock 1278c2ecf20Sopenharmony_ci * 1288c2ecf20Sopenharmony_ci * Calls befs_read_datastream to read in the btree superblock and 1298c2ecf20Sopenharmony_ci * makes sure it is in cpu byteorder, byteswapping if necessary. 1308c2ecf20Sopenharmony_ci * Return: BEFS_OK on success and if *@sup contains the btree superblock in cpu 1318c2ecf20Sopenharmony_ci * byte order. Otherwise return BEFS_ERR on error. 1328c2ecf20Sopenharmony_ci */ 1338c2ecf20Sopenharmony_cistatic int 1348c2ecf20Sopenharmony_cibefs_bt_read_super(struct super_block *sb, const befs_data_stream *ds, 1358c2ecf20Sopenharmony_ci befs_btree_super * sup) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci struct buffer_head *bh; 1388c2ecf20Sopenharmony_ci befs_disk_btree_super *od_sup; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci befs_debug(sb, "---> %s", __func__); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci bh = befs_read_datastream(sb, ds, 0, NULL); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci if (!bh) { 1458c2ecf20Sopenharmony_ci befs_error(sb, "Couldn't read index header."); 1468c2ecf20Sopenharmony_ci goto error; 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci od_sup = (befs_disk_btree_super *) bh->b_data; 1498c2ecf20Sopenharmony_ci befs_dump_index_entry(sb, od_sup); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci sup->magic = fs32_to_cpu(sb, od_sup->magic); 1528c2ecf20Sopenharmony_ci sup->node_size = fs32_to_cpu(sb, od_sup->node_size); 1538c2ecf20Sopenharmony_ci sup->max_depth = fs32_to_cpu(sb, od_sup->max_depth); 1548c2ecf20Sopenharmony_ci sup->data_type = fs32_to_cpu(sb, od_sup->data_type); 1558c2ecf20Sopenharmony_ci sup->root_node_ptr = fs64_to_cpu(sb, od_sup->root_node_ptr); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci brelse(bh); 1588c2ecf20Sopenharmony_ci if (sup->magic != BEFS_BTREE_MAGIC) { 1598c2ecf20Sopenharmony_ci befs_error(sb, "Index header has bad magic."); 1608c2ecf20Sopenharmony_ci goto error; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci befs_debug(sb, "<--- %s", __func__); 1648c2ecf20Sopenharmony_ci return BEFS_OK; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci error: 1678c2ecf20Sopenharmony_ci befs_debug(sb, "<--- %s ERROR", __func__); 1688c2ecf20Sopenharmony_ci return BEFS_ERR; 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci/** 1728c2ecf20Sopenharmony_ci * befs_bt_read_node - read in btree node and convert to cpu byteorder 1738c2ecf20Sopenharmony_ci * @sb: Filesystem superblock 1748c2ecf20Sopenharmony_ci * @ds: Datastream to read from 1758c2ecf20Sopenharmony_ci * @node: Buffer in which to place the btree node 1768c2ecf20Sopenharmony_ci * @node_off: Starting offset (in bytes) of the node in @ds 1778c2ecf20Sopenharmony_ci * 1788c2ecf20Sopenharmony_ci * Calls befs_read_datastream to read in the indicated btree node and 1798c2ecf20Sopenharmony_ci * makes sure its header fields are in cpu byteorder, byteswapping if 1808c2ecf20Sopenharmony_ci * necessary. 1818c2ecf20Sopenharmony_ci * Note: node->bh must be NULL when this function is called the first time. 1828c2ecf20Sopenharmony_ci * Don't forget brelse(node->bh) after last call. 1838c2ecf20Sopenharmony_ci * 1848c2ecf20Sopenharmony_ci * On success, returns BEFS_OK and *@node contains the btree node that 1858c2ecf20Sopenharmony_ci * starts at @node_off, with the node->head fields in cpu byte order. 1868c2ecf20Sopenharmony_ci * 1878c2ecf20Sopenharmony_ci * On failure, BEFS_ERR is returned. 1888c2ecf20Sopenharmony_ci */ 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic int 1918c2ecf20Sopenharmony_cibefs_bt_read_node(struct super_block *sb, const befs_data_stream *ds, 1928c2ecf20Sopenharmony_ci struct befs_btree_node *node, befs_off_t node_off) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci uint off = 0; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci befs_debug(sb, "---> %s", __func__); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci if (node->bh) 1998c2ecf20Sopenharmony_ci brelse(node->bh); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci node->bh = befs_read_datastream(sb, ds, node_off, &off); 2028c2ecf20Sopenharmony_ci if (!node->bh) { 2038c2ecf20Sopenharmony_ci befs_error(sb, "%s failed to read " 2048c2ecf20Sopenharmony_ci "node at %llu", __func__, node_off); 2058c2ecf20Sopenharmony_ci befs_debug(sb, "<--- %s ERROR", __func__); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci return BEFS_ERR; 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci node->od_node = 2108c2ecf20Sopenharmony_ci (befs_btree_nodehead *) ((void *) node->bh->b_data + off); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci befs_dump_index_node(sb, node->od_node); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci node->head.left = fs64_to_cpu(sb, node->od_node->left); 2158c2ecf20Sopenharmony_ci node->head.right = fs64_to_cpu(sb, node->od_node->right); 2168c2ecf20Sopenharmony_ci node->head.overflow = fs64_to_cpu(sb, node->od_node->overflow); 2178c2ecf20Sopenharmony_ci node->head.all_key_count = 2188c2ecf20Sopenharmony_ci fs16_to_cpu(sb, node->od_node->all_key_count); 2198c2ecf20Sopenharmony_ci node->head.all_key_length = 2208c2ecf20Sopenharmony_ci fs16_to_cpu(sb, node->od_node->all_key_length); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci befs_debug(sb, "<--- %s", __func__); 2238c2ecf20Sopenharmony_ci return BEFS_OK; 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci/** 2278c2ecf20Sopenharmony_ci * befs_btree_find - Find a key in a befs B+tree 2288c2ecf20Sopenharmony_ci * @sb: Filesystem superblock 2298c2ecf20Sopenharmony_ci * @ds: Datastream containing btree 2308c2ecf20Sopenharmony_ci * @key: Key string to lookup in btree 2318c2ecf20Sopenharmony_ci * @value: Value stored with @key 2328c2ecf20Sopenharmony_ci * 2338c2ecf20Sopenharmony_ci * On success, returns BEFS_OK and sets *@value to the value stored 2348c2ecf20Sopenharmony_ci * with @key (usually the disk block number of an inode). 2358c2ecf20Sopenharmony_ci * 2368c2ecf20Sopenharmony_ci * On failure, returns BEFS_ERR or BEFS_BT_NOT_FOUND. 2378c2ecf20Sopenharmony_ci * 2388c2ecf20Sopenharmony_ci * Algorithm: 2398c2ecf20Sopenharmony_ci * Read the superblock and rootnode of the b+tree. 2408c2ecf20Sopenharmony_ci * Drill down through the interior nodes using befs_find_key(). 2418c2ecf20Sopenharmony_ci * Once at the correct leaf node, use befs_find_key() again to get the 2428c2ecf20Sopenharmony_ci * actual value stored with the key. 2438c2ecf20Sopenharmony_ci */ 2448c2ecf20Sopenharmony_ciint 2458c2ecf20Sopenharmony_cibefs_btree_find(struct super_block *sb, const befs_data_stream *ds, 2468c2ecf20Sopenharmony_ci const char *key, befs_off_t * value) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci struct befs_btree_node *this_node; 2498c2ecf20Sopenharmony_ci befs_btree_super bt_super; 2508c2ecf20Sopenharmony_ci befs_off_t node_off; 2518c2ecf20Sopenharmony_ci int res; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci befs_debug(sb, "---> %s Key: %s", __func__, key); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci if (befs_bt_read_super(sb, ds, &bt_super) != BEFS_OK) { 2568c2ecf20Sopenharmony_ci befs_error(sb, 2578c2ecf20Sopenharmony_ci "befs_btree_find() failed to read index superblock"); 2588c2ecf20Sopenharmony_ci goto error; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci this_node = kmalloc(sizeof(struct befs_btree_node), 2628c2ecf20Sopenharmony_ci GFP_NOFS); 2638c2ecf20Sopenharmony_ci if (!this_node) { 2648c2ecf20Sopenharmony_ci befs_error(sb, "befs_btree_find() failed to allocate %zu " 2658c2ecf20Sopenharmony_ci "bytes of memory", sizeof(struct befs_btree_node)); 2668c2ecf20Sopenharmony_ci goto error; 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci this_node->bh = NULL; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci /* read in root node */ 2728c2ecf20Sopenharmony_ci node_off = bt_super.root_node_ptr; 2738c2ecf20Sopenharmony_ci if (befs_bt_read_node(sb, ds, this_node, node_off) != BEFS_OK) { 2748c2ecf20Sopenharmony_ci befs_error(sb, "befs_btree_find() failed to read " 2758c2ecf20Sopenharmony_ci "node at %llu", node_off); 2768c2ecf20Sopenharmony_ci goto error_alloc; 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci while (!befs_leafnode(this_node)) { 2808c2ecf20Sopenharmony_ci res = befs_find_key(sb, this_node, key, &node_off); 2818c2ecf20Sopenharmony_ci /* if no key set, try the overflow node */ 2828c2ecf20Sopenharmony_ci if (res == BEFS_BT_OVERFLOW) 2838c2ecf20Sopenharmony_ci node_off = this_node->head.overflow; 2848c2ecf20Sopenharmony_ci if (befs_bt_read_node(sb, ds, this_node, node_off) != BEFS_OK) { 2858c2ecf20Sopenharmony_ci befs_error(sb, "befs_btree_find() failed to read " 2868c2ecf20Sopenharmony_ci "node at %llu", node_off); 2878c2ecf20Sopenharmony_ci goto error_alloc; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci /* at a leaf node now, check if it is correct */ 2928c2ecf20Sopenharmony_ci res = befs_find_key(sb, this_node, key, value); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci brelse(this_node->bh); 2958c2ecf20Sopenharmony_ci kfree(this_node); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci if (res != BEFS_BT_MATCH) { 2988c2ecf20Sopenharmony_ci befs_error(sb, "<--- %s Key %s not found", __func__, key); 2998c2ecf20Sopenharmony_ci befs_debug(sb, "<--- %s ERROR", __func__); 3008c2ecf20Sopenharmony_ci *value = 0; 3018c2ecf20Sopenharmony_ci return BEFS_BT_NOT_FOUND; 3028c2ecf20Sopenharmony_ci } 3038c2ecf20Sopenharmony_ci befs_debug(sb, "<--- %s Found key %s, value %llu", __func__, 3048c2ecf20Sopenharmony_ci key, *value); 3058c2ecf20Sopenharmony_ci return BEFS_OK; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci error_alloc: 3088c2ecf20Sopenharmony_ci kfree(this_node); 3098c2ecf20Sopenharmony_ci error: 3108c2ecf20Sopenharmony_ci *value = 0; 3118c2ecf20Sopenharmony_ci befs_debug(sb, "<--- %s ERROR", __func__); 3128c2ecf20Sopenharmony_ci return BEFS_ERR; 3138c2ecf20Sopenharmony_ci} 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci/** 3168c2ecf20Sopenharmony_ci * befs_find_key - Search for a key within a node 3178c2ecf20Sopenharmony_ci * @sb: Filesystem superblock 3188c2ecf20Sopenharmony_ci * @node: Node to find the key within 3198c2ecf20Sopenharmony_ci * @findkey: Keystring to search for 3208c2ecf20Sopenharmony_ci * @value: If key is found, the value stored with the key is put here 3218c2ecf20Sopenharmony_ci * 3228c2ecf20Sopenharmony_ci * Finds exact match if one exists, and returns BEFS_BT_MATCH. 3238c2ecf20Sopenharmony_ci * If there is no match and node's value array is too small for key, return 3248c2ecf20Sopenharmony_ci * BEFS_BT_OVERFLOW. 3258c2ecf20Sopenharmony_ci * If no match and node should countain this key, return BEFS_BT_NOT_FOUND. 3268c2ecf20Sopenharmony_ci * 3278c2ecf20Sopenharmony_ci * Uses binary search instead of a linear. 3288c2ecf20Sopenharmony_ci */ 3298c2ecf20Sopenharmony_cistatic int 3308c2ecf20Sopenharmony_cibefs_find_key(struct super_block *sb, struct befs_btree_node *node, 3318c2ecf20Sopenharmony_ci const char *findkey, befs_off_t * value) 3328c2ecf20Sopenharmony_ci{ 3338c2ecf20Sopenharmony_ci int first, last, mid; 3348c2ecf20Sopenharmony_ci int eq; 3358c2ecf20Sopenharmony_ci u16 keylen; 3368c2ecf20Sopenharmony_ci int findkey_len; 3378c2ecf20Sopenharmony_ci char *thiskey; 3388c2ecf20Sopenharmony_ci fs64 *valarray; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci befs_debug(sb, "---> %s %s", __func__, findkey); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci findkey_len = strlen(findkey); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci /* if node can not contain key, just skip this node */ 3458c2ecf20Sopenharmony_ci last = node->head.all_key_count - 1; 3468c2ecf20Sopenharmony_ci thiskey = befs_bt_get_key(sb, node, last, &keylen); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci eq = befs_compare_strings(thiskey, keylen, findkey, findkey_len); 3498c2ecf20Sopenharmony_ci if (eq < 0) { 3508c2ecf20Sopenharmony_ci befs_debug(sb, "<--- node can't contain %s", findkey); 3518c2ecf20Sopenharmony_ci return BEFS_BT_OVERFLOW; 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci valarray = befs_bt_valarray(node); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci /* simple binary search */ 3578c2ecf20Sopenharmony_ci first = 0; 3588c2ecf20Sopenharmony_ci mid = 0; 3598c2ecf20Sopenharmony_ci while (last >= first) { 3608c2ecf20Sopenharmony_ci mid = (last + first) / 2; 3618c2ecf20Sopenharmony_ci befs_debug(sb, "first: %d, last: %d, mid: %d", first, last, 3628c2ecf20Sopenharmony_ci mid); 3638c2ecf20Sopenharmony_ci thiskey = befs_bt_get_key(sb, node, mid, &keylen); 3648c2ecf20Sopenharmony_ci eq = befs_compare_strings(thiskey, keylen, findkey, 3658c2ecf20Sopenharmony_ci findkey_len); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci if (eq == 0) { 3688c2ecf20Sopenharmony_ci befs_debug(sb, "<--- %s found %s at %d", 3698c2ecf20Sopenharmony_ci __func__, thiskey, mid); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci *value = fs64_to_cpu(sb, valarray[mid]); 3728c2ecf20Sopenharmony_ci return BEFS_BT_MATCH; 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci if (eq > 0) 3758c2ecf20Sopenharmony_ci last = mid - 1; 3768c2ecf20Sopenharmony_ci else 3778c2ecf20Sopenharmony_ci first = mid + 1; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci /* return an existing value so caller can arrive to a leaf node */ 3818c2ecf20Sopenharmony_ci if (eq < 0) 3828c2ecf20Sopenharmony_ci *value = fs64_to_cpu(sb, valarray[mid + 1]); 3838c2ecf20Sopenharmony_ci else 3848c2ecf20Sopenharmony_ci *value = fs64_to_cpu(sb, valarray[mid]); 3858c2ecf20Sopenharmony_ci befs_error(sb, "<--- %s %s not found", __func__, findkey); 3868c2ecf20Sopenharmony_ci befs_debug(sb, "<--- %s ERROR", __func__); 3878c2ecf20Sopenharmony_ci return BEFS_BT_NOT_FOUND; 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci/** 3918c2ecf20Sopenharmony_ci * befs_btree_read - Traverse leafnodes of a btree 3928c2ecf20Sopenharmony_ci * @sb: Filesystem superblock 3938c2ecf20Sopenharmony_ci * @ds: Datastream containing btree 3948c2ecf20Sopenharmony_ci * @key_no: Key number (alphabetical order) of key to read 3958c2ecf20Sopenharmony_ci * @bufsize: Size of the buffer to return key in 3968c2ecf20Sopenharmony_ci * @keybuf: Pointer to a buffer to put the key in 3978c2ecf20Sopenharmony_ci * @keysize: Length of the returned key 3988c2ecf20Sopenharmony_ci * @value: Value stored with the returned key 3998c2ecf20Sopenharmony_ci * 4008c2ecf20Sopenharmony_ci * Here's how it works: Key_no is the index of the key/value pair to 4018c2ecf20Sopenharmony_ci * return in keybuf/value. 4028c2ecf20Sopenharmony_ci * Bufsize is the size of keybuf (BEFS_NAME_LEN+1 is a good size). Keysize is 4038c2ecf20Sopenharmony_ci * the number of characters in the key (just a convenience). 4048c2ecf20Sopenharmony_ci * 4058c2ecf20Sopenharmony_ci * Algorithm: 4068c2ecf20Sopenharmony_ci * Get the first leafnode of the tree. See if the requested key is in that 4078c2ecf20Sopenharmony_ci * node. If not, follow the node->right link to the next leafnode. Repeat 4088c2ecf20Sopenharmony_ci * until the (key_no)th key is found or the tree is out of keys. 4098c2ecf20Sopenharmony_ci */ 4108c2ecf20Sopenharmony_ciint 4118c2ecf20Sopenharmony_cibefs_btree_read(struct super_block *sb, const befs_data_stream *ds, 4128c2ecf20Sopenharmony_ci loff_t key_no, size_t bufsize, char *keybuf, size_t * keysize, 4138c2ecf20Sopenharmony_ci befs_off_t * value) 4148c2ecf20Sopenharmony_ci{ 4158c2ecf20Sopenharmony_ci struct befs_btree_node *this_node; 4168c2ecf20Sopenharmony_ci befs_btree_super bt_super; 4178c2ecf20Sopenharmony_ci befs_off_t node_off; 4188c2ecf20Sopenharmony_ci int cur_key; 4198c2ecf20Sopenharmony_ci fs64 *valarray; 4208c2ecf20Sopenharmony_ci char *keystart; 4218c2ecf20Sopenharmony_ci u16 keylen; 4228c2ecf20Sopenharmony_ci int res; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci uint key_sum = 0; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci befs_debug(sb, "---> %s", __func__); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci if (befs_bt_read_super(sb, ds, &bt_super) != BEFS_OK) { 4298c2ecf20Sopenharmony_ci befs_error(sb, 4308c2ecf20Sopenharmony_ci "befs_btree_read() failed to read index superblock"); 4318c2ecf20Sopenharmony_ci goto error; 4328c2ecf20Sopenharmony_ci } 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci this_node = kmalloc(sizeof(struct befs_btree_node), GFP_NOFS); 4358c2ecf20Sopenharmony_ci if (this_node == NULL) { 4368c2ecf20Sopenharmony_ci befs_error(sb, "befs_btree_read() failed to allocate %zu " 4378c2ecf20Sopenharmony_ci "bytes of memory", sizeof(struct befs_btree_node)); 4388c2ecf20Sopenharmony_ci goto error; 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci node_off = bt_super.root_node_ptr; 4428c2ecf20Sopenharmony_ci this_node->bh = NULL; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci /* seeks down to first leafnode, reads it into this_node */ 4458c2ecf20Sopenharmony_ci res = befs_btree_seekleaf(sb, ds, &bt_super, this_node, &node_off); 4468c2ecf20Sopenharmony_ci if (res == BEFS_BT_EMPTY) { 4478c2ecf20Sopenharmony_ci brelse(this_node->bh); 4488c2ecf20Sopenharmony_ci kfree(this_node); 4498c2ecf20Sopenharmony_ci *value = 0; 4508c2ecf20Sopenharmony_ci *keysize = 0; 4518c2ecf20Sopenharmony_ci befs_debug(sb, "<--- %s Tree is EMPTY", __func__); 4528c2ecf20Sopenharmony_ci return BEFS_BT_EMPTY; 4538c2ecf20Sopenharmony_ci } else if (res == BEFS_ERR) { 4548c2ecf20Sopenharmony_ci goto error_alloc; 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci /* find the leaf node containing the key_no key */ 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci while (key_sum + this_node->head.all_key_count <= key_no) { 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci /* no more nodes to look in: key_no is too large */ 4628c2ecf20Sopenharmony_ci if (this_node->head.right == BEFS_BT_INVAL) { 4638c2ecf20Sopenharmony_ci *keysize = 0; 4648c2ecf20Sopenharmony_ci *value = 0; 4658c2ecf20Sopenharmony_ci befs_debug(sb, 4668c2ecf20Sopenharmony_ci "<--- %s END of keys at %llu", __func__, 4678c2ecf20Sopenharmony_ci (unsigned long long) 4688c2ecf20Sopenharmony_ci key_sum + this_node->head.all_key_count); 4698c2ecf20Sopenharmony_ci brelse(this_node->bh); 4708c2ecf20Sopenharmony_ci kfree(this_node); 4718c2ecf20Sopenharmony_ci return BEFS_BT_END; 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci key_sum += this_node->head.all_key_count; 4758c2ecf20Sopenharmony_ci node_off = this_node->head.right; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci if (befs_bt_read_node(sb, ds, this_node, node_off) != BEFS_OK) { 4788c2ecf20Sopenharmony_ci befs_error(sb, "%s failed to read node at %llu", 4798c2ecf20Sopenharmony_ci __func__, (unsigned long long)node_off); 4808c2ecf20Sopenharmony_ci goto error_alloc; 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci } 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci /* how many keys into this_node is key_no */ 4858c2ecf20Sopenharmony_ci cur_key = key_no - key_sum; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci /* get pointers to datastructures within the node body */ 4888c2ecf20Sopenharmony_ci valarray = befs_bt_valarray(this_node); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci keystart = befs_bt_get_key(sb, this_node, cur_key, &keylen); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci befs_debug(sb, "Read [%llu,%d]: keysize %d", 4938c2ecf20Sopenharmony_ci (long long unsigned int)node_off, (int)cur_key, 4948c2ecf20Sopenharmony_ci (int)keylen); 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci if (bufsize < keylen + 1) { 4978c2ecf20Sopenharmony_ci befs_error(sb, "%s keybuf too small (%zu) " 4988c2ecf20Sopenharmony_ci "for key of size %d", __func__, bufsize, keylen); 4998c2ecf20Sopenharmony_ci brelse(this_node->bh); 5008c2ecf20Sopenharmony_ci goto error_alloc; 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci strlcpy(keybuf, keystart, keylen + 1); 5048c2ecf20Sopenharmony_ci *value = fs64_to_cpu(sb, valarray[cur_key]); 5058c2ecf20Sopenharmony_ci *keysize = keylen; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci befs_debug(sb, "Read [%llu,%d]: Key \"%.*s\", Value %llu", node_off, 5088c2ecf20Sopenharmony_ci cur_key, keylen, keybuf, *value); 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci brelse(this_node->bh); 5118c2ecf20Sopenharmony_ci kfree(this_node); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci befs_debug(sb, "<--- %s", __func__); 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci return BEFS_OK; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci error_alloc: 5188c2ecf20Sopenharmony_ci kfree(this_node); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci error: 5218c2ecf20Sopenharmony_ci *keysize = 0; 5228c2ecf20Sopenharmony_ci *value = 0; 5238c2ecf20Sopenharmony_ci befs_debug(sb, "<--- %s ERROR", __func__); 5248c2ecf20Sopenharmony_ci return BEFS_ERR; 5258c2ecf20Sopenharmony_ci} 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci/** 5288c2ecf20Sopenharmony_ci * befs_btree_seekleaf - Find the first leafnode in the btree 5298c2ecf20Sopenharmony_ci * @sb: Filesystem superblock 5308c2ecf20Sopenharmony_ci * @ds: Datastream containing btree 5318c2ecf20Sopenharmony_ci * @bt_super: Pointer to the superblock of the btree 5328c2ecf20Sopenharmony_ci * @this_node: Buffer to return the leafnode in 5338c2ecf20Sopenharmony_ci * @node_off: Pointer to offset of current node within datastream. Modified 5348c2ecf20Sopenharmony_ci * by the function. 5358c2ecf20Sopenharmony_ci * 5368c2ecf20Sopenharmony_ci * Helper function for btree traverse. Moves the current position to the 5378c2ecf20Sopenharmony_ci * start of the first leaf node. 5388c2ecf20Sopenharmony_ci * 5398c2ecf20Sopenharmony_ci * Also checks for an empty tree. If there are no keys, returns BEFS_BT_EMPTY. 5408c2ecf20Sopenharmony_ci */ 5418c2ecf20Sopenharmony_cistatic int 5428c2ecf20Sopenharmony_cibefs_btree_seekleaf(struct super_block *sb, const befs_data_stream *ds, 5438c2ecf20Sopenharmony_ci befs_btree_super *bt_super, 5448c2ecf20Sopenharmony_ci struct befs_btree_node *this_node, 5458c2ecf20Sopenharmony_ci befs_off_t * node_off) 5468c2ecf20Sopenharmony_ci{ 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci befs_debug(sb, "---> %s", __func__); 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci if (befs_bt_read_node(sb, ds, this_node, *node_off) != BEFS_OK) { 5518c2ecf20Sopenharmony_ci befs_error(sb, "%s failed to read " 5528c2ecf20Sopenharmony_ci "node at %llu", __func__, *node_off); 5538c2ecf20Sopenharmony_ci goto error; 5548c2ecf20Sopenharmony_ci } 5558c2ecf20Sopenharmony_ci befs_debug(sb, "Seekleaf to root node %llu", *node_off); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci if (this_node->head.all_key_count == 0 && befs_leafnode(this_node)) { 5588c2ecf20Sopenharmony_ci befs_debug(sb, "<--- %s Tree is EMPTY", __func__); 5598c2ecf20Sopenharmony_ci return BEFS_BT_EMPTY; 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci while (!befs_leafnode(this_node)) { 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci if (this_node->head.all_key_count == 0) { 5658c2ecf20Sopenharmony_ci befs_debug(sb, "%s encountered " 5668c2ecf20Sopenharmony_ci "an empty interior node: %llu. Using Overflow " 5678c2ecf20Sopenharmony_ci "node: %llu", __func__, *node_off, 5688c2ecf20Sopenharmony_ci this_node->head.overflow); 5698c2ecf20Sopenharmony_ci *node_off = this_node->head.overflow; 5708c2ecf20Sopenharmony_ci } else { 5718c2ecf20Sopenharmony_ci fs64 *valarray = befs_bt_valarray(this_node); 5728c2ecf20Sopenharmony_ci *node_off = fs64_to_cpu(sb, valarray[0]); 5738c2ecf20Sopenharmony_ci } 5748c2ecf20Sopenharmony_ci if (befs_bt_read_node(sb, ds, this_node, *node_off) != BEFS_OK) { 5758c2ecf20Sopenharmony_ci befs_error(sb, "%s failed to read " 5768c2ecf20Sopenharmony_ci "node at %llu", __func__, *node_off); 5778c2ecf20Sopenharmony_ci goto error; 5788c2ecf20Sopenharmony_ci } 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci befs_debug(sb, "Seekleaf to child node %llu", *node_off); 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci befs_debug(sb, "Node %llu is a leaf node", *node_off); 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci return BEFS_OK; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci error: 5878c2ecf20Sopenharmony_ci befs_debug(sb, "<--- %s ERROR", __func__); 5888c2ecf20Sopenharmony_ci return BEFS_ERR; 5898c2ecf20Sopenharmony_ci} 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci/** 5928c2ecf20Sopenharmony_ci * befs_leafnode - Determine if the btree node is a leaf node or an 5938c2ecf20Sopenharmony_ci * interior node 5948c2ecf20Sopenharmony_ci * @node: Pointer to node structure to test 5958c2ecf20Sopenharmony_ci * 5968c2ecf20Sopenharmony_ci * Return 1 if leaf, 0 if interior 5978c2ecf20Sopenharmony_ci */ 5988c2ecf20Sopenharmony_cistatic int 5998c2ecf20Sopenharmony_cibefs_leafnode(struct befs_btree_node *node) 6008c2ecf20Sopenharmony_ci{ 6018c2ecf20Sopenharmony_ci /* all interior nodes (and only interior nodes) have an overflow node */ 6028c2ecf20Sopenharmony_ci if (node->head.overflow == BEFS_BT_INVAL) 6038c2ecf20Sopenharmony_ci return 1; 6048c2ecf20Sopenharmony_ci else 6058c2ecf20Sopenharmony_ci return 0; 6068c2ecf20Sopenharmony_ci} 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci/** 6098c2ecf20Sopenharmony_ci * befs_bt_keylen_index - Finds start of keylen index in a node 6108c2ecf20Sopenharmony_ci * @node: Pointer to the node structure to find the keylen index within 6118c2ecf20Sopenharmony_ci * 6128c2ecf20Sopenharmony_ci * Returns a pointer to the start of the key length index array 6138c2ecf20Sopenharmony_ci * of the B+tree node *@node 6148c2ecf20Sopenharmony_ci * 6158c2ecf20Sopenharmony_ci * "The length of all the keys in the node is added to the size of the 6168c2ecf20Sopenharmony_ci * header and then rounded up to a multiple of four to get the beginning 6178c2ecf20Sopenharmony_ci * of the key length index" (p.88, practical filesystem design). 6188c2ecf20Sopenharmony_ci * 6198c2ecf20Sopenharmony_ci * Except that rounding up to 8 works, and rounding up to 4 doesn't. 6208c2ecf20Sopenharmony_ci */ 6218c2ecf20Sopenharmony_cistatic fs16 * 6228c2ecf20Sopenharmony_cibefs_bt_keylen_index(struct befs_btree_node *node) 6238c2ecf20Sopenharmony_ci{ 6248c2ecf20Sopenharmony_ci const int keylen_align = 8; 6258c2ecf20Sopenharmony_ci unsigned long int off = 6268c2ecf20Sopenharmony_ci (sizeof (befs_btree_nodehead) + node->head.all_key_length); 6278c2ecf20Sopenharmony_ci ulong tmp = off % keylen_align; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci if (tmp) 6308c2ecf20Sopenharmony_ci off += keylen_align - tmp; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci return (fs16 *) ((void *) node->od_node + off); 6338c2ecf20Sopenharmony_ci} 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci/** 6368c2ecf20Sopenharmony_ci * befs_bt_valarray - Finds the start of value array in a node 6378c2ecf20Sopenharmony_ci * @node: Pointer to the node structure to find the value array within 6388c2ecf20Sopenharmony_ci * 6398c2ecf20Sopenharmony_ci * Returns a pointer to the start of the value array 6408c2ecf20Sopenharmony_ci * of the node pointed to by the node header 6418c2ecf20Sopenharmony_ci */ 6428c2ecf20Sopenharmony_cistatic fs64 * 6438c2ecf20Sopenharmony_cibefs_bt_valarray(struct befs_btree_node *node) 6448c2ecf20Sopenharmony_ci{ 6458c2ecf20Sopenharmony_ci void *keylen_index_start = (void *) befs_bt_keylen_index(node); 6468c2ecf20Sopenharmony_ci size_t keylen_index_size = node->head.all_key_count * sizeof (fs16); 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci return (fs64 *) (keylen_index_start + keylen_index_size); 6498c2ecf20Sopenharmony_ci} 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci/** 6528c2ecf20Sopenharmony_ci * befs_bt_keydata - Finds start of keydata array in a node 6538c2ecf20Sopenharmony_ci * @node: Pointer to the node structure to find the keydata array within 6548c2ecf20Sopenharmony_ci * 6558c2ecf20Sopenharmony_ci * Returns a pointer to the start of the keydata array 6568c2ecf20Sopenharmony_ci * of the node pointed to by the node header 6578c2ecf20Sopenharmony_ci */ 6588c2ecf20Sopenharmony_cistatic char * 6598c2ecf20Sopenharmony_cibefs_bt_keydata(struct befs_btree_node *node) 6608c2ecf20Sopenharmony_ci{ 6618c2ecf20Sopenharmony_ci return (char *) ((void *) node->od_node + sizeof (befs_btree_nodehead)); 6628c2ecf20Sopenharmony_ci} 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci/** 6658c2ecf20Sopenharmony_ci * befs_bt_get_key - returns a pointer to the start of a key 6668c2ecf20Sopenharmony_ci * @sb: filesystem superblock 6678c2ecf20Sopenharmony_ci * @node: node in which to look for the key 6688c2ecf20Sopenharmony_ci * @index: the index of the key to get 6698c2ecf20Sopenharmony_ci * @keylen: modified to be the length of the key at @index 6708c2ecf20Sopenharmony_ci * 6718c2ecf20Sopenharmony_ci * Returns a valid pointer into @node on success. 6728c2ecf20Sopenharmony_ci * Returns NULL on failure (bad input) and sets *@keylen = 0 6738c2ecf20Sopenharmony_ci */ 6748c2ecf20Sopenharmony_cistatic char * 6758c2ecf20Sopenharmony_cibefs_bt_get_key(struct super_block *sb, struct befs_btree_node *node, 6768c2ecf20Sopenharmony_ci int index, u16 * keylen) 6778c2ecf20Sopenharmony_ci{ 6788c2ecf20Sopenharmony_ci int prev_key_end; 6798c2ecf20Sopenharmony_ci char *keystart; 6808c2ecf20Sopenharmony_ci fs16 *keylen_index; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci if (index < 0 || index > node->head.all_key_count) { 6838c2ecf20Sopenharmony_ci *keylen = 0; 6848c2ecf20Sopenharmony_ci return NULL; 6858c2ecf20Sopenharmony_ci } 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci keystart = befs_bt_keydata(node); 6888c2ecf20Sopenharmony_ci keylen_index = befs_bt_keylen_index(node); 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci if (index == 0) 6918c2ecf20Sopenharmony_ci prev_key_end = 0; 6928c2ecf20Sopenharmony_ci else 6938c2ecf20Sopenharmony_ci prev_key_end = fs16_to_cpu(sb, keylen_index[index - 1]); 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci *keylen = fs16_to_cpu(sb, keylen_index[index]) - prev_key_end; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci return keystart + prev_key_end; 6988c2ecf20Sopenharmony_ci} 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci/** 7018c2ecf20Sopenharmony_ci * befs_compare_strings - compare two strings 7028c2ecf20Sopenharmony_ci * @key1: pointer to the first key to be compared 7038c2ecf20Sopenharmony_ci * @keylen1: length in bytes of key1 7048c2ecf20Sopenharmony_ci * @key2: pointer to the second key to be compared 7058c2ecf20Sopenharmony_ci * @keylen2: length in bytes of key2 7068c2ecf20Sopenharmony_ci * 7078c2ecf20Sopenharmony_ci * Returns 0 if @key1 and @key2 are equal. 7088c2ecf20Sopenharmony_ci * Returns >0 if @key1 is greater. 7098c2ecf20Sopenharmony_ci * Returns <0 if @key2 is greater. 7108c2ecf20Sopenharmony_ci */ 7118c2ecf20Sopenharmony_cistatic int 7128c2ecf20Sopenharmony_cibefs_compare_strings(const void *key1, int keylen1, 7138c2ecf20Sopenharmony_ci const void *key2, int keylen2) 7148c2ecf20Sopenharmony_ci{ 7158c2ecf20Sopenharmony_ci int len = min_t(int, keylen1, keylen2); 7168c2ecf20Sopenharmony_ci int result = strncmp(key1, key2, len); 7178c2ecf20Sopenharmony_ci if (result == 0) 7188c2ecf20Sopenharmony_ci result = keylen1 - keylen2; 7198c2ecf20Sopenharmony_ci return result; 7208c2ecf20Sopenharmony_ci} 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci/* These will be used for non-string keyed btrees */ 7238c2ecf20Sopenharmony_ci#if 0 7248c2ecf20Sopenharmony_cistatic int 7258c2ecf20Sopenharmony_cibtree_compare_int32(cont void *key1, int keylen1, const void *key2, int keylen2) 7268c2ecf20Sopenharmony_ci{ 7278c2ecf20Sopenharmony_ci return *(int32_t *) key1 - *(int32_t *) key2; 7288c2ecf20Sopenharmony_ci} 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_cistatic int 7318c2ecf20Sopenharmony_cibtree_compare_uint32(cont void *key1, int keylen1, 7328c2ecf20Sopenharmony_ci const void *key2, int keylen2) 7338c2ecf20Sopenharmony_ci{ 7348c2ecf20Sopenharmony_ci if (*(u_int32_t *) key1 == *(u_int32_t *) key2) 7358c2ecf20Sopenharmony_ci return 0; 7368c2ecf20Sopenharmony_ci else if (*(u_int32_t *) key1 > *(u_int32_t *) key2) 7378c2ecf20Sopenharmony_ci return 1; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci return -1; 7408c2ecf20Sopenharmony_ci} 7418c2ecf20Sopenharmony_cistatic int 7428c2ecf20Sopenharmony_cibtree_compare_int64(cont void *key1, int keylen1, const void *key2, int keylen2) 7438c2ecf20Sopenharmony_ci{ 7448c2ecf20Sopenharmony_ci if (*(int64_t *) key1 == *(int64_t *) key2) 7458c2ecf20Sopenharmony_ci return 0; 7468c2ecf20Sopenharmony_ci else if (*(int64_t *) key1 > *(int64_t *) key2) 7478c2ecf20Sopenharmony_ci return 1; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci return -1; 7508c2ecf20Sopenharmony_ci} 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_cistatic int 7538c2ecf20Sopenharmony_cibtree_compare_uint64(cont void *key1, int keylen1, 7548c2ecf20Sopenharmony_ci const void *key2, int keylen2) 7558c2ecf20Sopenharmony_ci{ 7568c2ecf20Sopenharmony_ci if (*(u_int64_t *) key1 == *(u_int64_t *) key2) 7578c2ecf20Sopenharmony_ci return 0; 7588c2ecf20Sopenharmony_ci else if (*(u_int64_t *) key1 > *(u_int64_t *) key2) 7598c2ecf20Sopenharmony_ci return 1; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci return -1; 7628c2ecf20Sopenharmony_ci} 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_cistatic int 7658c2ecf20Sopenharmony_cibtree_compare_float(cont void *key1, int keylen1, const void *key2, int keylen2) 7668c2ecf20Sopenharmony_ci{ 7678c2ecf20Sopenharmony_ci float result = *(float *) key1 - *(float *) key2; 7688c2ecf20Sopenharmony_ci if (result == 0.0f) 7698c2ecf20Sopenharmony_ci return 0; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci return (result < 0.0f) ? -1 : 1; 7728c2ecf20Sopenharmony_ci} 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_cistatic int 7758c2ecf20Sopenharmony_cibtree_compare_double(cont void *key1, int keylen1, 7768c2ecf20Sopenharmony_ci const void *key2, int keylen2) 7778c2ecf20Sopenharmony_ci{ 7788c2ecf20Sopenharmony_ci double result = *(double *) key1 - *(double *) key2; 7798c2ecf20Sopenharmony_ci if (result == 0.0) 7808c2ecf20Sopenharmony_ci return 0; 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci return (result < 0.0) ? -1 : 1; 7838c2ecf20Sopenharmony_ci} 7848c2ecf20Sopenharmony_ci#endif //0 785