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