📄 node.c
字号:
/* * hfsutils - tools for reading and writing Macintosh HFS volumes * Copyright (C) 1996, 1997 Robert Leslie * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#include <mconfig.h>#include <stdxlib.h>#include <strdefs.h>#include <errno.h>#include "internal.h"#include "data.h"#include "btree.h"#include "node.h"# define NODESPACE(n) \ (HFS_BLOCKSZ - (n).roff[(n).nd.ndNRecs] - 2 * ((n).nd.ndNRecs + 1))/* * NAME: node->init() * DESCRIPTION: construct an empty node */void n_init(np, bt, type, height) node *np; btree *bt; int type; int height;{ np->bt = bt; np->nnum = -1; np->nd.ndFLink = 0; np->nd.ndBLink = 0; np->nd.ndType = type; np->nd.ndNHeight = height; np->nd.ndNRecs = 0; np->nd.ndResv2 = 0; np->rnum = -1; np->roff[0] = 0x00e; memset(np->data, 0, sizeof(np->data));}/* * NAME: node->new() * DESCRIPTION: allocate a new b*-tree node */int n_new(np) node *np;{ btree *bt = np->bt; unsigned long num; if (bt->hdr.bthFree == 0) { ERROR(EIO, "b*-tree full"); return -1; } num = 0; while (num < bt->hdr.bthNNodes && BMTST(bt->map, num)) ++num; if (num == bt->hdr.bthNNodes) { ERROR(EIO, "free b*-tree node not found"); return -1; } np->nnum = num; BMSET(bt->map, num); --bt->hdr.bthFree; bt->flags |= HFS_UPDATE_BTHDR; return 0;}/* * NAME: node->free() * DESCRIPTION: deallocate a b*-tree node */void n_free(np) node *np;{ btree *bt = np->bt; BMCLR(bt->map, np->nnum); ++bt->hdr.bthFree; bt->flags |= HFS_UPDATE_BTHDR;}/* * NAME: node->compact() * DESCRIPTION: clean up a node, removing deleted records */void n_compact(np) node *np;{ unsigned char *ptr; int offset, nrecs, i; offset = 0x00e; ptr = np->data + offset; nrecs = 0; for (i = 0; i < np->nd.ndNRecs; ++i) { unsigned char *rec; int reclen; rec = HFS_NODEREC(*np, i); reclen = np->roff[i + 1] - np->roff[i]; if (HFS_RECKEYLEN(rec) > 0) { np->roff[nrecs++] = offset; offset += reclen; if (ptr == rec) ptr += reclen; else { while (reclen--) *ptr++ = *rec++; } } } np->roff[nrecs] = offset; np->nd.ndNRecs = nrecs;}/* * NAME: node->search() * DESCRIPTION: locate a record in a node, or the record it should follow */int n_search(np, key) node *np; unsigned char *key;{ btree *bt = np->bt; int i, comp = -1; for (i = np->nd.ndNRecs; i--; ) { unsigned char *rec; rec = HFS_NODEREC(*np, i); if (HFS_RECKEYLEN(rec) == 0) continue; /* deleted record */ comp = bt->compare(rec, key); if (comp <= 0) break; } np->rnum = i; return comp == 0;}/* * NAME: node->index() * DESCRIPTION: create an index record from a key and node pointer */void n_index(bt, key, nnum, record, reclen) btree *bt; unsigned char *key; unsigned long nnum; unsigned char *record; int *reclen;{ if (bt == &bt->f.vol->cat) { /* force the key length to be 0x25 */ HFS_RECKEYLEN(record) = 0x25; memset(record + 1, 0, 0x25); memcpy(record + 1, key + 1, HFS_RECKEYLEN(key)); } else memcpy(record, key, HFS_RECKEYSKIP(key)); d_putl(HFS_RECDATA(record), nnum); if (reclen) *reclen = HFS_RECKEYSKIP(record) + 4;}/* * NAME: node->split() * DESCRIPTION: divide a node into two and insert a record */int n_split(left, record, reclen) 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 <jwitford@hutch.com.au> */ n_search(&right, record); mid = nrecs/2; for(;;) { if (right.rnum < mid) { if ( mid > 0 && left->roff[mid] + *reclen + 2 > HFS_BLOCKSZ - 2 * (mid + 1)) { --mid; if (mid > 0) continue; } } else { if ( mid < nrecs && right.roff[nrecs] - right.roff[mid] + 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->insertx() * DESCRIPTION: insert a record into a node (which must already have room) */void n_insertx(np, record, reclen) node *np; unsigned char *record; int reclen;{ int rnum, i; unsigned char *ptr; rnum = np->rnum + 1; /* push other records down to make room */ for (ptr = HFS_NODEREC(*np, np->nd.ndNRecs) + reclen; ptr > HFS_NODEREC(*np, rnum) + reclen; --ptr) *(ptr - 1) = *(ptr - 1 - reclen); ++np->nd.ndNRecs; for (i = np->nd.ndNRecs; i > rnum; --i) np->roff[i] = np->roff[i - 1] + reclen; /* write the new record */ memcpy(HFS_NODEREC(*np, rnum), record, reclen);}/* * NAME: node->insert() * DESCRIPTION: insert a new record into a node; return a record for parent */int n_insert(np, record, reclen) node *np; unsigned char *record; int *reclen;{ n_compact(np); /* check for free space */ if (np->nd.ndNRecs >= HFS_MAXRECS || *reclen + 2 > NODESPACE(*np)) return n_split(np, record, reclen); n_insertx(np, record, *reclen); *reclen = 0; return bt_putnode(np);}/* * NAME: node->merge() * DESCRIPTION: combine two nodes into a single node */int n_merge(right, left, record, flag) 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 <= 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: node->delete() * DESCRIPTION: remove a record from a node */int n_delete(np, record, flag) 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 (np->nd.ndNRecs + left.nd.ndNRecs <= HFS_MAXRECS && np->roff[np->nd.ndNRecs] - np->roff[0] + 2 * np->nd.ndNRecs <= 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);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -