|
|
1.1 root 1: /*
2: * libhfs - library for reading and writing Macintosh HFS volumes
3: * The fucntions are used to handle the various forms of btrees
4: * found on HFS+ volumes.
5: *
6: * The fucntions are used to handle the various forms of btrees
7: * found on HFS+ volumes.
8: *
9: * Copyright (C) 2000 Klaus Halfmann <[email protected]>
10: * Original 1996-1998 Robert Leslie <[email protected]>
11: * Additional work by Brad Boyer ([email protected])
12: *
13: * This program is free software; you can redistribute it and/or modify
14: * it under the terms of the GNU General Public License as published by
15: * the Free Software Foundation; either version 2 of the License, or
16: * (at your option) any later version.
17: *
18: * This program is distributed in the hope that it will be useful,
19: * but WITHOUT ANY WARRANTY; without even the implied warranty of
20: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21: * GNU General Public License for more details.
22: *
23: * You should have received a copy of the GNU General Public License
24: * along with this program; if not, write to the Free Software
25: * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
26: * MA 02110-1301, USA.
27: *
28: * $Id: btree.c,v 1.14 2000/10/25 05:43:04 hasi Exp $
29: */
30:
31: #include "config.h"
32: #include "libhfsp.h"
33: #include "volume.h"
34: #include "btree.h"
35: #include "record.h"
36: #include "swab.h"
37:
38: /* Read the node from the given buffer and swap the bytes.
39: *
40: * return pointer after reading the structure
41: */
42: static void* btree_readnode(btree_node_desc* node, void *p)
43: {
44: node->next = bswabU32_inc(p);
45: node->prev = bswabU32_inc(p);
46: node->kind = bswabU8_inc(p);
47: node->height = bswabU8_inc(p);
48: node->num_rec = bswabU16_inc(p);
49: node->reserved = bswabU16_inc(p);
50: return p;
51: }
52:
53: /* read a btree header from the given buffer and swap the bytes.
54: *
55: * return pointer after reading the structure
56: */
57: static void* btree_readhead(btree_head* head, void *p)
58: {
59: UInt32 *q;
60: head->depth = bswabU16_inc(p);
61: head->root = bswabU32_inc(p);
62: head->leaf_count = bswabU32_inc(p);
63: head->leaf_head = bswabU32_inc(p);
64: head->leaf_tail = bswabU32_inc(p);
65: head->node_size = bswabU16_inc(p);
66: head->max_key_len = bswabU16_inc(p);
67: head->node_count = bswabU32_inc(p);
68: head->free_nodes = bswabU32_inc(p);
69: head->reserved1 = bswabU16_inc(p);
70: head->clump_size = bswabU32_inc(p);
71: head->btree_type = bswabU8_inc(p);
72: head->reserved2 = bswabU8_inc(p);
73: head->attributes = bswabU32_inc(p);
74: // skip reserved bytes
75: q=((UInt32*) p);
76: // ((UInt32*) p) += 16;
77: q+=16;
78: return q;
79: }
80:
81: /* Priority of the depth of the node compared to LRU value.
82: * Should be the average number of keys per node but these vary. */
83: #define DEPTH_FACTOR 1000
84:
85: /* Cache size is height of tree + this value
86: * Really big numbers wont help in case of ls -R
87: */
88: #define EXTRA_CACHESIZE 3
89:
90: /* Not in use by now ... */
91: #define CACHE_DIRTY 0x0001
92:
93: /* Intialize cache with default cache Size,
94: * must call node_cache_close to deallocate memory */
95: static int node_cache_init(node_cache* cache, btree* tree, int size)
96: {
97: int nodebufsize;
98: char * buf;
99:
100: cache->size = size;
101: cache->currindex = 0;
102: nodebufsize = tree->head.node_size + sizeof(node_buf);
103: buf = malloc(size *(sizeof(node_entry) + nodebufsize));
104: if (!buf)
105: return -1;
106: cache -> nodebufsize = nodebufsize;
107: cache -> entries = (node_entry*) buf;
108: cache -> buffers = (char*) &cache->entries[size];
109: bzero(cache->entries, size*sizeof(node_entry));
110: return 0;
111: }
112:
113: /* Like cache->buffers[i], since size of node_buf is variable */
114: static inline node_buf* node_buf_get(node_cache* cache, int i)
115: {
116: return (node_buf*) (cache->buffers + (i * cache->nodebufsize));
117: }
118:
119: /* flush the node at index */
120: static void node_cache_flush_node(node_cache* cache, int index)
121: {
122: // NYI
123: cache -> entries[index].index = 0; // invalidate entry
124: }
125:
126: static void node_cache_close(node_cache* cache)
127: {
128: if (!cache->entries) // not (fully) intialized ?
129: return;
130: free(cache->entries);
131: }
132:
133: /* Load the cach node indentified by index with
134: * the node identified by node_index */
135:
136: static node_buf* node_cache_load_buf
137: (btree* bt, node_cache* cache, int index, UInt16 node_index)
138: {
139: node_buf *result = node_buf_get(cache ,index);
140: UInt32 blkpernode = bt->blkpernode;
141: UInt32 block = node_index * blkpernode;
142: void* p = volume_readfromfork(bt->vol, result->node, bt->fork,
143: block, blkpernode, HFSP_EXTENT_DATA, bt->cnid);
144: node_entry *e = &cache->entries[index];
145:
146: if (!p)
147: return NULL; // evil ...
148:
149: result->index = node_index;
150: btree_readnode(&result->desc, p);
151:
152: e -> priority = result->desc.height * DEPTH_FACTOR;
153: e -> index = node_index;
154: return result;
155: }
156:
157: /* Read node at given index, using cache.
158: */
159: node_buf* btree_node_by_index(btree* bt, UInt16 index)
160: {
161: node_cache* cache = &bt->cache;
162: int oldindex, lruindex;
163: int currindex = cache->currindex;
164: UInt32 prio;
165: node_entry *e;
166:
167: // Shortcut acces to current node, will not change priorities
168: if (cache->entries[currindex].index == index)
169: return node_buf_get(cache ,currindex);
170: oldindex = currindex;
171: if (currindex == 0)
172: currindex = cache->size;
173: currindex--;
174: lruindex = oldindex; // entry to be flushed when needed
175: prio = 0; // current priority
176: while (currindex != oldindex) // round robin
177: {
178: e = &cache->entries[currindex];
179: if (e->index == index) // got it
180: {
181: if (e->priority != 0) // already top, uuh
182: e->priority--;
183: cache->currindex = currindex;
184: return node_buf_get(cache ,currindex);
185: }
186: else
187: {
188: if (!e->index)
189: {
190: lruindex = currindex;
191: break; // empty entry, load it
192: }
193: if (e->priority != UINT_MAX) // already least, uuh
194: e->priority++;
195: }
196: if (prio < e->priority)
197: {
198: lruindex = currindex;
199: prio = e->priority;
200: }
201: if (currindex == 0)
202: currindex = cache->size;
203: currindex--;
204: }
205: e = &cache->entries[lruindex];
206: cache->currindex = lruindex;
207: if (e->flags & CACHE_DIRTY)
208: node_cache_flush_node( cache, lruindex);
209: return node_cache_load_buf (bt, cache, lruindex, index);
210: }
211:
212: /** intialize the btree with the first entry in the fork */
213: static int btree_init(btree* bt, volume* vol, hfsp_fork_raw* fork)
214: {
215: void *p;
216: char buf[vol->blksize];
217: UInt16 node_size;
218: btree_node_desc node;
219:
220: bt->vol = vol;
221: bt->fork = fork;
222: p = volume_readfromfork(vol, buf, fork, 0, 1,
223: HFSP_EXTENT_DATA, bt->cnid);
224: if (!p)
225: return -1;
226: p = btree_readnode(&node, p);
227: if (node.kind != HFSP_NODE_HEAD)
228: return -1; // should not happen ?
229: btree_readhead(&bt->head, p);
230:
231: node_size = bt->head.node_size;
232: bt->blkpernode = node_size / vol->blksize;
233:
234: if (bt->blkpernode == 0 || vol->blksize *
235: bt->blkpernode != node_size)
236: return -1; // should never happen ...
237:
238: node_cache_init(&bt->cache, bt, bt->head.depth + EXTRA_CACHESIZE);
239:
240: // Allocate buffer
241: // bt->buf = malloc(node_size);
242: // if (!bt->buf)
243: // return ENOMEM;
244:
245: return 0;
246: }
247:
248: /** Intialize catalog btree, so that btree_close can safely be called. */
249: void btree_reset(btree* bt)
250: {
251: bt->cache.entries = NULL;
252: }
253:
254: /** Intialize catalog btree */
255: int btree_init_cat(btree* bt, volume* vol, hfsp_fork_raw* fork)
256: {
257: int result = btree_init(bt,vol,fork); // super (...)
258: bt->cnid = HFSP_CAT_CNID;
259: bt->kcomp = record_key_compare;
260: bt->kread = record_readkey;
261: return result;
262: }
263:
264: /** Intialize catalog btree */
265: int btree_init_extent(btree* bt, volume* vol, hfsp_fork_raw* fork)
266: {
267: int result = btree_init(bt,vol,fork); // super (...)
268: bt->cnid = HFSP_EXT_CNID;
269: bt->kcomp = record_extent_key_compare;
270: bt->kread = record_extent_readkey;
271: return result;
272: }
273:
274: /** close the btree and free any resources */
275: void btree_close(btree* bt)
276: {
277: node_cache_close(&bt->cache);
278: // free(bt->buf);
279: }
280:
281: /* returns pointer to key given by index in current node.
282: *
283: * Assumes that current node is not NODE_HEAD ...
284: */
285: void* btree_key_by_index(btree* bt, node_buf* buf, UInt16 index)
286: {
287: UInt16 node_size = bt->head.node_size;
288: // The offsets are found at the end of the node ...
289: UInt16 off_pos = node_size - (index +1) * sizeof(btree_record_offset);
290: // position of offset at end of node
291: btree_record_offset* offset =
292: (btree_record_offset*) (buf->node + off_pos);
293:
294: // now we have the offset and can read the key ...
295: #ifdef CONFIG_LITTLE_ENDIAN
296: return buf->node + bswabU16(*offset);
297: #else
298: return buf->node + *offset;
299: #endif
300: }
301:
302:
303: #ifdef DEBUG
304:
305: /* print btree header node information */
306: void btree_printhead(btree_head* head)
307: {
308: UInt32 attr;
309: printf(" depth : %#X\n", head->depth);
310: printf(" root : %#lX\n", head->root);
311: printf(" leaf_count : %#lX\n", head->leaf_count);
312: printf(" leaf_head : %#lX\n", head->leaf_head);
313: printf(" leaf_tail : %#lX\n", head->leaf_tail);
314: printf(" node_size : %#X\n", head->node_size);
315: printf(" max_key_len : %#X\n", head->max_key_len);
316: printf(" node_count : %#lX\n", head->node_count);
317: printf(" free_nodes : %#lX\n", head->free_nodes);
318: printf(" reserved1 : %#X\n", head->reserved1);
319: printf(" clump_size : %#lX\n", head->clump_size);
320: printf(" btree_type : %#X\n", head->btree_type);
321: attr = head->attributes;
322: printf(" reserved2 : %#X\n", head->reserved2);
323: if (attr & HFSPLUS_BAD_CLOSE)
324: printf(" HFSPLUS_BAD_CLOSE *** ");
325: else
326: printf(" !HFSPLUS_BAD_CLOSE");
327: if (attr & HFSPLUS_TREE_BIGKEYS)
328: printf(" HFSPLUS_TREE_BIGKEYS ");
329: else
330: printf(" !HFSPLUS_TREE_BIGKEYS");
331: if (attr & HFSPLUS_TREE_VAR_NDXKEY_SIZE)
332: printf(" HFSPLUS_TREE_VAR_NDXKEY_SIZE");
333: else
334: printf(" !HFSPLUS_TREE_VAR_NDXKEY_SIZE");
335: if (attr & HFSPLUS_TREE_UNUSED)
336: printf(" HFSPLUS_TREE_UNUSED ***\n");
337: printf("\n");
338: }
339:
340: /* Dump all the node information to stdout */
341: void btree_print(btree* bt)
342: {
343: btree_node_desc* node;
344:
345: btree_printhead(&bt->head);
346:
347: node = &bt->node;
348: printf("next : %#lX\n", node->next);
349: printf("prev : %#lX\n", node->prev);
350: printf("height : %#X\n", node->height);
351: printf("num_rec : %#X\n", node->num_rec);
352: printf("reserved : %#X\n", node->reserved);
353: printf("height : %#X\n", node->height); switch(node->kind)
354: {
355: case HFSP_NODE_NDX :
356: printf("HFSP_NODE_NDX\n");
357: break;
358: case HFSP_NODE_HEAD :
359: printf("HFSP_NODE_HEAD\n");
360: break;
361: case HFSP_NODE_MAP :
362: printf("HFSP_NODE_MAP\n");
363: break;
364: case HFSP_NODE_LEAF :
365: printf("HFSP_NODE_LEAF\n");
366: break;
367: default:
368: printf("*** Unknown Node type ***\n");
369: }
370: }
371:
372: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.