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