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