/* * NAME: node->merge() * DESCRIPTION: combine two nodes into a single node */ int n_merge(node *right, node *left, unsigned char *record, int *flag) { int i, offset; /* copy records and offsets */ memcpy(HFS_NODEREC(*left, left->nd.ndNRecs), HFS_NODEREC(*right, 0), right->roff[right->nd.ndNRecs] - right->roff[0]); offset = left->roff[left->nd.ndNRecs] - right->roff[0]; for (i = 1; i <= (int)right->nd.ndNRecs; ++i) left->roff[++left->nd.ndNRecs] = offset + right->roff[i]; /* update link pointers */ left->nd.ndFLink = right->nd.ndFLink; if (bt_putnode(left) < 0) return -1; if (right->bt->hdr.bthLNode == right->nnum) { right->bt->hdr.bthLNode = left->nnum; right->bt->flags |= HFS_UPDATE_BTHDR; } if (right->nd.ndFLink) { node n; n.bt = right->bt; n.nnum = right->nd.ndFLink; if (bt_getnode(&n) < 0) return -1; n.nd.ndBLink = left->nnum; if (bt_putnode(&n) < 0) return -1; } n_free(right); HFS_RECKEYLEN(record) = 0; *flag = 1; return 0; }
/* * NAME: join() * DESCRIPTION: combine two nodes into a single node */ static int join(node *left, node *right, byte *record, int *flag) { int i, offset; /* copy records and offsets */ memcpy(HFS_NODEREC(*left, left->nd.ndNRecs), HFS_NODEREC(*right, 0), NODEUSED(*right)); offset = left->roff[left->nd.ndNRecs] - right->roff[0]; for (i = 1; i <= right->nd.ndNRecs; ++i) left->roff[++left->nd.ndNRecs] = offset + right->roff[i]; if (bt_putnode(left) == -1) goto fail; /* eliminate node and update link pointers */ if (n_free(right) == -1) goto fail; HFS_SETKEYLEN(record, 0); *flag = 1; return 0; fail: return -1; }
/* * NAME: node->free() * DESCRIPTION: deallocate and remove a b*-tree node */ int n_free(node *np) { btree *bt = np->bt; node sib; if (bt->hdr.bthFNode == np->nnum) bt->hdr.bthFNode = np->nd.ndFLink; if (bt->hdr.bthLNode == np->nnum) bt->hdr.bthLNode = np->nd.ndBLink; if (np->nd.ndFLink > 0) { if (bt_getnode(&sib, bt, np->nd.ndFLink) == -1) goto fail; sib.nd.ndBLink = np->nd.ndBLink; if (bt_putnode(&sib) == -1) goto fail; } if (np->nd.ndBLink > 0) { if (bt_getnode(&sib, bt, np->nd.ndBLink) == -1) goto fail; sib.nd.ndFLink = np->nd.ndFLink; if (bt_putnode(&sib) == -1) goto fail; } BMCLR(bt->map, np->nnum); ++bt->hdr.bthFree; bt->flags |= HFS_BT_UPDATE_HDR; return 0; fail: return -1; }
/* * NAME: vol->putextrec() * DESCRIPTION: store extent information */ int v_putextrec(const ExtDataRec *data, node *np) { byte pdata[HFS_EXTDATALEN], *ptr; int len = 0; r_packextdata(data, pdata, &len); ptr = HFS_NODEREC(*np, np->rnum); memcpy(HFS_RECDATA(ptr), pdata, len); return bt_putnode(np); }
/* * NAME: vol->putcatrec() * DESCRIPTION: store catalog information */ int v_putcatrec(CatDataRec *data, node *np) { unsigned char pdata[HFS_CATDATALEN], *ptr; int len = 0; r_packcatdata(data, pdata, &len); ptr = HFS_NODEREC(*np, np->rnum); memcpy(HFS_RECDATA(ptr), pdata, len); return bt_putnode(np); }
/* * NAME: node->insert() * DESCRIPTION: insert a new record into a node; return a record for parent */ int n_insert(node *np, byte *record, unsigned int *reclen) { /* check for free space */ if (np->nd.ndNRecs >= HFS_MAX_NRECS || *reclen + 2 > NODEFREE(*np)) return split(np, record, reclen); n_insertx(np, record, *reclen); *reclen = 0; return bt_putnode(np); }
/* * NAME: node->insert() * DESCRIPTION: insert a new record into a node; return a record for parent */ int n_insert(node *np, unsigned char *record, int *reclen) { n_compact(np); /* check for free space */ if (np->nd.ndNRecs >= HFS_MAXRECS || *reclen + 2 > (int)NODESPACE(*np)) return n_split(np, record, reclen); n_insertx(np, record, *reclen); *reclen = 0; return bt_putnode(np); }
/* * NAME: node->delete() * DESCRIPTION: remove a record from a node */ int n_delete(node *np, byte *record, int *flag) { byte *rec; rec = HFS_NODEREC(*np, np->rnum); HFS_SETKEYLEN(rec, 0); compact(np); if (np->nd.ndNRecs == 0) { if (n_free(np) == -1) goto fail; HFS_SETKEYLEN(record, 0); *flag = 1; return 0; } /* see if we can join with our left sibling */ if (np->nd.ndBLink > 0) { node left; if (bt_getnode(&left, np->bt, np->nd.ndBLink) == -1) goto fail; if (np->nd.ndNRecs + left.nd.ndNRecs <= HFS_MAX_NRECS && NODEUSED(*np) + 2 * np->nd.ndNRecs <= NODEFREE(left)) return join(&left, np, record, flag); } if (np->rnum == 0) { /* special case: first record changed; update parent record key */ n_index(np, record, 0); *flag = 1; } return bt_putnode(np); fail: return -1; }
/* * NAME: node->delete() * DESCRIPTION: remove a record from a node */ int n_delete(node *np, unsigned char *record, int *flag) { node left; unsigned char *rec; rec = HFS_NODEREC(*np, np->rnum); HFS_RECKEYLEN(rec) = 0; n_compact(np); /* see if we can merge with our left sibling */ left.bt = np->bt; left.nnum = np->nd.ndBLink; if (left.nnum > 0) { if (bt_getnode(&left) < 0) return -1; if ((int)(np->nd.ndNRecs + left.nd.ndNRecs) <= HFS_MAXRECS && (int)(np->roff[np->nd.ndNRecs] - np->roff[0] + 2 * np->nd.ndNRecs) <= (int)NODESPACE(left)) return n_merge(np, &left, record, flag); } if (np->rnum == 0) { /* special case: first record changed; update parent record key */ n_index(np->bt, HFS_NODEREC(*np, 0), np->nnum, record, 0); *flag = 1; } return bt_putnode(np); }
/* * NAME: split() * DESCRIPTION: divide a node into two and insert a record */ static int split(node *left, byte *record, unsigned int *reclen) { btree *bt = left->bt; node n, *right = &n, *side = 0; int mark, i; /* create a second node by cloning the first */ *right = *left; if (n_new(right) == -1) goto fail; left->nd.ndFLink = right->nnum; right->nd.ndBLink = left->nnum; /* divide all records evenly between the two nodes */ mark = (NODEUSED(*left) + 2 * left->nd.ndNRecs + *reclen + 2) >> 1; if (left->rnum == -1) { side = left; mark -= *reclen + 2; } for (i = 0; i < left->nd.ndNRecs; ++i) { node *np; byte *rec; np = (mark > 0) ? right : left; rec = HFS_NODEREC(*np, i); mark -= HFS_RECLEN(*np, i) + 2; HFS_SETKEYLEN(rec, 0); if (left->rnum == i) { side = (mark > 0) ? left : right; mark -= *reclen + 2; } } compact(left); compact(right); /* insert the new record and store the modified nodes */ ASSERT(side); n_search(side, record); n_insertx(side, record, *reclen); if (bt_putnode(left) == -1 || bt_putnode(right) == -1) goto fail; /* create an index record in the parent for the new node */ n_index(right, record, reclen); /* update link pointers */ if (bt->hdr.bthLNode == left->nnum) { bt->hdr.bthLNode = right->nnum; bt->flags |= HFS_BT_UPDATE_HDR; } if (right->nd.ndFLink > 0) { node sib; if (bt_getnode(&sib, right->bt, right->nd.ndFLink) == -1) goto fail; sib.nd.ndBLink = right->nnum; if (bt_putnode(&sib) == -1) goto fail; } return 0; fail: return -1; }
/* * NAME: node->split() * DESCRIPTION: divide a node into two and insert a record */ int n_split(node *left, unsigned char *record, int *reclen) { node right; int nrecs, i, mid; unsigned char *rec; right = *left; right.nd.ndBLink = left->nnum; if (n_new(&right) < 0) return -1; left->nd.ndFLink = right.nnum; nrecs = left->nd.ndNRecs; /* * Ensure node split leaves enough room for new record. * The size calculations used are based on the NODESPACE() macro, but * I don't know what the extra 2's and 1's are needed for. * John Witford <*****@*****.**> */ n_search(&right, record); mid = nrecs/2; for(;;) { if (right.rnum < mid) { if ( mid > 0 && (int)left->roff[mid] + *reclen + 2 > HFS_BLOCKSZ - 2 * (mid + 1)) { --mid; if (mid > 0) continue; } } else { if ( mid < nrecs && (int)right.roff[nrecs] - (int)right.roff[mid] + (int)left->roff[0] + *reclen + 2 > HFS_BLOCKSZ - 2 * (mid + 1)) { ++mid; if (mid < nrecs) continue; } } break; } for (i = 0; i < nrecs; ++i) { if (i < mid) rec = HFS_NODEREC(right, i); else rec = HFS_NODEREC(*left, i); HFS_RECKEYLEN(rec) = 0; } /* original code ... for (i = 0; i < nrecs; ++i) { if (i < nrecs / 2) rec = HFS_NODEREC(right, i); else rec = HFS_NODEREC(*left, i); HFS_RECKEYLEN(rec) = 0; } */ n_compact(left); n_compact(&right); n_search(&right, record); if (right.rnum >= 0) n_insertx(&right, record, *reclen); else { n_search(left, record); n_insertx(left, record, *reclen); } /* store the new/modified nodes */ if (bt_putnode(left) < 0 || bt_putnode(&right) < 0) return -1; /* create an index record for the new node in the parent */ n_index(right.bt, HFS_NODEREC(right, 0), right.nnum, record, reclen); /* update link pointers */ if (left->bt->hdr.bthLNode == left->nnum) { left->bt->hdr.bthLNode = right.nnum; left->bt->flags |= HFS_UPDATE_BTHDR; } if (right.nd.ndFLink) { node n; n.bt = right.bt; n.nnum = right.nd.ndFLink; if (bt_getnode(&n) < 0) return -1; n.nd.ndBLink = right.nnum; if (bt_putnode(&n) < 0) return -1; } return 0; }
/* * NAME: node->split() * DESCRIPTION: divide a node into two and insert a record */ int n_split(node *left, unsigned char *record, int *reclen) { node right; int nrecs, i; unsigned char *rec; right = *left; right.nd.ndBLink = left->nnum; if (n_new(&right) < 0) return -1; left->nd.ndFLink = right.nnum; nrecs = left->nd.ndNRecs; for (i = 0; i < nrecs; ++i) { if (i < nrecs / 2) rec = HFS_NODEREC(right, i); else rec = HFS_NODEREC(*left, i); HFS_RECKEYLEN(rec) = 0; } n_compact(left); n_compact(&right); n_search(&right, record); if (right.rnum >= 0) n_insertx(&right, record, *reclen); else { n_search(left, record); n_insertx(left, record, *reclen); } /* store the new/modified nodes */ if (bt_putnode(left) < 0 || bt_putnode(&right) < 0) return -1; /* create an index record for the new node in the parent */ n_index(right.bt, HFS_NODEREC(right, 0), right.nnum, record, reclen); /* update link pointers */ if (left->bt->hdr.bthLNode == left->nnum) { left->bt->hdr.bthLNode = right.nnum; left->bt->flags |= HFS_UPDATE_BTHDR; } if (right.nd.ndFLink) { node n; n.bt = right.bt; n.nnum = right.nd.ndFLink; if (bt_getnode(&n) < 0) return -1; n.nd.ndBLink = right.nnum; if (bt_putnode(&n) < 0) return -1; } return 0; }