Merge git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-2.6-nmw
[pandora-kernel.git] / fs / hfsplus / brec.c
1 /*
2  *  linux/fs/hfsplus/brec.c
3  *
4  * Copyright (C) 2001
5  * Brad Boyer (flar@allandria.com)
6  * (C) 2003 Ardis Technologies <roman@ardistech.com>
7  *
8  * Handle individual btree records
9  */
10
11 #include "hfsplus_fs.h"
12 #include "hfsplus_raw.h"
13
14 static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd);
15 static int hfs_brec_update_parent(struct hfs_find_data *fd);
16 static int hfs_btree_inc_height(struct hfs_btree *);
17
18 /* Get the length and offset of the given record in the given node */
19 u16 hfs_brec_lenoff(struct hfs_bnode *node, u16 rec, u16 *off)
20 {
21         __be16 retval[2];
22         u16 dataoff;
23
24         dataoff = node->tree->node_size - (rec + 2) * 2;
25         hfs_bnode_read(node, retval, dataoff, 4);
26         *off = be16_to_cpu(retval[1]);
27         return be16_to_cpu(retval[0]) - *off;
28 }
29
30 /* Get the length of the key from a keyed record */
31 u16 hfs_brec_keylen(struct hfs_bnode *node, u16 rec)
32 {
33         u16 retval, recoff;
34
35         if (node->type != HFS_NODE_INDEX && node->type != HFS_NODE_LEAF)
36                 return 0;
37
38         if ((node->type == HFS_NODE_INDEX) &&
39            !(node->tree->attributes & HFS_TREE_VARIDXKEYS)) {
40                 retval = node->tree->max_key_len + 2;
41         } else {
42                 recoff = hfs_bnode_read_u16(node,
43                         node->tree->node_size - (rec + 1) * 2);
44                 if (!recoff)
45                         return 0;
46
47                 retval = hfs_bnode_read_u16(node, recoff) + 2;
48                 if (retval > node->tree->max_key_len + 2) {
49                         printk(KERN_ERR "hfs: keylen %d too large\n",
50                                 retval);
51                         retval = 0;
52                 }
53         }
54         return retval;
55 }
56
57 int hfs_brec_insert(struct hfs_find_data *fd, void *entry, int entry_len)
58 {
59         struct hfs_btree *tree;
60         struct hfs_bnode *node, *new_node;
61         int size, key_len, rec;
62         int data_off, end_off;
63         int idx_rec_off, data_rec_off, end_rec_off;
64         __be32 cnid;
65
66         tree = fd->tree;
67         if (!fd->bnode) {
68                 if (!tree->root)
69                         hfs_btree_inc_height(tree);
70                 fd->bnode = hfs_bnode_find(tree, tree->leaf_head);
71                 if (IS_ERR(fd->bnode))
72                         return PTR_ERR(fd->bnode);
73                 fd->record = -1;
74         }
75         new_node = NULL;
76         key_len = be16_to_cpu(fd->search_key->key_len) + 2;
77 again:
78         /* new record idx and complete record size */
79         rec = fd->record + 1;
80         size = key_len + entry_len;
81
82         node = fd->bnode;
83         hfs_bnode_dump(node);
84         /* get last offset */
85         end_rec_off = tree->node_size - (node->num_recs + 1) * 2;
86         end_off = hfs_bnode_read_u16(node, end_rec_off);
87         end_rec_off -= 2;
88         dprint(DBG_BNODE_MOD, "insert_rec: %d, %d, %d, %d\n",
89                 rec, size, end_off, end_rec_off);
90         if (size > end_rec_off - end_off) {
91                 if (new_node)
92                         panic("not enough room!\n");
93                 new_node = hfs_bnode_split(fd);
94                 if (IS_ERR(new_node))
95                         return PTR_ERR(new_node);
96                 goto again;
97         }
98         if (node->type == HFS_NODE_LEAF) {
99                 tree->leaf_count++;
100                 mark_inode_dirty(tree->inode);
101         }
102         node->num_recs++;
103         /* write new last offset */
104         hfs_bnode_write_u16(node,
105                 offsetof(struct hfs_bnode_desc, num_recs),
106                 node->num_recs);
107         hfs_bnode_write_u16(node, end_rec_off, end_off + size);
108         data_off = end_off;
109         data_rec_off = end_rec_off + 2;
110         idx_rec_off = tree->node_size - (rec + 1) * 2;
111         if (idx_rec_off == data_rec_off)
112                 goto skip;
113         /* move all following entries */
114         do {
115                 data_off = hfs_bnode_read_u16(node, data_rec_off + 2);
116                 hfs_bnode_write_u16(node, data_rec_off, data_off + size);
117                 data_rec_off += 2;
118         } while (data_rec_off < idx_rec_off);
119
120         /* move data away */
121         hfs_bnode_move(node, data_off + size, data_off,
122                        end_off - data_off);
123
124 skip:
125         hfs_bnode_write(node, fd->search_key, data_off, key_len);
126         hfs_bnode_write(node, entry, data_off + key_len, entry_len);
127         hfs_bnode_dump(node);
128
129         if (new_node) {
130                 /* update parent key if we inserted a key
131                  * at the start of the first node
132                  */
133                 if (!rec && new_node != node)
134                         hfs_brec_update_parent(fd);
135
136                 hfs_bnode_put(fd->bnode);
137                 if (!new_node->parent) {
138                         hfs_btree_inc_height(tree);
139                         new_node->parent = tree->root;
140                 }
141                 fd->bnode = hfs_bnode_find(tree, new_node->parent);
142
143                 /* create index data entry */
144                 cnid = cpu_to_be32(new_node->this);
145                 entry = &cnid;
146                 entry_len = sizeof(cnid);
147
148                 /* get index key */
149                 hfs_bnode_read_key(new_node, fd->search_key, 14);
150                 __hfs_brec_find(fd->bnode, fd);
151
152                 hfs_bnode_put(new_node);
153                 new_node = NULL;
154
155                 if (tree->attributes & HFS_TREE_VARIDXKEYS)
156                         key_len = be16_to_cpu(fd->search_key->key_len) + 2;
157                 else {
158                         fd->search_key->key_len =
159                                 cpu_to_be16(tree->max_key_len);
160                         key_len = tree->max_key_len + 2;
161                 }
162                 goto again;
163         }
164
165         if (!rec)
166                 hfs_brec_update_parent(fd);
167
168         return 0;
169 }
170
171 int hfs_brec_remove(struct hfs_find_data *fd)
172 {
173         struct hfs_btree *tree;
174         struct hfs_bnode *node, *parent;
175         int end_off, rec_off, data_off, size;
176
177         tree = fd->tree;
178         node = fd->bnode;
179 again:
180         rec_off = tree->node_size - (fd->record + 2) * 2;
181         end_off = tree->node_size - (node->num_recs + 1) * 2;
182
183         if (node->type == HFS_NODE_LEAF) {
184                 tree->leaf_count--;
185                 mark_inode_dirty(tree->inode);
186         }
187         hfs_bnode_dump(node);
188         dprint(DBG_BNODE_MOD, "remove_rec: %d, %d\n",
189                 fd->record, fd->keylength + fd->entrylength);
190         if (!--node->num_recs) {
191                 hfs_bnode_unlink(node);
192                 if (!node->parent)
193                         return 0;
194                 parent = hfs_bnode_find(tree, node->parent);
195                 if (IS_ERR(parent))
196                         return PTR_ERR(parent);
197                 hfs_bnode_put(node);
198                 node = fd->bnode = parent;
199
200                 __hfs_brec_find(node, fd);
201                 goto again;
202         }
203         hfs_bnode_write_u16(node,
204                 offsetof(struct hfs_bnode_desc, num_recs),
205                 node->num_recs);
206
207         if (rec_off == end_off)
208                 goto skip;
209         size = fd->keylength + fd->entrylength;
210
211         do {
212                 data_off = hfs_bnode_read_u16(node, rec_off);
213                 hfs_bnode_write_u16(node, rec_off + 2, data_off - size);
214                 rec_off -= 2;
215         } while (rec_off >= end_off);
216
217         /* fill hole */
218         hfs_bnode_move(node, fd->keyoffset, fd->keyoffset + size,
219                        data_off - fd->keyoffset - size);
220 skip:
221         hfs_bnode_dump(node);
222         if (!fd->record)
223                 hfs_brec_update_parent(fd);
224         return 0;
225 }
226
227 static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd)
228 {
229         struct hfs_btree *tree;
230         struct hfs_bnode *node, *new_node, *next_node;
231         struct hfs_bnode_desc node_desc;
232         int num_recs, new_rec_off, new_off, old_rec_off;
233         int data_start, data_end, size;
234
235         tree = fd->tree;
236         node = fd->bnode;
237         new_node = hfs_bmap_alloc(tree);
238         if (IS_ERR(new_node))
239                 return new_node;
240         hfs_bnode_get(node);
241         dprint(DBG_BNODE_MOD, "split_nodes: %d - %d - %d\n",
242                 node->this, new_node->this, node->next);
243         new_node->next = node->next;
244         new_node->prev = node->this;
245         new_node->parent = node->parent;
246         new_node->type = node->type;
247         new_node->height = node->height;
248
249         if (node->next)
250                 next_node = hfs_bnode_find(tree, node->next);
251         else
252                 next_node = NULL;
253
254         if (IS_ERR(next_node)) {
255                 hfs_bnode_put(node);
256                 hfs_bnode_put(new_node);
257                 return next_node;
258         }
259
260         size = tree->node_size / 2 - node->num_recs * 2 - 14;
261         old_rec_off = tree->node_size - 4;
262         num_recs = 1;
263         for (;;) {
264                 data_start = hfs_bnode_read_u16(node, old_rec_off);
265                 if (data_start > size)
266                         break;
267                 old_rec_off -= 2;
268                 if (++num_recs < node->num_recs)
269                         continue;
270                 /* panic? */
271                 hfs_bnode_put(node);
272                 hfs_bnode_put(new_node);
273                 if (next_node)
274                         hfs_bnode_put(next_node);
275                 return ERR_PTR(-ENOSPC);
276         }
277
278         if (fd->record + 1 < num_recs) {
279                 /* new record is in the lower half,
280                  * so leave some more space there
281                  */
282                 old_rec_off += 2;
283                 num_recs--;
284                 data_start = hfs_bnode_read_u16(node, old_rec_off);
285         } else {
286                 hfs_bnode_put(node);
287                 hfs_bnode_get(new_node);
288                 fd->bnode = new_node;
289                 fd->record -= num_recs;
290                 fd->keyoffset -= data_start - 14;
291                 fd->entryoffset -= data_start - 14;
292         }
293         new_node->num_recs = node->num_recs - num_recs;
294         node->num_recs = num_recs;
295
296         new_rec_off = tree->node_size - 2;
297         new_off = 14;
298         size = data_start - new_off;
299         num_recs = new_node->num_recs;
300         data_end = data_start;
301         while (num_recs) {
302                 hfs_bnode_write_u16(new_node, new_rec_off, new_off);
303                 old_rec_off -= 2;
304                 new_rec_off -= 2;
305                 data_end = hfs_bnode_read_u16(node, old_rec_off);
306                 new_off = data_end - size;
307                 num_recs--;
308         }
309         hfs_bnode_write_u16(new_node, new_rec_off, new_off);
310         hfs_bnode_copy(new_node, 14, node, data_start, data_end - data_start);
311
312         /* update new bnode header */
313         node_desc.next = cpu_to_be32(new_node->next);
314         node_desc.prev = cpu_to_be32(new_node->prev);
315         node_desc.type = new_node->type;
316         node_desc.height = new_node->height;
317         node_desc.num_recs = cpu_to_be16(new_node->num_recs);
318         node_desc.reserved = 0;
319         hfs_bnode_write(new_node, &node_desc, 0, sizeof(node_desc));
320
321         /* update previous bnode header */
322         node->next = new_node->this;
323         hfs_bnode_read(node, &node_desc, 0, sizeof(node_desc));
324         node_desc.next = cpu_to_be32(node->next);
325         node_desc.num_recs = cpu_to_be16(node->num_recs);
326         hfs_bnode_write(node, &node_desc, 0, sizeof(node_desc));
327
328         /* update next bnode header */
329         if (next_node) {
330                 next_node->prev = new_node->this;
331                 hfs_bnode_read(next_node, &node_desc, 0, sizeof(node_desc));
332                 node_desc.prev = cpu_to_be32(next_node->prev);
333                 hfs_bnode_write(next_node, &node_desc, 0, sizeof(node_desc));
334                 hfs_bnode_put(next_node);
335         } else if (node->this == tree->leaf_tail) {
336                 /* if there is no next node, this might be the new tail */
337                 tree->leaf_tail = new_node->this;
338                 mark_inode_dirty(tree->inode);
339         }
340
341         hfs_bnode_dump(node);
342         hfs_bnode_dump(new_node);
343         hfs_bnode_put(node);
344
345         return new_node;
346 }
347
348 static int hfs_brec_update_parent(struct hfs_find_data *fd)
349 {
350         struct hfs_btree *tree;
351         struct hfs_bnode *node, *new_node, *parent;
352         int newkeylen, diff;
353         int rec, rec_off, end_rec_off;
354         int start_off, end_off;
355
356         tree = fd->tree;
357         node = fd->bnode;
358         new_node = NULL;
359         if (!node->parent)
360                 return 0;
361
362 again:
363         parent = hfs_bnode_find(tree, node->parent);
364         if (IS_ERR(parent))
365                 return PTR_ERR(parent);
366         __hfs_brec_find(parent, fd);
367         hfs_bnode_dump(parent);
368         rec = fd->record;
369
370         /* size difference between old and new key */
371         if (tree->attributes & HFS_TREE_VARIDXKEYS)
372                 newkeylen = hfs_bnode_read_u16(node, 14) + 2;
373         else
374                 fd->keylength = newkeylen = tree->max_key_len + 2;
375         dprint(DBG_BNODE_MOD, "update_rec: %d, %d, %d\n",
376                 rec, fd->keylength, newkeylen);
377
378         rec_off = tree->node_size - (rec + 2) * 2;
379         end_rec_off = tree->node_size - (parent->num_recs + 1) * 2;
380         diff = newkeylen - fd->keylength;
381         if (!diff)
382                 goto skip;
383         if (diff > 0) {
384                 end_off = hfs_bnode_read_u16(parent, end_rec_off);
385                 if (end_rec_off - end_off < diff) {
386
387                         dprint(DBG_BNODE_MOD, "hfs: splitting index node.\n");
388                         fd->bnode = parent;
389                         new_node = hfs_bnode_split(fd);
390                         if (IS_ERR(new_node))
391                                 return PTR_ERR(new_node);
392                         parent = fd->bnode;
393                         rec = fd->record;
394                         rec_off = tree->node_size - (rec + 2) * 2;
395                         end_rec_off = tree->node_size -
396                                 (parent->num_recs + 1) * 2;
397                 }
398         }
399
400         end_off = start_off = hfs_bnode_read_u16(parent, rec_off);
401         hfs_bnode_write_u16(parent, rec_off, start_off + diff);
402         start_off -= 4; /* move previous cnid too */
403
404         while (rec_off > end_rec_off) {
405                 rec_off -= 2;
406                 end_off = hfs_bnode_read_u16(parent, rec_off);
407                 hfs_bnode_write_u16(parent, rec_off, end_off + diff);
408         }
409         hfs_bnode_move(parent, start_off + diff, start_off,
410                        end_off - start_off);
411 skip:
412         hfs_bnode_copy(parent, fd->keyoffset, node, 14, newkeylen);
413         hfs_bnode_dump(parent);
414
415         hfs_bnode_put(node);
416         node = parent;
417
418         if (new_node) {
419                 __be32 cnid;
420
421                 fd->bnode = hfs_bnode_find(tree, new_node->parent);
422                 /* create index key and entry */
423                 hfs_bnode_read_key(new_node, fd->search_key, 14);
424                 cnid = cpu_to_be32(new_node->this);
425
426                 __hfs_brec_find(fd->bnode, fd);
427                 hfs_brec_insert(fd, &cnid, sizeof(cnid));
428                 hfs_bnode_put(fd->bnode);
429                 hfs_bnode_put(new_node);
430
431                 if (!rec) {
432                         if (new_node == node)
433                                 goto out;
434                         /* restore search_key */
435                         hfs_bnode_read_key(node, fd->search_key, 14);
436                 }
437         }
438
439         if (!rec && node->parent)
440                 goto again;
441 out:
442         fd->bnode = node;
443         return 0;
444 }
445
446 static int hfs_btree_inc_height(struct hfs_btree *tree)
447 {
448         struct hfs_bnode *node, *new_node;
449         struct hfs_bnode_desc node_desc;
450         int key_size, rec;
451         __be32 cnid;
452
453         node = NULL;
454         if (tree->root) {
455                 node = hfs_bnode_find(tree, tree->root);
456                 if (IS_ERR(node))
457                         return PTR_ERR(node);
458         }
459         new_node = hfs_bmap_alloc(tree);
460         if (IS_ERR(new_node)) {
461                 hfs_bnode_put(node);
462                 return PTR_ERR(new_node);
463         }
464
465         tree->root = new_node->this;
466         if (!tree->depth) {
467                 tree->leaf_head = tree->leaf_tail = new_node->this;
468                 new_node->type = HFS_NODE_LEAF;
469                 new_node->num_recs = 0;
470         } else {
471                 new_node->type = HFS_NODE_INDEX;
472                 new_node->num_recs = 1;
473         }
474         new_node->parent = 0;
475         new_node->next = 0;
476         new_node->prev = 0;
477         new_node->height = ++tree->depth;
478
479         node_desc.next = cpu_to_be32(new_node->next);
480         node_desc.prev = cpu_to_be32(new_node->prev);
481         node_desc.type = new_node->type;
482         node_desc.height = new_node->height;
483         node_desc.num_recs = cpu_to_be16(new_node->num_recs);
484         node_desc.reserved = 0;
485         hfs_bnode_write(new_node, &node_desc, 0, sizeof(node_desc));
486
487         rec = tree->node_size - 2;
488         hfs_bnode_write_u16(new_node, rec, 14);
489
490         if (node) {
491                 /* insert old root idx into new root */
492                 node->parent = tree->root;
493                 if (node->type == HFS_NODE_LEAF ||
494                     tree->attributes & HFS_TREE_VARIDXKEYS)
495                         key_size = hfs_bnode_read_u16(node, 14) + 2;
496                 else
497                         key_size = tree->max_key_len + 2;
498                 hfs_bnode_copy(new_node, 14, node, 14, key_size);
499
500                 if (!(tree->attributes & HFS_TREE_VARIDXKEYS)) {
501                         key_size = tree->max_key_len + 2;
502                         hfs_bnode_write_u16(new_node, 14, tree->max_key_len);
503                 }
504                 cnid = cpu_to_be32(node->this);
505                 hfs_bnode_write(new_node, &cnid, 14 + key_size, 4);
506
507                 rec -= 2;
508                 hfs_bnode_write_u16(new_node, rec, 14 + key_size + 4);
509
510                 hfs_bnode_put(node);
511         }
512         hfs_bnode_put(new_node);
513         mark_inode_dirty(tree->inode);
514
515         return 0;
516 }