Home | History | Annotate | Line # | Download | only in hfs
libhfs.c revision 1.3
      1 /*	$NetBSD: libhfs.c,v 1.3 2007/03/09 22:14:09 dillo Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2005, 2007 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Yevgeny Binder and Dieter Baron.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 /*
     33  *  All functions and variable types have the prefix "hfs_". All constants
     34  *  have the prefix "HFS_".
     35  *
     36  *  Naming convention for functions which read/write raw, linear data
     37  *	into/from a structured form:
     38  *
     39  *  hfs_read/write[d][a]_foo_bar
     40  *      [d] - read/write from/to [d]isk instead of a memory buffer
     41  *      [a] - [a]llocate output buffer instead of using an existing one
     42  *            (not applicable for writing functions)
     43  *
     44  *  Most functions do not have either of these options, so they will read from
     45  *	or write to a memory buffer, which has been previously allocated by the
     46  *	caller.
     47  */
     48 
     49 #include "libhfs.h"
     50 
     51 /* global private file/folder keys */
     52 hfs_catalog_key_t hfs_gMetadataDirectoryKey; /* contains HFS+ inodes */
     53 hfs_catalog_key_t hfs_gJournalInfoBlockFileKey;
     54 hfs_catalog_key_t hfs_gJournalBufferFileKey;
     55 hfs_catalog_key_t* hfs_gPrivateObjectKeys[4] = {
     56 	&hfs_gMetadataDirectoryKey,
     57 	&hfs_gJournalInfoBlockFileKey,
     58 	&hfs_gJournalBufferFileKey,
     59 	NULL};
     60 
     61 
     62 extern uint16_t be16tohp(void** inout_ptr);
     63 extern uint32_t be32tohp(void** inout_ptr);
     64 extern uint64_t be64tohp(void** inout_ptr);
     65 
     66 int hfslib_create_casefolding_table(void);
     67 
     68 #ifdef DLO_DEBUG
     69 #include <stdio.h>
     70 void
     71 dlo_print_key(hfs_catalog_key_t *key)
     72 {
     73 	int i;
     74 
     75 	printf("%ld:[", (long)key->parent_cnid);
     76 	for (i=0; i<key->name.length; i++) {
     77 		if (key->name.unicode[i] < 256
     78 		    && isprint(key->name.unicode[i]))
     79 			putchar(key->name.unicode[i]);
     80 		else
     81 			printf("<%04x>", key->name.unicode[i]);
     82 	}
     83 	printf("]");
     84 }
     85 #endif
     86 
     87 void
     88 hfslib_init(hfs_callbacks* in_callbacks)
     89 {
     90 	unichar_t	temp[256];
     91 
     92 	if(in_callbacks!=NULL)
     93 		memcpy(&hfs_gcb, in_callbacks, sizeof(hfs_callbacks));
     94 
     95 	hfs_gcft = NULL;
     96 
     97 	/*
     98 	 * Create keys for the HFS+ "private" files so we can reuse them whenever
     99 	 * we perform a user-visible operation, such as listing directory contents.
    100 	 */
    101 
    102 #define ATOU(str, len) /* quick & dirty ascii-to-unicode conversion */ \
    103 	do{ int i; for(i=0; i<len; i++) temp[i]=str[i]; } \
    104 	while( /*CONSTCOND*/ 0)
    105 
    106 	ATOU("\0\0\0\0HFS+ Private Data", 21);
    107 	hfslib_make_catalog_key(HFS_CNID_ROOT_FOLDER, 21, temp,
    108 		&hfs_gMetadataDirectoryKey);
    109 
    110 	ATOU(".journal_info_block", 19);
    111 	hfslib_make_catalog_key(HFS_CNID_ROOT_FOLDER, 19, temp,
    112 		&hfs_gJournalInfoBlockFileKey);
    113 
    114 	ATOU(".journal", 8);
    115 	hfslib_make_catalog_key(HFS_CNID_ROOT_FOLDER, 8, temp,
    116 		&hfs_gJournalBufferFileKey);
    117 
    118 #undef ATOU
    119 }
    120 
    121 void
    122 hfslib_done(void)
    123 {
    124 	hfs_callback_args	cbargs;
    125 
    126 	if(hfs_gcft!=NULL) {
    127 		hfslib_init_cbargs(&cbargs);
    128 		hfslib_free(hfs_gcft, &cbargs);
    129 		hfs_gcft = NULL;
    130 	}
    131 
    132 	return;
    133 }
    134 
    135 void
    136 hfslib_init_cbargs(hfs_callback_args* ptr)
    137 {
    138 	memset(ptr, 0, sizeof(hfs_callback_args));
    139 }
    140 
    141 #if 0
    142 #pragma mark -
    143 #pragma mark High-Level Routines
    144 #endif
    145 
    146 int
    147 hfslib_open_volume(
    148 	const char* in_device,
    149 	uint64_t in_offset, /* given in BYTES, not BLOCKS */
    150 	int in_readonly,
    151 	hfs_volume* out_vol,
    152 	hfs_callback_args* cbargs)
    153 {
    154 	hfs_catalog_key_t		rootkey;
    155 	hfs_thread_record_t	rootthread;
    156 	uint16_t	node_rec_sizes[1];
    157 	void*		node_recs[1];
    158 	void*		buffer;
    159 	void*		buffer2;	/* used as temporary pointer for realloc() */
    160 	int			result;
    161 
    162 	result = 1;
    163 	buffer = NULL;
    164 
    165 	if(in_device==NULL || out_vol==NULL)
    166 		return 1;
    167 
    168 	out_vol->readonly = in_readonly;
    169 
    170 	if(hfslib_openvoldevice(out_vol, in_device, in_offset, cbargs) != 0)
    171 		HFS_LIBERR("could not open device");
    172 
    173 	/*
    174 	 *	Read the volume header.
    175 	 */
    176 	buffer = hfslib_malloc(sizeof(hfs_volume_header_t), cbargs);
    177 	if(buffer==NULL)
    178 		HFS_LIBERR("could not allocate volume header");
    179 
    180 	if(hfslib_readd(out_vol, buffer, sizeof(hfs_volume_header_t),
    181 		HFS_VOLUME_HEAD_RESERVE_SIZE, cbargs)!=0)
    182 		HFS_LIBERR("could not read volume header");
    183 	if(hfslib_read_volume_header(buffer, &(out_vol->vh))==0)
    184 		HFS_LIBERR("could not parse volume header");
    185 
    186 	/*
    187 	 * Check the volume signature to see if this is a legitimate HFS+ or HFSX
    188 	 * volume. If so, set the key comparison function pointers appropriately.
    189 	 */
    190 	switch(out_vol->vh.signature)
    191 	{
    192 		case HFS_SIG_HFSP:
    193 			out_vol->keycmp = hfslib_compare_catalog_keys_cf;
    194 			break;
    195 
    196 		case HFS_SIG_HFSX:
    197 			out_vol->keycmp = NULL; /* will be set below */
    198 			break;
    199 
    200 		case HFS_SIG_HFS:
    201 			HFS_LIBERR("HFS volumes and HFS+ volumes with HFS wrappers are"
    202 						"not currently supported");
    203 			break;
    204 
    205 		default:
    206 			HFS_LIBERR("unrecognized volume format");
    207 	}
    208 
    209 
    210 	/*
    211 	 *	Read the catalog header.
    212 	 */
    213 	buffer2 = hfslib_realloc(buffer, 512, cbargs);
    214 	if(buffer2==NULL)
    215 		HFS_LIBERR("could not allocate catalog header node");
    216 	buffer = buffer2;
    217 
    218 	/*
    219 	  We are only interested in the node header, so read the first
    220 	  512 bytes and construct the node descriptor by hand.
    221 	*/
    222 	if(hfslib_readd(out_vol, buffer, 512,
    223 	       out_vol->vh.catalog_file.extents[0].start_block
    224 	       *(uint64_t)out_vol->vh.block_size,
    225 		cbargs) != 0)
    226 		HFS_LIBERR("could not read catalog header node");
    227 	node_recs[0] = (char *)buffer+14;
    228 	node_rec_sizes[0] = 120;
    229 	if(hfslib_read_header_node(node_recs, node_rec_sizes, 1,
    230 		&out_vol->chr, NULL, NULL)==0)
    231 		HFS_LIBERR("could not parse catalog header node");
    232 
    233 	/* If this is an HFSX volume, the catalog header specifies the type of
    234 	 * key comparison method (case-folding or binary compare) we should use. */
    235 	if(out_vol->keycmp == NULL)
    236 	{
    237 		if(out_vol->chr.keycomp_type == HFS_KEY_CASEFOLD)
    238 			out_vol->keycmp = hfslib_compare_catalog_keys_cf;
    239 		else if(out_vol->chr.keycomp_type == HFS_KEY_BINARY)
    240 			out_vol->keycmp = hfslib_compare_catalog_keys_bc;
    241 		else
    242 			HFS_LIBERR("undefined key compare method");
    243 	}
    244 
    245 	out_vol->catkeysizefieldsize
    246 	    = (out_vol->chr.attributes & HFS_BIG_KEYS_MASK) ?
    247 	    sizeof(uint16_t) : sizeof(uint8_t);
    248 
    249 	/*
    250 	 *	Read the extent overflow header.
    251 	 */
    252 	/*
    253 	  We are only interested in the node header, so read the first
    254 	  512 bytes and construct the node descriptor by hand.
    255 	  buffer is already 512 bytes long.
    256 	*/
    257 	if(hfslib_readd(out_vol, buffer, 512,
    258 	       out_vol->vh.extents_file.extents[0].start_block
    259 	       *(uint64_t)out_vol->vh.block_size,
    260 		cbargs) != 0)
    261 		HFS_LIBERR("could not read extent header node");
    262 
    263 	node_recs[0] = (char *)buffer+14;
    264 	node_rec_sizes[0] = 120;
    265 	if(hfslib_read_header_node(node_recs, node_rec_sizes, 1,
    266 		&out_vol->ehr, NULL, NULL)==0)
    267 		HFS_LIBERR("could not parse extent header node");
    268 	out_vol->extkeysizefieldsize
    269 	    = (out_vol->ehr.attributes & HFS_BIG_KEYS_MASK) ?
    270 	    sizeof(uint16_t):sizeof(uint8_t);
    271 	/*
    272 	 * Read the journal info block and journal header (if volume journaled).
    273 	 */
    274 	if(out_vol->vh.attributes & (1<<HFS_VOL_JOURNALED))
    275 	{
    276 		/* journal info block */
    277 		buffer2 = hfslib_realloc(buffer, sizeof(hfs_journal_info_t), cbargs);
    278 		if(buffer2==NULL)
    279 			HFS_LIBERR("could not allocate journal info block");
    280 		buffer = buffer2;
    281 
    282 		if(hfslib_readd(out_vol, buffer, sizeof(hfs_journal_info_t),
    283 			out_vol->vh.journal_info_block * out_vol->vh.block_size,
    284 			cbargs) != 0)
    285 			HFS_LIBERR("could not read journal info block");
    286 
    287 		if(hfslib_read_journal_info(buffer, &out_vol->jib)==0)
    288 			HFS_LIBERR("could not parse journal info block");
    289 
    290 		/* journal header */
    291 		buffer2 = hfslib_realloc(buffer, sizeof(hfs_journal_header_t),cbargs);
    292 		if(buffer2==NULL)
    293 			HFS_LIBERR("could not allocate journal header");
    294 		buffer = buffer2;
    295 
    296 		if(hfslib_readd(out_vol, buffer, sizeof(hfs_journal_header_t),
    297 			out_vol->jib.offset, cbargs) != 0)
    298 			HFS_LIBERR("could not read journal header");
    299 
    300 		if(hfslib_read_journal_header(buffer, &out_vol->jh)==0)
    301 			HFS_LIBERR("could not parse journal header");
    302 
    303 		out_vol->journaled = 1;
    304 	}
    305 	else
    306 	{
    307 		out_vol->journaled = 0;
    308 	}
    309 
    310 	/*
    311 	 * If this volume uses case-folding comparison and the folding table hasn't
    312 	 * been created yet, do that here. (We don't do this in hfslib_init()
    313 	 * because the table is large and we might never even need to use it.)
    314 	 */
    315 	if(out_vol->keycmp==hfslib_compare_catalog_keys_cf && hfs_gcft==NULL)
    316 		result = hfslib_create_casefolding_table();
    317 	else
    318 		result = 0;
    319 
    320 	/*
    321 	 * Find and store the volume name.
    322 	 */
    323 	if(hfslib_make_catalog_key(HFS_CNID_ROOT_FOLDER, 0, NULL, &rootkey)==0)
    324 		HFS_LIBERR("could not make root search key");
    325 
    326 	if(hfslib_find_catalog_record_with_key(out_vol, &rootkey,
    327 		(hfs_catalog_keyed_record_t*)&rootthread, cbargs)!=0)
    328 		HFS_LIBERR("could not find root parent");
    329 
    330 	memcpy(&out_vol->name, &rootthread.name, sizeof(hfs_unistr255_t));
    331 
    332 
    333 	/* FALLTHROUGH */
    334 error:
    335 	if(buffer!=NULL)
    336 		hfslib_free(buffer, cbargs);
    337 
    338 	return result;
    339 }
    340 
    341 void
    342 hfslib_close_volume(hfs_volume* in_vol, hfs_callback_args* cbargs)
    343 {
    344 	if(in_vol==NULL)
    345 		return;
    346 
    347 	hfslib_closevoldevice(in_vol, cbargs);
    348 }
    349 
    350 int
    351 hfslib_path_to_cnid(hfs_volume* in_vol,
    352 	hfs_cnid_t in_cnid,
    353 	char** out_unicode,
    354 	uint16_t* out_length,
    355 	hfs_callback_args* cbargs)
    356 {
    357 	hfs_thread_record_t	parent_thread;
    358 	hfs_cnid_t	parent_cnid, child_cnid;
    359 	char*		newpath;
    360 	char*		path;
    361 	int			path_offset = 0;
    362 	int			result;
    363 	uint16_t*	ptr;	/* dummy var */
    364 	uint16_t	uchar;	/* dummy var */
    365 	uint16_t	total_path_length;
    366 
    367 	if(in_vol==NULL || in_cnid==0 || out_unicode==NULL || out_length==NULL)
    368 		return 1;
    369 
    370 	result = 1;
    371 	*out_unicode = NULL;
    372 	*out_length = 0;
    373 	path = NULL;
    374 	total_path_length = 0;
    375 
    376 	path = hfslib_malloc(514, cbargs); /* 256 unichars plus a forward slash */
    377 	if(path==NULL)
    378 		return 1;
    379 
    380 	child_cnid = in_cnid;
    381 	parent_cnid = child_cnid; /* skips loop in case in_cnid is root id */
    382 	while(parent_cnid != HFS_CNID_ROOT_FOLDER
    383 		&& parent_cnid != HFS_CNID_ROOT_PARENT)
    384 	{
    385 		if(child_cnid!=in_cnid)
    386 		{
    387 			newpath = hfslib_realloc(path, 514 + total_path_length*2, cbargs);
    388 
    389 			if(newpath==NULL)
    390 				goto exit;
    391 			path = newpath;
    392 
    393 			memmove(path + 514, path + path_offset, total_path_length*2);
    394 		}
    395 
    396 		parent_cnid = hfslib_find_parent_thread(in_vol, child_cnid,
    397 			&parent_thread, cbargs);
    398 		if(parent_cnid==0)
    399 			goto exit;
    400 
    401 		path_offset = 512 - parent_thread.name.length*2;
    402 
    403 		memcpy(path + path_offset, parent_thread.name.unicode,
    404 			parent_thread.name.length*2);
    405 
    406 		/*	Add a forward slash. The unicode string was specified in big endian
    407 		 *	format, so convert to core format if necessary. */
    408 		path[512]=0x00;
    409 		path[513]=0x2F;
    410 
    411 		ptr = (uint16_t*)path + 256;
    412 		uchar = be16tohp((void*)&ptr);
    413 		*(ptr-1) = uchar;
    414 
    415 		total_path_length += parent_thread.name.length + 1;
    416 
    417 		child_cnid = parent_cnid;
    418 	}
    419 
    420 	/*
    421 	 *	At this point, 'path' holds a sequence of unicode characters which
    422 	 *	represent the absolute path to the given cnid. This string is missing
    423 	 *	a terminating null char and an initial forward slash that represents
    424 	 *	the root of the filesystem. It most likely also has extra space in
    425 	 *	the beginning, due to the fact that we reserve 512 bytes for each path
    426 	 *	component and won't usually use all that space. So, we allocate the
    427 	 *	final string based on the actual length of the absolute path, plus four
    428 	 *	additional bytes (two unichars) for the forward slash and the null char.
    429 	 */
    430 
    431 	*out_unicode = hfslib_malloc((total_path_length+2)*2, cbargs);
    432 	if(*out_unicode == NULL)
    433 		goto exit;
    434 
    435 	/* copy only the bytes that are actually used */
    436 	memcpy(*out_unicode+2, path + path_offset, total_path_length*2);
    437 
    438 	/* insert forward slash at start */
    439 	(*out_unicode)[0] = 0x00;
    440 	(*out_unicode)[1] = 0x2F;
    441 	ptr = (uint16_t*)*out_unicode;
    442 	uchar = be16tohp((void*)&ptr);
    443 	*(ptr-1) = uchar;
    444 
    445 	/* insert null char at end */
    446 	(*out_unicode)[total_path_length*2+2] = 0x00;
    447 	(*out_unicode)[total_path_length*2+3] = 0x00;
    448 
    449 	*out_length = total_path_length + 1 /* extra for forward slash */ ;
    450 
    451 	result = 0;
    452 
    453 exit:
    454 	if(path!=NULL)
    455 		hfslib_free(path, cbargs);
    456 
    457 	return result;
    458 }
    459 
    460 hfs_cnid_t
    461 hfslib_find_parent_thread(
    462 	hfs_volume* in_vol,
    463 	hfs_cnid_t in_child,
    464 	hfs_thread_record_t* out_thread,
    465 	hfs_callback_args* cbargs)
    466 {
    467 	hfs_catalog_key_t	childkey;
    468 
    469 	if(in_vol==NULL || in_child==0 || out_thread==NULL)
    470 		return 0;
    471 
    472 	if(hfslib_make_catalog_key(in_child, 0, NULL, &childkey)==0)
    473 		return 0;
    474 
    475 	if(hfslib_find_catalog_record_with_key(in_vol, &childkey,
    476 		(hfs_catalog_keyed_record_t*)out_thread, cbargs)!=0)
    477 		return 0;
    478 
    479 	return out_thread->parent_cnid;
    480 }
    481 
    482 /*
    483  * hfslib_find_catalog_record_with_cnid()
    484  *
    485  * Looks up a catalog record by calling hfslib_find_parent_thread() and
    486  * hfslib_find_catalog_record_with_key(). out_key may be NULL; if not, the key
    487  * corresponding to this cnid is stuffed in it. Returns 0 on success.
    488  */
    489 int
    490 hfslib_find_catalog_record_with_cnid(
    491 	hfs_volume* in_vol,
    492 	hfs_cnid_t in_cnid,
    493 	hfs_catalog_keyed_record_t* out_rec,
    494 	hfs_catalog_key_t* out_key,
    495 	hfs_callback_args* cbargs)
    496 {
    497 	hfs_cnid_t					parentcnid;
    498 	hfs_thread_record_t		parentthread;
    499 	hfs_catalog_key_t			key;
    500 
    501 	if(in_vol==NULL || in_cnid==0 || out_rec==NULL)
    502 		return 0;
    503 
    504 	parentcnid =
    505 		hfslib_find_parent_thread(in_vol, in_cnid, &parentthread, cbargs);
    506 	if(parentcnid == 0)
    507 		HFS_LIBERR("could not find parent thread for cnid %i", in_cnid);
    508 
    509 	if(hfslib_make_catalog_key(parentthread.parent_cnid,
    510 		parentthread.name.length, parentthread.name.unicode, &key) == 0)
    511 		HFS_LIBERR("could not make catalog search key");
    512 
    513 	if(out_key!=NULL)
    514 		memcpy(out_key, &key, sizeof(key));
    515 
    516 	return hfslib_find_catalog_record_with_key(in_vol, &key, out_rec, cbargs);
    517 
    518 error:
    519 	return 1;
    520 }
    521 
    522 /* Returns 0 on success, 1 on error, and -1 if record was not found. */
    523 int
    524 hfslib_find_catalog_record_with_key(
    525 	hfs_volume* in_vol,
    526 	hfs_catalog_key_t* in_key,
    527 	hfs_catalog_keyed_record_t* out_rec,
    528 	hfs_callback_args* cbargs)
    529 {
    530 	hfs_node_descriptor_t			nd;
    531 	hfs_extent_descriptor_t*		extents;
    532 	hfs_catalog_keyed_record_t		lastrec;
    533 	hfs_catalog_key_t*	curkey;
    534 	void**				recs;
    535 	void*				buffer;
    536 	uint64_t			bytesread;
    537 	uint32_t			curnode;
    538 	uint16_t*			recsizes;
    539 	uint16_t			numextents;
    540 	uint16_t			recnum;
    541 	int16_t				leaftype;
    542 	int					keycompare;
    543 	int					result;
    544 
    545 	if(in_key==NULL || out_rec==NULL || in_vol==NULL)
    546 		return 1;
    547 
    548 	result = 1;
    549 	buffer = NULL;
    550 	curkey = NULL;
    551 	extents = NULL;
    552 	recs = NULL;
    553 	recsizes = NULL;
    554 
    555 	/* The key takes up over half a kb of ram, which is a lot for the BSD
    556 	 * kernel stack. So allocate it in the heap instead to play it safe. */
    557 	curkey = hfslib_malloc(sizeof(hfs_catalog_key_t), cbargs);
    558 	if(curkey==NULL)
    559 		HFS_LIBERR("could not allocate catalog search key");
    560 
    561 	buffer = hfslib_malloc(in_vol->chr.node_size, cbargs);
    562 	if(buffer==NULL)
    563 		HFS_LIBERR("could not allocate node buffer");
    564 
    565 	numextents = hfslib_get_file_extents(in_vol, HFS_CNID_CATALOG,
    566 		HFS_DATAFORK, &extents, cbargs);
    567 	if(numextents==0)
    568 		HFS_LIBERR("could not locate fork extents");
    569 
    570 	nd.num_recs = 0;
    571 	curnode = in_vol->chr.root_node;
    572 
    573 #ifdef DLO_DEBUG
    574 	printf("-> key ");
    575 	dlo_print_key(in_key);
    576 	printf("\n");
    577 #endif
    578 
    579 	do
    580 	{
    581 #ifdef DLO_DEBUG
    582 		printf("--> node %d\n", curnode);
    583 #endif
    584 
    585 		if(hfslib_readd_with_extents(in_vol, buffer,
    586 			&bytesread,in_vol->chr.node_size, curnode * in_vol->chr.node_size,
    587 			extents, numextents, cbargs)!=0)
    588 			HFS_LIBERR("could not read catalog node #%i", curnode);
    589 
    590 		if(hfslib_reada_node(buffer, &nd, &recs, &recsizes, HFS_CATALOG_FILE,
    591 			in_vol, cbargs)==0)
    592 			HFS_LIBERR("could not parse catalog node #%i", curnode);
    593 
    594 		for(recnum=0; recnum<nd.num_recs; recnum++)
    595 		{
    596 			leaftype = nd.kind;
    597 			if(hfslib_read_catalog_keyed_record(recs[recnum], out_rec,
    598 				&leaftype, curkey, in_vol)==0)
    599 				HFS_LIBERR("could not read catalog record #%i",recnum);
    600 
    601 #ifdef DLO_DEBUG
    602 			printf("---> record %d: ", recnum);
    603 			dlo_print_key(curkey);
    604 			fflush(stdout);
    605 #endif
    606 			keycompare = in_vol->keycmp(in_key, curkey);
    607 #ifdef DLO_DEBUG
    608 			printf(" %c\n",
    609 			       keycompare < 0 ? '<'
    610 			       : keycompare == 0 ? '=' : '>');
    611 #endif
    612 
    613 			if(keycompare < 0)
    614 			{
    615 				/* Check if key is less than *every* record, which should never
    616 				 * happen if the volume is consistent and the key legit. */
    617 				if(recnum==0)
    618 					HFS_LIBERR("all records greater than key");
    619 
    620 				/* Otherwise, we've found the first record that exceeds our key,
    621 				 * so retrieve the previous record, which is still less... */
    622 				memcpy(out_rec, &lastrec,
    623 					sizeof(hfs_catalog_keyed_record_t));
    624 
    625 				/* ...unless this is a leaf node, which means we've gone from
    626 				 * a key which is smaller than the search key, in the previous
    627 				 * loop, to a key which is larger, in this loop, and that
    628 				 * implies that our search key does not exist on the volume. */
    629 				if(nd.kind==HFS_LEAFNODE)
    630 					result = -1;
    631 
    632 				break;
    633 			}
    634 			else if(keycompare == 0)
    635 			{
    636 				/* If leaf node, found an exact match. */
    637 				result = 0;
    638 				break;
    639 			}
    640 			else if(recnum==nd.num_recs-1 && keycompare > 0)
    641 			{
    642 				/* If leaf node, we've reached the last record with no match,
    643 				 * which means this key is not present on the volume. */
    644 				result = -1;
    645 				break;
    646 			}
    647 
    648 			memcpy(&lastrec, out_rec, sizeof(hfs_catalog_keyed_record_t));
    649 		}
    650 
    651 		if(nd.kind==HFS_INDEXNODE)
    652 			curnode = out_rec->child;
    653 		else if(nd.kind==HFS_LEAFNODE)
    654 			break;
    655 
    656 		hfslib_free_recs(&recs, &recsizes, &nd.num_recs, cbargs);
    657 	}
    658 	while(nd.kind!=HFS_LEAFNODE);
    659 
    660 	/* FALLTHROUGH */
    661 error:
    662 	if(extents!=NULL)
    663 		hfslib_free(extents, cbargs);
    664 	hfslib_free_recs(&recs, &recsizes, &nd.num_recs, cbargs);
    665 	if(curkey!=NULL)
    666 		hfslib_free(curkey, cbargs);
    667 	if(buffer!=NULL)
    668 		hfslib_free(buffer, cbargs);
    669 
    670 	return result;
    671 }
    672 
    673 /* returns 0 on success */
    674 /* XXX Need to look this over and make sure it gracefully handles cases where
    675  * XXX the key is not found. */
    676 int
    677 hfslib_find_extent_record_with_key(hfs_volume* in_vol,
    678 	hfs_extent_key_t* in_key,
    679 	hfs_extent_record_t* out_rec,
    680 	hfs_callback_args* cbargs)
    681 {
    682 	hfs_node_descriptor_t		nd;
    683 	hfs_extent_descriptor_t*	extents;
    684 	hfs_extent_record_t		lastrec;
    685 	hfs_extent_key_t	curkey;
    686 	void**				recs;
    687 	void*				buffer;
    688 	uint64_t			bytesread;
    689 	uint32_t			curnode;
    690 	uint16_t*			recsizes;
    691 	uint16_t			numextents;
    692 	uint16_t			recnum;
    693 	int					keycompare;
    694 	int					result;
    695 
    696 	if(in_vol==NULL || in_key==NULL || out_rec==NULL)
    697 		return 1;
    698 
    699 	result = 1;
    700 	buffer = NULL;
    701 	extents = NULL;
    702 	recs = NULL;
    703 	recsizes = NULL;
    704 
    705 	buffer = hfslib_malloc(in_vol->ehr.node_size, cbargs);
    706 	if(buffer==NULL)
    707 		HFS_LIBERR("could not allocate node buffer");
    708 
    709 	numextents = hfslib_get_file_extents(in_vol, HFS_CNID_EXTENTS,
    710 		HFS_DATAFORK, &extents, cbargs);
    711 	if(numextents==0)
    712 		HFS_LIBERR("could not locate fork extents");
    713 
    714 	nd.num_recs = 0;
    715 	curnode = in_vol->ehr.root_node;
    716 
    717 	do
    718 	{
    719 		hfslib_free_recs(&recs, &recsizes, &nd.num_recs, cbargs);
    720 		recnum = 0;
    721 
    722 		if(hfslib_readd_with_extents(in_vol, buffer, &bytesread,
    723 			in_vol->ehr.node_size, curnode * in_vol->ehr.node_size, extents,
    724 			numextents, cbargs)!=0)
    725 			HFS_LIBERR("could not read extents overflow node #%i", curnode);
    726 
    727 		if(hfslib_reada_node(buffer, &nd, &recs, &recsizes, HFS_EXTENTS_FILE,
    728 			in_vol, cbargs)==0)
    729 			HFS_LIBERR("could not parse extents overflow node #%i",curnode);
    730 
    731 		for(recnum=0; recnum<nd.num_recs; recnum++)
    732 		{
    733 			memcpy(&lastrec, out_rec, sizeof(hfs_extent_record_t));
    734 
    735 			if(hfslib_read_extent_record(recs[recnum], out_rec, nd.kind,
    736 				&curkey, in_vol)==0)
    737 				HFS_LIBERR("could not read extents record #%i",recnum);
    738 
    739 			keycompare = hfslib_compare_extent_keys(in_key, &curkey);
    740 			if(keycompare < 0)
    741 			{
    742 				/* this should never happen for any legitimate key */
    743 				if(recnum==0)
    744 					return 1;
    745 
    746 				memcpy(out_rec, &lastrec, sizeof(hfs_extent_record_t));
    747 
    748 				break;
    749 			}
    750 			else if(keycompare == 0 ||
    751 				(recnum==nd.num_recs-1 && keycompare > 0))
    752 				break;
    753 		}
    754 
    755 		if(nd.kind==HFS_INDEXNODE)
    756 			curnode = *((uint32_t *)out_rec); /* out_rec is a node ptr in this case */
    757 		else if(nd.kind==HFS_LEAFNODE)
    758 			break;
    759 		else
    760 		    HFS_LIBERR("unknwon node type for extents overflow node #%i",curnode);
    761 	}
    762 	while(nd.kind!=HFS_LEAFNODE);
    763 
    764 	result = 0;
    765 
    766 	/* FALLTHROUGH */
    767 
    768 error:
    769 	if(buffer!=NULL)
    770 		hfslib_free(buffer, cbargs);
    771 	if(extents!=NULL)
    772 		hfslib_free(extents, cbargs);
    773 	hfslib_free_recs(&recs, &recsizes, &nd.num_recs, cbargs);
    774 
    775 	return result;
    776 }
    777 
    778 /* out_extents may be NULL. */
    779 uint16_t
    780 hfslib_get_file_extents(hfs_volume* in_vol,
    781 	hfs_cnid_t in_cnid,
    782 	uint8_t in_forktype,
    783 	hfs_extent_descriptor_t** out_extents,
    784 	hfs_callback_args* cbargs)
    785 {
    786 	hfs_extent_descriptor_t*	dummy;
    787 	hfs_extent_key_t		extentkey;
    788 	hfs_file_record_t		file;
    789 	hfs_catalog_key_t		filekey;
    790 	hfs_thread_record_t	fileparent;
    791 	hfs_fork_t				fork;
    792 	hfs_extent_record_t	nextextentrec;
    793 	uint32_t	numblocks;
    794 	uint16_t	numextents, n;
    795 
    796 	if(in_vol==NULL || in_cnid==0)
    797 		return 0;
    798 
    799 	if(out_extents!=NULL)
    800 	{
    801 		*out_extents = hfslib_malloc(sizeof(hfs_extent_descriptor_t), cbargs);
    802 		if(*out_extents==NULL)
    803 			return 0;
    804 	}
    805 
    806 	switch(in_cnid)
    807 	{
    808 		case HFS_CNID_CATALOG:
    809 			fork = in_vol->vh.catalog_file;
    810 			break;
    811 
    812 		case HFS_CNID_EXTENTS:
    813 			fork = in_vol->vh.extents_file;
    814 			break;
    815 
    816 		case HFS_CNID_ALLOCATION:
    817 			fork = in_vol->vh.allocation_file;
    818 			break;
    819 
    820 		case HFS_CNID_ATTRIBUTES:
    821 			fork = in_vol->vh.attributes_file;
    822 			break;
    823 
    824 		case HFS_CNID_STARTUP:
    825 			fork = in_vol->vh.startup_file;
    826 			break;
    827 
    828 		default:
    829 			if(hfslib_find_parent_thread(in_vol, in_cnid, &fileparent,
    830 				cbargs)==0)
    831 				goto error;
    832 
    833 			if(hfslib_make_catalog_key(fileparent.parent_cnid,
    834 				fileparent.name.length, fileparent.name.unicode, &filekey)==0)
    835 				goto error;
    836 
    837 			if(hfslib_find_catalog_record_with_key(in_vol, &filekey,
    838 				(hfs_catalog_keyed_record_t*)&file, cbargs)!=0)
    839 				goto error;
    840 
    841 			/* only files have extents, not folders or threads */
    842 			if(file.rec_type!=HFS_REC_FILE)
    843 				goto error;
    844 
    845 			if(in_forktype==HFS_DATAFORK)
    846 				fork = file.data_fork;
    847 			else if(in_forktype==HFS_RSRCFORK)
    848 				fork = file.rsrc_fork;
    849 	}
    850 
    851 	numextents = 0;
    852 	numblocks = 0;
    853 	memcpy(&nextextentrec, &fork.extents, sizeof(hfs_extent_record_t));
    854 
    855 	while(1)
    856 	{
    857 		for(n=0; n<8; n++)
    858 		{
    859 			if(nextextentrec[n].block_count==0)
    860 				break;
    861 
    862 			numblocks += nextextentrec[n].block_count;
    863 		}
    864 
    865 		if(out_extents!=NULL)
    866 		{
    867 			dummy = hfslib_realloc(*out_extents,
    868 			    (numextents+n) * sizeof(hfs_extent_descriptor_t),
    869 			    cbargs);
    870 			if(dummy==NULL)
    871 				goto error;
    872 			*out_extents = dummy;
    873 
    874 			memcpy(*out_extents + numextents,
    875 			    &nextextentrec, n*sizeof(hfs_extent_descriptor_t));
    876 		}
    877 		numextents += n;
    878 
    879 		if(numblocks >= fork.total_blocks)
    880 			break;
    881 
    882 		if(hfslib_make_extent_key(in_cnid, in_forktype, numblocks,
    883 			&extentkey)==0)
    884 			goto error;
    885 
    886 		if(hfslib_find_extent_record_with_key(in_vol, &extentkey,
    887 			&nextextentrec, cbargs)!=0)
    888 			goto error;
    889 	}
    890 
    891 	goto exit;
    892 
    893 error:
    894 	if(out_extents!=NULL && *out_extents!=NULL)
    895 	{
    896 		hfslib_free(*out_extents, cbargs);
    897 		*out_extents = NULL;
    898 	}
    899 	return 0;
    900 
    901 exit:
    902 	return numextents;
    903 }
    904 
    905 /*
    906  * hfslib_get_directory_contents()
    907  *
    908  * Finds the immediate children of a given directory CNID and places their
    909  * CNIDs in an array allocated here. The first child is found by doing a
    910  * catalog search that only compares parent CNIDs (ignoring file/folder names)
    911  * and skips over thread records. Then the remaining children are listed in
    912  * ascending order by name, according to the HFS+ spec, so just read off each
    913  * successive leaf node until a different parent CNID is found.
    914  *
    915  * If out_childnames is not NULL, it will be allocated and set to an array of
    916  * hfs_unistr255_t's which correspond to the name of the child with that same
    917  * index.
    918  *
    919  * out_children may be NULL.
    920  *
    921  * Returns 0 on success.
    922  */
    923 int
    924 hfslib_get_directory_contents(
    925 	hfs_volume* in_vol,
    926 	hfs_cnid_t in_dir,
    927 	hfs_catalog_keyed_record_t** out_children,
    928 	hfs_unistr255_t** out_childnames,
    929 	uint32_t* out_numchildren,
    930 	hfs_callback_args* cbargs)
    931 {
    932 	hfs_node_descriptor_t			nd;
    933 	hfs_extent_descriptor_t*		extents;
    934 	hfs_catalog_keyed_record_t		currec;
    935 	hfs_catalog_key_t	curkey;
    936 	void**				recs;
    937 	void*				buffer;
    938 	void*				ptr; /* temporary pointer for realloc() */
    939 	uint64_t			bytesread;
    940 	uint32_t			curnode;
    941 	uint32_t			lastnode;
    942 	uint16_t*			recsizes;
    943 	uint16_t			numextents;
    944 	uint16_t			recnum;
    945 	int16_t				leaftype;
    946 	int					keycompare;
    947 	int					result;
    948 
    949 	if(in_vol==NULL || in_dir==0 || out_numchildren==NULL)
    950 		return 1;
    951 
    952 	result = 1;
    953 	buffer = NULL;
    954 	extents = NULL;
    955 	lastnode = 0;
    956 	recs = NULL;
    957 	recsizes = NULL;
    958 	*out_numchildren = 0;
    959 	if(out_children!=NULL)
    960 		*out_children = NULL;
    961 	if(out_childnames!=NULL)
    962 		*out_childnames = NULL;
    963 
    964 	buffer = hfslib_malloc(in_vol->chr.node_size, cbargs);
    965 	if(buffer==NULL)
    966 		HFS_LIBERR("could not allocate node buffer");
    967 
    968 	numextents = hfslib_get_file_extents(in_vol, HFS_CNID_CATALOG,
    969 		HFS_DATAFORK, &extents, cbargs);
    970 	if(numextents==0)
    971 		HFS_LIBERR("could not locate fork extents");
    972 
    973 	nd.num_recs = 0;
    974 	curnode = in_vol->chr.root_node;
    975 
    976 	while(1)
    977 	{
    978 		hfslib_free_recs(&recs, &recsizes, &nd.num_recs, cbargs);
    979 		recnum = 0;
    980 
    981 		if(hfslib_readd_with_extents(in_vol, buffer, &bytesread,
    982 			in_vol->chr.node_size, curnode * in_vol->chr.node_size, extents,
    983 			numextents, cbargs)!=0)
    984 			HFS_LIBERR("could not read catalog node #%i", curnode);
    985 
    986 		if(hfslib_reada_node(buffer, &nd, &recs, &recsizes, HFS_CATALOG_FILE,
    987 			in_vol, cbargs)==0)
    988 			HFS_LIBERR("could not parse catalog node #%i", curnode);
    989 
    990 		for(recnum=0; recnum<nd.num_recs; recnum++)
    991 		{
    992 			leaftype = nd.kind; /* needed b/c leaftype might be modified now */
    993 			if(hfslib_read_catalog_keyed_record(recs[recnum], &currec,
    994 				&leaftype, &curkey, in_vol)==0)
    995 				HFS_LIBERR("could not read cat record %i:%i", curnode, recnum);
    996 
    997 			if(nd.kind==HFS_INDEXNODE)
    998 			{
    999 				keycompare = in_dir - curkey.parent_cnid;
   1000 				if(keycompare < 0)
   1001 				{
   1002 					/* Check if key is less than *every* record, which should
   1003 					 * never happen if the volume and key are good. */
   1004 					if(recnum==0)
   1005 						HFS_LIBERR("all records greater than key");
   1006 
   1007 					/* Otherwise, we've found the first record that exceeds our
   1008 					 * key, so retrieve the previous, lesser record. */
   1009 					curnode = lastnode;
   1010 					break;
   1011 				}
   1012 				else if(keycompare == 0)
   1013 				{
   1014 					/*
   1015 					 * Normally, if we were doing a typical catalog lookup with
   1016 					 * both a parent cnid AND a name, keycompare==0 would be an
   1017 					 * exact match. However, since we are ignoring object names
   1018 					 * in this case and only comparing parent cnids, a direct
   1019 					 * match on only a parent cnid could mean that we've found
   1020 					 * an object with that parent cnid BUT which is NOT the
   1021 					 * first object (according to the HFS+ spec) with that
   1022 					 * parent cnid. Thus, when we find a parent cnid match, we
   1023 					 * still go back to the previously found leaf node and start
   1024 					 * checking it for a possible prior instance of an object
   1025 					 * with our desired parent cnid.
   1026 					 */
   1027 					curnode = lastnode;
   1028 					break;
   1029 				}
   1030 				else if (recnum==nd.num_recs-1 && keycompare > 0)
   1031 				{
   1032 					/* Descend to child node if we found an exact match, or if
   1033 					 * this is the last pointer record. */
   1034 					curnode = currec.child;
   1035 					break;
   1036 				}
   1037 
   1038 				lastnode = currec.child;
   1039 			}
   1040 			else
   1041 			{
   1042 				/*
   1043 				 * We have now descended down the hierarchy of index nodes into
   1044 				 * the leaf node that contains the first catalog record with a
   1045 				 * matching parent CNID. Since all leaf nodes are chained
   1046 				 * through their flink/blink, we can simply walk forward through
   1047 				 * this chain, copying every matching non-thread record, until
   1048 				 * we hit a record with a different parent CNID. At that point,
   1049 				 * we've retrieved all of our directory's items, if any.
   1050 				 */
   1051 				curnode = nd.flink;
   1052 
   1053 				if(curkey.parent_cnid<in_dir)
   1054 					continue;
   1055 				else if(curkey.parent_cnid==in_dir)
   1056 				{
   1057 					/* Hide files/folders which are supposed to be invisible
   1058 					 * to users, according to the hfs+ spec. */
   1059 					if(hfslib_is_private_file(&curkey))
   1060 						continue;
   1061 
   1062 					/* leaftype has now been set to the catalog record type */
   1063 					if(leaftype==HFS_REC_FLDR || leaftype==HFS_REC_FILE)
   1064 					{
   1065 						(*out_numchildren)++;
   1066 
   1067 						if(out_children!=NULL)
   1068 						{
   1069 							ptr = hfslib_realloc(*out_children,
   1070 								*out_numchildren *
   1071 								sizeof(hfs_catalog_keyed_record_t), cbargs);
   1072 							if(ptr==NULL)
   1073 								HFS_LIBERR("could not allocate child record");
   1074 							*out_children = ptr;
   1075 
   1076 							memcpy(&((*out_children)[*out_numchildren-1]),
   1077 								&currec, sizeof(hfs_catalog_keyed_record_t));
   1078 						}
   1079 
   1080 						if(out_childnames!=NULL)
   1081 						{
   1082 							ptr = hfslib_realloc(*out_childnames,
   1083 								*out_numchildren * sizeof(hfs_unistr255_t),
   1084 								cbargs);
   1085 							if(ptr==NULL)
   1086 								HFS_LIBERR("could not allocate child name");
   1087 							*out_childnames = ptr;
   1088 
   1089 							memcpy(&((*out_childnames)[*out_numchildren-1]),
   1090 								&curkey.name, sizeof(hfs_unistr255_t));
   1091 						}
   1092 					}
   1093 				} else {
   1094 					result = 0;
   1095 					/* We have just now passed the last item in the desired
   1096 					 * folder (or the folder was empty), so exit. */
   1097 					goto exit;
   1098 				}
   1099 			}
   1100 		}
   1101 	}
   1102 
   1103 	result = 0;
   1104 
   1105 	goto exit;
   1106 
   1107 error:
   1108 	if(out_children!=NULL && *out_children!=NULL)
   1109 		hfslib_free(*out_children, cbargs);
   1110 	if(out_childnames!=NULL && *out_childnames!=NULL)
   1111 		hfslib_free(*out_childnames, cbargs);
   1112 
   1113 	/* FALLTHROUGH */
   1114 
   1115 exit:
   1116 	if(extents!=NULL)
   1117 		hfslib_free(extents, cbargs);
   1118 	hfslib_free_recs(&recs, &recsizes, &nd.num_recs, cbargs);
   1119 	if(buffer!=NULL)
   1120 		hfslib_free(buffer, cbargs);
   1121 
   1122 	return result;
   1123 }
   1124 
   1125 int
   1126 hfslib_is_journal_clean(hfs_volume* in_vol)
   1127 {
   1128 	if(in_vol==NULL)
   1129 		return 0;
   1130 
   1131 	/* return true if no journal */
   1132 	if(!(in_vol->vh.attributes & (1<<HFS_VOL_JOURNALED)))
   1133 		return 1;
   1134 
   1135 	return (in_vol->jh.start == in_vol->jh.end);
   1136 }
   1137 
   1138 /*
   1139  * hfslib_is_private_file()
   1140  *
   1141  * Given a file/folder's key and parent CNID, determines if it should be hidden
   1142  * from the user (e.g., the journal header file or the HFS+ Private Data folder)
   1143  */
   1144 int
   1145 hfslib_is_private_file(hfs_catalog_key_t *filekey)
   1146 {
   1147 	hfs_catalog_key_t* curkey = NULL;
   1148 	int i = 0;
   1149 
   1150 	/*
   1151 	 * According to the HFS+ spec to date, all special objects are located in
   1152 	 * the root directory of the volume, so don't bother going further if the
   1153 	 * requested object is not.
   1154 	 */
   1155 	if(filekey->parent_cnid != HFS_CNID_ROOT_FOLDER)
   1156 		return 0;
   1157 
   1158 	while((curkey = hfs_gPrivateObjectKeys[i]) != NULL)
   1159 	{
   1160 		/* XXX Always use binary compare here, or use volume's specific key
   1161 		 * XXX comparison routine? */
   1162 		if(filekey->name.length == curkey->name.length
   1163 			&& memcmp(filekey->name.unicode, curkey->name.unicode,
   1164 				2 * curkey->name.length)==0)
   1165 			return 1;
   1166 
   1167 		i++;
   1168 	}
   1169 
   1170 	return 0;
   1171 }
   1172 
   1173 
   1174 /* bool
   1175 hfslib_is_journal_valid(hfs_volume* in_vol)
   1176 {
   1177 	- check magic numbers
   1178 	- check Other Things
   1179 }*/
   1180 
   1181 #if 0
   1182 #pragma mark -
   1183 #pragma mark Major Structures
   1184 #endif
   1185 
   1186 /*
   1187  *	hfslib_read_volume_header()
   1188  *
   1189  *	Reads in_bytes, formats the data appropriately, and places the result
   1190  *	in out_header, which is assumed to be previously allocated. Returns number
   1191  *	of bytes read, 0 if failed.
   1192  */
   1193 
   1194 size_t
   1195 hfslib_read_volume_header(void* in_bytes, hfs_volume_header_t* out_header)
   1196 {
   1197 	void*	ptr;
   1198 	size_t	last_bytes_read;
   1199 	int		i;
   1200 
   1201 	if(in_bytes==NULL || out_header==NULL)
   1202 		return 0;
   1203 
   1204 	ptr = in_bytes;
   1205 
   1206 	out_header->signature = be16tohp(&ptr);
   1207 	out_header->version = be16tohp(&ptr);
   1208 	out_header->attributes = be32tohp(&ptr);
   1209 	out_header->last_mounting_version = be32tohp(&ptr);
   1210 	out_header->journal_info_block = be32tohp(&ptr);
   1211 
   1212 	out_header->date_created = be32tohp(&ptr);
   1213 	out_header->date_modified = be32tohp(&ptr);
   1214 	out_header->date_backedup = be32tohp(&ptr);
   1215 	out_header->date_checked = be32tohp(&ptr);
   1216 
   1217 	out_header->file_count = be32tohp(&ptr);
   1218 	out_header->folder_count = be32tohp(&ptr);
   1219 
   1220 	out_header->block_size = be32tohp(&ptr);
   1221 	out_header->total_blocks = be32tohp(&ptr);
   1222 	out_header->free_blocks = be32tohp(&ptr);
   1223 	out_header->next_alloc_block = be32tohp(&ptr);
   1224 	out_header->rsrc_clump_size = be32tohp(&ptr);
   1225 	out_header->data_clump_size = be32tohp(&ptr);
   1226 	out_header->next_cnid = be32tohp(&ptr);
   1227 
   1228 	out_header->write_count = be32tohp(&ptr);
   1229 	out_header->encodings = be64tohp(&ptr);
   1230 
   1231 	for(i=0;i<8;i++)
   1232 		out_header->finder_info[i] = be32tohp(&ptr);
   1233 
   1234 	if((last_bytes_read = hfslib_read_fork_descriptor(ptr,
   1235 		&out_header->allocation_file))==0)
   1236 		return 0;
   1237 	ptr = (uint8_t*)ptr + last_bytes_read;
   1238 
   1239 	if((last_bytes_read = hfslib_read_fork_descriptor(ptr,
   1240 		&out_header->extents_file))==0)
   1241 		return 0;
   1242 	ptr = (uint8_t*)ptr + last_bytes_read;
   1243 
   1244 	if((last_bytes_read = hfslib_read_fork_descriptor(ptr,
   1245 		&out_header->catalog_file))==0)
   1246 		return 0;
   1247 	ptr = (uint8_t*)ptr + last_bytes_read;
   1248 
   1249 	if((last_bytes_read = hfslib_read_fork_descriptor(ptr,
   1250 		&out_header->attributes_file))==0)
   1251 		return 0;
   1252 	ptr = (uint8_t*)ptr + last_bytes_read;
   1253 
   1254 	if((last_bytes_read = hfslib_read_fork_descriptor(ptr,
   1255 		&out_header->startup_file))==0)
   1256 		return 0;
   1257 	ptr = (uint8_t*)ptr + last_bytes_read;
   1258 
   1259 	return ((uint8_t*)ptr - (uint8_t*)in_bytes);
   1260 }
   1261 
   1262 /*
   1263  *	hfslib_reada_node()
   1264  *
   1265  *	Given the pointer to and size of a buffer containing the entire, raw
   1266  *	contents of any b-tree node from the disk, this function will:
   1267  *
   1268  *		1.	determine the type of node and read its contents
   1269  *		2.	allocate memory for each record and fill it appropriately
   1270  *		3.	set out_record_ptrs_array to point to an array (which it allocates)
   1271  *			which has out_node_descriptor->num_recs many pointers to the
   1272  *			records themselves
   1273  *		4.	allocate out_record_ptr_sizes_array and fill it with the sizes of
   1274  *			each record
   1275  *		5.	return the number of bytes read (i.e., the size of the node)
   1276  *			or 0 on failure
   1277  *
   1278  *	out_node_descriptor must be allocated by the caller and may not be NULL.
   1279  *
   1280  *	out_record_ptrs_array and out_record_ptr_sizes_array must both be specified,
   1281  *	or both be NULL if the caller is not interested in reading the records.
   1282  *
   1283  *	out_record_ptr_sizes_array may be NULL if the caller is not interested in
   1284  *	reading the records, but must not be NULL if out_record_ptrs_array is not.
   1285  *
   1286  *	in_parent_file is HFS_CATALOG_FILE, HFS_EXTENTS_FILE, or
   1287  *	HFS_ATTRIBUTES_FILE, depending on the special file in which this node
   1288  *	resides.
   1289  *
   1290  *	inout_volume must have its catnodesize or extnodesize field (depending on
   1291  *	the parent file) set to the correct value if this is an index, leaf, or map
   1292  *	node. If this is a header node, the field will be set to its correct value.
   1293  */
   1294 size_t
   1295 hfslib_reada_node(void* in_bytes,
   1296 	hfs_node_descriptor_t* out_node_descriptor,
   1297 	void** out_record_ptrs_array[],
   1298 	uint16_t* out_record_ptr_sizes_array[],
   1299 	hfs_btree_file_type in_parent_file,
   1300 	hfs_volume* inout_volume,
   1301 	hfs_callback_args* cbargs)
   1302 {
   1303 	void*		ptr;
   1304 	uint16_t*	rec_offsets;
   1305 	size_t		last_bytes_read;
   1306 	uint16_t	nodesize;
   1307 	uint16_t	numrecords;
   1308 	uint16_t	free_space_offset;	/* offset to free space in node */
   1309 	int			keysizefieldsize;
   1310 	int			i;
   1311 
   1312 	numrecords = 0;
   1313 	rec_offsets = NULL;
   1314 	if(out_record_ptrs_array!=NULL)
   1315 		*out_record_ptrs_array = NULL;
   1316 	if(out_record_ptr_sizes_array!=NULL)
   1317 		*out_record_ptr_sizes_array = NULL;
   1318 
   1319 	if(in_bytes==NULL || inout_volume==NULL || out_node_descriptor==NULL
   1320 		|| (out_record_ptrs_array==NULL && out_record_ptr_sizes_array!=NULL)
   1321 		|| (out_record_ptrs_array!=NULL && out_record_ptr_sizes_array==NULL) )
   1322 		goto error;
   1323 
   1324 	ptr = in_bytes;
   1325 
   1326 	out_node_descriptor->flink = be32tohp(&ptr);
   1327 	out_node_descriptor->blink = be32tohp(&ptr);
   1328 	out_node_descriptor->kind = *(((int8_t*)ptr));
   1329 	ptr = (uint8_t*)ptr + 1;
   1330 	out_node_descriptor->height = *(((uint8_t*)ptr));
   1331 	ptr = (uint8_t*)ptr + 1;
   1332 	out_node_descriptor->num_recs = be16tohp(&ptr);
   1333 	out_node_descriptor->reserved = be16tohp(&ptr);
   1334 
   1335 	numrecords = out_node_descriptor->num_recs;
   1336 
   1337 	/*
   1338 	 *	To go any further, we will need to know the size of this node, as well
   1339 	 *	as the width of keyed records' key_len parameters for this btree. If
   1340 	 *	this is an index, leaf, or map node, inout_volume already has the node
   1341 	 *	size set in its catnodesize or extnodesize field and the key length set
   1342 	 *	in the catkeysizefieldsize or extkeysizefieldsize for catalog files and
   1343 	 *	extent files, respectively. However, if this is a header node, this
   1344 	 *	information has not yet been determined, so this is the place to do it.
   1345 	 */
   1346 	if(out_node_descriptor->kind == HFS_HEADERNODE)
   1347 	{
   1348 		hfs_header_record_t	hr;
   1349 		void*		header_rec_offset[1];
   1350 		uint16_t	header_rec_size[1];
   1351 
   1352 		/* sanity check to ensure this is a good header node */
   1353 		if(numrecords!=3)
   1354 			HFS_LIBERR("header node does not have exactly 3 records");
   1355 
   1356 		header_rec_offset[0] = ptr;
   1357 		header_rec_size[0] = sizeof(hfs_header_record_t);
   1358 
   1359 		last_bytes_read = hfslib_read_header_node(header_rec_offset,
   1360 			header_rec_size, 1, &hr, NULL, NULL);
   1361 		if(last_bytes_read==0)
   1362 			HFS_LIBERR("could not read header node");
   1363 
   1364 		switch(in_parent_file)
   1365 		{
   1366 			case HFS_CATALOG_FILE:
   1367 				inout_volume->chr.node_size = hr.node_size;
   1368 				inout_volume->catkeysizefieldsize =
   1369 					(hr.attributes & HFS_BIG_KEYS_MASK) ?
   1370 						sizeof(uint16_t):sizeof(uint8_t);
   1371 				break;
   1372 
   1373 			case HFS_EXTENTS_FILE:
   1374 				inout_volume->ehr.node_size = hr.node_size;
   1375 				inout_volume->extkeysizefieldsize =
   1376 					(hr.attributes & HFS_BIG_KEYS_MASK) ?
   1377 						sizeof(uint16_t):sizeof(uint8_t);
   1378 				break;
   1379 
   1380 			case HFS_ATTRIBUTES_FILE:
   1381 			default:
   1382 				HFS_LIBERR("invalid parent file type specified");
   1383 				/* NOTREACHED */
   1384 		}
   1385 	}
   1386 
   1387 	switch(in_parent_file)
   1388 	{
   1389 		case HFS_CATALOG_FILE:
   1390 			nodesize = inout_volume->chr.node_size;
   1391 			keysizefieldsize = inout_volume->catkeysizefieldsize;
   1392 			break;
   1393 
   1394 		case HFS_EXTENTS_FILE:
   1395 			nodesize = inout_volume->ehr.node_size;
   1396 			keysizefieldsize = inout_volume->extkeysizefieldsize;
   1397 			break;
   1398 
   1399 		case HFS_ATTRIBUTES_FILE:
   1400 		default:
   1401 			HFS_LIBERR("invalid parent file type specified");
   1402 			/* NOTREACHED */
   1403 	}
   1404 
   1405 	/*
   1406 	 *	Don't care about records so just exit after getting the node descriptor.
   1407 	 *	Note: This happens after the header node code, and not before it, in
   1408 	 *	case the caller calls this function and ignores the record data just to
   1409 	 *	get at the node descriptor, but then tries to call it again on a non-
   1410 	 *	header node without first setting inout_volume->cat/extnodesize.
   1411 	 */
   1412 	if(out_record_ptrs_array==NULL)
   1413 		return ((uint8_t*)ptr - (uint8_t*)in_bytes);
   1414 
   1415 	rec_offsets = hfslib_malloc(numrecords * sizeof(uint16_t), cbargs);
   1416 	*out_record_ptr_sizes_array =
   1417 		hfslib_malloc(numrecords * sizeof(uint16_t), cbargs);
   1418 	if(rec_offsets==NULL || *out_record_ptr_sizes_array==NULL)
   1419 		HFS_LIBERR("could not allocate node record offsets");
   1420 
   1421 	*out_record_ptrs_array = hfslib_malloc(numrecords * sizeof(void*), cbargs);
   1422 	if(*out_record_ptrs_array==NULL)
   1423 		HFS_LIBERR("could not allocate node records");
   1424 
   1425 	last_bytes_read = hfslib_reada_node_offsets((uint8_t*)in_bytes + nodesize -
   1426 			numrecords * sizeof(uint16_t), rec_offsets);
   1427 	if(last_bytes_read==0)
   1428 		HFS_LIBERR("could not read node record offsets");
   1429 
   1430 	/*	The size of the last record (i.e. the first one listed in the offsets)
   1431 	 *	must be determined using the offset to the node's free space. */
   1432 	free_space_offset = be16toh(*(uint16_t*)((uint8_t*)in_bytes + nodesize -
   1433 			(numrecords+1) * sizeof(uint16_t)));
   1434 
   1435 	(*out_record_ptr_sizes_array)[numrecords-1] =
   1436 		free_space_offset - rec_offsets[0];
   1437 	for(i=1;i<numrecords;i++)
   1438 	{
   1439 		(*out_record_ptr_sizes_array)[numrecords-i-1] =
   1440 			rec_offsets[i-1] - rec_offsets[i];
   1441 	}
   1442 
   1443 	for(i=0;i<numrecords;i++)
   1444 	{
   1445 		(*out_record_ptrs_array)[i] =
   1446 			hfslib_malloc((*out_record_ptr_sizes_array)[i], cbargs);
   1447 
   1448 		if((*out_record_ptrs_array)[i]==NULL)
   1449 			HFS_LIBERR("could not allocate node record #%i",i);
   1450 
   1451 		/*
   1452 		 *	If this is a keyed node (i.e., a leaf or index node), there are two
   1453 		 *	boundary rules that each record must obey:
   1454 		 *
   1455 		 *		1.	A pad byte must be placed between the key and data if the
   1456 		 *			size of the key plus the size of the key_len field is odd.
   1457 		 *
   1458 		 *		2.	A pad byte must be placed after the data if the data size
   1459 		 *			is odd.
   1460 		 *
   1461 		 *	So in the first case we increment the starting point of the data
   1462 		 *	and correspondingly decrement the record size. In the second case
   1463 		 *	we decrement the record size.
   1464 		 */
   1465 		if(out_node_descriptor->kind == HFS_LEAFNODE ||
   1466 		   out_node_descriptor->kind == HFS_INDEXNODE)
   1467 		{
   1468 			hfs_catalog_key_t	reckey;
   1469 			uint16_t			rectype;
   1470 
   1471 			rectype = out_node_descriptor->kind;
   1472 			last_bytes_read = hfslib_read_catalog_keyed_record(ptr, NULL,
   1473 				&rectype, &reckey, inout_volume);
   1474 			if(last_bytes_read==0)
   1475 				HFS_LIBERR("could not read node record");
   1476 
   1477 			if((reckey.key_len + keysizefieldsize) % 2 == 1)
   1478 			{
   1479 				ptr = (uint8_t*)ptr + 1;
   1480 				(*out_record_ptr_sizes_array)[i]--;
   1481 			}
   1482 
   1483 			if((*out_record_ptr_sizes_array)[i] % 2 == 1)
   1484 				(*out_record_ptr_sizes_array)[i]--;
   1485 		}
   1486 
   1487 		memcpy((*out_record_ptrs_array)[i], ptr,
   1488 				(*out_record_ptr_sizes_array)[i]);
   1489 		ptr = (uint8_t*)ptr + (*out_record_ptr_sizes_array)[i];
   1490 	}
   1491 
   1492 	goto exit;
   1493 
   1494 error:
   1495 	hfslib_free_recs(out_record_ptrs_array, out_record_ptr_sizes_array,
   1496 		&numrecords, cbargs);
   1497 
   1498 	ptr = in_bytes;
   1499 
   1500 	/* warn("error occurred in hfslib_reada_node()"); */
   1501 
   1502 	/* FALLTHROUGH */
   1503 
   1504 exit:
   1505 	if(rec_offsets!=NULL)
   1506 		hfslib_free(rec_offsets, cbargs);
   1507 
   1508 	return ((uint8_t*)ptr - (uint8_t*)in_bytes);
   1509 }
   1510 
   1511 /*
   1512  *	hfslib_reada_node_offsets()
   1513  *
   1514  *	Sets out_offset_array to contain the offsets to each record in the node,
   1515  *	in reverse order. Does not read the free space offset.
   1516  */
   1517 size_t
   1518 hfslib_reada_node_offsets(void* in_bytes, uint16_t* out_offset_array)
   1519 {
   1520 	void*		ptr;
   1521 
   1522 	if(in_bytes==NULL || out_offset_array==NULL)
   1523 		return 0;
   1524 
   1525 	ptr = in_bytes;
   1526 
   1527 	/*
   1528 	 *	The offset for record 0 (which is the very last offset in the node) is
   1529 	 *	always equal to 14, the size of the node descriptor. So, once we hit
   1530 	 *	offset=14, we know this is the last offset. In this way, we don't need
   1531 	 *	to know the number of records beforehand.
   1532 	*/
   1533 	out_offset_array--;
   1534 	do
   1535 	{
   1536 		out_offset_array++;
   1537 		*out_offset_array = be16tohp(&ptr);
   1538 	}
   1539 	while(*out_offset_array != (uint16_t)14);
   1540 
   1541 	return ((uint8_t*)ptr - (uint8_t*)in_bytes);
   1542 }
   1543 
   1544 /*	hfslib_read_header_node()
   1545  *
   1546  *	out_header_record and/or out_map_record may be NULL if the caller doesn't
   1547  *	care about their contents.
   1548  */
   1549 size_t
   1550 hfslib_read_header_node(void** in_recs,
   1551 	uint16_t* in_rec_sizes,
   1552 	uint16_t in_num_recs,
   1553 	hfs_header_record_t* out_hr,
   1554 	void* out_userdata,
   1555 	void* out_map)
   1556 {
   1557 	void*	ptr;
   1558 	int		i;
   1559 
   1560 	if(in_recs==NULL || in_rec_sizes==NULL)
   1561 		return 0;
   1562 
   1563 	if(out_hr!=NULL)
   1564 	{
   1565 		ptr = in_recs[0];
   1566 
   1567 		out_hr->tree_depth = be16tohp(&ptr);
   1568 		out_hr->root_node = be32tohp(&ptr);
   1569 		out_hr->leaf_recs = be32tohp(&ptr);
   1570 		out_hr->first_leaf = be32tohp(&ptr);
   1571 		out_hr->last_leaf = be32tohp(&ptr);
   1572 		out_hr->node_size = be16tohp(&ptr);
   1573 		out_hr->max_key_len = be16tohp(&ptr);
   1574 		out_hr->total_nodes = be32tohp(&ptr);
   1575 		out_hr->free_nodes = be32tohp(&ptr);
   1576 		out_hr->reserved = be16tohp(&ptr);
   1577 		out_hr->clump_size = be32tohp(&ptr);
   1578 		out_hr->btree_type = *(((uint8_t*)ptr));
   1579 		ptr = (uint8_t*)ptr + 1;
   1580 		out_hr->keycomp_type = *(((uint8_t*)ptr));
   1581 		ptr = (uint8_t*)ptr + 1;
   1582 		out_hr->attributes = be32tohp(&ptr);
   1583 		for(i=0;i<16;i++)
   1584 			out_hr->reserved2[i] = be32tohp(&ptr);
   1585 	}
   1586 
   1587 	if(out_userdata!=NULL)
   1588 	{
   1589 		memcpy(out_userdata, in_recs[1], in_rec_sizes[1]);
   1590 	}
   1591 	ptr = (uint8_t*)ptr + in_rec_sizes[1];	/* size of user data record */
   1592 
   1593 	if(out_map!=NULL)
   1594 	{
   1595 		memcpy(out_map, in_recs[2], in_rec_sizes[2]);
   1596 	}
   1597 	ptr = (uint8_t*)ptr + in_rec_sizes[2];	/* size of map record */
   1598 
   1599 	return ((uint8_t*)ptr - (uint8_t*)in_recs[0]);
   1600 }
   1601 
   1602 /*
   1603  *	hfslib_read_catalog_keyed_record()
   1604  *
   1605  *	out_recdata can be NULL. inout_rectype must be set to either HFS_LEAFNODE
   1606  *	or HFS_INDEXNODE upon calling this function, and will be set by the
   1607  *	function to one of HFS_REC_FLDR, HFS_REC_FILE, HFS_REC_FLDR_THREAD, or
   1608  *	HFS_REC_FLDR_THREAD upon return if the node is a leaf node. If it is an
   1609  *	index node, inout_rectype will not be changed.
   1610  */
   1611 size_t
   1612 hfslib_read_catalog_keyed_record(
   1613 	void* in_bytes,
   1614 	hfs_catalog_keyed_record_t* out_recdata,
   1615 	int16_t* inout_rectype,
   1616 	hfs_catalog_key_t* out_key,
   1617 	hfs_volume* in_volume)
   1618 {
   1619 	void*		ptr;
   1620 	size_t		last_bytes_read;
   1621 
   1622 	if(in_bytes==NULL || out_key==NULL || inout_rectype==NULL)
   1623 		return 0;
   1624 
   1625 	ptr = in_bytes;
   1626 
   1627 	/*	For HFS+, the key length is always a 2-byte number. This is indicated
   1628 	 *	by the HFS_BIG_KEYS_MASK bit in the attributes field of the catalog
   1629 	 *	header record. However, we just assume this bit is set, since all HFS+
   1630 	 *	volumes should have it set anyway. */
   1631 	if(in_volume->catkeysizefieldsize == sizeof(uint16_t))
   1632 		out_key->key_len = be16tohp(&ptr);
   1633 	else if (in_volume->catkeysizefieldsize == sizeof(uint8_t)) {
   1634 		out_key->key_len = *(((uint8_t*)ptr));
   1635 		ptr = (uint8_t*)ptr + 1;
   1636 	}
   1637 
   1638 	out_key->parent_cnid = be32tohp(&ptr);
   1639 
   1640 	last_bytes_read = hfslib_read_unistr255(ptr, &out_key->name);
   1641 	if(last_bytes_read==0)
   1642 		return 0;
   1643 	ptr = (uint8_t*)ptr + last_bytes_read;
   1644 
   1645 	/* don't waste time if the user just wanted the key and/or record type */
   1646 	if(out_recdata==NULL)
   1647 	{
   1648 		if(*inout_rectype == HFS_LEAFNODE)
   1649 			*inout_rectype = be16tohp(&ptr);
   1650 		else if(*inout_rectype != HFS_INDEXNODE)
   1651 			return 0;	/* should not happen if we were given valid arguments */
   1652 
   1653 		return ((uint8_t*)ptr - (uint8_t*)in_bytes);
   1654 	}
   1655 
   1656 	if(*inout_rectype == HFS_INDEXNODE)
   1657 	{
   1658 		out_recdata->child = be32tohp(&ptr);
   1659 	}
   1660 	else
   1661 	{
   1662 		/* first need to determine what kind of record this is */
   1663 		*inout_rectype = be16tohp(&ptr);
   1664 		out_recdata->type = *inout_rectype;
   1665 
   1666 		switch(out_recdata->type)
   1667 		{
   1668 			case HFS_REC_FLDR:
   1669 			{
   1670 				out_recdata->folder.flags = be16tohp(&ptr);
   1671 				out_recdata->folder.valence = be32tohp(&ptr);
   1672 				out_recdata->folder.cnid = be32tohp(&ptr);
   1673 				out_recdata->folder.date_created = be32tohp(&ptr);
   1674 				out_recdata->folder.date_content_mod = be32tohp(&ptr);
   1675 				out_recdata->folder.date_attrib_mod = be32tohp(&ptr);
   1676 				out_recdata->folder.date_accessed = be32tohp(&ptr);
   1677 				out_recdata->folder.date_backedup = be32tohp(&ptr);
   1678 
   1679 				last_bytes_read = hfslib_read_bsd_data(ptr,
   1680 					&out_recdata->folder.bsd);
   1681 				if(last_bytes_read==0)
   1682 					return 0;
   1683 				ptr = (uint8_t*)ptr + last_bytes_read;
   1684 
   1685 				last_bytes_read = hfslib_read_folder_userinfo(ptr,
   1686 					&out_recdata->folder.user_info);
   1687 				if(last_bytes_read==0)
   1688 					return 0;
   1689 				ptr = (uint8_t*)ptr + last_bytes_read;
   1690 
   1691 				last_bytes_read = hfslib_read_folder_finderinfo(ptr,
   1692 					&out_recdata->folder.finder_info);
   1693 				if(last_bytes_read==0)
   1694 					return 0;
   1695 				ptr = (uint8_t*)ptr + last_bytes_read;
   1696 
   1697 				out_recdata->folder.text_encoding = be32tohp(&ptr);
   1698 				out_recdata->folder.reserved = be32tohp(&ptr);
   1699 			}
   1700 			break;
   1701 
   1702 			case HFS_REC_FILE:
   1703 			{
   1704 				out_recdata->file.flags = be16tohp(&ptr);
   1705 				out_recdata->file.reserved = be32tohp(&ptr);
   1706 				out_recdata->file.cnid = be32tohp(&ptr);
   1707 				out_recdata->file.date_created = be32tohp(&ptr);
   1708 				out_recdata->file.date_content_mod = be32tohp(&ptr);
   1709 				out_recdata->file.date_attrib_mod = be32tohp(&ptr);
   1710 				out_recdata->file.date_accessed = be32tohp(&ptr);
   1711 				out_recdata->file.date_backedup = be32tohp(&ptr);
   1712 
   1713 				last_bytes_read = hfslib_read_bsd_data(ptr,
   1714 					&out_recdata->file.bsd);
   1715 				if(last_bytes_read==0)
   1716 					return 0;
   1717 				ptr = (uint8_t*)ptr + last_bytes_read;
   1718 
   1719 				last_bytes_read = hfslib_read_file_userinfo(ptr,
   1720 					&out_recdata->file.user_info);
   1721 				if(last_bytes_read==0)
   1722 					return 0;
   1723 				ptr = (uint8_t*)ptr + last_bytes_read;
   1724 
   1725 				last_bytes_read = hfslib_read_file_finderinfo(ptr,
   1726 					&out_recdata->file.finder_info);
   1727 				if(last_bytes_read==0)
   1728 					return 0;
   1729 				ptr = (uint8_t*)ptr + last_bytes_read;
   1730 
   1731 				out_recdata->file.text_encoding = be32tohp(&ptr);
   1732 				out_recdata->file.reserved2 = be32tohp(&ptr);
   1733 
   1734 				last_bytes_read = hfslib_read_fork_descriptor(ptr,
   1735 					&out_recdata->file.data_fork);
   1736 				if(last_bytes_read==0)
   1737 					return 0;
   1738 				ptr = (uint8_t*)ptr + last_bytes_read;
   1739 
   1740 				last_bytes_read = hfslib_read_fork_descriptor(ptr,
   1741 					&out_recdata->file.rsrc_fork);
   1742 				if(last_bytes_read==0)
   1743 					return 0;
   1744 				ptr = (uint8_t*)ptr + last_bytes_read;
   1745 			}
   1746 			break;
   1747 
   1748 			case HFS_REC_FLDR_THREAD:
   1749 			case HFS_REC_FILE_THREAD:
   1750 			{
   1751 				out_recdata->thread.reserved = be16tohp(&ptr);
   1752 				out_recdata->thread.parent_cnid = be32tohp(&ptr);
   1753 
   1754 				last_bytes_read = hfslib_read_unistr255(ptr,
   1755 					&out_recdata->thread.name);
   1756 				if(last_bytes_read==0)
   1757 					return 0;
   1758 				ptr = (uint8_t*)ptr + last_bytes_read;
   1759 			}
   1760 			break;
   1761 
   1762 			default:
   1763 				return 1;
   1764 				/* NOTREACHED */
   1765 		}
   1766 	}
   1767 
   1768 	return ((uint8_t*)ptr - (uint8_t*)in_bytes);
   1769 }
   1770 
   1771 /* out_rec may be NULL */
   1772 size_t
   1773 hfslib_read_extent_record(
   1774 	void* in_bytes,
   1775 	hfs_extent_record_t* out_rec,
   1776 	hfs_node_kind in_nodekind,
   1777 	hfs_extent_key_t* out_key,
   1778 	hfs_volume* in_volume)
   1779 {
   1780 	void*		ptr;
   1781 	size_t		last_bytes_read;
   1782 
   1783 	if(in_bytes==NULL || out_key==NULL
   1784 		|| (in_nodekind!=HFS_LEAFNODE && in_nodekind!=HFS_INDEXNODE))
   1785 		return 0;
   1786 
   1787 	ptr = in_bytes;
   1788 
   1789 	/*	For HFS+, the key length is always a 2-byte number. This is indicated
   1790 	 *	by the HFS_BIG_KEYS_MASK bit in the attributes field of the extent
   1791 	 *	overflow header record. However, we just assume this bit is set, since
   1792 	 *	all HFS+ volumes should have it set anyway. */
   1793 	if(in_volume->extkeysizefieldsize == sizeof(uint16_t))
   1794 		out_key->key_length = be16tohp(&ptr);
   1795 	else if (in_volume->extkeysizefieldsize == sizeof(uint8_t)) {
   1796 		out_key->key_length = *(((uint8_t*)ptr));
   1797 		ptr = (uint8_t*)ptr + 1;
   1798 	}
   1799 
   1800 	out_key->fork_type = *(((uint8_t*)ptr));
   1801 	ptr = (uint8_t*)ptr + 1;
   1802 	out_key->padding = *(((uint8_t*)ptr));
   1803 	ptr = (uint8_t*)ptr + 1;
   1804 	out_key->file_cnid = be32tohp(&ptr);
   1805 	out_key->start_block = be32tohp(&ptr);
   1806 
   1807 	/* don't waste time if the user just wanted the key */
   1808 	if(out_rec==NULL)
   1809 		return ((uint8_t*)ptr - (uint8_t*)in_bytes);
   1810 
   1811 	if(in_nodekind==HFS_LEAFNODE)
   1812 	{
   1813 		last_bytes_read = hfslib_read_extent_descriptors(ptr, out_rec);
   1814 		if(last_bytes_read==0)
   1815 			return 0;
   1816 		ptr = (uint8_t*)ptr + last_bytes_read;
   1817 	}
   1818 	else
   1819 	{
   1820 		/* XXX: this is completely bogus */
   1821                 /*      (uint32_t*)*out_rec = be32tohp(&ptr); */
   1822 	    uint32_t *ptr_32 = (uint32_t *)out_rec;
   1823 		*ptr_32 = be32tohp(&ptr);
   1824 	        /* (*out_rec)[0].start_block = be32tohp(&ptr); */
   1825 	}
   1826 
   1827 	return ((uint8_t*)ptr - (uint8_t*)in_bytes);
   1828 }
   1829 
   1830 void
   1831 hfslib_free_recs(
   1832 	void*** inout_node_recs,
   1833 	uint16_t** inout_rec_sizes,
   1834 	uint16_t* inout_num_recs,
   1835 	hfs_callback_args* cbargs)
   1836 {
   1837 	uint16_t	i;
   1838 
   1839 	if(inout_num_recs==NULL || *inout_num_recs==0)
   1840 		return;
   1841 
   1842 	if(inout_node_recs!=NULL && *inout_node_recs!=NULL)
   1843 	{
   1844 		for(i=0;i<*inout_num_recs;i++)
   1845 		{
   1846 			if((*inout_node_recs)[i]!=NULL)
   1847 			{
   1848 				hfslib_free((*inout_node_recs)[i], cbargs);
   1849 				(*inout_node_recs)[i] = NULL;
   1850 			}
   1851 		}
   1852 
   1853 		hfslib_free(*inout_node_recs, cbargs);
   1854 		*inout_node_recs = NULL;
   1855 	}
   1856 
   1857 	if(inout_rec_sizes!=NULL && *inout_rec_sizes!=NULL)
   1858 	{
   1859 		hfslib_free(*inout_rec_sizes, cbargs);
   1860 		*inout_rec_sizes = NULL;
   1861 	}
   1862 
   1863 	*inout_num_recs = 0;
   1864 }
   1865 
   1866 #if 0
   1867 #pragma mark -
   1868 #pragma mark Individual Fields
   1869 #endif
   1870 
   1871 size_t
   1872 hfslib_read_fork_descriptor(void* in_bytes, hfs_fork_t* out_forkdata)
   1873 {
   1874 	void*	ptr;
   1875 	size_t	last_bytes_read;
   1876 
   1877 	if(in_bytes==NULL || out_forkdata==NULL)
   1878 		return 0;
   1879 
   1880 	ptr = in_bytes;
   1881 
   1882 	out_forkdata->logical_size = be64tohp(&ptr);
   1883 	out_forkdata->clump_size = be32tohp(&ptr);
   1884 	out_forkdata->total_blocks = be32tohp(&ptr);
   1885 
   1886 	if((last_bytes_read = hfslib_read_extent_descriptors(ptr,
   1887 		&out_forkdata->extents))==0)
   1888 		return 0;
   1889 	ptr = (uint8_t*)ptr + last_bytes_read;
   1890 
   1891 	return ((uint8_t*)ptr - (uint8_t*)in_bytes);
   1892 }
   1893 
   1894 size_t
   1895 hfslib_read_extent_descriptors(
   1896 	void* in_bytes,
   1897 	hfs_extent_record_t* out_extentrecord)
   1898 {
   1899 	void*	ptr;
   1900 	int		i;
   1901 
   1902 	if(in_bytes==NULL || out_extentrecord==NULL)
   1903 		return 0;
   1904 
   1905 	ptr = in_bytes;
   1906 
   1907 	for(i=0;i<8;i++)
   1908 	{
   1909 		(((hfs_extent_descriptor_t*)*out_extentrecord)[i]).start_block =
   1910 			be32tohp(&ptr);
   1911 		(((hfs_extent_descriptor_t*)*out_extentrecord)[i]).block_count =
   1912 			be32tohp(&ptr);
   1913 	}
   1914 
   1915 	return ((uint8_t*)ptr - (uint8_t*)in_bytes);
   1916 }
   1917 
   1918 size_t
   1919 hfslib_read_unistr255(void* in_bytes, hfs_unistr255_t* out_string)
   1920 {
   1921 	void*		ptr;
   1922 	uint16_t	i, length;
   1923 
   1924 	if(in_bytes==NULL || out_string==NULL)
   1925 		return 0;
   1926 
   1927 	ptr = in_bytes;
   1928 
   1929 	length = be16tohp(&ptr);
   1930 	if(length>255)
   1931 		length = 255; /* hfs+ folder/file names have a limit of 255 chars */
   1932 	out_string->length = length;
   1933 
   1934 	for(i=0; i<length; i++)
   1935 	{
   1936 		out_string->unicode[i] = be16tohp(&ptr);
   1937 	}
   1938 
   1939 	return ((uint8_t*)ptr - (uint8_t*)in_bytes);
   1940 }
   1941 
   1942 size_t
   1943 hfslib_read_bsd_data(void* in_bytes, hfs_bsd_data_t* out_perms)
   1944 {
   1945 	void*	ptr;
   1946 
   1947 	if(in_bytes==NULL || out_perms==NULL)
   1948 		return 0;
   1949 
   1950 	ptr = in_bytes;
   1951 
   1952 	out_perms->owner_id = be32tohp(&ptr);
   1953 	out_perms->group_id = be32tohp(&ptr);
   1954 	out_perms->admin_flags = *(((uint8_t*)ptr));
   1955 	ptr = (uint8_t*)ptr + 1;
   1956 	out_perms->owner_flags = *(((uint8_t*)ptr));
   1957 	ptr = (uint8_t*)ptr + 1;
   1958 	out_perms->file_mode = be16tohp(&ptr);
   1959 	out_perms->special.inode_num = be32tohp(&ptr); /* this field is a union */
   1960 
   1961 	return ((uint8_t*)ptr - (uint8_t*)in_bytes);
   1962 }
   1963 
   1964 size_t
   1965 hfslib_read_file_userinfo(void* in_bytes, hfs_macos_file_info_t* out_info)
   1966 {
   1967 	void*	ptr;
   1968 
   1969 	if(in_bytes==NULL || out_info==NULL)
   1970 		return 0;
   1971 
   1972 	ptr = in_bytes;
   1973 
   1974 	out_info->file_type = be32tohp(&ptr);
   1975 	out_info->file_creator = be32tohp(&ptr);
   1976 	out_info->finder_flags = be16tohp(&ptr);
   1977 	out_info->location.v = be16tohp(&ptr);
   1978 	out_info->location.h = be16tohp(&ptr);
   1979 	out_info->reserved = be16tohp(&ptr);
   1980 
   1981 	return ((uint8_t*)ptr - (uint8_t*)in_bytes);
   1982 }
   1983 
   1984 size_t
   1985 hfslib_read_file_finderinfo(
   1986 	void* in_bytes,
   1987 	hfs_macos_extended_file_info_t* out_info)
   1988 {
   1989 	void*	ptr;
   1990 
   1991 	if(in_bytes==NULL || out_info==NULL)
   1992 		return 0;
   1993 
   1994 	ptr = in_bytes;
   1995 
   1996 #if 0
   1997 	#pragma warn Fill in with real code!
   1998 #endif
   1999 	/* FIXME: Fill in with real code! */
   2000 	memset(out_info, 0, sizeof(*out_info));
   2001 	ptr = (uint8_t*)ptr + sizeof(hfs_macos_extended_file_info_t);
   2002 
   2003 	return ((uint8_t*)ptr - (uint8_t*)in_bytes);
   2004 }
   2005 
   2006 size_t
   2007 hfslib_read_folder_userinfo(void* in_bytes, hfs_macos_folder_info_t* out_info)
   2008 {
   2009 	void*	ptr;
   2010 
   2011 	if(in_bytes==NULL || out_info==NULL)
   2012 		return 0;
   2013 
   2014 	ptr = in_bytes;
   2015 
   2016 #if 0
   2017 	#pragma warn Fill in with real code!
   2018 #endif
   2019 	/* FIXME: Fill in with real code! */
   2020 	memset(out_info, 0, sizeof(*out_info));
   2021 	ptr = (uint8_t*)ptr + sizeof(hfs_macos_folder_info_t);
   2022 
   2023 	return ((uint8_t*)ptr - (uint8_t*)in_bytes);
   2024 }
   2025 
   2026 size_t
   2027 hfslib_read_folder_finderinfo(
   2028 	void* in_bytes,
   2029 	hfs_macos_extended_folder_info_t* out_info)
   2030 {
   2031 	void*	ptr;
   2032 
   2033 	if(in_bytes==NULL || out_info==NULL)
   2034 		return 0;
   2035 
   2036 	ptr = in_bytes;
   2037 
   2038 #if 0
   2039 	#pragma warn Fill in with real code!
   2040 #endif
   2041 	/* FIXME: Fill in with real code! */
   2042 	memset(out_info, 0, sizeof(*out_info));
   2043 	ptr = (uint8_t*)ptr + sizeof(hfs_macos_extended_folder_info_t);
   2044 
   2045 	return ((uint8_t*)ptr - (uint8_t*)in_bytes);
   2046 }
   2047 
   2048 size_t
   2049 hfslib_read_journal_info(void* in_bytes, hfs_journal_info_t* out_info)
   2050 {
   2051 	void*	ptr;
   2052 	int		i;
   2053 
   2054 	if(in_bytes==NULL || out_info==NULL)
   2055 		return 0;
   2056 
   2057 	ptr = in_bytes;
   2058 
   2059 	out_info->flags = be32tohp(&ptr);
   2060 	for(i=0; i<8; i++)
   2061 	{
   2062 		out_info->device_signature[i] = be32tohp(&ptr);
   2063 	}
   2064 	out_info->offset = be64tohp(&ptr);
   2065 	out_info->size = be64tohp(&ptr);
   2066 	for(i=0; i<32; i++)
   2067 	{
   2068 		out_info->reserved[i] = be64tohp(&ptr);
   2069 	}
   2070 
   2071 	return ((uint8_t*)ptr - (uint8_t*)in_bytes);
   2072 }
   2073 
   2074 size_t
   2075 hfslib_read_journal_header(void* in_bytes, hfs_journal_header_t* out_header)
   2076 {
   2077 	void*	ptr;
   2078 
   2079 	if(in_bytes==NULL || out_header==NULL)
   2080 		return 0;
   2081 
   2082 	ptr = in_bytes;
   2083 
   2084 	out_header->magic = be32tohp(&ptr);
   2085 	out_header->endian = be32tohp(&ptr);
   2086 	out_header->start = be64tohp(&ptr);
   2087 	out_header->end = be64tohp(&ptr);
   2088 	out_header->size = be64tohp(&ptr);
   2089 	out_header->blocklist_header_size = be32tohp(&ptr);
   2090 	out_header->checksum = be32tohp(&ptr);
   2091 	out_header->journal_header_size = be32tohp(&ptr);
   2092 
   2093 	return ((uint8_t*)ptr - (uint8_t*)in_bytes);
   2094 }
   2095 
   2096 #if 0
   2097 #pragma mark -
   2098 #pragma mark Disk Access
   2099 #endif
   2100 
   2101 /*
   2102  *	hfslib_readd_with_extents()
   2103  *
   2104  *	This function reads the contents of a file from the volume, given an array
   2105  *	of extent descriptors which specify where every extent of the file is
   2106  *	located (in addition to the usual pread() arguments). out_bytes is presumed
   2107  *  to exist and be large enough to hold in_length number of bytes. Returns 0
   2108  *	on success.
   2109  */
   2110 int
   2111 hfslib_readd_with_extents(
   2112 	hfs_volume*	in_vol,
   2113 	void*		out_bytes,
   2114 	uint64_t*	out_bytesread,
   2115 	uint64_t	in_length,
   2116 	uint64_t	in_offset,
   2117 	hfs_extent_descriptor_t in_extents[],
   2118 	uint16_t	in_numextents,
   2119 	hfs_callback_args*	cbargs)
   2120 {
   2121 	uint64_t	ext_length, last_offset;
   2122 	uint16_t	i;
   2123 	int			error;
   2124 
   2125 	if(in_vol==NULL || out_bytes==NULL || in_extents==NULL || in_numextents==0
   2126 		|| out_bytesread==NULL)
   2127 		return -1;
   2128 
   2129 	*out_bytesread = 0;
   2130 	last_offset = 0;
   2131 
   2132 	for(i=0; i<in_numextents; i++)
   2133 	{
   2134 		if(in_extents[i].block_count==0)
   2135 			continue;
   2136 
   2137 		ext_length = in_extents[i].block_count * in_vol->vh.block_size;
   2138 
   2139 		if(in_offset < last_offset+ext_length
   2140 			&& in_offset+in_length >= last_offset)
   2141 		{
   2142 			uint64_t	isect_start, isect_end;
   2143 
   2144 			isect_start = max(in_offset, last_offset);
   2145 			isect_end = min(in_offset+in_length, last_offset+ext_length);
   2146 			error = hfslib_readd(in_vol, out_bytes, isect_end-isect_start,
   2147 				isect_start - last_offset + (uint64_t)in_extents[i].start_block
   2148 					* in_vol->vh.block_size, cbargs);
   2149 
   2150 			if(error!=0)
   2151 				return error;
   2152 
   2153 			*out_bytesread += isect_end-isect_start;
   2154 			out_bytes = (uint8_t*)out_bytes + isect_end-isect_start;
   2155 		}
   2156 
   2157 		last_offset += ext_length;
   2158 	}
   2159 
   2160 
   2161 	return 0;
   2162 }
   2163 
   2164 #if 0
   2165 #pragma mark -
   2166 #pragma mark Callback Wrappers
   2167 #endif
   2168 
   2169 void
   2170 hfslib_error(const char* in_format, const char* in_file, int in_line, ...)
   2171 {
   2172 	va_list		ap;
   2173 
   2174 	if(in_format==NULL)
   2175 		return;
   2176 
   2177 	if(hfs_gcb.error!=NULL)
   2178 	{
   2179 		va_start(ap, in_line);
   2180 
   2181 		hfs_gcb.error(in_format, in_file, in_line, ap);
   2182 
   2183 		va_end(ap);
   2184 	}
   2185 }
   2186 
   2187 void*
   2188 hfslib_malloc(size_t size, hfs_callback_args* cbargs)
   2189 {
   2190 	if(hfs_gcb.allocmem!=NULL)
   2191 		return hfs_gcb.allocmem(size, cbargs);
   2192 
   2193 	return NULL;
   2194 }
   2195 
   2196 void*
   2197 hfslib_realloc(void* ptr, size_t size, hfs_callback_args* cbargs)
   2198 {
   2199 	if(hfs_gcb.reallocmem!=NULL)
   2200 		return hfs_gcb.reallocmem(ptr, size, cbargs);
   2201 
   2202 	return NULL;
   2203 }
   2204 
   2205 void
   2206 hfslib_free(void* ptr, hfs_callback_args* cbargs)
   2207 {
   2208 	if(hfs_gcb.freemem!=NULL && ptr!=NULL)
   2209 		hfs_gcb.freemem(ptr, cbargs);
   2210 }
   2211 
   2212 int
   2213 hfslib_openvoldevice(
   2214 	hfs_volume* in_vol,
   2215 	const char* in_device,
   2216 	uint64_t in_offset,
   2217 	hfs_callback_args* cbargs)
   2218 {
   2219 	if(hfs_gcb.openvol!=NULL && in_device!=NULL)
   2220 		return hfs_gcb.openvol(in_vol, in_device, in_offset, cbargs);
   2221 
   2222 	return 1;
   2223 }
   2224 
   2225 void
   2226 hfslib_closevoldevice(hfs_volume* in_vol, hfs_callback_args* cbargs)
   2227 {
   2228 	if(hfs_gcb.closevol!=NULL)
   2229 		hfs_gcb.closevol(in_vol, cbargs);
   2230 }
   2231 
   2232 int
   2233 hfslib_readd(
   2234 	hfs_volume* in_vol,
   2235 	void* out_bytes,
   2236 	uint64_t in_length,
   2237 	uint64_t in_offset,
   2238 	hfs_callback_args* cbargs)
   2239 {
   2240 	if(in_vol==NULL || out_bytes==NULL)
   2241 		return -1;
   2242 
   2243 	if(hfs_gcb.read!=NULL)
   2244 		return hfs_gcb.read(in_vol, out_bytes, in_length, in_offset, cbargs);
   2245 
   2246 	return -1;
   2247 }
   2248 
   2249 #if 0
   2250 #pragma mark -
   2251 #pragma mark Other
   2252 #endif
   2253 
   2254 /* returns key length */
   2255 uint16_t
   2256 hfslib_make_catalog_key(
   2257 	hfs_cnid_t in_parent_cnid,
   2258 	uint16_t in_name_len,
   2259 	unichar_t* in_unicode,
   2260 	hfs_catalog_key_t* out_key)
   2261 {
   2262 	if(in_parent_cnid==0 || (in_name_len>0 && in_unicode==NULL) || out_key==0)
   2263 		return 0;
   2264 
   2265 	if(in_name_len>255)
   2266 		in_name_len = 255;
   2267 
   2268 	out_key->key_len = 6 + 2 * in_name_len;
   2269 	out_key->parent_cnid = in_parent_cnid;
   2270 	out_key->name.length = in_name_len;
   2271 	if(in_name_len>0)
   2272 		memcpy(&out_key->name.unicode, in_unicode, in_name_len*2);
   2273 
   2274 	return out_key->key_len;
   2275 }
   2276 
   2277 /* returns key length */
   2278 uint16_t
   2279 hfslib_make_extent_key(
   2280 	hfs_cnid_t in_cnid,
   2281 	uint8_t in_forktype,
   2282 	uint32_t in_startblock,
   2283 	hfs_extent_key_t* out_key)
   2284 {
   2285 	if(in_cnid==0 || out_key==0)
   2286 		return 0;
   2287 
   2288 	out_key->key_length = HFS_MAX_EXT_KEY_LEN;
   2289 	out_key->fork_type = in_forktype;
   2290 	out_key->padding = 0;
   2291 	out_key->file_cnid = in_cnid;
   2292 	out_key->start_block = in_startblock;
   2293 
   2294 	return out_key->key_length;
   2295 }
   2296 
   2297 /* case-folding */
   2298 int
   2299 hfslib_compare_catalog_keys_cf (
   2300 	const void *ap,
   2301 	const void *bp)
   2302 {
   2303 	const hfs_catalog_key_t	*a, *b;
   2304 	unichar_t	ac, bc; /* current character from a, b */
   2305 	unichar_t	lc; /* lowercase version of current character */
   2306 	uint8_t		apos, bpos; /* current character indices */
   2307 
   2308 	a = (const hfs_catalog_key_t*)ap;
   2309 	b = (const hfs_catalog_key_t*)bp;
   2310 
   2311 	if(a->parent_cnid != b->parent_cnid)
   2312 	{
   2313 		return (a->parent_cnid - b->parent_cnid);
   2314 	}
   2315 	else
   2316 	{
   2317 		/*
   2318 		 * The following code implements the pseudocode suggested by
   2319 		 * the HFS+ technote.
   2320 		 */
   2321 
   2322 /*
   2323  * XXX These need to be revised to be endian-independent!
   2324  */
   2325 #define hbyte(x) ((x) >> 8)
   2326 #define lbyte(x) ((x) & 0x00FF)
   2327 
   2328 		apos = bpos = 0;
   2329 		while(1)
   2330 		{
   2331 			/* get next valid character from a */
   2332 			for (lc=0; lc == 0 && apos < a->name.length; apos++) {
   2333 				ac = a->name.unicode[apos];
   2334 				lc = hfs_gcft[hbyte(ac)];
   2335 				if(lc==0)
   2336 					lc = ac;
   2337 				else
   2338 					lc = hfs_gcft[lc + lbyte(ac)];
   2339 			};
   2340 			ac=lc;
   2341 
   2342 			/* get next valid character from b */
   2343 			for (lc=0; lc == 0 && bpos < b->name.length; bpos++) {
   2344 				bc = b->name.unicode[bpos];
   2345 				lc = hfs_gcft[hbyte(bc)];
   2346 				if(lc==0)
   2347 					lc = bc;
   2348 				else
   2349 					lc = hfs_gcft[lc + lbyte(bc)];
   2350 			};
   2351 			bc=lc;
   2352 
   2353 			/* on end of string ac/bc are 0, otherwise > 0 */
   2354 			if (ac != bc || (ac == 0  && bc == 0))
   2355 				return ac - bc;
   2356 		}
   2357 #undef hbyte
   2358 #undef lbyte
   2359 	}
   2360 }
   2361 
   2362 /* binary compare (i.e., not case folding) */
   2363 int
   2364 hfslib_compare_catalog_keys_bc (
   2365 	const void *a,
   2366 	const void *b)
   2367 {
   2368 	if(((const hfs_catalog_key_t*)a)->parent_cnid
   2369 		== ((const hfs_catalog_key_t*)b)->parent_cnid)
   2370 	{
   2371 		if(((const hfs_catalog_key_t*)a)->name.length == 0 &&
   2372 			((const hfs_catalog_key_t*)b)->name.length == 0)
   2373 			return 0;
   2374 
   2375 		if(((const hfs_catalog_key_t*)a)->name.length == 0)
   2376 			return -1;
   2377 		if(((const hfs_catalog_key_t*)b)->name.length == 0)
   2378 			return 1;
   2379 
   2380 		/* FIXME: This does a byte-per-byte comparison, whereas the HFS spec
   2381 		 * mandates a uint16_t chunk comparison. */
   2382 		return memcmp(((const hfs_catalog_key_t*)a)->name.unicode,
   2383 			((const hfs_catalog_key_t*)b)->name.unicode,
   2384 			min(((const hfs_catalog_key_t*)a)->name.length,
   2385 				((const hfs_catalog_key_t*)b)->name.length));
   2386 	}
   2387 	else
   2388 	{
   2389 		return (((const hfs_catalog_key_t*)a)->parent_cnid -
   2390 				((const hfs_catalog_key_t*)b)->parent_cnid);
   2391 	}
   2392 }
   2393 
   2394 int
   2395 hfslib_compare_extent_keys (
   2396 	const void *a,
   2397 	const void *b)
   2398 {
   2399 	/*
   2400 	 *	Comparison order, in descending importance:
   2401 	 *
   2402 	 *		CNID -> fork type -> start block
   2403 	 */
   2404 
   2405 	if(((const hfs_extent_key_t*)a)->file_cnid
   2406 		== ((const hfs_extent_key_t*)b)->file_cnid)
   2407 	{
   2408 		if(((const hfs_extent_key_t*)a)->fork_type
   2409 			== ((const hfs_extent_key_t*)b)->fork_type)
   2410 		{
   2411 			if(((const hfs_extent_key_t*)a)->start_block
   2412 				== ((const hfs_extent_key_t*)b)->start_block)
   2413 			{
   2414 				return 0;
   2415 			}
   2416 			else
   2417 			{
   2418 				return (((const hfs_extent_key_t*)a)->start_block -
   2419 						((const hfs_extent_key_t*)b)->start_block);
   2420 			}
   2421 		}
   2422 		else
   2423 		{
   2424 			return (((const hfs_extent_key_t*)a)->fork_type -
   2425 					((const hfs_extent_key_t*)b)->fork_type);
   2426 		}
   2427 	}
   2428 	else
   2429 	{
   2430 		return (((const hfs_extent_key_t*)a)->file_cnid -
   2431 				((const hfs_extent_key_t*)b)->file_cnid);
   2432 	}
   2433 }
   2434 
   2435 /* 1+10 tables of 16 rows and 16 columns, each 2 bytes wide = 5632 bytes */
   2436 int
   2437 hfslib_create_casefolding_table(void)
   2438 {
   2439 	hfs_callback_args	cbargs;
   2440 	unichar_t*	t; /* convenience */
   2441 	uint16_t	s; /* current subtable * 256 */
   2442 	uint16_t	i; /* current subtable index (0 to 255) */
   2443 
   2444 	if(hfs_gcft!=NULL)
   2445 		return 0; /* no sweat, table already exists */
   2446 
   2447 	hfslib_init_cbargs(&cbargs);
   2448 	hfs_gcft = hfslib_malloc(5632, &cbargs);
   2449 	if(hfs_gcft==NULL)
   2450 		HFS_LIBERR("could not allocate case folding table");
   2451 
   2452 	t = hfs_gcft;	 /* easier to type :) */
   2453 
   2454 	/*
   2455 	 * high byte indices
   2456 	 */
   2457 	s = 0 * 256;
   2458 	memset(t, 0x00, 512);
   2459 	t[s+  0] = 0x0100;
   2460 	t[s+  1] = 0x0200;
   2461 	t[s+  3] = 0x0300;
   2462 	t[s+  4] = 0x0400;
   2463 	t[s+  5] = 0x0500;
   2464 	t[s+ 16] = 0x0600;
   2465 	t[s+ 32] = 0x0700;
   2466 	t[s+ 33] = 0x0800;
   2467 	t[s+254] = 0x0900;
   2468 	t[s+255] = 0x0a00;
   2469 
   2470 	/*
   2471 	 * table 1 (high byte 0x00)
   2472 	 */
   2473 	s = 1 * 256;
   2474 	for(i=0; i<65; i++)
   2475 		t[s+i] = i;
   2476 	t[s+  0] = 0xffff;
   2477 	for(i=65; i<91; i++)
   2478 		t[s+i] = i + 0x20;
   2479 	for(i=91; i<256; i++)
   2480 		t[s+i] = i;
   2481 	t[s+198] = 0x00e6;
   2482 	t[s+208] = 0x00f0;
   2483 	t[s+216] = 0x00f8;
   2484 	t[s+222] = 0x00fe;
   2485 
   2486 	/*
   2487 	 * table 2 (high byte 0x01)
   2488 	 */
   2489 	s = 2 * 256;
   2490 	for(i=0; i<256; i++)
   2491 		t[s+i] = i + 0x0100;
   2492 	t[s+ 16] = 0x0111;
   2493 	t[s+ 38] = 0x0127;
   2494 	t[s+ 50] = 0x0133;
   2495 	t[s+ 63] = 0x0140;
   2496 	t[s+ 65] = 0x0142;
   2497 	t[s+ 74] = 0x014b;
   2498 	t[s+ 82] = 0x0153;
   2499 	t[s+102] = 0x0167;
   2500 	t[s+129] = 0x0253;
   2501 	t[s+130] = 0x0183;
   2502 	t[s+132] = 0x0185;
   2503 	t[s+134] = 0x0254;
   2504 	t[s+135] = 0x0188;
   2505 	t[s+137] = 0x0256;
   2506 	t[s+138] = 0x0257;
   2507 	t[s+139] = 0x018c;
   2508 	t[s+142] = 0x01dd;
   2509 	t[s+143] = 0x0259;
   2510 	t[s+144] = 0x025b;
   2511 	t[s+145] = 0x0192;
   2512 	t[s+147] = 0x0260;
   2513 	t[s+148] = 0x0263;
   2514 	t[s+150] = 0x0269;
   2515 	t[s+151] = 0x0268;
   2516 	t[s+152] = 0x0199;
   2517 	t[s+156] = 0x026f;
   2518 	t[s+157] = 0x0272;
   2519 	t[s+159] = 0x0275;
   2520 	t[s+162] = 0x01a3;
   2521 	t[s+164] = 0x01a5;
   2522 	t[s+167] = 0x01a8;
   2523 	t[s+169] = 0x0283;
   2524 	t[s+172] = 0x01ad;
   2525 	t[s+174] = 0x0288;
   2526 	t[s+177] = 0x028a;
   2527 	t[s+178] = 0x028b;
   2528 	t[s+179] = 0x01b4;
   2529 	t[s+181] = 0x01b6;
   2530 	t[s+183] = 0x0292;
   2531 	t[s+184] = 0x01b9;
   2532 	t[s+188] = 0x01bd;
   2533 	t[s+196] = 0x01c6;
   2534 	t[s+197] = 0x01c6;
   2535 	t[s+199] = 0x01c9;
   2536 	t[s+200] = 0x01c9;
   2537 	t[s+202] = 0x01cc;
   2538 	t[s+203] = 0x01cc;
   2539 	t[s+228] = 0x01e5;
   2540 	t[s+241] = 0x01f3;
   2541 	t[s+242] = 0x01f3;
   2542 
   2543 	/*
   2544 	 * table 3 (high byte 0x03)
   2545 	 */
   2546 	s = 3 * 256;
   2547 	for(i=0; i<145; i++)
   2548 		t[s+i] = i + 0x0300;
   2549 	for(i=145; i<170; i++)
   2550 		t[s+i] = i + 0x0320;
   2551 	t[s+162] = 0x03a2;
   2552 	for(i=170; i<256; i++)
   2553 		t[s+i] = i + 0x0300;
   2554 
   2555 	for(i=226; i<239; i+=2)
   2556 		t[s+i] = i + 0x0301;
   2557 
   2558 	/*
   2559 	 * table 4 (high byte 0x04)
   2560 	 */
   2561 	s = 4 * 256;
   2562 	for(i=0; i<16; i++)
   2563 		t[s+i] = i + 0x0400;
   2564 	t[s+  2] = 0x0452;
   2565 	t[s+  4] = 0x0454;
   2566 	t[s+  5] = 0x0455;
   2567 	t[s+  6] = 0x0456;
   2568 	t[s+  8] = 0x0458;
   2569 	t[s+  9] = 0x0459;
   2570 	t[s+ 10] = 0x045a;
   2571 	t[s+ 11] = 0x045b;
   2572 	t[s+ 15] = 0x045f;
   2573 
   2574 	for(i=16; i<48; i++)
   2575 		t[s+i] = i + 0x0420;
   2576 	t[s+ 25] = 0x0419;
   2577 	for(i=48; i<256; i++)
   2578 		t[s+i] = i + 0x0400;
   2579 	t[s+195] = 0x04c4;
   2580 	t[s+199] = 0x04c8;
   2581 	t[s+203] = 0x04cc;
   2582 
   2583 	for(i=96; i<129; i+=2)
   2584 		t[s+i] = i + 0x0401;
   2585 	t[s+118] = 0x0476;
   2586 	for(i=144; i<191; i+=2)
   2587 		t[s+i] = i + 0x0401;
   2588 
   2589 	/*
   2590 	 * table 5 (high byte 0x05)
   2591 	 */
   2592 	s = 5 * 256;
   2593 	for(i=0; i<49; i++)
   2594 		t[s+i] = i + 0x0500;
   2595 	for(i=49; i<87; i++)
   2596 		t[s+i] = i + 0x0530;
   2597 	for(i=87; i<256; i++)
   2598 		t[s+i] = i + 0x0500;
   2599 
   2600 	/*
   2601 	 * table 6 (high byte 0x10)
   2602 	 */
   2603 	s = 6 * 256;
   2604 	for(i=0; i<160; i++)
   2605 		t[s+i] = i + 0x1000;
   2606 	for(i=160; i<198; i++)
   2607 		t[s+i] = i + 0x1030;
   2608 	for(i=198; i<256; i++)
   2609 		t[s+i] = i + 0x1000;
   2610 
   2611 	/*
   2612 	 * table 7 (high byte 0x20)
   2613 	 */
   2614 	s = 7 * 256;
   2615 	for(i=0; i<256; i++)
   2616 		t[s+i] = i + 0x2000;
   2617 	{
   2618 		uint8_t zi[15] = { 12,  13,  14,  15,
   2619 						   42,  43,  44,  45,  46,
   2620 						  106, 107, 108, 109, 110, 111};
   2621 
   2622 		for(i=0; i<15; i++)
   2623 			t[s+zi[i]] = 0x0000;
   2624 	}
   2625 
   2626 	/*
   2627 	 * table 8 (high byte 0x21)
   2628 	 */
   2629 	s = 8 * 256;
   2630 	for(i=0; i<96; i++)
   2631 		t[s+i] = i + 0x2100;
   2632 	for(i=96; i<112; i++)
   2633 		t[s+i] = i + 0x2110;
   2634 	for(i=112; i<256; i++)
   2635 		t[s+i] = i + 0x2100;
   2636 
   2637 	/*
   2638 	 * table 9 (high byte 0xFE)
   2639 	 */
   2640 	s = 9 * 256;
   2641 	for(i=0; i<256; i++)
   2642 		t[s+i] = i + 0xFE00;
   2643 	t[s+255] = 0x0000;
   2644 
   2645 	/*
   2646 	 * table 10 (high byte 0xFF)
   2647 	 */
   2648 	s = 10 * 256;
   2649 	for(i=0; i<33; i++)
   2650 		t[s+i] = i + 0xFF00;
   2651 	for(i=33; i<59; i++)
   2652 		t[s+i] = i + 0xFF20;
   2653 	for(i=59; i<256; i++)
   2654 		t[s+i] = i + 0xFF00;
   2655 
   2656 	return 0;
   2657 
   2658 error:
   2659 	return 1;
   2660 }
   2661 
   2662 int
   2663 hfslib_get_hardlink(hfs_volume *vol, uint32_t inode_num,
   2664 		     hfs_catalog_keyed_record_t *rec,
   2665 		     hfs_callback_args *cbargs)
   2666 {
   2667 	hfs_catalog_keyed_record_t metadata;
   2668 	hfs_catalog_key_t key;
   2669 	char name[16];
   2670 	unichar_t name_uni[16];
   2671 	int i, len;
   2672 
   2673 	/* XXX: cache this */
   2674 	if (hfslib_find_catalog_record_with_key(vol,
   2675 						 &hfs_gMetadataDirectoryKey,
   2676 						 &metadata, cbargs) != 0
   2677 		|| metadata.type != HFS_REC_FLDR)
   2678 		return -1;
   2679 
   2680 	len = snprintf(name, sizeof(name), "iNode%d", inode_num);
   2681 	for (i=0; i<len; i++)
   2682 		name_uni[i] = name[i];
   2683 
   2684 	if (hfslib_make_catalog_key(metadata.folder.cnid, len, name_uni,
   2685 				     &key) == 0)
   2686 		return -1;
   2687 
   2688 	return hfslib_find_catalog_record_with_key(vol, &key, rec, cbargs);
   2689 }
   2690