1*f0d9efc0Sbeck /*
2*f0d9efc0Sbeck * hfsutils - tools for reading and writing Macintosh HFS volumes
3*f0d9efc0Sbeck * Copyright (C) 1996, 1997 Robert Leslie
4*f0d9efc0Sbeck *
5*f0d9efc0Sbeck * This program is free software; you can redistribute it and/or modify
6*f0d9efc0Sbeck * it under the terms of the GNU General Public License as published by
7*f0d9efc0Sbeck * the Free Software Foundation; either version 2 of the License, or
8*f0d9efc0Sbeck * (at your option) any later version.
9*f0d9efc0Sbeck *
10*f0d9efc0Sbeck * This program is distributed in the hope that it will be useful,
11*f0d9efc0Sbeck * but WITHOUT ANY WARRANTY; without even the implied warranty of
12*f0d9efc0Sbeck * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13*f0d9efc0Sbeck * GNU General Public License for more details.
14*f0d9efc0Sbeck *
15*f0d9efc0Sbeck * You should have received a copy of the GNU General Public License
16*f0d9efc0Sbeck * along with this program; if not, write to the Free Software
17*f0d9efc0Sbeck * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18*f0d9efc0Sbeck */
19*f0d9efc0Sbeck
20*f0d9efc0Sbeck # include <stdlib.h>
21*f0d9efc0Sbeck # include <string.h>
22*f0d9efc0Sbeck # include <errno.h>
23*f0d9efc0Sbeck
24*f0d9efc0Sbeck # include "internal.h"
25*f0d9efc0Sbeck # include "data.h"
26*f0d9efc0Sbeck # include "btree.h"
27*f0d9efc0Sbeck # include "node.h"
28*f0d9efc0Sbeck
29*f0d9efc0Sbeck # define NODESPACE(n) \
30*f0d9efc0Sbeck (HFS_BLOCKSZ - (n).roff[(n).nd.ndNRecs] - 2 * ((n).nd.ndNRecs + 1))
31*f0d9efc0Sbeck
32*f0d9efc0Sbeck /*
33*f0d9efc0Sbeck * NAME: node->init()
34*f0d9efc0Sbeck * DESCRIPTION: construct an empty node
35*f0d9efc0Sbeck */
n_init(node * np,btree * bt,int type,int height)36*f0d9efc0Sbeck void n_init(node *np, btree *bt, int type, int height)
37*f0d9efc0Sbeck {
38*f0d9efc0Sbeck np->bt = bt;
39*f0d9efc0Sbeck np->nnum = -1;
40*f0d9efc0Sbeck
41*f0d9efc0Sbeck np->nd.ndFLink = 0;
42*f0d9efc0Sbeck np->nd.ndBLink = 0;
43*f0d9efc0Sbeck np->nd.ndType = type;
44*f0d9efc0Sbeck np->nd.ndNHeight = height;
45*f0d9efc0Sbeck np->nd.ndNRecs = 0;
46*f0d9efc0Sbeck np->nd.ndResv2 = 0;
47*f0d9efc0Sbeck
48*f0d9efc0Sbeck np->rnum = -1;
49*f0d9efc0Sbeck np->roff[0] = 0x00e;
50*f0d9efc0Sbeck
51*f0d9efc0Sbeck memset(np->data, 0, sizeof(np->data));
52*f0d9efc0Sbeck }
53*f0d9efc0Sbeck
54*f0d9efc0Sbeck /*
55*f0d9efc0Sbeck * NAME: node->new()
56*f0d9efc0Sbeck * DESCRIPTION: allocate a new b*-tree node
57*f0d9efc0Sbeck */
n_new(node * np)58*f0d9efc0Sbeck int n_new(node *np)
59*f0d9efc0Sbeck {
60*f0d9efc0Sbeck btree *bt = np->bt;
61*f0d9efc0Sbeck unsigned long num;
62*f0d9efc0Sbeck
63*f0d9efc0Sbeck if (bt->hdr.bthFree == 0)
64*f0d9efc0Sbeck {
65*f0d9efc0Sbeck ERROR(EIO, "b*-tree full");
66*f0d9efc0Sbeck return -1;
67*f0d9efc0Sbeck }
68*f0d9efc0Sbeck
69*f0d9efc0Sbeck num = 0;
70*f0d9efc0Sbeck while (num < bt->hdr.bthNNodes && BMTST(bt->map, num))
71*f0d9efc0Sbeck ++num;
72*f0d9efc0Sbeck
73*f0d9efc0Sbeck if (num == bt->hdr.bthNNodes)
74*f0d9efc0Sbeck {
75*f0d9efc0Sbeck ERROR(EIO, "free b*-tree node not found");
76*f0d9efc0Sbeck return -1;
77*f0d9efc0Sbeck }
78*f0d9efc0Sbeck
79*f0d9efc0Sbeck np->nnum = num;
80*f0d9efc0Sbeck
81*f0d9efc0Sbeck BMSET(bt->map, num);
82*f0d9efc0Sbeck --bt->hdr.bthFree;
83*f0d9efc0Sbeck
84*f0d9efc0Sbeck bt->flags |= HFS_UPDATE_BTHDR;
85*f0d9efc0Sbeck
86*f0d9efc0Sbeck return 0;
87*f0d9efc0Sbeck }
88*f0d9efc0Sbeck
89*f0d9efc0Sbeck /*
90*f0d9efc0Sbeck * NAME: node->free()
91*f0d9efc0Sbeck * DESCRIPTION: deallocate a b*-tree node
92*f0d9efc0Sbeck */
n_free(node * np)93*f0d9efc0Sbeck void n_free(node *np)
94*f0d9efc0Sbeck {
95*f0d9efc0Sbeck btree *bt = np->bt;
96*f0d9efc0Sbeck
97*f0d9efc0Sbeck BMCLR(bt->map, np->nnum);
98*f0d9efc0Sbeck ++bt->hdr.bthFree;
99*f0d9efc0Sbeck
100*f0d9efc0Sbeck bt->flags |= HFS_UPDATE_BTHDR;
101*f0d9efc0Sbeck }
102*f0d9efc0Sbeck
103*f0d9efc0Sbeck /*
104*f0d9efc0Sbeck * NAME: node->compact()
105*f0d9efc0Sbeck * DESCRIPTION: clean up a node, removing deleted records
106*f0d9efc0Sbeck */
n_compact(node * np)107*f0d9efc0Sbeck void n_compact(node *np)
108*f0d9efc0Sbeck {
109*f0d9efc0Sbeck unsigned char *ptr;
110*f0d9efc0Sbeck int offset, nrecs, i;
111*f0d9efc0Sbeck
112*f0d9efc0Sbeck offset = 0x00e;
113*f0d9efc0Sbeck ptr = np->data + offset;
114*f0d9efc0Sbeck nrecs = 0;
115*f0d9efc0Sbeck
116*f0d9efc0Sbeck for (i = 0; i < np->nd.ndNRecs; ++i)
117*f0d9efc0Sbeck {
118*f0d9efc0Sbeck unsigned char *rec;
119*f0d9efc0Sbeck int reclen;
120*f0d9efc0Sbeck
121*f0d9efc0Sbeck rec = HFS_NODEREC(*np, i);
122*f0d9efc0Sbeck reclen = np->roff[i + 1] - np->roff[i];
123*f0d9efc0Sbeck
124*f0d9efc0Sbeck if (HFS_RECKEYLEN(rec) > 0)
125*f0d9efc0Sbeck {
126*f0d9efc0Sbeck np->roff[nrecs++] = offset;
127*f0d9efc0Sbeck offset += reclen;
128*f0d9efc0Sbeck
129*f0d9efc0Sbeck if (ptr == rec)
130*f0d9efc0Sbeck ptr += reclen;
131*f0d9efc0Sbeck else
132*f0d9efc0Sbeck {
133*f0d9efc0Sbeck while (reclen--)
134*f0d9efc0Sbeck *ptr++ = *rec++;
135*f0d9efc0Sbeck }
136*f0d9efc0Sbeck }
137*f0d9efc0Sbeck }
138*f0d9efc0Sbeck
139*f0d9efc0Sbeck np->roff[nrecs] = offset;
140*f0d9efc0Sbeck np->nd.ndNRecs = nrecs;
141*f0d9efc0Sbeck }
142*f0d9efc0Sbeck
143*f0d9efc0Sbeck /*
144*f0d9efc0Sbeck * NAME: node->search()
145*f0d9efc0Sbeck * DESCRIPTION: locate a record in a node, or the record it should follow
146*f0d9efc0Sbeck */
n_search(node * np,unsigned char * key)147*f0d9efc0Sbeck int n_search(node *np, unsigned char *key)
148*f0d9efc0Sbeck {
149*f0d9efc0Sbeck btree *bt = np->bt;
150*f0d9efc0Sbeck int i, comp = -1;
151*f0d9efc0Sbeck
152*f0d9efc0Sbeck for (i = np->nd.ndNRecs; i--; )
153*f0d9efc0Sbeck {
154*f0d9efc0Sbeck unsigned char *rec;
155*f0d9efc0Sbeck
156*f0d9efc0Sbeck rec = HFS_NODEREC(*np, i);
157*f0d9efc0Sbeck
158*f0d9efc0Sbeck if (HFS_RECKEYLEN(rec) == 0)
159*f0d9efc0Sbeck continue; /* deleted record */
160*f0d9efc0Sbeck
161*f0d9efc0Sbeck comp = bt->compare(rec, key);
162*f0d9efc0Sbeck
163*f0d9efc0Sbeck if (comp <= 0)
164*f0d9efc0Sbeck break;
165*f0d9efc0Sbeck }
166*f0d9efc0Sbeck
167*f0d9efc0Sbeck np->rnum = i;
168*f0d9efc0Sbeck
169*f0d9efc0Sbeck return comp == 0;
170*f0d9efc0Sbeck }
171*f0d9efc0Sbeck
172*f0d9efc0Sbeck /*
173*f0d9efc0Sbeck * NAME: node->index()
174*f0d9efc0Sbeck * DESCRIPTION: create an index record from a key and node pointer
175*f0d9efc0Sbeck */
n_index(btree * bt,unsigned char * key,unsigned long nnum,unsigned char * record,int * reclen)176*f0d9efc0Sbeck void n_index(btree *bt, unsigned char *key, unsigned long nnum,
177*f0d9efc0Sbeck unsigned char *record, int *reclen)
178*f0d9efc0Sbeck {
179*f0d9efc0Sbeck if (bt == &bt->f.vol->cat)
180*f0d9efc0Sbeck {
181*f0d9efc0Sbeck /* force the key length to be 0x25 */
182*f0d9efc0Sbeck
183*f0d9efc0Sbeck HFS_RECKEYLEN(record) = 0x25;
184*f0d9efc0Sbeck memset(record + 1, 0, 0x25);
185*f0d9efc0Sbeck memcpy(record + 1, key + 1, HFS_RECKEYLEN(key));
186*f0d9efc0Sbeck }
187*f0d9efc0Sbeck else
188*f0d9efc0Sbeck memcpy(record, key, HFS_RECKEYSKIP(key));
189*f0d9efc0Sbeck
190*f0d9efc0Sbeck d_putl(HFS_RECDATA(record), nnum);
191*f0d9efc0Sbeck
192*f0d9efc0Sbeck if (reclen)
193*f0d9efc0Sbeck *reclen = HFS_RECKEYSKIP(record) + 4;
194*f0d9efc0Sbeck }
195*f0d9efc0Sbeck
196*f0d9efc0Sbeck /*
197*f0d9efc0Sbeck * NAME: node->split()
198*f0d9efc0Sbeck * DESCRIPTION: divide a node into two and insert a record
199*f0d9efc0Sbeck */
n_split(node * left,unsigned char * record,int * reclen)200*f0d9efc0Sbeck int n_split(node *left, unsigned char *record, int *reclen)
201*f0d9efc0Sbeck {
202*f0d9efc0Sbeck node right;
203*f0d9efc0Sbeck int nrecs, i, mid;
204*f0d9efc0Sbeck unsigned char *rec;
205*f0d9efc0Sbeck
206*f0d9efc0Sbeck right = *left;
207*f0d9efc0Sbeck right.nd.ndBLink = left->nnum;
208*f0d9efc0Sbeck
209*f0d9efc0Sbeck if (n_new(&right) < 0)
210*f0d9efc0Sbeck return -1;
211*f0d9efc0Sbeck
212*f0d9efc0Sbeck left->nd.ndFLink = right.nnum;
213*f0d9efc0Sbeck nrecs = left->nd.ndNRecs;
214*f0d9efc0Sbeck
215*f0d9efc0Sbeck /*
216*f0d9efc0Sbeck * Ensure node split leaves enough room for new record.
217*f0d9efc0Sbeck * The size calculations used are based on the NODESPACE() macro, but
218*f0d9efc0Sbeck * I don't know what the extra 2's and 1's are needed for.
219*f0d9efc0Sbeck * John Witford <jwitford@hutch.com.au>
220*f0d9efc0Sbeck */
221*f0d9efc0Sbeck n_search(&right, record);
222*f0d9efc0Sbeck mid = nrecs/2;
223*f0d9efc0Sbeck for(;;)
224*f0d9efc0Sbeck {
225*f0d9efc0Sbeck if (right.rnum < mid)
226*f0d9efc0Sbeck {
227*f0d9efc0Sbeck if ( mid > 0
228*f0d9efc0Sbeck && left->roff[mid] + *reclen + 2 > HFS_BLOCKSZ - 2 * (mid + 1))
229*f0d9efc0Sbeck {
230*f0d9efc0Sbeck --mid;
231*f0d9efc0Sbeck if (mid > 0)
232*f0d9efc0Sbeck continue;
233*f0d9efc0Sbeck }
234*f0d9efc0Sbeck }
235*f0d9efc0Sbeck else
236*f0d9efc0Sbeck {
237*f0d9efc0Sbeck if ( mid < nrecs
238*f0d9efc0Sbeck && right.roff[nrecs] - right.roff[mid] + left->roff[0] + *reclen + 2 > HFS_BLOCKSZ - 2 * (mid + 1))
239*f0d9efc0Sbeck {
240*f0d9efc0Sbeck ++mid;
241*f0d9efc0Sbeck if (mid < nrecs)
242*f0d9efc0Sbeck continue;
243*f0d9efc0Sbeck }
244*f0d9efc0Sbeck }
245*f0d9efc0Sbeck break;
246*f0d9efc0Sbeck }
247*f0d9efc0Sbeck
248*f0d9efc0Sbeck for (i = 0; i < nrecs; ++i)
249*f0d9efc0Sbeck {
250*f0d9efc0Sbeck if (i < mid)
251*f0d9efc0Sbeck rec = HFS_NODEREC(right, i);
252*f0d9efc0Sbeck else
253*f0d9efc0Sbeck rec = HFS_NODEREC(*left, i);
254*f0d9efc0Sbeck
255*f0d9efc0Sbeck HFS_RECKEYLEN(rec) = 0;
256*f0d9efc0Sbeck }
257*f0d9efc0Sbeck
258*f0d9efc0Sbeck /* original code ...
259*f0d9efc0Sbeck for (i = 0; i < nrecs; ++i)
260*f0d9efc0Sbeck {
261*f0d9efc0Sbeck if (i < nrecs / 2)
262*f0d9efc0Sbeck rec = HFS_NODEREC(right, i);
263*f0d9efc0Sbeck else
264*f0d9efc0Sbeck rec = HFS_NODEREC(*left, i);
265*f0d9efc0Sbeck
266*f0d9efc0Sbeck HFS_RECKEYLEN(rec) = 0;
267*f0d9efc0Sbeck }
268*f0d9efc0Sbeck */
269*f0d9efc0Sbeck n_compact(left);
270*f0d9efc0Sbeck n_compact(&right);
271*f0d9efc0Sbeck
272*f0d9efc0Sbeck n_search(&right, record);
273*f0d9efc0Sbeck if (right.rnum >= 0)
274*f0d9efc0Sbeck n_insertx(&right, record, *reclen);
275*f0d9efc0Sbeck else
276*f0d9efc0Sbeck {
277*f0d9efc0Sbeck n_search(left, record);
278*f0d9efc0Sbeck n_insertx(left, record, *reclen);
279*f0d9efc0Sbeck }
280*f0d9efc0Sbeck
281*f0d9efc0Sbeck /* store the new/modified nodes */
282*f0d9efc0Sbeck
283*f0d9efc0Sbeck if (bt_putnode(left) < 0 ||
284*f0d9efc0Sbeck bt_putnode(&right) < 0)
285*f0d9efc0Sbeck return -1;
286*f0d9efc0Sbeck
287*f0d9efc0Sbeck /* create an index record for the new node in the parent */
288*f0d9efc0Sbeck
289*f0d9efc0Sbeck n_index(right.bt, HFS_NODEREC(right, 0), right.nnum, record, reclen);
290*f0d9efc0Sbeck
291*f0d9efc0Sbeck /* update link pointers */
292*f0d9efc0Sbeck
293*f0d9efc0Sbeck if (left->bt->hdr.bthLNode == left->nnum)
294*f0d9efc0Sbeck {
295*f0d9efc0Sbeck left->bt->hdr.bthLNode = right.nnum;
296*f0d9efc0Sbeck left->bt->flags |= HFS_UPDATE_BTHDR;
297*f0d9efc0Sbeck }
298*f0d9efc0Sbeck
299*f0d9efc0Sbeck if (right.nd.ndFLink)
300*f0d9efc0Sbeck {
301*f0d9efc0Sbeck node n;
302*f0d9efc0Sbeck
303*f0d9efc0Sbeck n.bt = right.bt;
304*f0d9efc0Sbeck n.nnum = right.nd.ndFLink;
305*f0d9efc0Sbeck
306*f0d9efc0Sbeck if (bt_getnode(&n) < 0)
307*f0d9efc0Sbeck return -1;
308*f0d9efc0Sbeck
309*f0d9efc0Sbeck n.nd.ndBLink = right.nnum;
310*f0d9efc0Sbeck
311*f0d9efc0Sbeck if (bt_putnode(&n) < 0)
312*f0d9efc0Sbeck return -1;
313*f0d9efc0Sbeck }
314*f0d9efc0Sbeck
315*f0d9efc0Sbeck return 0;
316*f0d9efc0Sbeck }
317*f0d9efc0Sbeck
318*f0d9efc0Sbeck /*
319*f0d9efc0Sbeck * NAME: node->insertx()
320*f0d9efc0Sbeck * DESCRIPTION: insert a record into a node (which must already have room)
321*f0d9efc0Sbeck */
n_insertx(node * np,unsigned char * record,int reclen)322*f0d9efc0Sbeck void n_insertx(node *np, unsigned char *record, int reclen)
323*f0d9efc0Sbeck {
324*f0d9efc0Sbeck int rnum, i;
325*f0d9efc0Sbeck unsigned char *ptr;
326*f0d9efc0Sbeck
327*f0d9efc0Sbeck rnum = np->rnum + 1;
328*f0d9efc0Sbeck
329*f0d9efc0Sbeck /* push other records down to make room */
330*f0d9efc0Sbeck
331*f0d9efc0Sbeck for (ptr = HFS_NODEREC(*np, np->nd.ndNRecs) + reclen;
332*f0d9efc0Sbeck ptr > HFS_NODEREC(*np, rnum) + reclen; --ptr)
333*f0d9efc0Sbeck *(ptr - 1) = *(ptr - 1 - reclen);
334*f0d9efc0Sbeck
335*f0d9efc0Sbeck ++np->nd.ndNRecs;
336*f0d9efc0Sbeck
337*f0d9efc0Sbeck for (i = np->nd.ndNRecs; i > rnum; --i)
338*f0d9efc0Sbeck np->roff[i] = np->roff[i - 1] + reclen;
339*f0d9efc0Sbeck
340*f0d9efc0Sbeck /* write the new record */
341*f0d9efc0Sbeck
342*f0d9efc0Sbeck memcpy(HFS_NODEREC(*np, rnum), record, reclen);
343*f0d9efc0Sbeck }
344*f0d9efc0Sbeck
345*f0d9efc0Sbeck /*
346*f0d9efc0Sbeck * NAME: node->insert()
347*f0d9efc0Sbeck * DESCRIPTION: insert a new record into a node; return a record for parent
348*f0d9efc0Sbeck */
n_insert(node * np,unsigned char * record,int * reclen)349*f0d9efc0Sbeck int n_insert(node *np, unsigned char *record, int *reclen)
350*f0d9efc0Sbeck {
351*f0d9efc0Sbeck n_compact(np);
352*f0d9efc0Sbeck
353*f0d9efc0Sbeck /* check for free space */
354*f0d9efc0Sbeck
355*f0d9efc0Sbeck if (np->nd.ndNRecs >= HFS_MAXRECS ||
356*f0d9efc0Sbeck *reclen + 2 > NODESPACE(*np))
357*f0d9efc0Sbeck return n_split(np, record, reclen);
358*f0d9efc0Sbeck
359*f0d9efc0Sbeck n_insertx(np, record, *reclen);
360*f0d9efc0Sbeck *reclen = 0;
361*f0d9efc0Sbeck
362*f0d9efc0Sbeck return bt_putnode(np);
363*f0d9efc0Sbeck }
364*f0d9efc0Sbeck
365*f0d9efc0Sbeck /*
366*f0d9efc0Sbeck * NAME: node->merge()
367*f0d9efc0Sbeck * DESCRIPTION: combine two nodes into a single node
368*f0d9efc0Sbeck */
n_merge(node * right,node * left,unsigned char * record,int * flag)369*f0d9efc0Sbeck int n_merge(node *right, node *left, unsigned char *record, int *flag)
370*f0d9efc0Sbeck {
371*f0d9efc0Sbeck int i, offset;
372*f0d9efc0Sbeck
373*f0d9efc0Sbeck /* copy records and offsets */
374*f0d9efc0Sbeck
375*f0d9efc0Sbeck memcpy(HFS_NODEREC(*left, left->nd.ndNRecs), HFS_NODEREC(*right, 0),
376*f0d9efc0Sbeck right->roff[right->nd.ndNRecs] - right->roff[0]);
377*f0d9efc0Sbeck
378*f0d9efc0Sbeck offset = left->roff[left->nd.ndNRecs] - right->roff[0];
379*f0d9efc0Sbeck
380*f0d9efc0Sbeck for (i = 1; i <= right->nd.ndNRecs; ++i)
381*f0d9efc0Sbeck left->roff[++left->nd.ndNRecs] = offset + right->roff[i];
382*f0d9efc0Sbeck
383*f0d9efc0Sbeck /* update link pointers */
384*f0d9efc0Sbeck
385*f0d9efc0Sbeck left->nd.ndFLink = right->nd.ndFLink;
386*f0d9efc0Sbeck
387*f0d9efc0Sbeck if (bt_putnode(left) < 0)
388*f0d9efc0Sbeck return -1;
389*f0d9efc0Sbeck
390*f0d9efc0Sbeck if (right->bt->hdr.bthLNode == right->nnum)
391*f0d9efc0Sbeck {
392*f0d9efc0Sbeck right->bt->hdr.bthLNode = left->nnum;
393*f0d9efc0Sbeck right->bt->flags |= HFS_UPDATE_BTHDR;
394*f0d9efc0Sbeck }
395*f0d9efc0Sbeck
396*f0d9efc0Sbeck if (right->nd.ndFLink)
397*f0d9efc0Sbeck {
398*f0d9efc0Sbeck node n;
399*f0d9efc0Sbeck
400*f0d9efc0Sbeck n.bt = right->bt;
401*f0d9efc0Sbeck n.nnum = right->nd.ndFLink;
402*f0d9efc0Sbeck
403*f0d9efc0Sbeck if (bt_getnode(&n) < 0)
404*f0d9efc0Sbeck return -1;
405*f0d9efc0Sbeck
406*f0d9efc0Sbeck n.nd.ndBLink = left->nnum;
407*f0d9efc0Sbeck
408*f0d9efc0Sbeck if (bt_putnode(&n) < 0)
409*f0d9efc0Sbeck return -1;
410*f0d9efc0Sbeck }
411*f0d9efc0Sbeck
412*f0d9efc0Sbeck n_free(right);
413*f0d9efc0Sbeck
414*f0d9efc0Sbeck HFS_RECKEYLEN(record) = 0;
415*f0d9efc0Sbeck *flag = 1;
416*f0d9efc0Sbeck
417*f0d9efc0Sbeck return 0;
418*f0d9efc0Sbeck }
419*f0d9efc0Sbeck
420*f0d9efc0Sbeck /*
421*f0d9efc0Sbeck * NAME: node->delete()
422*f0d9efc0Sbeck * DESCRIPTION: remove a record from a node
423*f0d9efc0Sbeck */
n_delete(node * np,unsigned char * record,int * flag)424*f0d9efc0Sbeck int n_delete(node *np, unsigned char *record, int *flag)
425*f0d9efc0Sbeck {
426*f0d9efc0Sbeck node left;
427*f0d9efc0Sbeck unsigned char *rec;
428*f0d9efc0Sbeck
429*f0d9efc0Sbeck rec = HFS_NODEREC(*np, np->rnum);
430*f0d9efc0Sbeck
431*f0d9efc0Sbeck HFS_RECKEYLEN(rec) = 0;
432*f0d9efc0Sbeck n_compact(np);
433*f0d9efc0Sbeck
434*f0d9efc0Sbeck /* see if we can merge with our left sibling */
435*f0d9efc0Sbeck
436*f0d9efc0Sbeck left.bt = np->bt;
437*f0d9efc0Sbeck left.nnum = np->nd.ndBLink;
438*f0d9efc0Sbeck
439*f0d9efc0Sbeck if (left.nnum > 0)
440*f0d9efc0Sbeck {
441*f0d9efc0Sbeck if (bt_getnode(&left) < 0)
442*f0d9efc0Sbeck return -1;
443*f0d9efc0Sbeck
444*f0d9efc0Sbeck if (np->nd.ndNRecs + left.nd.ndNRecs <= HFS_MAXRECS &&
445*f0d9efc0Sbeck np->roff[np->nd.ndNRecs] - np->roff[0] +
446*f0d9efc0Sbeck 2 * np->nd.ndNRecs <= NODESPACE(left))
447*f0d9efc0Sbeck return n_merge(np, &left, record, flag);
448*f0d9efc0Sbeck }
449*f0d9efc0Sbeck
450*f0d9efc0Sbeck if (np->rnum == 0)
451*f0d9efc0Sbeck {
452*f0d9efc0Sbeck /* special case: first record changed; update parent record key */
453*f0d9efc0Sbeck
454*f0d9efc0Sbeck n_index(np->bt, HFS_NODEREC(*np, 0), np->nnum, record, 0);
455*f0d9efc0Sbeck *flag = 1;
456*f0d9efc0Sbeck }
457*f0d9efc0Sbeck
458*f0d9efc0Sbeck return bt_putnode(np);
459*f0d9efc0Sbeck }
460