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