2 * This file has been modified for the cdrkit suite.
4 * The behaviour and appearence of the program code below can differ to a major
5 * extent from the version distributed by the original author(s).
7 * For details, see Changelog file distributed with the cdrkit package. If you
8 * received this file from another source then ask the distributing person for
9 * a log of modifications.
13 /* @(#)node.c 1.2 02/02/10 joerg */
15 * hfsutils - tools for reading and writing Macintosh HFS volumes
16 * Copyright (C) 1996, 1997 Robert Leslie
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
43 # define NODESPACE(n) \
44 (HFS_BLOCKSZ - (n).roff[(n).nd.ndNRecs] - 2 * ((n).nd.ndNRecs + 1))
48 * DESCRIPTION: construct an empty node
50 void n_init(node *np, btree *bt, int type, int height)
58 np->nd.ndNHeight = height;
65 memset(np->data, 0, sizeof(np->data));
70 * DESCRIPTION: allocate a new b*-tree node
77 if (bt->hdr.bthFree == 0)
79 ERROR(EIO, "b*-tree full");
84 while (num < bt->hdr.bthNNodes && BMTST(bt->map, num))
87 if (num == bt->hdr.bthNNodes)
89 ERROR(EIO, "free b*-tree node not found");
98 bt->flags |= HFS_UPDATE_BTHDR;
105 * DESCRIPTION: deallocate a b*-tree node
107 void n_free(node *np)
111 BMCLR(bt->map, np->nnum);
114 bt->flags |= HFS_UPDATE_BTHDR;
118 * NAME: node->compact()
119 * DESCRIPTION: clean up a node, removing deleted records
121 void n_compact(node *np)
124 int offset, nrecs, i;
127 ptr = np->data + offset;
130 for (i = 0; i < (int)np->nd.ndNRecs; ++i)
135 rec = HFS_NODEREC(*np, i);
136 reclen = np->roff[i + 1] - np->roff[i];
138 if (HFS_RECKEYLEN(rec) > 0)
140 np->roff[nrecs++] = offset;
153 np->roff[nrecs] = offset;
154 np->nd.ndNRecs = nrecs;
158 * NAME: node->search()
159 * DESCRIPTION: locate a record in a node, or the record it should follow
161 int n_search(node *np, unsigned char *key)
166 for (i = np->nd.ndNRecs; i--; )
170 rec = HFS_NODEREC(*np, i);
172 if (HFS_RECKEYLEN(rec) == 0)
173 continue; /* deleted record */
175 comp = bt->compare(rec, key);
187 * NAME: node->index()
188 * DESCRIPTION: create an index record from a key and node pointer
190 void n_index(btree *bt, unsigned char *key, unsigned long nnum,
191 unsigned char *record, int *reclen)
193 if (bt == &bt->f.vol->cat)
195 /* force the key length to be 0x25 */
197 HFS_RECKEYLEN(record) = 0x25;
198 memset(record + 1, 0, 0x25);
199 memcpy(record + 1, key + 1, HFS_RECKEYLEN(key));
202 memcpy(record, key, HFS_RECKEYSKIP(key));
204 d_putl(HFS_RECDATA(record), nnum);
207 *reclen = HFS_RECKEYSKIP(record) + 4;
211 * NAME: node->split()
212 * DESCRIPTION: divide a node into two and insert a record
214 int n_split(node *left, unsigned char *record, int *reclen)
221 right.nd.ndBLink = left->nnum;
223 if (n_new(&right) < 0)
226 left->nd.ndFLink = right.nnum;
227 nrecs = left->nd.ndNRecs;
230 * Ensure node split leaves enough room for new record.
231 * The size calculations used are based on the NODESPACE() macro, but
232 * I don't know what the extra 2's and 1's are needed for.
233 * John Witford <jwitford@hutch.com.au>
235 n_search(&right, record);
239 if (right.rnum < mid)
242 && (int)left->roff[mid] + *reclen + 2 > HFS_BLOCKSZ - 2 * (mid + 1))
252 && (int)right.roff[nrecs] - (int)right.roff[mid] + (int)left->roff[0] + *reclen + 2 > HFS_BLOCKSZ - 2 * (mid + 1))
262 for (i = 0; i < nrecs; ++i)
265 rec = HFS_NODEREC(right, i);
267 rec = HFS_NODEREC(*left, i);
269 HFS_RECKEYLEN(rec) = 0;
273 for (i = 0; i < nrecs; ++i)
276 rec = HFS_NODEREC(right, i);
278 rec = HFS_NODEREC(*left, i);
280 HFS_RECKEYLEN(rec) = 0;
286 n_search(&right, record);
288 n_insertx(&right, record, *reclen);
291 n_search(left, record);
292 n_insertx(left, record, *reclen);
295 /* store the new/modified nodes */
297 if (bt_putnode(left) < 0 ||
298 bt_putnode(&right) < 0)
301 /* create an index record for the new node in the parent */
303 n_index(right.bt, HFS_NODEREC(right, 0), right.nnum, record, reclen);
305 /* update link pointers */
307 if (left->bt->hdr.bthLNode == left->nnum)
309 left->bt->hdr.bthLNode = right.nnum;
310 left->bt->flags |= HFS_UPDATE_BTHDR;
313 if (right.nd.ndFLink)
318 n.nnum = right.nd.ndFLink;
320 if (bt_getnode(&n) < 0)
323 n.nd.ndBLink = right.nnum;
325 if (bt_putnode(&n) < 0)
333 * NAME: node->insertx()
334 * DESCRIPTION: insert a record into a node (which must already have room)
336 void n_insertx(node *np, unsigned char *record, int reclen)
343 /* push other records down to make room */
345 for (ptr = HFS_NODEREC(*np, np->nd.ndNRecs) + reclen;
346 ptr > HFS_NODEREC(*np, rnum) + reclen; --ptr)
347 *(ptr - 1) = *(ptr - 1 - reclen);
351 for (i = np->nd.ndNRecs; i > rnum; --i)
352 np->roff[i] = np->roff[i - 1] + reclen;
354 /* write the new record */
356 memcpy(HFS_NODEREC(*np, rnum), record, reclen);
360 * NAME: node->insert()
361 * DESCRIPTION: insert a new record into a node; return a record for parent
363 int n_insert(node *np, unsigned char *record, int *reclen)
367 /* check for free space */
369 if (np->nd.ndNRecs >= HFS_MAXRECS ||
370 *reclen + 2 > (int)NODESPACE(*np))
371 return n_split(np, record, reclen);
373 n_insertx(np, record, *reclen);
376 return bt_putnode(np);
380 * NAME: node->merge()
381 * DESCRIPTION: combine two nodes into a single node
383 int n_merge(node *right, node *left, unsigned char *record, int *flag)
387 /* copy records and offsets */
389 memcpy(HFS_NODEREC(*left, left->nd.ndNRecs), HFS_NODEREC(*right, 0),
390 right->roff[right->nd.ndNRecs] - right->roff[0]);
392 offset = left->roff[left->nd.ndNRecs] - right->roff[0];
394 for (i = 1; i <= (int)right->nd.ndNRecs; ++i)
395 left->roff[++left->nd.ndNRecs] = offset + right->roff[i];
397 /* update link pointers */
399 left->nd.ndFLink = right->nd.ndFLink;
401 if (bt_putnode(left) < 0)
404 if (right->bt->hdr.bthLNode == right->nnum)
406 right->bt->hdr.bthLNode = left->nnum;
407 right->bt->flags |= HFS_UPDATE_BTHDR;
410 if (right->nd.ndFLink)
415 n.nnum = right->nd.ndFLink;
417 if (bt_getnode(&n) < 0)
420 n.nd.ndBLink = left->nnum;
422 if (bt_putnode(&n) < 0)
428 HFS_RECKEYLEN(record) = 0;
435 * NAME: node->delete()
436 * DESCRIPTION: remove a record from a node
438 int n_delete(node *np, unsigned char *record, int *flag)
443 rec = HFS_NODEREC(*np, np->rnum);
445 HFS_RECKEYLEN(rec) = 0;
448 /* see if we can merge with our left sibling */
451 left.nnum = np->nd.ndBLink;
455 if (bt_getnode(&left) < 0)
458 if ((int)(np->nd.ndNRecs + left.nd.ndNRecs) <= HFS_MAXRECS &&
459 (int)(np->roff[np->nd.ndNRecs] - np->roff[0] +
460 2 * np->nd.ndNRecs) <= (int)NODESPACE(left))
461 return n_merge(np, &left, record, flag);
466 /* special case: first record changed; update parent record key */
468 n_index(np->bt, HFS_NODEREC(*np, 0), np->nnum, record, 0);
472 return bt_putnode(np);