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