xref: /openbsd-src/gnu/usr.sbin/mkhybrid/src/libhfs_iso/btree.c (revision f0d9efc08bdf8f314c206a5c81ebc300245394f8)
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 "block.h"
27*f0d9efc0Sbeck # include "file.h"
28*f0d9efc0Sbeck # include "btree.h"
29*f0d9efc0Sbeck # include "node.h"
30*f0d9efc0Sbeck 
31*f0d9efc0Sbeck /*
32*f0d9efc0Sbeck  * NAME:	btree->getnode()
33*f0d9efc0Sbeck  * DESCRIPTION:	retrieve a numbered node from a B*-tree file
34*f0d9efc0Sbeck  */
bt_getnode(node * np)35*f0d9efc0Sbeck int bt_getnode(node *np)
36*f0d9efc0Sbeck {
37*f0d9efc0Sbeck   btree *bt = np->bt;
38*f0d9efc0Sbeck   block *bp = &np->data;
39*f0d9efc0Sbeck   unsigned char *ptr;
40*f0d9efc0Sbeck   int i;
41*f0d9efc0Sbeck 
42*f0d9efc0Sbeck   /* verify the node exists and is marked as in-use */
43*f0d9efc0Sbeck 
44*f0d9efc0Sbeck   if (np->nnum < 0 || (np->nnum > 0 && np->nnum >= bt->hdr.bthNNodes))
45*f0d9efc0Sbeck     {
46*f0d9efc0Sbeck       ERROR(EIO, "read nonexistent b*-tree node");
47*f0d9efc0Sbeck       return -1;
48*f0d9efc0Sbeck     }
49*f0d9efc0Sbeck 
50*f0d9efc0Sbeck   if (bt->map && ! BMTST(bt->map, np->nnum))
51*f0d9efc0Sbeck     {
52*f0d9efc0Sbeck       ERROR(EIO, "read unallocated b*-tree node");
53*f0d9efc0Sbeck       return -1;
54*f0d9efc0Sbeck     }
55*f0d9efc0Sbeck 
56*f0d9efc0Sbeck   if (f_getblock(&bt->f, np->nnum, bp) < 0)
57*f0d9efc0Sbeck     return -1;
58*f0d9efc0Sbeck 
59*f0d9efc0Sbeck   ptr = *bp;
60*f0d9efc0Sbeck 
61*f0d9efc0Sbeck   d_fetchl(&ptr, (long *) &np->nd.ndFLink);
62*f0d9efc0Sbeck   d_fetchl(&ptr, (long *) &np->nd.ndBLink);
63*f0d9efc0Sbeck   d_fetchb(&ptr, (char *) &np->nd.ndType);
64*f0d9efc0Sbeck   d_fetchb(&ptr, (char *) &np->nd.ndNHeight);
65*f0d9efc0Sbeck   d_fetchw(&ptr, (short *) &np->nd.ndNRecs);
66*f0d9efc0Sbeck   d_fetchw(&ptr, &np->nd.ndResv2);
67*f0d9efc0Sbeck 
68*f0d9efc0Sbeck   if (np->nd.ndNRecs > HFS_MAXRECS)
69*f0d9efc0Sbeck     {
70*f0d9efc0Sbeck       ERROR(EIO, "too many b*-tree node records");
71*f0d9efc0Sbeck       return -1;
72*f0d9efc0Sbeck     }
73*f0d9efc0Sbeck 
74*f0d9efc0Sbeck   i = np->nd.ndNRecs + 1;
75*f0d9efc0Sbeck 
76*f0d9efc0Sbeck   ptr = *bp + HFS_BLOCKSZ - (2 * i);
77*f0d9efc0Sbeck 
78*f0d9efc0Sbeck   while (i--)
79*f0d9efc0Sbeck     d_fetchw(&ptr, (short *) &np->roff[i]);
80*f0d9efc0Sbeck 
81*f0d9efc0Sbeck   return 0;
82*f0d9efc0Sbeck }
83*f0d9efc0Sbeck 
84*f0d9efc0Sbeck /*
85*f0d9efc0Sbeck  * NAME:	btree->putnode()
86*f0d9efc0Sbeck  * DESCRIPTION:	store a numbered node into a B*-tree file
87*f0d9efc0Sbeck  */
bt_putnode(node * np)88*f0d9efc0Sbeck int bt_putnode(node *np)
89*f0d9efc0Sbeck {
90*f0d9efc0Sbeck   btree *bt = np->bt;
91*f0d9efc0Sbeck   block *bp = &np->data;
92*f0d9efc0Sbeck   unsigned char *ptr;
93*f0d9efc0Sbeck   int i;
94*f0d9efc0Sbeck 
95*f0d9efc0Sbeck   /* verify the node exists and is marked as in-use */
96*f0d9efc0Sbeck 
97*f0d9efc0Sbeck   if (np->nnum && np->nnum >= bt->hdr.bthNNodes)
98*f0d9efc0Sbeck     {
99*f0d9efc0Sbeck       ERROR(EIO, "write nonexistent b*-tree node");
100*f0d9efc0Sbeck       return -1;
101*f0d9efc0Sbeck     }
102*f0d9efc0Sbeck   else if (bt->map && ! BMTST(bt->map, np->nnum))
103*f0d9efc0Sbeck     {
104*f0d9efc0Sbeck       ERROR(EIO, "write unallocated b*-tree node");
105*f0d9efc0Sbeck       return -1;
106*f0d9efc0Sbeck     }
107*f0d9efc0Sbeck 
108*f0d9efc0Sbeck   ptr = *bp;
109*f0d9efc0Sbeck 
110*f0d9efc0Sbeck   d_storel(&ptr, np->nd.ndFLink);
111*f0d9efc0Sbeck   d_storel(&ptr, np->nd.ndBLink);
112*f0d9efc0Sbeck   d_storeb(&ptr, np->nd.ndType);
113*f0d9efc0Sbeck   d_storeb(&ptr, np->nd.ndNHeight);
114*f0d9efc0Sbeck   d_storew(&ptr, np->nd.ndNRecs);
115*f0d9efc0Sbeck   d_storew(&ptr, np->nd.ndResv2);
116*f0d9efc0Sbeck 
117*f0d9efc0Sbeck   if (np->nd.ndNRecs > HFS_MAXRECS)
118*f0d9efc0Sbeck     {
119*f0d9efc0Sbeck       ERROR(EIO, "too many b*-tree node records");
120*f0d9efc0Sbeck       return -1;
121*f0d9efc0Sbeck     }
122*f0d9efc0Sbeck 
123*f0d9efc0Sbeck   i = np->nd.ndNRecs + 1;
124*f0d9efc0Sbeck 
125*f0d9efc0Sbeck   ptr = *bp + HFS_BLOCKSZ - (2 * i);
126*f0d9efc0Sbeck 
127*f0d9efc0Sbeck   while (i--)
128*f0d9efc0Sbeck     d_storew(&ptr, np->roff[i]);
129*f0d9efc0Sbeck 
130*f0d9efc0Sbeck   if (f_putblock(&bt->f, np->nnum, bp) < 0)
131*f0d9efc0Sbeck     return -1;
132*f0d9efc0Sbeck 
133*f0d9efc0Sbeck   return 0;
134*f0d9efc0Sbeck }
135*f0d9efc0Sbeck 
136*f0d9efc0Sbeck /*
137*f0d9efc0Sbeck  * NAME:	btree->readhdr()
138*f0d9efc0Sbeck  * DESCRIPTION:	read the header node of a B*-tree
139*f0d9efc0Sbeck  */
bt_readhdr(btree * bt)140*f0d9efc0Sbeck int bt_readhdr(btree *bt)
141*f0d9efc0Sbeck {
142*f0d9efc0Sbeck   unsigned char *ptr;
143*f0d9efc0Sbeck   char *map;
144*f0d9efc0Sbeck   int i;
145*f0d9efc0Sbeck   unsigned long nnum;
146*f0d9efc0Sbeck 
147*f0d9efc0Sbeck   bt->hdrnd.bt   = bt;
148*f0d9efc0Sbeck   bt->hdrnd.nnum = 0;
149*f0d9efc0Sbeck 
150*f0d9efc0Sbeck   if (bt_getnode(&bt->hdrnd) < 0)
151*f0d9efc0Sbeck     return -1;
152*f0d9efc0Sbeck 
153*f0d9efc0Sbeck   if (bt->hdrnd.nd.ndType != ndHdrNode ||
154*f0d9efc0Sbeck       bt->hdrnd.nd.ndNRecs != 3 ||
155*f0d9efc0Sbeck       bt->hdrnd.roff[0] != 0x00e ||
156*f0d9efc0Sbeck       bt->hdrnd.roff[1] != 0x078 ||
157*f0d9efc0Sbeck       bt->hdrnd.roff[2] != 0x0f8 ||
158*f0d9efc0Sbeck       bt->hdrnd.roff[3] != 0x1f8)
159*f0d9efc0Sbeck     {
160*f0d9efc0Sbeck       ERROR(EIO, "malformed b*-tree header node");
161*f0d9efc0Sbeck       return -1;
162*f0d9efc0Sbeck     }
163*f0d9efc0Sbeck 
164*f0d9efc0Sbeck   /* read header record */
165*f0d9efc0Sbeck 
166*f0d9efc0Sbeck   ptr = HFS_NODEREC(bt->hdrnd, 0);
167*f0d9efc0Sbeck 
168*f0d9efc0Sbeck   d_fetchw(&ptr, (short *) &bt->hdr.bthDepth);
169*f0d9efc0Sbeck   d_fetchl(&ptr, (long *) &bt->hdr.bthRoot);
170*f0d9efc0Sbeck   d_fetchl(&ptr, (long *) &bt->hdr.bthNRecs);
171*f0d9efc0Sbeck   d_fetchl(&ptr, (long *) &bt->hdr.bthFNode);
172*f0d9efc0Sbeck   d_fetchl(&ptr, (long *) &bt->hdr.bthLNode);
173*f0d9efc0Sbeck   d_fetchw(&ptr, (short *) &bt->hdr.bthNodeSize);
174*f0d9efc0Sbeck   d_fetchw(&ptr, (short *) &bt->hdr.bthKeyLen);
175*f0d9efc0Sbeck   d_fetchl(&ptr, (long *) &bt->hdr.bthNNodes);
176*f0d9efc0Sbeck   d_fetchl(&ptr, (long *) &bt->hdr.bthFree);
177*f0d9efc0Sbeck 
178*f0d9efc0Sbeck   for (i = 0; i < 76; ++i)
179*f0d9efc0Sbeck     d_fetchb(&ptr, (char *) &bt->hdr.bthResv[i]);
180*f0d9efc0Sbeck 
181*f0d9efc0Sbeck   if (bt->hdr.bthNodeSize != HFS_BLOCKSZ)
182*f0d9efc0Sbeck     {
183*f0d9efc0Sbeck       ERROR(EINVAL, "unsupported b*-tree node size");
184*f0d9efc0Sbeck       return -1;
185*f0d9efc0Sbeck     }
186*f0d9efc0Sbeck 
187*f0d9efc0Sbeck   /* read map record; construct btree bitmap */
188*f0d9efc0Sbeck   /* don't set bt->map until we're done, since getnode() checks it */
189*f0d9efc0Sbeck 
190*f0d9efc0Sbeck   map = ALLOC(char, HFS_MAP1SZ);
191*f0d9efc0Sbeck   if (map == 0)
192*f0d9efc0Sbeck     {
193*f0d9efc0Sbeck       ERROR(ENOMEM, 0);
194*f0d9efc0Sbeck       return -1;
195*f0d9efc0Sbeck     }
196*f0d9efc0Sbeck 
197*f0d9efc0Sbeck   memcpy(map, HFS_NODEREC(bt->hdrnd, 2), HFS_MAP1SZ);
198*f0d9efc0Sbeck   bt->mapsz = HFS_MAP1SZ;
199*f0d9efc0Sbeck 
200*f0d9efc0Sbeck   /* read continuation map records, if any */
201*f0d9efc0Sbeck 
202*f0d9efc0Sbeck   nnum = bt->hdrnd.nd.ndFLink;
203*f0d9efc0Sbeck 
204*f0d9efc0Sbeck   while (nnum)
205*f0d9efc0Sbeck     {
206*f0d9efc0Sbeck       node n;
207*f0d9efc0Sbeck       char *newmap;
208*f0d9efc0Sbeck 
209*f0d9efc0Sbeck       n.bt   = bt;
210*f0d9efc0Sbeck       n.nnum = nnum;
211*f0d9efc0Sbeck 
212*f0d9efc0Sbeck       if (bt_getnode(&n) < 0)
213*f0d9efc0Sbeck 	{
214*f0d9efc0Sbeck 	  FREE(map);
215*f0d9efc0Sbeck 	  return -1;
216*f0d9efc0Sbeck 	}
217*f0d9efc0Sbeck 
218*f0d9efc0Sbeck       if (n.nd.ndType != ndMapNode ||
219*f0d9efc0Sbeck 	  n.nd.ndNRecs != 1 ||
220*f0d9efc0Sbeck 	  n.roff[0] != 0x00e ||
221*f0d9efc0Sbeck 	  n.roff[1] != 0x1fa)
222*f0d9efc0Sbeck 	{
223*f0d9efc0Sbeck 	  FREE(map);
224*f0d9efc0Sbeck 	  ERROR(EIO, "malformed b*-tree map node");
225*f0d9efc0Sbeck 	  return -1;
226*f0d9efc0Sbeck 	}
227*f0d9efc0Sbeck 
228*f0d9efc0Sbeck       newmap = REALLOC(map, char, bt->mapsz + HFS_MAPXSZ);
229*f0d9efc0Sbeck       if (newmap == 0)
230*f0d9efc0Sbeck 	{
231*f0d9efc0Sbeck 	  FREE(map);
232*f0d9efc0Sbeck 	  ERROR(ENOMEM, 0);
233*f0d9efc0Sbeck 	  return -1;
234*f0d9efc0Sbeck 	}
235*f0d9efc0Sbeck       map = newmap;
236*f0d9efc0Sbeck 
237*f0d9efc0Sbeck       memcpy(map + bt->mapsz, HFS_NODEREC(n, 0), HFS_MAPXSZ);
238*f0d9efc0Sbeck       bt->mapsz += HFS_MAPXSZ;
239*f0d9efc0Sbeck 
240*f0d9efc0Sbeck       nnum = n.nd.ndFLink;
241*f0d9efc0Sbeck     }
242*f0d9efc0Sbeck 
243*f0d9efc0Sbeck   bt->map = map;
244*f0d9efc0Sbeck 
245*f0d9efc0Sbeck   return 0;
246*f0d9efc0Sbeck }
247*f0d9efc0Sbeck 
248*f0d9efc0Sbeck /*
249*f0d9efc0Sbeck  * NAME:	btree->writehdr()
250*f0d9efc0Sbeck  * DESCRIPTION:	write the header node of a B*-tree
251*f0d9efc0Sbeck  */
bt_writehdr(btree * bt)252*f0d9efc0Sbeck int bt_writehdr(btree *bt)
253*f0d9efc0Sbeck {
254*f0d9efc0Sbeck   unsigned char *ptr;
255*f0d9efc0Sbeck   char *map;
256*f0d9efc0Sbeck   unsigned long mapsz, nnum;
257*f0d9efc0Sbeck   int i;
258*f0d9efc0Sbeck 
259*f0d9efc0Sbeck   if (bt->hdrnd.bt != bt ||
260*f0d9efc0Sbeck       bt->hdrnd.nnum != 0 ||
261*f0d9efc0Sbeck       bt->hdrnd.nd.ndType != ndHdrNode ||
262*f0d9efc0Sbeck       bt->hdrnd.nd.ndNRecs != 3)
263*f0d9efc0Sbeck     abort();
264*f0d9efc0Sbeck 
265*f0d9efc0Sbeck   ptr = HFS_NODEREC(bt->hdrnd, 0);
266*f0d9efc0Sbeck 
267*f0d9efc0Sbeck   d_storew(&ptr, bt->hdr.bthDepth);
268*f0d9efc0Sbeck   d_storel(&ptr, bt->hdr.bthRoot);
269*f0d9efc0Sbeck   d_storel(&ptr, bt->hdr.bthNRecs);
270*f0d9efc0Sbeck   d_storel(&ptr, bt->hdr.bthFNode);
271*f0d9efc0Sbeck   d_storel(&ptr, bt->hdr.bthLNode);
272*f0d9efc0Sbeck   d_storew(&ptr, bt->hdr.bthNodeSize);
273*f0d9efc0Sbeck   d_storew(&ptr, bt->hdr.bthKeyLen);
274*f0d9efc0Sbeck   d_storel(&ptr, bt->hdr.bthNNodes);
275*f0d9efc0Sbeck   d_storel(&ptr, bt->hdr.bthFree);
276*f0d9efc0Sbeck 
277*f0d9efc0Sbeck   for (i = 0; i < 76; ++i)
278*f0d9efc0Sbeck     d_storeb(&ptr, bt->hdr.bthResv[i]);
279*f0d9efc0Sbeck 
280*f0d9efc0Sbeck   memcpy(HFS_NODEREC(bt->hdrnd, 2), bt->map, HFS_MAP1SZ);
281*f0d9efc0Sbeck 
282*f0d9efc0Sbeck   if (bt_putnode(&bt->hdrnd) < 0)
283*f0d9efc0Sbeck     return -1;
284*f0d9efc0Sbeck 
285*f0d9efc0Sbeck   map   = bt->map   + HFS_MAP1SZ;
286*f0d9efc0Sbeck   mapsz = bt->mapsz - HFS_MAP1SZ;
287*f0d9efc0Sbeck 
288*f0d9efc0Sbeck   nnum  = bt->hdrnd.nd.ndFLink;
289*f0d9efc0Sbeck 
290*f0d9efc0Sbeck   while (mapsz)
291*f0d9efc0Sbeck     {
292*f0d9efc0Sbeck       node n;
293*f0d9efc0Sbeck 
294*f0d9efc0Sbeck       if (nnum == 0)
295*f0d9efc0Sbeck 	{
296*f0d9efc0Sbeck 	  ERROR(EIO, "truncated b*-tree map");
297*f0d9efc0Sbeck 	  return -1;
298*f0d9efc0Sbeck 	}
299*f0d9efc0Sbeck 
300*f0d9efc0Sbeck       n.bt   = bt;
301*f0d9efc0Sbeck       n.nnum = nnum;
302*f0d9efc0Sbeck 
303*f0d9efc0Sbeck       if (bt_getnode(&n) < 0)
304*f0d9efc0Sbeck 	return -1;
305*f0d9efc0Sbeck 
306*f0d9efc0Sbeck       if (n.nd.ndType != ndMapNode ||
307*f0d9efc0Sbeck 	  n.nd.ndNRecs != 1 ||
308*f0d9efc0Sbeck 	  n.roff[0] != 0x00e ||
309*f0d9efc0Sbeck 	  n.roff[1] != 0x1fa)
310*f0d9efc0Sbeck 	{
311*f0d9efc0Sbeck 	  ERROR(EIO, "malformed b*-tree map node");
312*f0d9efc0Sbeck 	  return -1;
313*f0d9efc0Sbeck 	}
314*f0d9efc0Sbeck 
315*f0d9efc0Sbeck       memcpy(HFS_NODEREC(n, 0), map, HFS_MAPXSZ);
316*f0d9efc0Sbeck 
317*f0d9efc0Sbeck       if (bt_putnode(&n) < 0)
318*f0d9efc0Sbeck 	return -1;
319*f0d9efc0Sbeck 
320*f0d9efc0Sbeck       map   += HFS_MAPXSZ;
321*f0d9efc0Sbeck       mapsz -= HFS_MAPXSZ;
322*f0d9efc0Sbeck 
323*f0d9efc0Sbeck       nnum = n.nd.ndFLink;
324*f0d9efc0Sbeck     }
325*f0d9efc0Sbeck 
326*f0d9efc0Sbeck   bt->flags &= ~HFS_UPDATE_BTHDR;
327*f0d9efc0Sbeck 
328*f0d9efc0Sbeck   return 0;
329*f0d9efc0Sbeck }
330*f0d9efc0Sbeck 
331*f0d9efc0Sbeck /* High-Level B*-Tree Routines ============================================= */
332*f0d9efc0Sbeck 
333*f0d9efc0Sbeck /*
334*f0d9efc0Sbeck  * NAME:	btree->space()
335*f0d9efc0Sbeck  * DESCRIPTION:	assert space for new records, or extend the file
336*f0d9efc0Sbeck  */
bt_space(btree * bt,unsigned int nrecs)337*f0d9efc0Sbeck int bt_space(btree *bt, unsigned int nrecs)
338*f0d9efc0Sbeck {
339*f0d9efc0Sbeck   unsigned int nnodes;
340*f0d9efc0Sbeck   int space;
341*f0d9efc0Sbeck 
342*f0d9efc0Sbeck   nnodes = nrecs * (bt->hdr.bthDepth + 1);
343*f0d9efc0Sbeck 
344*f0d9efc0Sbeck   if (nnodes <= bt->hdr.bthFree)
345*f0d9efc0Sbeck     return 0;
346*f0d9efc0Sbeck 
347*f0d9efc0Sbeck   /* make sure the extents tree has room too */
348*f0d9efc0Sbeck 
349*f0d9efc0Sbeck   if (bt != &bt->f.vol->ext)
350*f0d9efc0Sbeck     {
351*f0d9efc0Sbeck       if (bt_space(&bt->f.vol->ext, 1) < 0)
352*f0d9efc0Sbeck 	return -1;
353*f0d9efc0Sbeck     }
354*f0d9efc0Sbeck 
355*f0d9efc0Sbeck   space = f_alloc(&bt->f);
356*f0d9efc0Sbeck   if (space < 0)
357*f0d9efc0Sbeck     return -1;
358*f0d9efc0Sbeck 
359*f0d9efc0Sbeck   nnodes = space * (bt->f.vol->mdb.drAlBlkSiz / bt->hdr.bthNodeSize);
360*f0d9efc0Sbeck 
361*f0d9efc0Sbeck   bt->hdr.bthNNodes += nnodes;
362*f0d9efc0Sbeck   bt->hdr.bthFree   += nnodes;
363*f0d9efc0Sbeck 
364*f0d9efc0Sbeck   bt->flags |= HFS_UPDATE_BTHDR;
365*f0d9efc0Sbeck 
366*f0d9efc0Sbeck   bt->f.vol->flags |= HFS_UPDATE_ALTMDB;
367*f0d9efc0Sbeck 
368*f0d9efc0Sbeck   while (bt->hdr.bthNNodes > bt->mapsz * 8)
369*f0d9efc0Sbeck     {
370*f0d9efc0Sbeck       char *newmap;
371*f0d9efc0Sbeck       node mapnd;
372*f0d9efc0Sbeck 
373*f0d9efc0Sbeck       /* extend tree map */
374*f0d9efc0Sbeck 
375*f0d9efc0Sbeck       newmap = REALLOC(bt->map, char, bt->mapsz + HFS_MAPXSZ);
376*f0d9efc0Sbeck       if (newmap == 0)
377*f0d9efc0Sbeck 	{
378*f0d9efc0Sbeck 	  ERROR(ENOMEM, 0);
379*f0d9efc0Sbeck 	  return -1;
380*f0d9efc0Sbeck 	}
381*f0d9efc0Sbeck 
382*f0d9efc0Sbeck       memset(newmap + bt->mapsz, 0, HFS_MAPXSZ);
383*f0d9efc0Sbeck 
384*f0d9efc0Sbeck       bt->map    = newmap;
385*f0d9efc0Sbeck       bt->mapsz += HFS_MAPXSZ;
386*f0d9efc0Sbeck 
387*f0d9efc0Sbeck       n_init(&mapnd, bt, ndMapNode, 0);
388*f0d9efc0Sbeck       if (n_new(&mapnd) < 0)
389*f0d9efc0Sbeck 	return -1;
390*f0d9efc0Sbeck 
391*f0d9efc0Sbeck       /* link the new map node */
392*f0d9efc0Sbeck 
393*f0d9efc0Sbeck       if (bt->hdrnd.nd.ndFLink == 0)
394*f0d9efc0Sbeck 	{
395*f0d9efc0Sbeck 	  bt->hdrnd.nd.ndFLink = mapnd.nnum;
396*f0d9efc0Sbeck 	  mapnd.nd.ndBLink     = 0;
397*f0d9efc0Sbeck 	}
398*f0d9efc0Sbeck       else
399*f0d9efc0Sbeck 	{
400*f0d9efc0Sbeck 	  node n;
401*f0d9efc0Sbeck 
402*f0d9efc0Sbeck 	  n.bt   = bt;
403*f0d9efc0Sbeck 	  n.nnum = bt->hdrnd.nd.ndFLink;
404*f0d9efc0Sbeck 
405*f0d9efc0Sbeck 	  while (1)
406*f0d9efc0Sbeck 	    {
407*f0d9efc0Sbeck 	      if (bt_getnode(&n) < 0)
408*f0d9efc0Sbeck 		return -1;
409*f0d9efc0Sbeck 
410*f0d9efc0Sbeck 	      if (n.nd.ndFLink == 0)
411*f0d9efc0Sbeck 		break;
412*f0d9efc0Sbeck 
413*f0d9efc0Sbeck 	      n.nnum = n.nd.ndFLink;
414*f0d9efc0Sbeck 	    }
415*f0d9efc0Sbeck 
416*f0d9efc0Sbeck 	  n.nd.ndFLink     = mapnd.nnum;
417*f0d9efc0Sbeck 	  mapnd.nd.ndBLink = n.nnum;
418*f0d9efc0Sbeck 
419*f0d9efc0Sbeck 	  if (bt_putnode(&n) < 0)
420*f0d9efc0Sbeck 	    return -1;
421*f0d9efc0Sbeck 	}
422*f0d9efc0Sbeck 
423*f0d9efc0Sbeck       mapnd.nd.ndNRecs = 1;
424*f0d9efc0Sbeck       mapnd.roff[1]    = 0x1fa;
425*f0d9efc0Sbeck 
426*f0d9efc0Sbeck       if (bt_putnode(&mapnd) < 0)
427*f0d9efc0Sbeck 	return -1;
428*f0d9efc0Sbeck     }
429*f0d9efc0Sbeck 
430*f0d9efc0Sbeck   return 0;
431*f0d9efc0Sbeck }
432*f0d9efc0Sbeck 
433*f0d9efc0Sbeck /*
434*f0d9efc0Sbeck  * NAME:	btree->insertx()
435*f0d9efc0Sbeck  * DESCRIPTION:	recursively locate a node and insert a record
436*f0d9efc0Sbeck  */
bt_insertx(node * np,unsigned char * record,int * reclen)437*f0d9efc0Sbeck int bt_insertx(node *np, unsigned char *record, int *reclen)
438*f0d9efc0Sbeck {
439*f0d9efc0Sbeck   node child;
440*f0d9efc0Sbeck   unsigned char *rec;
441*f0d9efc0Sbeck 
442*f0d9efc0Sbeck   if (n_search(np, record))
443*f0d9efc0Sbeck     {
444*f0d9efc0Sbeck       ERROR(EIO, "b*-tree record already exists");
445*f0d9efc0Sbeck       return -1;
446*f0d9efc0Sbeck     }
447*f0d9efc0Sbeck 
448*f0d9efc0Sbeck   switch ((unsigned char) np->nd.ndType)
449*f0d9efc0Sbeck     {
450*f0d9efc0Sbeck     case ndIndxNode:
451*f0d9efc0Sbeck       if (np->rnum < 0)
452*f0d9efc0Sbeck 	rec = HFS_NODEREC(*np, 0);
453*f0d9efc0Sbeck       else
454*f0d9efc0Sbeck 	rec = HFS_NODEREC(*np, np->rnum);
455*f0d9efc0Sbeck 
456*f0d9efc0Sbeck       child.bt   = np->bt;
457*f0d9efc0Sbeck       child.nnum = d_getl(HFS_RECDATA(rec));
458*f0d9efc0Sbeck 
459*f0d9efc0Sbeck       if (bt_getnode(&child) < 0 ||
460*f0d9efc0Sbeck 	  bt_insertx(&child, record, reclen) < 0)
461*f0d9efc0Sbeck 	return -1;
462*f0d9efc0Sbeck 
463*f0d9efc0Sbeck       if (np->rnum < 0)
464*f0d9efc0Sbeck 	{
465*f0d9efc0Sbeck 	  n_index(np->bt, HFS_NODEREC(child, 0), child.nnum, rec, 0);
466*f0d9efc0Sbeck 	  if (*reclen == 0)
467*f0d9efc0Sbeck 	    return bt_putnode(np);
468*f0d9efc0Sbeck 	}
469*f0d9efc0Sbeck 
470*f0d9efc0Sbeck       return *reclen ? n_insert(np, record, reclen) : 0;
471*f0d9efc0Sbeck 
472*f0d9efc0Sbeck     case ndLeafNode:
473*f0d9efc0Sbeck       return n_insert(np, record, reclen);
474*f0d9efc0Sbeck 
475*f0d9efc0Sbeck     default:
476*f0d9efc0Sbeck       ERROR(EIO, "unexpected b*-tree node");
477*f0d9efc0Sbeck       return -1;
478*f0d9efc0Sbeck     }
479*f0d9efc0Sbeck }
480*f0d9efc0Sbeck 
481*f0d9efc0Sbeck /*
482*f0d9efc0Sbeck  * NAME:	btree->insert()
483*f0d9efc0Sbeck  * DESCRIPTION:	insert a new node record into a tree
484*f0d9efc0Sbeck  */
bt_insert(btree * bt,unsigned char * record,int reclen)485*f0d9efc0Sbeck int bt_insert(btree *bt, unsigned char *record, int reclen)
486*f0d9efc0Sbeck {
487*f0d9efc0Sbeck   node root;
488*f0d9efc0Sbeck 
489*f0d9efc0Sbeck   if (bt->hdr.bthRoot == 0)
490*f0d9efc0Sbeck     {
491*f0d9efc0Sbeck       /* create root node */
492*f0d9efc0Sbeck 
493*f0d9efc0Sbeck       n_init(&root, bt, ndLeafNode, 1);
494*f0d9efc0Sbeck       if (n_new(&root) < 0 ||
495*f0d9efc0Sbeck 	  bt_putnode(&root) < 0)
496*f0d9efc0Sbeck 	return -1;
497*f0d9efc0Sbeck 
498*f0d9efc0Sbeck       bt->hdr.bthDepth = 1;
499*f0d9efc0Sbeck       bt->hdr.bthRoot  = root.nnum;
500*f0d9efc0Sbeck       bt->hdr.bthFNode = root.nnum;
501*f0d9efc0Sbeck       bt->hdr.bthLNode = root.nnum;
502*f0d9efc0Sbeck 
503*f0d9efc0Sbeck       bt->flags |= HFS_UPDATE_BTHDR;
504*f0d9efc0Sbeck     }
505*f0d9efc0Sbeck   else
506*f0d9efc0Sbeck     {
507*f0d9efc0Sbeck       root.bt   = bt;
508*f0d9efc0Sbeck       root.nnum = bt->hdr.bthRoot;
509*f0d9efc0Sbeck 
510*f0d9efc0Sbeck       if (bt_getnode(&root) < 0)
511*f0d9efc0Sbeck 	return -1;
512*f0d9efc0Sbeck     }
513*f0d9efc0Sbeck 
514*f0d9efc0Sbeck   if (bt_insertx(&root, record, &reclen) < 0)
515*f0d9efc0Sbeck     return -1;
516*f0d9efc0Sbeck 
517*f0d9efc0Sbeck   if (reclen)
518*f0d9efc0Sbeck     {
519*f0d9efc0Sbeck       unsigned char oroot[HFS_MAXRECLEN];
520*f0d9efc0Sbeck       int orootlen;
521*f0d9efc0Sbeck 
522*f0d9efc0Sbeck       /* root node was split; create a new root */
523*f0d9efc0Sbeck 
524*f0d9efc0Sbeck       n_index(bt, HFS_NODEREC(root, 0), root.nnum, oroot, &orootlen);
525*f0d9efc0Sbeck 
526*f0d9efc0Sbeck       n_init(&root, bt, ndIndxNode, root.nd.ndNHeight + 1);
527*f0d9efc0Sbeck       if (n_new(&root) < 0)
528*f0d9efc0Sbeck 	return -1;
529*f0d9efc0Sbeck 
530*f0d9efc0Sbeck       ++bt->hdr.bthDepth;
531*f0d9efc0Sbeck       bt->hdr.bthRoot = root.nnum;
532*f0d9efc0Sbeck 
533*f0d9efc0Sbeck       bt->flags |= HFS_UPDATE_BTHDR;
534*f0d9efc0Sbeck 
535*f0d9efc0Sbeck       /* insert index records for new root */
536*f0d9efc0Sbeck 
537*f0d9efc0Sbeck       n_search(&root, oroot);
538*f0d9efc0Sbeck       n_insertx(&root, oroot, orootlen);
539*f0d9efc0Sbeck 
540*f0d9efc0Sbeck       n_search(&root, record);
541*f0d9efc0Sbeck       n_insertx(&root, record, reclen);
542*f0d9efc0Sbeck 
543*f0d9efc0Sbeck       if (bt_putnode(&root) < 0)
544*f0d9efc0Sbeck 	return -1;
545*f0d9efc0Sbeck     }
546*f0d9efc0Sbeck 
547*f0d9efc0Sbeck   ++bt->hdr.bthNRecs;
548*f0d9efc0Sbeck   bt->flags |= HFS_UPDATE_BTHDR;
549*f0d9efc0Sbeck 
550*f0d9efc0Sbeck   return 0;
551*f0d9efc0Sbeck }
552*f0d9efc0Sbeck 
553*f0d9efc0Sbeck /*
554*f0d9efc0Sbeck  * NAME:	btree->deletex()
555*f0d9efc0Sbeck  * DESCRIPTION:	recursively locate a node and delete a record
556*f0d9efc0Sbeck  */
bt_deletex(node * np,unsigned char * key,unsigned char * record,int * flag)557*f0d9efc0Sbeck int bt_deletex(node *np, unsigned char *key, unsigned char *record, int *flag)
558*f0d9efc0Sbeck {
559*f0d9efc0Sbeck   node child;
560*f0d9efc0Sbeck   unsigned char *rec;
561*f0d9efc0Sbeck   int found;
562*f0d9efc0Sbeck 
563*f0d9efc0Sbeck   found = n_search(np, key);
564*f0d9efc0Sbeck 
565*f0d9efc0Sbeck   switch ((unsigned char) np->nd.ndType)
566*f0d9efc0Sbeck     {
567*f0d9efc0Sbeck     case ndIndxNode:
568*f0d9efc0Sbeck       if (np->rnum < 0)
569*f0d9efc0Sbeck 	{
570*f0d9efc0Sbeck 	  ERROR(EIO, "b*-tree record not found");
571*f0d9efc0Sbeck 	  return -1;
572*f0d9efc0Sbeck 	}
573*f0d9efc0Sbeck 
574*f0d9efc0Sbeck       rec = HFS_NODEREC(*np, np->rnum);
575*f0d9efc0Sbeck 
576*f0d9efc0Sbeck       child.bt   = np->bt;
577*f0d9efc0Sbeck       child.nnum = d_getl(HFS_RECDATA(rec));
578*f0d9efc0Sbeck 
579*f0d9efc0Sbeck       if (bt_getnode(&child) < 0 ||
580*f0d9efc0Sbeck 	  bt_deletex(&child, key, rec, flag) < 0)
581*f0d9efc0Sbeck 	return -1;
582*f0d9efc0Sbeck 
583*f0d9efc0Sbeck       if (*flag)
584*f0d9efc0Sbeck 	{
585*f0d9efc0Sbeck 	  *flag = 0;
586*f0d9efc0Sbeck 
587*f0d9efc0Sbeck 	  if (HFS_RECKEYLEN(rec) == 0)
588*f0d9efc0Sbeck 	    return n_delete(np, record, flag);
589*f0d9efc0Sbeck 
590*f0d9efc0Sbeck 	  if (np->rnum == 0)
591*f0d9efc0Sbeck 	    {
592*f0d9efc0Sbeck 	      n_index(np->bt, HFS_NODEREC(*np, 0), np->nnum, record, 0);
593*f0d9efc0Sbeck 	      *flag = 1;
594*f0d9efc0Sbeck 	    }
595*f0d9efc0Sbeck 
596*f0d9efc0Sbeck 	  return bt_putnode(np);
597*f0d9efc0Sbeck 	}
598*f0d9efc0Sbeck 
599*f0d9efc0Sbeck       return 0;
600*f0d9efc0Sbeck 
601*f0d9efc0Sbeck     case ndLeafNode:
602*f0d9efc0Sbeck       if (found == 0)
603*f0d9efc0Sbeck 	{
604*f0d9efc0Sbeck 	  ERROR(EIO, "b*-tree record not found");
605*f0d9efc0Sbeck 	  return -1;
606*f0d9efc0Sbeck 	}
607*f0d9efc0Sbeck 
608*f0d9efc0Sbeck       return n_delete(np, record, flag);
609*f0d9efc0Sbeck 
610*f0d9efc0Sbeck     default:
611*f0d9efc0Sbeck       ERROR(EIO, "unexpected b*-tree node");
612*f0d9efc0Sbeck       return -1;
613*f0d9efc0Sbeck     }
614*f0d9efc0Sbeck }
615*f0d9efc0Sbeck 
616*f0d9efc0Sbeck /*
617*f0d9efc0Sbeck  * NAME:	btree->delete()
618*f0d9efc0Sbeck  * DESCRIPTION:	remove a node record from a tree
619*f0d9efc0Sbeck  */
bt_delete(btree * bt,unsigned char * key)620*f0d9efc0Sbeck int bt_delete(btree *bt, unsigned char *key)
621*f0d9efc0Sbeck {
622*f0d9efc0Sbeck   node root;
623*f0d9efc0Sbeck   unsigned char record[HFS_MAXRECLEN];
624*f0d9efc0Sbeck   int flag = 0;
625*f0d9efc0Sbeck 
626*f0d9efc0Sbeck   root.bt   = bt;
627*f0d9efc0Sbeck   root.nnum = bt->hdr.bthRoot;
628*f0d9efc0Sbeck 
629*f0d9efc0Sbeck   if (root.nnum == 0)
630*f0d9efc0Sbeck     {
631*f0d9efc0Sbeck       ERROR(EIO, "empty b*-tree");
632*f0d9efc0Sbeck       return -1;
633*f0d9efc0Sbeck     }
634*f0d9efc0Sbeck 
635*f0d9efc0Sbeck   if (bt_getnode(&root) < 0 ||
636*f0d9efc0Sbeck       bt_deletex(&root, key, record, &flag) < 0)
637*f0d9efc0Sbeck     return -1;
638*f0d9efc0Sbeck 
639*f0d9efc0Sbeck   if (bt->hdr.bthDepth > 1 && root.nd.ndNRecs == 1)
640*f0d9efc0Sbeck     {
641*f0d9efc0Sbeck       unsigned char *rec;
642*f0d9efc0Sbeck 
643*f0d9efc0Sbeck       /* chop the root */
644*f0d9efc0Sbeck 
645*f0d9efc0Sbeck       rec = HFS_NODEREC(root, 0);
646*f0d9efc0Sbeck 
647*f0d9efc0Sbeck       --bt->hdr.bthDepth;
648*f0d9efc0Sbeck       bt->hdr.bthRoot = d_getl(HFS_RECDATA(rec));
649*f0d9efc0Sbeck 
650*f0d9efc0Sbeck       n_free(&root);
651*f0d9efc0Sbeck     }
652*f0d9efc0Sbeck   else if (bt->hdr.bthDepth == 1 && root.nd.ndNRecs == 0)
653*f0d9efc0Sbeck     {
654*f0d9efc0Sbeck       /* delete the root node */
655*f0d9efc0Sbeck 
656*f0d9efc0Sbeck       bt->hdr.bthDepth = 0;
657*f0d9efc0Sbeck       bt->hdr.bthRoot  = 0;
658*f0d9efc0Sbeck       bt->hdr.bthFNode = 0;
659*f0d9efc0Sbeck       bt->hdr.bthLNode = 0;
660*f0d9efc0Sbeck 
661*f0d9efc0Sbeck       n_free(&root);
662*f0d9efc0Sbeck     }
663*f0d9efc0Sbeck 
664*f0d9efc0Sbeck   --bt->hdr.bthNRecs;
665*f0d9efc0Sbeck   bt->flags |= HFS_UPDATE_BTHDR;
666*f0d9efc0Sbeck 
667*f0d9efc0Sbeck   return 0;
668*f0d9efc0Sbeck }
669*f0d9efc0Sbeck 
670*f0d9efc0Sbeck /*
671*f0d9efc0Sbeck  * NAME:	btree->search()
672*f0d9efc0Sbeck  * DESCRIPTION:	locate a data record given a search key
673*f0d9efc0Sbeck  */
bt_search(btree * bt,unsigned char * key,node * np)674*f0d9efc0Sbeck int bt_search(btree *bt, unsigned char *key, node *np)
675*f0d9efc0Sbeck {
676*f0d9efc0Sbeck   np->bt   = bt;
677*f0d9efc0Sbeck   np->nnum = bt->hdr.bthRoot;
678*f0d9efc0Sbeck 
679*f0d9efc0Sbeck   if (np->nnum == 0)
680*f0d9efc0Sbeck     {
681*f0d9efc0Sbeck       ERROR(ENOENT, 0);
682*f0d9efc0Sbeck       return 0;
683*f0d9efc0Sbeck     }
684*f0d9efc0Sbeck 
685*f0d9efc0Sbeck   while (1)
686*f0d9efc0Sbeck     {
687*f0d9efc0Sbeck       int found;
688*f0d9efc0Sbeck       unsigned char *rec;
689*f0d9efc0Sbeck 
690*f0d9efc0Sbeck       if (bt_getnode(np) < 0)
691*f0d9efc0Sbeck 	return -1;
692*f0d9efc0Sbeck 
693*f0d9efc0Sbeck       found = n_search(np, key);
694*f0d9efc0Sbeck 
695*f0d9efc0Sbeck       switch ((unsigned char) np->nd.ndType)
696*f0d9efc0Sbeck 	{
697*f0d9efc0Sbeck 	case ndIndxNode:
698*f0d9efc0Sbeck 	  if (np->rnum < 0)
699*f0d9efc0Sbeck 	    {
700*f0d9efc0Sbeck 	      ERROR(ENOENT, 0);
701*f0d9efc0Sbeck 	      return 0;
702*f0d9efc0Sbeck 	    }
703*f0d9efc0Sbeck 
704*f0d9efc0Sbeck 	  rec = HFS_NODEREC(*np, np->rnum);
705*f0d9efc0Sbeck 	  np->nnum = d_getl(HFS_RECDATA(rec));
706*f0d9efc0Sbeck 	  break;
707*f0d9efc0Sbeck 
708*f0d9efc0Sbeck 	case ndLeafNode:
709*f0d9efc0Sbeck 	  if (! found)
710*f0d9efc0Sbeck 	    ERROR(ENOENT, 0);
711*f0d9efc0Sbeck 
712*f0d9efc0Sbeck 	  return found;
713*f0d9efc0Sbeck 
714*f0d9efc0Sbeck 	default:
715*f0d9efc0Sbeck 	  ERROR(EIO, "unexpected b*-tree node");
716*f0d9efc0Sbeck 	  return -1;
717*f0d9efc0Sbeck 	}
718*f0d9efc0Sbeck     }
719*f0d9efc0Sbeck }
720