0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include "btree.h"
0013
0014 static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd);
0015 static int hfs_brec_update_parent(struct hfs_find_data *fd);
0016 static int hfs_btree_inc_height(struct hfs_btree *tree);
0017
0018
0019 u16 hfs_brec_lenoff(struct hfs_bnode *node, u16 rec, u16 *off)
0020 {
0021 __be16 retval[2];
0022 u16 dataoff;
0023
0024 dataoff = node->tree->node_size - (rec + 2) * 2;
0025 hfs_bnode_read(node, retval, dataoff, 4);
0026 *off = be16_to_cpu(retval[1]);
0027 return be16_to_cpu(retval[0]) - *off;
0028 }
0029
0030
0031 u16 hfs_brec_keylen(struct hfs_bnode *node, u16 rec)
0032 {
0033 u16 retval, recoff;
0034
0035 if (node->type != HFS_NODE_INDEX && node->type != HFS_NODE_LEAF)
0036 return 0;
0037
0038 if ((node->type == HFS_NODE_INDEX) &&
0039 !(node->tree->attributes & HFS_TREE_VARIDXKEYS)) {
0040 if (node->tree->attributes & HFS_TREE_BIGKEYS)
0041 retval = node->tree->max_key_len + 2;
0042 else
0043 retval = node->tree->max_key_len + 1;
0044 } else {
0045 recoff = hfs_bnode_read_u16(node, node->tree->node_size - (rec + 1) * 2);
0046 if (!recoff)
0047 return 0;
0048 if (node->tree->attributes & HFS_TREE_BIGKEYS) {
0049 retval = hfs_bnode_read_u16(node, recoff) + 2;
0050 if (retval > node->tree->max_key_len + 2) {
0051 pr_err("keylen %d too large\n", retval);
0052 retval = 0;
0053 }
0054 } else {
0055 retval = (hfs_bnode_read_u8(node, recoff) | 1) + 1;
0056 if (retval > node->tree->max_key_len + 1) {
0057 pr_err("keylen %d too large\n", retval);
0058 retval = 0;
0059 }
0060 }
0061 }
0062 return retval;
0063 }
0064
0065 int hfs_brec_insert(struct hfs_find_data *fd, void *entry, int entry_len)
0066 {
0067 struct hfs_btree *tree;
0068 struct hfs_bnode *node, *new_node;
0069 int size, key_len, rec;
0070 int data_off, end_off;
0071 int idx_rec_off, data_rec_off, end_rec_off;
0072 __be32 cnid;
0073
0074 tree = fd->tree;
0075 if (!fd->bnode) {
0076 if (!tree->root)
0077 hfs_btree_inc_height(tree);
0078 node = hfs_bnode_find(tree, tree->leaf_head);
0079 if (IS_ERR(node))
0080 return PTR_ERR(node);
0081 fd->bnode = node;
0082 fd->record = -1;
0083 }
0084 new_node = NULL;
0085 key_len = (fd->search_key->key_len | 1) + 1;
0086 again:
0087
0088 rec = fd->record + 1;
0089 size = key_len + entry_len;
0090
0091 node = fd->bnode;
0092 hfs_bnode_dump(node);
0093
0094 end_rec_off = tree->node_size - (node->num_recs + 1) * 2;
0095 end_off = hfs_bnode_read_u16(node, end_rec_off);
0096 end_rec_off -= 2;
0097 hfs_dbg(BNODE_MOD, "insert_rec: %d, %d, %d, %d\n",
0098 rec, size, end_off, end_rec_off);
0099 if (size > end_rec_off - end_off) {
0100 if (new_node)
0101 panic("not enough room!\n");
0102 new_node = hfs_bnode_split(fd);
0103 if (IS_ERR(new_node))
0104 return PTR_ERR(new_node);
0105 goto again;
0106 }
0107 if (node->type == HFS_NODE_LEAF) {
0108 tree->leaf_count++;
0109 mark_inode_dirty(tree->inode);
0110 }
0111 node->num_recs++;
0112
0113 hfs_bnode_write_u16(node, offsetof(struct hfs_bnode_desc, num_recs), node->num_recs);
0114 hfs_bnode_write_u16(node, end_rec_off, end_off + size);
0115 data_off = end_off;
0116 data_rec_off = end_rec_off + 2;
0117 idx_rec_off = tree->node_size - (rec + 1) * 2;
0118 if (idx_rec_off == data_rec_off)
0119 goto skip;
0120
0121 do {
0122 data_off = hfs_bnode_read_u16(node, data_rec_off + 2);
0123 hfs_bnode_write_u16(node, data_rec_off, data_off + size);
0124 data_rec_off += 2;
0125 } while (data_rec_off < idx_rec_off);
0126
0127
0128 hfs_bnode_move(node, data_off + size, data_off,
0129 end_off - data_off);
0130
0131 skip:
0132 hfs_bnode_write(node, fd->search_key, data_off, key_len);
0133 hfs_bnode_write(node, entry, data_off + key_len, entry_len);
0134 hfs_bnode_dump(node);
0135
0136
0137
0138
0139
0140 if (!rec && new_node != node) {
0141 hfs_bnode_read_key(node, fd->search_key, data_off + size);
0142 hfs_brec_update_parent(fd);
0143 }
0144
0145 if (new_node) {
0146 hfs_bnode_put(fd->bnode);
0147 if (!new_node->parent) {
0148 hfs_btree_inc_height(tree);
0149 new_node->parent = tree->root;
0150 }
0151 fd->bnode = hfs_bnode_find(tree, new_node->parent);
0152
0153
0154 cnid = cpu_to_be32(new_node->this);
0155 entry = &cnid;
0156 entry_len = sizeof(cnid);
0157
0158
0159 hfs_bnode_read_key(new_node, fd->search_key, 14);
0160 __hfs_brec_find(fd->bnode, fd);
0161
0162 hfs_bnode_put(new_node);
0163 new_node = NULL;
0164
0165 if (tree->attributes & HFS_TREE_VARIDXKEYS)
0166 key_len = fd->search_key->key_len + 1;
0167 else {
0168 fd->search_key->key_len = tree->max_key_len;
0169 key_len = tree->max_key_len + 1;
0170 }
0171 goto again;
0172 }
0173
0174 return 0;
0175 }
0176
0177 int hfs_brec_remove(struct hfs_find_data *fd)
0178 {
0179 struct hfs_btree *tree;
0180 struct hfs_bnode *node, *parent;
0181 int end_off, rec_off, data_off, size;
0182
0183 tree = fd->tree;
0184 node = fd->bnode;
0185 again:
0186 rec_off = tree->node_size - (fd->record + 2) * 2;
0187 end_off = tree->node_size - (node->num_recs + 1) * 2;
0188
0189 if (node->type == HFS_NODE_LEAF) {
0190 tree->leaf_count--;
0191 mark_inode_dirty(tree->inode);
0192 }
0193 hfs_bnode_dump(node);
0194 hfs_dbg(BNODE_MOD, "remove_rec: %d, %d\n",
0195 fd->record, fd->keylength + fd->entrylength);
0196 if (!--node->num_recs) {
0197 hfs_bnode_unlink(node);
0198 if (!node->parent)
0199 return 0;
0200 parent = hfs_bnode_find(tree, node->parent);
0201 if (IS_ERR(parent))
0202 return PTR_ERR(parent);
0203 hfs_bnode_put(node);
0204 node = fd->bnode = parent;
0205
0206 __hfs_brec_find(node, fd);
0207 goto again;
0208 }
0209 hfs_bnode_write_u16(node, offsetof(struct hfs_bnode_desc, num_recs), node->num_recs);
0210
0211 if (rec_off == end_off)
0212 goto skip;
0213 size = fd->keylength + fd->entrylength;
0214
0215 do {
0216 data_off = hfs_bnode_read_u16(node, rec_off);
0217 hfs_bnode_write_u16(node, rec_off + 2, data_off - size);
0218 rec_off -= 2;
0219 } while (rec_off >= end_off);
0220
0221
0222 hfs_bnode_move(node, fd->keyoffset, fd->keyoffset + size,
0223 data_off - fd->keyoffset - size);
0224 skip:
0225 hfs_bnode_dump(node);
0226 if (!fd->record)
0227 hfs_brec_update_parent(fd);
0228 return 0;
0229 }
0230
0231 static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd)
0232 {
0233 struct hfs_btree *tree;
0234 struct hfs_bnode *node, *new_node, *next_node;
0235 struct hfs_bnode_desc node_desc;
0236 int num_recs, new_rec_off, new_off, old_rec_off;
0237 int data_start, data_end, size;
0238
0239 tree = fd->tree;
0240 node = fd->bnode;
0241 new_node = hfs_bmap_alloc(tree);
0242 if (IS_ERR(new_node))
0243 return new_node;
0244 hfs_bnode_get(node);
0245 hfs_dbg(BNODE_MOD, "split_nodes: %d - %d - %d\n",
0246 node->this, new_node->this, node->next);
0247 new_node->next = node->next;
0248 new_node->prev = node->this;
0249 new_node->parent = node->parent;
0250 new_node->type = node->type;
0251 new_node->height = node->height;
0252
0253 if (node->next)
0254 next_node = hfs_bnode_find(tree, node->next);
0255 else
0256 next_node = NULL;
0257
0258 if (IS_ERR(next_node)) {
0259 hfs_bnode_put(node);
0260 hfs_bnode_put(new_node);
0261 return next_node;
0262 }
0263
0264 size = tree->node_size / 2 - node->num_recs * 2 - 14;
0265 old_rec_off = tree->node_size - 4;
0266 num_recs = 1;
0267 for (;;) {
0268 data_start = hfs_bnode_read_u16(node, old_rec_off);
0269 if (data_start > size)
0270 break;
0271 old_rec_off -= 2;
0272 if (++num_recs < node->num_recs)
0273 continue;
0274
0275 hfs_bnode_put(node);
0276 hfs_bnode_put(new_node);
0277 if (next_node)
0278 hfs_bnode_put(next_node);
0279 return ERR_PTR(-ENOSPC);
0280 }
0281
0282 if (fd->record + 1 < num_recs) {
0283
0284
0285
0286 old_rec_off += 2;
0287 num_recs--;
0288 data_start = hfs_bnode_read_u16(node, old_rec_off);
0289 } else {
0290 hfs_bnode_put(node);
0291 hfs_bnode_get(new_node);
0292 fd->bnode = new_node;
0293 fd->record -= num_recs;
0294 fd->keyoffset -= data_start - 14;
0295 fd->entryoffset -= data_start - 14;
0296 }
0297 new_node->num_recs = node->num_recs - num_recs;
0298 node->num_recs = num_recs;
0299
0300 new_rec_off = tree->node_size - 2;
0301 new_off = 14;
0302 size = data_start - new_off;
0303 num_recs = new_node->num_recs;
0304 data_end = data_start;
0305 while (num_recs) {
0306 hfs_bnode_write_u16(new_node, new_rec_off, new_off);
0307 old_rec_off -= 2;
0308 new_rec_off -= 2;
0309 data_end = hfs_bnode_read_u16(node, old_rec_off);
0310 new_off = data_end - size;
0311 num_recs--;
0312 }
0313 hfs_bnode_write_u16(new_node, new_rec_off, new_off);
0314 hfs_bnode_copy(new_node, 14, node, data_start, data_end - data_start);
0315
0316
0317 node_desc.next = cpu_to_be32(new_node->next);
0318 node_desc.prev = cpu_to_be32(new_node->prev);
0319 node_desc.type = new_node->type;
0320 node_desc.height = new_node->height;
0321 node_desc.num_recs = cpu_to_be16(new_node->num_recs);
0322 node_desc.reserved = 0;
0323 hfs_bnode_write(new_node, &node_desc, 0, sizeof(node_desc));
0324
0325
0326 node->next = new_node->this;
0327 hfs_bnode_read(node, &node_desc, 0, sizeof(node_desc));
0328 node_desc.next = cpu_to_be32(node->next);
0329 node_desc.num_recs = cpu_to_be16(node->num_recs);
0330 hfs_bnode_write(node, &node_desc, 0, sizeof(node_desc));
0331
0332
0333 if (next_node) {
0334 next_node->prev = new_node->this;
0335 hfs_bnode_read(next_node, &node_desc, 0, sizeof(node_desc));
0336 node_desc.prev = cpu_to_be32(next_node->prev);
0337 hfs_bnode_write(next_node, &node_desc, 0, sizeof(node_desc));
0338 hfs_bnode_put(next_node);
0339 } else if (node->this == tree->leaf_tail) {
0340
0341 tree->leaf_tail = new_node->this;
0342 mark_inode_dirty(tree->inode);
0343 }
0344
0345 hfs_bnode_dump(node);
0346 hfs_bnode_dump(new_node);
0347 hfs_bnode_put(node);
0348
0349 return new_node;
0350 }
0351
0352 static int hfs_brec_update_parent(struct hfs_find_data *fd)
0353 {
0354 struct hfs_btree *tree;
0355 struct hfs_bnode *node, *new_node, *parent;
0356 int newkeylen, diff;
0357 int rec, rec_off, end_rec_off;
0358 int start_off, end_off;
0359
0360 tree = fd->tree;
0361 node = fd->bnode;
0362 new_node = NULL;
0363 if (!node->parent)
0364 return 0;
0365
0366 again:
0367 parent = hfs_bnode_find(tree, node->parent);
0368 if (IS_ERR(parent))
0369 return PTR_ERR(parent);
0370 __hfs_brec_find(parent, fd);
0371 if (fd->record < 0)
0372 return -ENOENT;
0373 hfs_bnode_dump(parent);
0374 rec = fd->record;
0375
0376
0377 if (tree->attributes & HFS_TREE_VARIDXKEYS)
0378 newkeylen = (hfs_bnode_read_u8(node, 14) | 1) + 1;
0379 else
0380 fd->keylength = newkeylen = tree->max_key_len + 1;
0381 hfs_dbg(BNODE_MOD, "update_rec: %d, %d, %d\n",
0382 rec, fd->keylength, newkeylen);
0383
0384 rec_off = tree->node_size - (rec + 2) * 2;
0385 end_rec_off = tree->node_size - (parent->num_recs + 1) * 2;
0386 diff = newkeylen - fd->keylength;
0387 if (!diff)
0388 goto skip;
0389 if (diff > 0) {
0390 end_off = hfs_bnode_read_u16(parent, end_rec_off);
0391 if (end_rec_off - end_off < diff) {
0392
0393 printk(KERN_DEBUG "splitting index node...\n");
0394 fd->bnode = parent;
0395 new_node = hfs_bnode_split(fd);
0396 if (IS_ERR(new_node))
0397 return PTR_ERR(new_node);
0398 parent = fd->bnode;
0399 rec = fd->record;
0400 rec_off = tree->node_size - (rec + 2) * 2;
0401 end_rec_off = tree->node_size - (parent->num_recs + 1) * 2;
0402 }
0403 }
0404
0405 end_off = start_off = hfs_bnode_read_u16(parent, rec_off);
0406 hfs_bnode_write_u16(parent, rec_off, start_off + diff);
0407 start_off -= 4;
0408
0409 while (rec_off > end_rec_off) {
0410 rec_off -= 2;
0411 end_off = hfs_bnode_read_u16(parent, rec_off);
0412 hfs_bnode_write_u16(parent, rec_off, end_off + diff);
0413 }
0414 hfs_bnode_move(parent, start_off + diff, start_off,
0415 end_off - start_off);
0416 skip:
0417 hfs_bnode_copy(parent, fd->keyoffset, node, 14, newkeylen);
0418 if (!(tree->attributes & HFS_TREE_VARIDXKEYS))
0419 hfs_bnode_write_u8(parent, fd->keyoffset, newkeylen - 1);
0420 hfs_bnode_dump(parent);
0421
0422 hfs_bnode_put(node);
0423 node = parent;
0424
0425 if (new_node) {
0426 __be32 cnid;
0427
0428 if (!new_node->parent) {
0429 hfs_btree_inc_height(tree);
0430 new_node->parent = tree->root;
0431 }
0432 fd->bnode = hfs_bnode_find(tree, new_node->parent);
0433
0434 hfs_bnode_read_key(new_node, fd->search_key, 14);
0435 cnid = cpu_to_be32(new_node->this);
0436
0437 __hfs_brec_find(fd->bnode, fd);
0438 hfs_brec_insert(fd, &cnid, sizeof(cnid));
0439 hfs_bnode_put(fd->bnode);
0440 hfs_bnode_put(new_node);
0441
0442 if (!rec) {
0443 if (new_node == node)
0444 goto out;
0445
0446 hfs_bnode_read_key(node, fd->search_key, 14);
0447 }
0448 new_node = NULL;
0449 }
0450
0451 if (!rec && node->parent)
0452 goto again;
0453 out:
0454 fd->bnode = node;
0455 return 0;
0456 }
0457
0458 static int hfs_btree_inc_height(struct hfs_btree *tree)
0459 {
0460 struct hfs_bnode *node, *new_node;
0461 struct hfs_bnode_desc node_desc;
0462 int key_size, rec;
0463 __be32 cnid;
0464
0465 node = NULL;
0466 if (tree->root) {
0467 node = hfs_bnode_find(tree, tree->root);
0468 if (IS_ERR(node))
0469 return PTR_ERR(node);
0470 }
0471 new_node = hfs_bmap_alloc(tree);
0472 if (IS_ERR(new_node)) {
0473 hfs_bnode_put(node);
0474 return PTR_ERR(new_node);
0475 }
0476
0477 tree->root = new_node->this;
0478 if (!tree->depth) {
0479 tree->leaf_head = tree->leaf_tail = new_node->this;
0480 new_node->type = HFS_NODE_LEAF;
0481 new_node->num_recs = 0;
0482 } else {
0483 new_node->type = HFS_NODE_INDEX;
0484 new_node->num_recs = 1;
0485 }
0486 new_node->parent = 0;
0487 new_node->next = 0;
0488 new_node->prev = 0;
0489 new_node->height = ++tree->depth;
0490
0491 node_desc.next = cpu_to_be32(new_node->next);
0492 node_desc.prev = cpu_to_be32(new_node->prev);
0493 node_desc.type = new_node->type;
0494 node_desc.height = new_node->height;
0495 node_desc.num_recs = cpu_to_be16(new_node->num_recs);
0496 node_desc.reserved = 0;
0497 hfs_bnode_write(new_node, &node_desc, 0, sizeof(node_desc));
0498
0499 rec = tree->node_size - 2;
0500 hfs_bnode_write_u16(new_node, rec, 14);
0501
0502 if (node) {
0503
0504 node->parent = tree->root;
0505 if (node->type == HFS_NODE_LEAF ||
0506 tree->attributes & HFS_TREE_VARIDXKEYS)
0507 key_size = hfs_bnode_read_u8(node, 14) + 1;
0508 else
0509 key_size = tree->max_key_len + 1;
0510 hfs_bnode_copy(new_node, 14, node, 14, key_size);
0511
0512 if (!(tree->attributes & HFS_TREE_VARIDXKEYS)) {
0513 key_size = tree->max_key_len + 1;
0514 hfs_bnode_write_u8(new_node, 14, tree->max_key_len);
0515 }
0516 key_size = (key_size + 1) & -2;
0517 cnid = cpu_to_be32(node->this);
0518 hfs_bnode_write(new_node, &cnid, 14 + key_size, 4);
0519
0520 rec -= 2;
0521 hfs_bnode_write_u16(new_node, rec, 14 + key_size + 4);
0522
0523 hfs_bnode_put(node);
0524 }
0525 hfs_bnode_put(new_node);
0526 mark_inode_dirty(tree->inode);
0527
0528 return 0;
0529 }