2 * libhfs - library for reading and writing Macintosh HFS volumes
3 * Copyright (C) 1996-1998 Robert Leslie
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20 * $Id: btree.c,v 1.10 1998/11/02 22:08:54 rob Exp $
33 * NAME: btree->getnode()
34 * DESCRIPTION: retrieve a numbered node from a B*-tree file
36 int bt_getnode(node *np, btree *bt, unsigned long nnum)
38 block *bp = &np->data;
46 fprintf(stderr, "BTREE: GET vol \"%s\" btree \"%s\" node %lu\n",
47 bt->f.vol->mdb.drVN, bt->f.name, np->nnum);
50 /* verify the node exists and is marked as in-use */
52 if (nnum > 0 && nnum >= bt->hdr.bthNNodes)
53 ERROR(EIO, "read nonexistent b*-tree node");
54 else if (bt->map && ! BMTST(bt->map, nnum))
55 ERROR(EIO, "read unallocated b*-tree node");
57 if (f_getblock(&bt->f, nnum, bp) == -1)
62 d_fetchul(&ptr, &np->nd.ndFLink);
63 d_fetchul(&ptr, &np->nd.ndBLink);
64 d_fetchsb(&ptr, &np->nd.ndType);
65 d_fetchsb(&ptr, &np->nd.ndNHeight);
66 d_fetchuw(&ptr, &np->nd.ndNRecs);
67 d_fetchsw(&ptr, &np->nd.ndResv2);
69 if (np->nd.ndNRecs > HFS_MAX_NRECS)
70 ERROR(EIO, "too many b*-tree node records");
72 i = np->nd.ndNRecs + 1;
74 ptr = *bp + HFS_BLOCKSZ - (2 * i);
77 d_fetchuw(&ptr, &np->roff[i]);
87 * NAME: btree->readhdr()
88 * DESCRIPTION: read the header node of a B*-tree
90 int bt_readhdr(btree *bt)
97 if (bt_getnode(&bt->hdrnd, bt, 0) == -1)
100 if (bt->hdrnd.nd.ndType != ndHdrNode ||
101 bt->hdrnd.nd.ndNRecs != 3 ||
102 bt->hdrnd.roff[0] != 0x00e ||
103 bt->hdrnd.roff[1] != 0x078 ||
104 bt->hdrnd.roff[2] != 0x0f8 ||
105 bt->hdrnd.roff[3] != 0x1f8)
106 ERROR(EIO, "malformed b*-tree header node");
108 /* read header record */
110 ptr = HFS_NODEREC(bt->hdrnd, 0);
112 d_fetchuw(&ptr, &bt->hdr.bthDepth);
113 d_fetchul(&ptr, &bt->hdr.bthRoot);
114 d_fetchul(&ptr, &bt->hdr.bthNRecs);
115 d_fetchul(&ptr, &bt->hdr.bthFNode);
116 d_fetchul(&ptr, &bt->hdr.bthLNode);
117 d_fetchuw(&ptr, &bt->hdr.bthNodeSize);
118 d_fetchuw(&ptr, &bt->hdr.bthKeyLen);
119 d_fetchul(&ptr, &bt->hdr.bthNNodes);
120 d_fetchul(&ptr, &bt->hdr.bthFree);
122 for (i = 0; i < 76; ++i)
123 d_fetchsb(&ptr, &bt->hdr.bthResv[i]);
125 if (bt->hdr.bthNodeSize != HFS_BLOCKSZ)
126 ERROR(EINVAL, "unsupported b*-tree node size");
128 /* read map record; construct btree bitmap */
129 /* don't set bt->map until we're done, since getnode() checks it */
131 map = ALLOC(byte, HFS_MAP1SZ);
135 memcpy(map, HFS_NODEREC(bt->hdrnd, 2), HFS_MAP1SZ);
136 bt->mapsz = HFS_MAP1SZ;
138 /* read continuation map records, if any */
140 nnum = bt->hdrnd.nd.ndFLink;
147 if (bt_getnode(&n, bt, nnum) == -1)
150 if (n.nd.ndType != ndMapNode ||
152 n.roff[0] != 0x00e ||
154 ERROR(EIO, "malformed b*-tree map node");
156 newmap = REALLOC(map, byte, bt->mapsz + HFS_MAPXSZ);
162 memcpy(map + bt->mapsz, HFS_NODEREC(n, 0), HFS_MAPXSZ);
163 bt->mapsz += HFS_MAPXSZ;
179 * NAME: btree->search()
180 * DESCRIPTION: locate a data record given a search key
182 int bt_search(btree *bt, const byte *key, node *np)
187 nnum = bt->hdr.bthRoot;
196 if (bt_getnode(np, bt, nnum) == -1)
202 found = n_search(np, key);
204 switch (np->nd.ndType)
210 rec = HFS_NODEREC(*np, np->rnum);
211 nnum = d_getul(HFS_RECDATA(rec));
223 ERROR(EIO, "unexpected b*-tree node");