Linux Audio

Check our new training course

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