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