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