1*dd6a5058Smrg /* $NetBSD: libhfs.c,v 1.19 2023/08/11 05:51:34 mrg Exp $ */
225e99827Sdillo
325e99827Sdillo /*-
425e99827Sdillo * Copyright (c) 2005, 2007 The NetBSD Foundation, Inc.
525e99827Sdillo * All rights reserved.
625e99827Sdillo *
725e99827Sdillo * This code is derived from software contributed to The NetBSD Foundation
841627b2cSdillo * by Yevgeny Binder, Dieter Baron, and Pelle Johansson.
925e99827Sdillo *
1025e99827Sdillo * Redistribution and use in source and binary forms, with or without
1125e99827Sdillo * modification, are permitted provided that the following conditions
1225e99827Sdillo * are met:
1325e99827Sdillo * 1. Redistributions of source code must retain the above copyright
1425e99827Sdillo * notice, this list of conditions and the following disclaimer.
1525e99827Sdillo * 2. Redistributions in binary form must reproduce the above copyright
1625e99827Sdillo * notice, this list of conditions and the following disclaimer in the
1725e99827Sdillo * documentation and/or other materials provided with the distribution.
1825e99827Sdillo *
1925e99827Sdillo * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2025e99827Sdillo * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2125e99827Sdillo * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2225e99827Sdillo * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2325e99827Sdillo * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2425e99827Sdillo * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2525e99827Sdillo * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2625e99827Sdillo * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2725e99827Sdillo * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2825e99827Sdillo * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2925e99827Sdillo * POSSIBILITY OF SUCH DAMAGE.
3025e99827Sdillo */
3125e99827Sdillo
3225e99827Sdillo /*
3356c3e412Sdillo * All functions and variable types have the prefix "hfs_". All constants
3456c3e412Sdillo * have the prefix "HFS_".
3525e99827Sdillo *
3625e99827Sdillo * Naming convention for functions which read/write raw, linear data
3725e99827Sdillo * into/from a structured form:
3825e99827Sdillo *
3956c3e412Sdillo * hfs_read/write[d][a]_foo_bar
4025e99827Sdillo * [d] - read/write from/to [d]isk instead of a memory buffer
4125e99827Sdillo * [a] - [a]llocate output buffer instead of using an existing one
4225e99827Sdillo * (not applicable for writing functions)
4325e99827Sdillo *
4425e99827Sdillo * Most functions do not have either of these options, so they will read from
4525e99827Sdillo * or write to a memory buffer, which has been previously allocated by the
4625e99827Sdillo * caller.
4725e99827Sdillo */
4825e99827Sdillo
49ceed9c72Slukem #include <sys/cdefs.h>
50*dd6a5058Smrg __KERNEL_RCSID(0, "$NetBSD: libhfs.c,v 1.19 2023/08/11 05:51:34 mrg Exp $");
51ceed9c72Slukem
5256c3e412Sdillo #include "libhfs.h"
5325e99827Sdillo
5425e99827Sdillo /* global private file/folder keys */
5556c3e412Sdillo hfs_catalog_key_t hfs_gMetadataDirectoryKey; /* contains HFS+ inodes */
5656c3e412Sdillo hfs_catalog_key_t hfs_gJournalInfoBlockFileKey;
5756c3e412Sdillo hfs_catalog_key_t hfs_gJournalBufferFileKey;
5856c3e412Sdillo hfs_catalog_key_t* hfs_gPrivateObjectKeys[4] = {
5956c3e412Sdillo &hfs_gMetadataDirectoryKey,
6056c3e412Sdillo &hfs_gJournalInfoBlockFileKey,
6156c3e412Sdillo &hfs_gJournalBufferFileKey,
626a896067Smaxv NULL
636a896067Smaxv };
6425e99827Sdillo
6525e99827Sdillo
6625e99827Sdillo extern uint16_t be16tohp(void** inout_ptr);
6725e99827Sdillo extern uint32_t be32tohp(void** inout_ptr);
6825e99827Sdillo extern uint64_t be64tohp(void** inout_ptr);
6925e99827Sdillo
70b1afbb31Smatt hfs_callbacks hfs_gcb; /* global callbacks */
71b1afbb31Smatt
72b1afbb31Smatt /*
73b1afbb31Smatt * global case folding table
74b1afbb31Smatt * (lazily initialized; see comments at bottom of hfs_open_volume())
75b1afbb31Smatt */
76b1afbb31Smatt unichar_t* hfs_gcft;
77b1afbb31Smatt
78b1afbb31Smatt
7956c3e412Sdillo int hfslib_create_casefolding_table(void);
8025e99827Sdillo
8125e99827Sdillo #ifdef DLO_DEBUG
8225e99827Sdillo #include <stdio.h>
8325e99827Sdillo void
dlo_print_key(hfs_catalog_key_t * key)8456c3e412Sdillo dlo_print_key(hfs_catalog_key_t *key)
8525e99827Sdillo {
8625e99827Sdillo int i;
8725e99827Sdillo
8825e99827Sdillo printf("%ld:[", (long)key->parent_cnid);
8925e99827Sdillo for (i=0; i<key->name.length; i++) {
9025e99827Sdillo if (key->name.unicode[i] < 256
9125e99827Sdillo && isprint(key->name.unicode[i]))
9225e99827Sdillo putchar(key->name.unicode[i]);
9325e99827Sdillo else
9425e99827Sdillo printf("<%04x>", key->name.unicode[i]);
9525e99827Sdillo }
9625e99827Sdillo printf("]");
9725e99827Sdillo }
9825e99827Sdillo #endif
9925e99827Sdillo
10025e99827Sdillo void
hfslib_init(hfs_callbacks * in_callbacks)10156c3e412Sdillo hfslib_init(hfs_callbacks* in_callbacks)
10225e99827Sdillo {
10325e99827Sdillo unichar_t temp[256];
10425e99827Sdillo
10525e99827Sdillo if (in_callbacks != NULL)
10656c3e412Sdillo memcpy(&hfs_gcb, in_callbacks, sizeof(hfs_callbacks));
10725e99827Sdillo
10856c3e412Sdillo hfs_gcft = NULL;
10925e99827Sdillo
11025e99827Sdillo /*
11125e99827Sdillo * Create keys for the HFS+ "private" files so we can reuse them whenever
11225e99827Sdillo * we perform a user-visible operation, such as listing directory contents.
11325e99827Sdillo */
11425e99827Sdillo
11525e99827Sdillo #define ATOU(str, len) /* quick & dirty ascii-to-unicode conversion */ \
11625e99827Sdillo do{ int i; for(i=0; i<len; i++) temp[i]=str[i]; } \
11725e99827Sdillo while( /*CONSTCOND*/ 0)
11825e99827Sdillo
11925e99827Sdillo ATOU("\0\0\0\0HFS+ Private Data", 21);
12056c3e412Sdillo hfslib_make_catalog_key(HFS_CNID_ROOT_FOLDER, 21, temp,
12156c3e412Sdillo &hfs_gMetadataDirectoryKey);
12225e99827Sdillo
12325e99827Sdillo ATOU(".journal_info_block", 19);
12456c3e412Sdillo hfslib_make_catalog_key(HFS_CNID_ROOT_FOLDER, 19, temp,
12556c3e412Sdillo &hfs_gJournalInfoBlockFileKey);
12625e99827Sdillo
12725e99827Sdillo ATOU(".journal", 8);
12856c3e412Sdillo hfslib_make_catalog_key(HFS_CNID_ROOT_FOLDER, 8, temp,
12956c3e412Sdillo &hfs_gJournalBufferFileKey);
13025e99827Sdillo
13125e99827Sdillo #undef ATOU
13225e99827Sdillo }
13325e99827Sdillo
13425e99827Sdillo void
hfslib_done(void)13556c3e412Sdillo hfslib_done(void)
13625e99827Sdillo {
13756c3e412Sdillo hfs_callback_args cbargs;
13825e99827Sdillo
13956c3e412Sdillo if (hfs_gcft != NULL) {
14056c3e412Sdillo hfslib_init_cbargs(&cbargs);
14156c3e412Sdillo hfslib_free(hfs_gcft, &cbargs);
14256c3e412Sdillo hfs_gcft = NULL;
14325e99827Sdillo }
14425e99827Sdillo
14525e99827Sdillo return;
14625e99827Sdillo }
14725e99827Sdillo
14825e99827Sdillo void
hfslib_init_cbargs(hfs_callback_args * ptr)14956c3e412Sdillo hfslib_init_cbargs(hfs_callback_args* ptr)
15025e99827Sdillo {
15156c3e412Sdillo memset(ptr, 0, sizeof(hfs_callback_args));
15225e99827Sdillo }
15325e99827Sdillo
15425e99827Sdillo #if 0
15525e99827Sdillo #pragma mark -
15625e99827Sdillo #pragma mark High-Level Routines
15725e99827Sdillo #endif
15825e99827Sdillo
15925e99827Sdillo int
hfslib_open_volume(const char * in_device,int in_readonly,hfs_volume * out_vol,hfs_callback_args * cbargs)16056c3e412Sdillo hfslib_open_volume(
16125e99827Sdillo const char* in_device,
16225e99827Sdillo int in_readonly,
16356c3e412Sdillo hfs_volume* out_vol,
16456c3e412Sdillo hfs_callback_args* cbargs)
16525e99827Sdillo {
16656c3e412Sdillo hfs_catalog_key_t rootkey;
16756c3e412Sdillo hfs_thread_record_t rootthread;
16841627b2cSdillo hfs_hfs_master_directory_block_t mdb;
169e100c48aSdillo uint16_t node_rec_sizes[1];
170e100c48aSdillo void* node_recs[1];
17125e99827Sdillo void* buffer;
17225e99827Sdillo void* buffer2; /* used as temporary pointer for realloc() */
17325e99827Sdillo int result;
174f75bcfdeSpooka int isopen = 0;
17525e99827Sdillo
17625e99827Sdillo result = 1;
17725e99827Sdillo buffer = NULL;
17825e99827Sdillo
17925e99827Sdillo if (in_device == NULL || out_vol == NULL)
18025e99827Sdillo return 1;
18125e99827Sdillo
18225e99827Sdillo out_vol->readonly = in_readonly;
18341627b2cSdillo out_vol->offset = 0;
18425e99827Sdillo
18541627b2cSdillo if (hfslib_openvoldevice(out_vol, in_device, cbargs) != 0)
18656c3e412Sdillo HFS_LIBERR("could not open device");
187f75bcfdeSpooka isopen = 1;
18825e99827Sdillo
18925e99827Sdillo /*
19025e99827Sdillo * Read the volume header.
19125e99827Sdillo */
19241627b2cSdillo buffer = hfslib_malloc(max(sizeof(hfs_volume_header_t),
19341627b2cSdillo sizeof(hfs_hfs_master_directory_block_t)), cbargs);
19425e99827Sdillo if (buffer == NULL)
19556c3e412Sdillo HFS_LIBERR("could not allocate volume header");
19641627b2cSdillo if (hfslib_readd(out_vol, buffer, max(sizeof(hfs_volume_header_t),
19741627b2cSdillo sizeof(hfs_hfs_master_directory_block_t)),
19856c3e412Sdillo HFS_VOLUME_HEAD_RESERVE_SIZE, cbargs) != 0)
19956c3e412Sdillo HFS_LIBERR("could not read volume header");
20041627b2cSdillo
20141627b2cSdillo if (be16toh(*((uint16_t *)buffer)) == HFS_SIG_HFS) {
20241627b2cSdillo if (hfslib_read_master_directory_block(buffer, &mdb) == 0)
20341627b2cSdillo HFS_LIBERR("could not parse master directory block");
2046a896067Smaxv if (mdb.embedded_signature == HFS_SIG_HFSP) {
20541627b2cSdillo /* XXX: is 512 always correct? */
20641627b2cSdillo out_vol->offset =
20741627b2cSdillo mdb.first_block * 512
20841627b2cSdillo + mdb.embedded_extent.start_block
20941627b2cSdillo * (uint64_t)mdb.block_size;
21041627b2cSdillo
21141627b2cSdillo if (hfslib_readd(out_vol, buffer,
21241627b2cSdillo sizeof(hfs_volume_header_t),
21341627b2cSdillo HFS_VOLUME_HEAD_RESERVE_SIZE, cbargs) != 0)
21441627b2cSdillo HFS_LIBERR("could not read volume header");
2156a896067Smaxv } else
21641627b2cSdillo HFS_LIBERR("Plain HFS volumes not currently supported");
21741627b2cSdillo }
21841627b2cSdillo
21956c3e412Sdillo if (hfslib_read_volume_header(buffer, &(out_vol->vh)) == 0)
22056c3e412Sdillo HFS_LIBERR("could not parse volume header");
22125e99827Sdillo
22225e99827Sdillo /*
22325e99827Sdillo * Check the volume signature to see if this is a legitimate HFS+ or HFSX
22425e99827Sdillo * volume. If so, set the key comparison function pointers appropriately.
22525e99827Sdillo */
2266a896067Smaxv switch(out_vol->vh.signature) {
22756c3e412Sdillo case HFS_SIG_HFSP:
22856c3e412Sdillo out_vol->keycmp = hfslib_compare_catalog_keys_cf;
22925e99827Sdillo break;
23056c3e412Sdillo case HFS_SIG_HFSX:
23125e99827Sdillo out_vol->keycmp = NULL; /* will be set below */
23225e99827Sdillo break;
23325e99827Sdillo default:
23485fb4c9dSpooka /* HFS_LIBERR("unrecognized volume format"); */
23585fb4c9dSpooka goto error;
23685fb4c9dSpooka break;
23725e99827Sdillo }
23825e99827Sdillo
23925e99827Sdillo /*
24025e99827Sdillo * Read the catalog header.
24125e99827Sdillo */
242e100c48aSdillo buffer2 = hfslib_realloc(buffer, 512, cbargs);
24325e99827Sdillo if (buffer2 == NULL)
24456c3e412Sdillo HFS_LIBERR("could not allocate catalog header node");
24525e99827Sdillo buffer = buffer2;
24625e99827Sdillo
247e100c48aSdillo /*
2486a896067Smaxv * We are only interested in the node header, so read the first
2496a896067Smaxv * 512 bytes and construct the node descriptor by hand.
250e100c48aSdillo */
251e100c48aSdillo if (hfslib_readd(out_vol, buffer, 512,
2526a896067Smaxv out_vol->vh.catalog_file.extents[0].start_block *
2536a896067Smaxv (uint64_t)out_vol->vh.block_size, cbargs) != 0)
25456c3e412Sdillo HFS_LIBERR("could not read catalog header node");
255e100c48aSdillo node_recs[0] = (char *)buffer+14;
256e100c48aSdillo node_rec_sizes[0] = 120;
257e100c48aSdillo if (hfslib_read_header_node(node_recs, node_rec_sizes, 1,
25825e99827Sdillo &out_vol->chr, NULL, NULL) == 0)
25956c3e412Sdillo HFS_LIBERR("could not parse catalog header node");
26025e99827Sdillo
2616a896067Smaxv /*
2626a896067Smaxv * If this is an HFSX volume, the catalog header specifies the type of
2636a896067Smaxv * key comparison method (case-folding or binary compare) we should
2646a896067Smaxv * use.
2656a896067Smaxv */
2666a896067Smaxv if (out_vol->keycmp == NULL) {
26756c3e412Sdillo if (out_vol->chr.keycomp_type == HFS_KEY_CASEFOLD)
26856c3e412Sdillo out_vol->keycmp = hfslib_compare_catalog_keys_cf;
26956c3e412Sdillo else if (out_vol->chr.keycomp_type == HFS_KEY_BINARY)
27056c3e412Sdillo out_vol->keycmp = hfslib_compare_catalog_keys_bc;
27125e99827Sdillo else
27256c3e412Sdillo HFS_LIBERR("undefined key compare method");
27325e99827Sdillo }
27425e99827Sdillo
275e100c48aSdillo out_vol->catkeysizefieldsize
276e100c48aSdillo = (out_vol->chr.attributes & HFS_BIG_KEYS_MASK) ?
277e100c48aSdillo sizeof(uint16_t) : sizeof(uint8_t);
278e100c48aSdillo
27925e99827Sdillo /*
28025e99827Sdillo * Read the extent overflow header.
28125e99827Sdillo */
282e100c48aSdillo /*
2836a896067Smaxv * We are only interested in the node header, so read the first
2846a896067Smaxv * 512 bytes and construct the node descriptor by hand.
2856a896067Smaxv * buffer is already 512 bytes long.
286e100c48aSdillo */
287e100c48aSdillo if (hfslib_readd(out_vol, buffer, 512,
2886a896067Smaxv out_vol->vh.extents_file.extents[0].start_block *
2896a896067Smaxv (uint64_t)out_vol->vh.block_size, cbargs) != 0)
29056c3e412Sdillo HFS_LIBERR("could not read extent header node");
29125e99827Sdillo
292e100c48aSdillo node_recs[0] = (char *)buffer+14;
293e100c48aSdillo node_rec_sizes[0] = 120;
294e100c48aSdillo if (hfslib_read_header_node(node_recs, node_rec_sizes, 1,
29525e99827Sdillo &out_vol->ehr, NULL, NULL) == 0)
29656c3e412Sdillo HFS_LIBERR("could not parse extent header node");
297e100c48aSdillo out_vol->extkeysizefieldsize
298e100c48aSdillo = (out_vol->ehr.attributes & HFS_BIG_KEYS_MASK) ?
299e100c48aSdillo sizeof(uint16_t):sizeof(uint8_t);
30025e99827Sdillo /*
30125e99827Sdillo * Read the journal info block and journal header (if volume journaled).
30225e99827Sdillo */
3036a896067Smaxv if (out_vol->vh.attributes & (1<<HFS_VOL_JOURNALED)) {
30425e99827Sdillo /* journal info block */
30556c3e412Sdillo buffer2 = hfslib_realloc(buffer, sizeof(hfs_journal_info_t), cbargs);
30625e99827Sdillo if (buffer2 == NULL)
30756c3e412Sdillo HFS_LIBERR("could not allocate journal info block");
30825e99827Sdillo buffer = buffer2;
30925e99827Sdillo
31056c3e412Sdillo if (hfslib_readd(out_vol, buffer, sizeof(hfs_journal_info_t),
31125e99827Sdillo out_vol->vh.journal_info_block * out_vol->vh.block_size,
31225e99827Sdillo cbargs) != 0)
31356c3e412Sdillo HFS_LIBERR("could not read journal info block");
31425e99827Sdillo
31556c3e412Sdillo if (hfslib_read_journal_info(buffer, &out_vol->jib) == 0)
31656c3e412Sdillo HFS_LIBERR("could not parse journal info block");
31725e99827Sdillo
31825e99827Sdillo /* journal header */
31956c3e412Sdillo buffer2 = hfslib_realloc(buffer, sizeof(hfs_journal_header_t), cbargs);
32025e99827Sdillo if (buffer2 == NULL)
32156c3e412Sdillo HFS_LIBERR("could not allocate journal header");
32225e99827Sdillo buffer = buffer2;
32325e99827Sdillo
32456c3e412Sdillo if (hfslib_readd(out_vol, buffer, sizeof(hfs_journal_header_t),
32525e99827Sdillo out_vol->jib.offset, cbargs) != 0)
32656c3e412Sdillo HFS_LIBERR("could not read journal header");
32725e99827Sdillo
32856c3e412Sdillo if (hfslib_read_journal_header(buffer, &out_vol->jh) == 0)
32956c3e412Sdillo HFS_LIBERR("could not parse journal header");
33025e99827Sdillo
33125e99827Sdillo out_vol->journaled = 1;
3326a896067Smaxv } else {
33325e99827Sdillo out_vol->journaled = 0;
33425e99827Sdillo }
33525e99827Sdillo
33625e99827Sdillo /*
33725e99827Sdillo * If this volume uses case-folding comparison and the folding table hasn't
33856c3e412Sdillo * been created yet, do that here. (We don't do this in hfslib_init()
33925e99827Sdillo * because the table is large and we might never even need to use it.)
34025e99827Sdillo */
34156c3e412Sdillo if (out_vol->keycmp == hfslib_compare_catalog_keys_cf && hfs_gcft == NULL)
34256c3e412Sdillo result = hfslib_create_casefolding_table();
34325e99827Sdillo else
34425e99827Sdillo result = 0;
34525e99827Sdillo
34625e99827Sdillo /*
34725e99827Sdillo * Find and store the volume name.
34825e99827Sdillo */
34956c3e412Sdillo if (hfslib_make_catalog_key(HFS_CNID_ROOT_FOLDER, 0, NULL, &rootkey) == 0)
35056c3e412Sdillo HFS_LIBERR("could not make root search key");
35125e99827Sdillo
35256c3e412Sdillo if (hfslib_find_catalog_record_with_key(out_vol, &rootkey,
35356c3e412Sdillo (hfs_catalog_keyed_record_t*)&rootthread, cbargs)!=0)
35456c3e412Sdillo HFS_LIBERR("could not find root parent");
35525e99827Sdillo
35656c3e412Sdillo memcpy(&out_vol->name, &rootthread.name, sizeof(hfs_unistr255_t));
35725e99827Sdillo
35825e99827Sdillo /* FALLTHROUGH */
35925e99827Sdillo error:
360696e7eaeSpooka if (result != 0 && isopen)
361f75bcfdeSpooka hfslib_close_volume(out_vol, cbargs);
36225e99827Sdillo if (buffer != NULL)
36356c3e412Sdillo hfslib_free(buffer, cbargs);
36425e99827Sdillo return result;
36525e99827Sdillo }
36625e99827Sdillo
36725e99827Sdillo void
hfslib_close_volume(hfs_volume * in_vol,hfs_callback_args * cbargs)36856c3e412Sdillo hfslib_close_volume(hfs_volume* in_vol, hfs_callback_args* cbargs)
36925e99827Sdillo {
37025e99827Sdillo if (in_vol == NULL)
37125e99827Sdillo return;
37256c3e412Sdillo hfslib_closevoldevice(in_vol, cbargs);
37325e99827Sdillo }
37425e99827Sdillo
37525e99827Sdillo int
hfslib_path_to_cnid(hfs_volume * in_vol,hfs_cnid_t in_cnid,char ** out_unicode,uint16_t * out_length,hfs_callback_args * cbargs)37656c3e412Sdillo hfslib_path_to_cnid(hfs_volume* in_vol,
37756c3e412Sdillo hfs_cnid_t in_cnid,
37825e99827Sdillo char** out_unicode,
37925e99827Sdillo uint16_t* out_length,
38056c3e412Sdillo hfs_callback_args* cbargs)
38125e99827Sdillo {
38256c3e412Sdillo hfs_thread_record_t parent_thread;
38356c3e412Sdillo hfs_cnid_t parent_cnid, child_cnid;
38425e99827Sdillo char* newpath;
38525e99827Sdillo char* path;
38625e99827Sdillo int path_offset = 0;
38725e99827Sdillo int result;
38825e99827Sdillo uint16_t* ptr; /* dummy var */
38925e99827Sdillo uint16_t uchar; /* dummy var */
39025e99827Sdillo uint16_t total_path_length;
39125e99827Sdillo
3926a896067Smaxv if (in_vol == NULL || in_cnid == 0 || out_unicode == NULL ||
3936a896067Smaxv out_length == NULL)
39425e99827Sdillo return 1;
39525e99827Sdillo
39625e99827Sdillo result = 1;
39725e99827Sdillo *out_unicode = NULL;
39825e99827Sdillo *out_length = 0;
39925e99827Sdillo path = NULL;
40025e99827Sdillo total_path_length = 0;
40125e99827Sdillo
40256c3e412Sdillo path = hfslib_malloc(514, cbargs); /* 256 unichars plus a forward slash */
40325e99827Sdillo if (path == NULL)
40425e99827Sdillo return 1;
40525e99827Sdillo
40625e99827Sdillo child_cnid = in_cnid;
40725e99827Sdillo parent_cnid = child_cnid; /* skips loop in case in_cnid is root id */
4086a896067Smaxv while (parent_cnid != HFS_CNID_ROOT_FOLDER &&
4096a896067Smaxv parent_cnid != HFS_CNID_ROOT_PARENT)
41025e99827Sdillo {
4116a896067Smaxv if (child_cnid != in_cnid) {
41256c3e412Sdillo newpath = hfslib_realloc(path, 514 + total_path_length*2, cbargs);
41325e99827Sdillo if (newpath == NULL)
41425e99827Sdillo goto exit;
41525e99827Sdillo path = newpath;
41625e99827Sdillo memmove(path + 514, path + path_offset, total_path_length*2);
41725e99827Sdillo }
41825e99827Sdillo
41956c3e412Sdillo parent_cnid = hfslib_find_parent_thread(in_vol, child_cnid,
42025e99827Sdillo &parent_thread, cbargs);
42125e99827Sdillo if (parent_cnid == 0)
42225e99827Sdillo goto exit;
42325e99827Sdillo
42425e99827Sdillo path_offset = 512 - parent_thread.name.length*2;
42525e99827Sdillo
42625e99827Sdillo memcpy(path + path_offset, parent_thread.name.unicode,
42725e99827Sdillo parent_thread.name.length*2);
42825e99827Sdillo
42925e99827Sdillo /* Add a forward slash. The unicode string was specified in big endian
43025e99827Sdillo * format, so convert to core format if necessary. */
43125e99827Sdillo path[512] = 0x00;
43225e99827Sdillo path[513] = 0x2F;
43325e99827Sdillo
43425e99827Sdillo ptr = (uint16_t*)path + 256;
43525e99827Sdillo uchar = be16tohp((void*)&ptr);
43625e99827Sdillo *(ptr-1) = uchar;
43725e99827Sdillo
43825e99827Sdillo total_path_length += parent_thread.name.length + 1;
43925e99827Sdillo child_cnid = parent_cnid;
44025e99827Sdillo }
44125e99827Sdillo
44225e99827Sdillo /*
44325e99827Sdillo * At this point, 'path' holds a sequence of unicode characters which
44425e99827Sdillo * represent the absolute path to the given cnid. This string is missing
44525e99827Sdillo * a terminating null char and an initial forward slash that represents
44625e99827Sdillo * the root of the filesystem. It most likely also has extra space in
44725e99827Sdillo * the beginning, due to the fact that we reserve 512 bytes for each path
44825e99827Sdillo * component and won't usually use all that space. So, we allocate the
44925e99827Sdillo * final string based on the actual length of the absolute path, plus four
45025e99827Sdillo * additional bytes (two unichars) for the forward slash and the null char.
45125e99827Sdillo */
45225e99827Sdillo
45356c3e412Sdillo *out_unicode = hfslib_malloc((total_path_length+2)*2, cbargs);
45425e99827Sdillo if (*out_unicode == NULL)
45525e99827Sdillo goto exit;
45625e99827Sdillo
45725e99827Sdillo /* copy only the bytes that are actually used */
45825e99827Sdillo memcpy(*out_unicode + 2, path + path_offset, total_path_length*2);
45925e99827Sdillo
46025e99827Sdillo /* insert forward slash at start */
461b6ccfb3aSchristos uchar = be16toh(0x2F);
462b6ccfb3aSchristos memcpy(*out_unicode, &uchar, sizeof(uchar));
46325e99827Sdillo
46425e99827Sdillo /* insert null char at end */
46525e99827Sdillo (*out_unicode)[total_path_length*2+2] = 0x00;
46625e99827Sdillo (*out_unicode)[total_path_length*2+3] = 0x00;
46725e99827Sdillo
46825e99827Sdillo *out_length = total_path_length + 1 /* extra for forward slash */ ;
46925e99827Sdillo
47025e99827Sdillo result = 0;
47125e99827Sdillo
47225e99827Sdillo exit:
47325e99827Sdillo if (path != NULL)
47456c3e412Sdillo hfslib_free(path, cbargs);
47525e99827Sdillo return result;
47625e99827Sdillo }
47725e99827Sdillo
47856c3e412Sdillo hfs_cnid_t
hfslib_find_parent_thread(hfs_volume * in_vol,hfs_cnid_t in_child,hfs_thread_record_t * out_thread,hfs_callback_args * cbargs)47956c3e412Sdillo hfslib_find_parent_thread(
48056c3e412Sdillo hfs_volume* in_vol,
48156c3e412Sdillo hfs_cnid_t in_child,
48256c3e412Sdillo hfs_thread_record_t* out_thread,
48356c3e412Sdillo hfs_callback_args* cbargs)
48425e99827Sdillo {
48556c3e412Sdillo hfs_catalog_key_t childkey;
48625e99827Sdillo
48725e99827Sdillo if (in_vol == NULL || in_child == 0 || out_thread == NULL)
48825e99827Sdillo return 0;
48925e99827Sdillo
49056c3e412Sdillo if (hfslib_make_catalog_key(in_child, 0, NULL, &childkey) == 0)
49125e99827Sdillo return 0;
49225e99827Sdillo
49356c3e412Sdillo if (hfslib_find_catalog_record_with_key(in_vol, &childkey,
49456c3e412Sdillo (hfs_catalog_keyed_record_t*)out_thread, cbargs) != 0)
49525e99827Sdillo return 0;
49625e99827Sdillo
49725e99827Sdillo return out_thread->parent_cnid;
49825e99827Sdillo }
49925e99827Sdillo
50025e99827Sdillo /*
50156c3e412Sdillo * hfslib_find_catalog_record_with_cnid()
50225e99827Sdillo *
50356c3e412Sdillo * Looks up a catalog record by calling hfslib_find_parent_thread() and
50456c3e412Sdillo * hfslib_find_catalog_record_with_key(). out_key may be NULL; if not, the key
50525e99827Sdillo * corresponding to this cnid is stuffed in it. Returns 0 on success.
50625e99827Sdillo */
50725e99827Sdillo int
hfslib_find_catalog_record_with_cnid(hfs_volume * in_vol,hfs_cnid_t in_cnid,hfs_catalog_keyed_record_t * out_rec,hfs_catalog_key_t * out_key,hfs_callback_args * cbargs)50856c3e412Sdillo hfslib_find_catalog_record_with_cnid(
50956c3e412Sdillo hfs_volume* in_vol,
51056c3e412Sdillo hfs_cnid_t in_cnid,
51156c3e412Sdillo hfs_catalog_keyed_record_t* out_rec,
51256c3e412Sdillo hfs_catalog_key_t* out_key,
51356c3e412Sdillo hfs_callback_args* cbargs)
51425e99827Sdillo {
51556c3e412Sdillo hfs_cnid_t parentcnid;
51656c3e412Sdillo hfs_thread_record_t parentthread;
51756c3e412Sdillo hfs_catalog_key_t key;
51825e99827Sdillo
51925e99827Sdillo if (in_vol == NULL || in_cnid == 0 || out_rec == NULL)
52025e99827Sdillo return 0;
52125e99827Sdillo
52225e99827Sdillo parentcnid =
52356c3e412Sdillo hfslib_find_parent_thread(in_vol, in_cnid, &parentthread, cbargs);
52425e99827Sdillo if (parentcnid == 0)
52556c3e412Sdillo HFS_LIBERR("could not find parent thread for cnid %i", in_cnid);
52625e99827Sdillo
52756c3e412Sdillo if (hfslib_make_catalog_key(parentthread.parent_cnid,
52825e99827Sdillo parentthread.name.length, parentthread.name.unicode, &key) == 0)
52956c3e412Sdillo HFS_LIBERR("could not make catalog search key");
53025e99827Sdillo
53125e99827Sdillo if (out_key != NULL)
53225e99827Sdillo memcpy(out_key, &key, sizeof(key));
53325e99827Sdillo
53456c3e412Sdillo return hfslib_find_catalog_record_with_key(in_vol, &key, out_rec, cbargs);
53525e99827Sdillo
53625e99827Sdillo error:
53725e99827Sdillo return 1;
53825e99827Sdillo }
53925e99827Sdillo
54025e99827Sdillo /* Returns 0 on success, 1 on error, and -1 if record was not found. */
54125e99827Sdillo int
hfslib_find_catalog_record_with_key(hfs_volume * in_vol,hfs_catalog_key_t * in_key,hfs_catalog_keyed_record_t * out_rec,hfs_callback_args * cbargs)54256c3e412Sdillo hfslib_find_catalog_record_with_key(
54356c3e412Sdillo hfs_volume* in_vol,
54456c3e412Sdillo hfs_catalog_key_t* in_key,
54556c3e412Sdillo hfs_catalog_keyed_record_t* out_rec,
54656c3e412Sdillo hfs_callback_args* cbargs)
54725e99827Sdillo {
548*dd6a5058Smrg hfs_node_descriptor_t nd = { .num_recs = 0 };
54956c3e412Sdillo hfs_extent_descriptor_t* extents;
55056c3e412Sdillo hfs_catalog_keyed_record_t lastrec;
55156c3e412Sdillo hfs_catalog_key_t* curkey;
55225e99827Sdillo void** recs;
55325e99827Sdillo void* buffer;
55425e99827Sdillo uint64_t bytesread;
55525e99827Sdillo uint32_t curnode;
55625e99827Sdillo uint16_t* recsizes;
55725e99827Sdillo uint16_t numextents;
55825e99827Sdillo uint16_t recnum;
55925e99827Sdillo int16_t leaftype;
56025e99827Sdillo int keycompare;
56125e99827Sdillo int result;
56225e99827Sdillo
56325e99827Sdillo if (in_key == NULL || out_rec == NULL || in_vol == NULL)
56425e99827Sdillo return 1;
56525e99827Sdillo
56625e99827Sdillo result = 1;
56725e99827Sdillo buffer = NULL;
56825e99827Sdillo curkey = NULL;
56925e99827Sdillo extents = NULL;
57025e99827Sdillo recs = NULL;
57125e99827Sdillo recsizes = NULL;
57225e99827Sdillo
57325e99827Sdillo /* The key takes up over half a kb of ram, which is a lot for the BSD
57425e99827Sdillo * kernel stack. So allocate it in the heap instead to play it safe. */
57556c3e412Sdillo curkey = hfslib_malloc(sizeof(hfs_catalog_key_t), cbargs);
57625e99827Sdillo if (curkey == NULL)
57756c3e412Sdillo HFS_LIBERR("could not allocate catalog search key");
57825e99827Sdillo
57956c3e412Sdillo buffer = hfslib_malloc(in_vol->chr.node_size, cbargs);
58025e99827Sdillo if (buffer == NULL)
58156c3e412Sdillo HFS_LIBERR("could not allocate node buffer");
58225e99827Sdillo
58356c3e412Sdillo numextents = hfslib_get_file_extents(in_vol, HFS_CNID_CATALOG,
58456c3e412Sdillo HFS_DATAFORK, &extents, cbargs);
58525e99827Sdillo if (numextents == 0)
58656c3e412Sdillo HFS_LIBERR("could not locate fork extents");
58725e99827Sdillo
58825e99827Sdillo curnode = in_vol->chr.root_node;
58925e99827Sdillo
59025e99827Sdillo #ifdef DLO_DEBUG
59125e99827Sdillo printf("-> key ");
59225e99827Sdillo dlo_print_key(in_key);
59325e99827Sdillo printf("\n");
59425e99827Sdillo #endif
59525e99827Sdillo
596547d41caSmaxv do {
59725e99827Sdillo #ifdef DLO_DEBUG
59825e99827Sdillo printf("--> node %d\n", curnode);
59925e99827Sdillo #endif
60025e99827Sdillo
60156c3e412Sdillo if (hfslib_readd_with_extents(in_vol, buffer,
60225e99827Sdillo &bytesread,in_vol->chr.node_size, curnode * in_vol->chr.node_size,
60325e99827Sdillo extents, numextents, cbargs) != 0)
60456c3e412Sdillo HFS_LIBERR("could not read catalog node #%i", curnode);
60525e99827Sdillo
60656c3e412Sdillo if (hfslib_reada_node(buffer, &nd, &recs, &recsizes, HFS_CATALOG_FILE,
60725e99827Sdillo in_vol, cbargs) == 0)
60856c3e412Sdillo HFS_LIBERR("could not parse catalog node #%i", curnode);
60925e99827Sdillo
61025e99827Sdillo for (recnum = 0; recnum < nd.num_recs; recnum++)
61125e99827Sdillo {
61225e99827Sdillo leaftype = nd.kind;
61356c3e412Sdillo if (hfslib_read_catalog_keyed_record(recs[recnum], out_rec,
61425e99827Sdillo &leaftype, curkey, in_vol) == 0)
61556c3e412Sdillo HFS_LIBERR("could not read catalog record #%i",recnum);
61625e99827Sdillo
61725e99827Sdillo #ifdef DLO_DEBUG
61825e99827Sdillo printf("---> record %d: ", recnum);
61925e99827Sdillo dlo_print_key(curkey);
62025e99827Sdillo fflush(stdout);
62125e99827Sdillo #endif
62225e99827Sdillo keycompare = in_vol->keycmp(in_key, curkey);
62325e99827Sdillo #ifdef DLO_DEBUG
62425e99827Sdillo printf(" %c\n",
62525e99827Sdillo keycompare < 0 ? '<'
62625e99827Sdillo : keycompare == 0 ? '=' : '>');
62725e99827Sdillo #endif
62825e99827Sdillo
629547d41caSmaxv if (keycompare < 0) {
63025e99827Sdillo /* Check if key is less than *every* record, which should never
63125e99827Sdillo * happen if the volume is consistent and the key legit. */
63225e99827Sdillo if (recnum == 0)
63356c3e412Sdillo HFS_LIBERR("all records greater than key");
63425e99827Sdillo
63525e99827Sdillo /* Otherwise, we've found the first record that exceeds our key,
63625e99827Sdillo * so retrieve the previous record, which is still less... */
63725e99827Sdillo memcpy(out_rec, &lastrec,
63856c3e412Sdillo sizeof(hfs_catalog_keyed_record_t));
63925e99827Sdillo
64025e99827Sdillo /* ...unless this is a leaf node, which means we've gone from
64125e99827Sdillo * a key which is smaller than the search key, in the previous
64225e99827Sdillo * loop, to a key which is larger, in this loop, and that
64325e99827Sdillo * implies that our search key does not exist on the volume. */
64456c3e412Sdillo if (nd.kind == HFS_LEAFNODE)
64525e99827Sdillo result = -1;
64625e99827Sdillo break;
647547d41caSmaxv } else if (keycompare == 0) {
64825e99827Sdillo /* If leaf node, found an exact match. */
64925e99827Sdillo result = 0;
65025e99827Sdillo break;
651547d41caSmaxv } else if (recnum == nd.num_recs-1 && keycompare > 0) {
65225e99827Sdillo /* If leaf node, we've reached the last record with no match,
65325e99827Sdillo * which means this key is not present on the volume. */
65425e99827Sdillo result = -1;
65525e99827Sdillo break;
65625e99827Sdillo }
65725e99827Sdillo
65856c3e412Sdillo memcpy(&lastrec, out_rec, sizeof(hfs_catalog_keyed_record_t));
65925e99827Sdillo }
66025e99827Sdillo
66156c3e412Sdillo if (nd.kind == HFS_INDEXNODE)
66225e99827Sdillo curnode = out_rec->child;
66356c3e412Sdillo else if (nd.kind == HFS_LEAFNODE)
66425e99827Sdillo break;
66556c3e412Sdillo hfslib_free_recs(&recs, &recsizes, &nd.num_recs, cbargs);
666547d41caSmaxv } while (nd.kind != HFS_LEAFNODE);
66725e99827Sdillo
66825e99827Sdillo /* FALLTHROUGH */
66925e99827Sdillo error:
67025e99827Sdillo if (extents != NULL)
67156c3e412Sdillo hfslib_free(extents, cbargs);
67256c3e412Sdillo hfslib_free_recs(&recs, &recsizes, &nd.num_recs, cbargs);
67325e99827Sdillo if (curkey != NULL)
67456c3e412Sdillo hfslib_free(curkey, cbargs);
67525e99827Sdillo if (buffer != NULL)
67656c3e412Sdillo hfslib_free(buffer, cbargs);
67725e99827Sdillo return result;
67825e99827Sdillo }
67925e99827Sdillo
68025e99827Sdillo /* returns 0 on success */
68125e99827Sdillo /* XXX Need to look this over and make sure it gracefully handles cases where
68225e99827Sdillo * XXX the key is not found. */
68325e99827Sdillo int
hfslib_find_extent_record_with_key(hfs_volume * in_vol,hfs_extent_key_t * in_key,hfs_extent_record_t * out_rec,hfs_callback_args * cbargs)68456c3e412Sdillo hfslib_find_extent_record_with_key(hfs_volume* in_vol,
68556c3e412Sdillo hfs_extent_key_t* in_key,
68656c3e412Sdillo hfs_extent_record_t* out_rec,
68756c3e412Sdillo hfs_callback_args* cbargs)
68825e99827Sdillo {
689*dd6a5058Smrg hfs_node_descriptor_t nd = { .num_recs = 0 };
69056c3e412Sdillo hfs_extent_descriptor_t* extents;
69156c3e412Sdillo hfs_extent_record_t lastrec;
69256c3e412Sdillo hfs_extent_key_t curkey;
69325e99827Sdillo void** recs;
69425e99827Sdillo void* buffer;
69525e99827Sdillo uint64_t bytesread;
69625e99827Sdillo uint32_t curnode;
69725e99827Sdillo uint16_t* recsizes;
69825e99827Sdillo uint16_t numextents;
69925e99827Sdillo uint16_t recnum;
70025e99827Sdillo int keycompare;
70125e99827Sdillo int result;
70225e99827Sdillo
70325e99827Sdillo if (in_vol == NULL || in_key == NULL || out_rec == NULL)
70425e99827Sdillo return 1;
70525e99827Sdillo
70625e99827Sdillo result = 1;
70725e99827Sdillo buffer = NULL;
70825e99827Sdillo extents = NULL;
70925e99827Sdillo recs = NULL;
71025e99827Sdillo recsizes = NULL;
71125e99827Sdillo
71256c3e412Sdillo buffer = hfslib_malloc(in_vol->ehr.node_size, cbargs);
71325e99827Sdillo if (buffer == NULL)
71456c3e412Sdillo HFS_LIBERR("could not allocate node buffer");
71525e99827Sdillo
71656c3e412Sdillo numextents = hfslib_get_file_extents(in_vol, HFS_CNID_EXTENTS,
71756c3e412Sdillo HFS_DATAFORK, &extents, cbargs);
71825e99827Sdillo if (numextents == 0)
71956c3e412Sdillo HFS_LIBERR("could not locate fork extents");
72025e99827Sdillo
72125e99827Sdillo nd.num_recs = 0;
72225e99827Sdillo curnode = in_vol->ehr.root_node;
72325e99827Sdillo
724547d41caSmaxv do {
72556c3e412Sdillo hfslib_free_recs(&recs, &recsizes, &nd.num_recs, cbargs);
72625e99827Sdillo recnum = 0;
72725e99827Sdillo
72856c3e412Sdillo if (hfslib_readd_with_extents(in_vol, buffer, &bytesread,
72925e99827Sdillo in_vol->ehr.node_size, curnode * in_vol->ehr.node_size, extents,
73025e99827Sdillo numextents, cbargs) != 0)
73156c3e412Sdillo HFS_LIBERR("could not read extents overflow node #%i", curnode);
73225e99827Sdillo
73356c3e412Sdillo if (hfslib_reada_node(buffer, &nd, &recs, &recsizes, HFS_EXTENTS_FILE,
73425e99827Sdillo in_vol, cbargs) == 0)
73556c3e412Sdillo HFS_LIBERR("could not parse extents overflow node #%i",curnode);
73625e99827Sdillo
737547d41caSmaxv for (recnum = 0; recnum < nd.num_recs; recnum++) {
73856c3e412Sdillo memcpy(&lastrec, out_rec, sizeof(hfs_extent_record_t));
73925e99827Sdillo
74056c3e412Sdillo if (hfslib_read_extent_record(recs[recnum], out_rec, nd.kind,
74125e99827Sdillo &curkey, in_vol) == 0)
74256c3e412Sdillo HFS_LIBERR("could not read extents record #%i",recnum);
74325e99827Sdillo
74456c3e412Sdillo keycompare = hfslib_compare_extent_keys(in_key, &curkey);
745547d41caSmaxv if (keycompare < 0) {
74625e99827Sdillo /* this should never happen for any legitimate key */
74725e99827Sdillo if (recnum == 0)
74825e99827Sdillo return 1;
74956c3e412Sdillo memcpy(out_rec, &lastrec, sizeof(hfs_extent_record_t));
75025e99827Sdillo break;
751547d41caSmaxv } else if (keycompare == 0 ||
75225e99827Sdillo (recnum == nd.num_recs-1 && keycompare > 0))
75325e99827Sdillo break;
75425e99827Sdillo }
75525e99827Sdillo
75656c3e412Sdillo if (nd.kind == HFS_INDEXNODE)
75725e99827Sdillo curnode = *((uint32_t *)out_rec); /* out_rec is a node ptr in this case */
75856c3e412Sdillo else if (nd.kind == HFS_LEAFNODE)
75925e99827Sdillo break;
76025e99827Sdillo else
7614e7cd698Smsaitoh HFS_LIBERR("unknown node type for extents overflow node #%i",curnode);
762547d41caSmaxv } while (nd.kind != HFS_LEAFNODE);
76325e99827Sdillo
76425e99827Sdillo result = 0;
76525e99827Sdillo
76625e99827Sdillo /* FALLTHROUGH */
76725e99827Sdillo
76825e99827Sdillo error:
76925e99827Sdillo if (buffer != NULL)
77056c3e412Sdillo hfslib_free(buffer, cbargs);
77125e99827Sdillo if (extents != NULL)
77256c3e412Sdillo hfslib_free(extents, cbargs);
77356c3e412Sdillo hfslib_free_recs(&recs, &recsizes, &nd.num_recs, cbargs);
77425e99827Sdillo return result;
77525e99827Sdillo }
77625e99827Sdillo
77725e99827Sdillo /* out_extents may be NULL. */
77825e99827Sdillo uint16_t
hfslib_get_file_extents(hfs_volume * in_vol,hfs_cnid_t in_cnid,uint8_t in_forktype,hfs_extent_descriptor_t ** out_extents,hfs_callback_args * cbargs)77956c3e412Sdillo hfslib_get_file_extents(hfs_volume* in_vol,
78056c3e412Sdillo hfs_cnid_t in_cnid,
78125e99827Sdillo uint8_t in_forktype,
78256c3e412Sdillo hfs_extent_descriptor_t** out_extents,
78356c3e412Sdillo hfs_callback_args* cbargs)
78425e99827Sdillo {
78556c3e412Sdillo hfs_extent_descriptor_t* dummy;
78656c3e412Sdillo hfs_extent_key_t extentkey;
78756c3e412Sdillo hfs_file_record_t file;
78856c3e412Sdillo hfs_catalog_key_t filekey;
78956c3e412Sdillo hfs_thread_record_t fileparent;
7900a2587beSapb hfs_fork_t fork = {.logical_size = 0};
79156c3e412Sdillo hfs_extent_record_t nextextentrec;
79225e99827Sdillo uint32_t numblocks;
79325e99827Sdillo uint16_t numextents, n;
79425e99827Sdillo
79525e99827Sdillo if (in_vol == NULL || in_cnid == 0)
79625e99827Sdillo return 0;
79725e99827Sdillo
798547d41caSmaxv if (out_extents != NULL) {
79956c3e412Sdillo *out_extents = hfslib_malloc(sizeof(hfs_extent_descriptor_t), cbargs);
80025e99827Sdillo if (*out_extents == NULL)
80125e99827Sdillo return 0;
80225e99827Sdillo }
80325e99827Sdillo
80425e99827Sdillo switch(in_cnid)
80525e99827Sdillo {
80656c3e412Sdillo case HFS_CNID_CATALOG:
80725e99827Sdillo fork = in_vol->vh.catalog_file;
80825e99827Sdillo break;
80925e99827Sdillo
81056c3e412Sdillo case HFS_CNID_EXTENTS:
81125e99827Sdillo fork = in_vol->vh.extents_file;
81225e99827Sdillo break;
81325e99827Sdillo
81456c3e412Sdillo case HFS_CNID_ALLOCATION:
81525e99827Sdillo fork = in_vol->vh.allocation_file;
81625e99827Sdillo break;
81725e99827Sdillo
81856c3e412Sdillo case HFS_CNID_ATTRIBUTES:
81925e99827Sdillo fork = in_vol->vh.attributes_file;
82025e99827Sdillo break;
82125e99827Sdillo
82256c3e412Sdillo case HFS_CNID_STARTUP:
82325e99827Sdillo fork = in_vol->vh.startup_file;
82425e99827Sdillo break;
82525e99827Sdillo
82625e99827Sdillo default:
82756c3e412Sdillo if (hfslib_find_parent_thread(in_vol, in_cnid, &fileparent,
82825e99827Sdillo cbargs) == 0)
82925e99827Sdillo goto error;
83025e99827Sdillo
83156c3e412Sdillo if (hfslib_make_catalog_key(fileparent.parent_cnid,
83225e99827Sdillo fileparent.name.length, fileparent.name.unicode, &filekey) == 0)
83325e99827Sdillo goto error;
83425e99827Sdillo
83556c3e412Sdillo if (hfslib_find_catalog_record_with_key(in_vol, &filekey,
83656c3e412Sdillo (hfs_catalog_keyed_record_t*)&file, cbargs) != 0)
83725e99827Sdillo goto error;
83825e99827Sdillo
83925e99827Sdillo /* only files have extents, not folders or threads */
84056c3e412Sdillo if (file.rec_type != HFS_REC_FILE)
84125e99827Sdillo goto error;
84225e99827Sdillo
84356c3e412Sdillo if (in_forktype == HFS_DATAFORK)
84425e99827Sdillo fork = file.data_fork;
84556c3e412Sdillo else if (in_forktype == HFS_RSRCFORK)
84625e99827Sdillo fork = file.rsrc_fork;
84725e99827Sdillo }
84825e99827Sdillo
84925e99827Sdillo numextents = 0;
85025e99827Sdillo numblocks = 0;
85156c3e412Sdillo memcpy(&nextextentrec, &fork.extents, sizeof(hfs_extent_record_t));
85225e99827Sdillo
853547d41caSmaxv while (1) {
854547d41caSmaxv for (n = 0; n < 8; n++) {
85525e99827Sdillo if (nextextentrec[n].block_count == 0)
85625e99827Sdillo break;
85725e99827Sdillo numblocks += nextextentrec[n].block_count;
85825e99827Sdillo }
859547d41caSmaxv if (out_extents != NULL) {
86056c3e412Sdillo dummy = hfslib_realloc(*out_extents,
86156c3e412Sdillo (numextents+n) * sizeof(hfs_extent_descriptor_t),
86225e99827Sdillo cbargs);
86325e99827Sdillo if (dummy == NULL)
86425e99827Sdillo goto error;
86525e99827Sdillo *out_extents = dummy;
86625e99827Sdillo
86725e99827Sdillo memcpy(*out_extents + numextents,
86856c3e412Sdillo &nextextentrec, n*sizeof(hfs_extent_descriptor_t));
86925e99827Sdillo }
87025e99827Sdillo numextents += n;
87125e99827Sdillo
87225e99827Sdillo if (numblocks >= fork.total_blocks)
87325e99827Sdillo break;
87425e99827Sdillo
87556c3e412Sdillo if (hfslib_make_extent_key(in_cnid, in_forktype, numblocks,
87625e99827Sdillo &extentkey) == 0)
87725e99827Sdillo goto error;
87825e99827Sdillo
87956c3e412Sdillo if (hfslib_find_extent_record_with_key(in_vol, &extentkey,
88025e99827Sdillo &nextextentrec, cbargs) != 0)
88125e99827Sdillo goto error;
88225e99827Sdillo }
88325e99827Sdillo
88425e99827Sdillo goto exit;
88525e99827Sdillo
88625e99827Sdillo error:
887547d41caSmaxv if (out_extents != NULL && *out_extents != NULL) {
88856c3e412Sdillo hfslib_free(*out_extents, cbargs);
88925e99827Sdillo *out_extents = NULL;
89025e99827Sdillo }
89125e99827Sdillo return 0;
89225e99827Sdillo
89325e99827Sdillo exit:
89425e99827Sdillo return numextents;
89525e99827Sdillo }
89625e99827Sdillo
89725e99827Sdillo /*
89856c3e412Sdillo * hfslib_get_directory_contents()
89925e99827Sdillo *
90025e99827Sdillo * Finds the immediate children of a given directory CNID and places their
90125e99827Sdillo * CNIDs in an array allocated here. The first child is found by doing a
90225e99827Sdillo * catalog search that only compares parent CNIDs (ignoring file/folder names)
90325e99827Sdillo * and skips over thread records. Then the remaining children are listed in
90425e99827Sdillo * ascending order by name, according to the HFS+ spec, so just read off each
90525e99827Sdillo * successive leaf node until a different parent CNID is found.
90625e99827Sdillo *
90725e99827Sdillo * If out_childnames is not NULL, it will be allocated and set to an array of
90856c3e412Sdillo * hfs_unistr255_t's which correspond to the name of the child with that same
90925e99827Sdillo * index.
91025e99827Sdillo *
91125e99827Sdillo * out_children may be NULL.
91225e99827Sdillo *
91325e99827Sdillo * Returns 0 on success.
91425e99827Sdillo */
91525e99827Sdillo int
hfslib_get_directory_contents(hfs_volume * in_vol,hfs_cnid_t in_dir,hfs_catalog_keyed_record_t ** out_children,hfs_unistr255_t ** out_childnames,uint32_t * out_numchildren,hfs_callback_args * cbargs)91656c3e412Sdillo hfslib_get_directory_contents(
91756c3e412Sdillo hfs_volume* in_vol,
91856c3e412Sdillo hfs_cnid_t in_dir,
91956c3e412Sdillo hfs_catalog_keyed_record_t** out_children,
92056c3e412Sdillo hfs_unistr255_t** out_childnames,
92125e99827Sdillo uint32_t* out_numchildren,
92256c3e412Sdillo hfs_callback_args* cbargs)
92325e99827Sdillo {
924*dd6a5058Smrg hfs_node_descriptor_t nd = { .num_recs = 0 };
92556c3e412Sdillo hfs_extent_descriptor_t* extents;
92656c3e412Sdillo hfs_catalog_keyed_record_t currec;
92756c3e412Sdillo hfs_catalog_key_t curkey;
92825e99827Sdillo void** recs;
92925e99827Sdillo void* buffer;
93025e99827Sdillo void* ptr; /* temporary pointer for realloc() */
93125e99827Sdillo uint64_t bytesread;
93225e99827Sdillo uint32_t curnode;
93325e99827Sdillo uint32_t lastnode;
93425e99827Sdillo uint16_t* recsizes;
93525e99827Sdillo uint16_t numextents;
93625e99827Sdillo uint16_t recnum;
93725e99827Sdillo int16_t leaftype;
93825e99827Sdillo int keycompare;
93925e99827Sdillo int result;
94025e99827Sdillo
94125e99827Sdillo if (in_vol == NULL || in_dir == 0 || out_numchildren == NULL)
94225e99827Sdillo return 1;
94325e99827Sdillo
94425e99827Sdillo result = 1;
94525e99827Sdillo buffer = NULL;
94625e99827Sdillo extents = NULL;
94725e99827Sdillo lastnode = 0;
94825e99827Sdillo recs = NULL;
94925e99827Sdillo recsizes = NULL;
95025e99827Sdillo *out_numchildren = 0;
95125e99827Sdillo if (out_children != NULL)
95225e99827Sdillo *out_children = NULL;
95325e99827Sdillo if (out_childnames != NULL)
95425e99827Sdillo *out_childnames = NULL;
95525e99827Sdillo
95656c3e412Sdillo buffer = hfslib_malloc(in_vol->chr.node_size, cbargs);
95725e99827Sdillo if (buffer == NULL)
95856c3e412Sdillo HFS_LIBERR("could not allocate node buffer");
95925e99827Sdillo
96056c3e412Sdillo numextents = hfslib_get_file_extents(in_vol, HFS_CNID_CATALOG,
96156c3e412Sdillo HFS_DATAFORK, &extents, cbargs);
96225e99827Sdillo if (numextents == 0)
96356c3e412Sdillo HFS_LIBERR("could not locate fork extents");
96425e99827Sdillo
96525e99827Sdillo nd.num_recs = 0;
96625e99827Sdillo curnode = in_vol->chr.root_node;
96725e99827Sdillo
96825e99827Sdillo while (1)
96925e99827Sdillo {
97056c3e412Sdillo hfslib_free_recs(&recs, &recsizes, &nd.num_recs, cbargs);
97125e99827Sdillo recnum = 0;
97225e99827Sdillo
97356c3e412Sdillo if (hfslib_readd_with_extents(in_vol, buffer, &bytesread,
97425e99827Sdillo in_vol->chr.node_size, curnode * in_vol->chr.node_size, extents,
97525e99827Sdillo numextents, cbargs) != 0)
97656c3e412Sdillo HFS_LIBERR("could not read catalog node #%i", curnode);
97725e99827Sdillo
97856c3e412Sdillo if (hfslib_reada_node(buffer, &nd, &recs, &recsizes, HFS_CATALOG_FILE,
97925e99827Sdillo in_vol, cbargs) == 0)
98056c3e412Sdillo HFS_LIBERR("could not parse catalog node #%i", curnode);
98125e99827Sdillo
98225e99827Sdillo for (recnum = 0; recnum < nd.num_recs; recnum++)
98325e99827Sdillo {
98425e99827Sdillo leaftype = nd.kind; /* needed b/c leaftype might be modified now */
98556c3e412Sdillo if (hfslib_read_catalog_keyed_record(recs[recnum], &currec,
98625e99827Sdillo &leaftype, &curkey, in_vol) == 0)
98756c3e412Sdillo HFS_LIBERR("could not read cat record %i:%i", curnode, recnum);
98825e99827Sdillo
98956c3e412Sdillo if (nd.kind == HFS_INDEXNODE)
99025e99827Sdillo {
99125e99827Sdillo keycompare = in_dir - curkey.parent_cnid;
992547d41caSmaxv if (keycompare < 0) {
99325e99827Sdillo /* Check if key is less than *every* record, which should
99425e99827Sdillo * never happen if the volume and key are good. */
99525e99827Sdillo if (recnum == 0)
99656c3e412Sdillo HFS_LIBERR("all records greater than key");
99725e99827Sdillo
99825e99827Sdillo /* Otherwise, we've found the first record that exceeds our
99925e99827Sdillo * key, so retrieve the previous, lesser record. */
100025e99827Sdillo curnode = lastnode;
100125e99827Sdillo break;
1002547d41caSmaxv } else if (keycompare == 0) {
100325e99827Sdillo /*
100425e99827Sdillo * Normally, if we were doing a typical catalog lookup with
100525e99827Sdillo * both a parent cnid AND a name, keycompare==0 would be an
100625e99827Sdillo * exact match. However, since we are ignoring object names
100725e99827Sdillo * in this case and only comparing parent cnids, a direct
100825e99827Sdillo * match on only a parent cnid could mean that we've found
100925e99827Sdillo * an object with that parent cnid BUT which is NOT the
101025e99827Sdillo * first object (according to the HFS+ spec) with that
101125e99827Sdillo * parent cnid. Thus, when we find a parent cnid match, we
101225e99827Sdillo * still go back to the previously found leaf node and start
101325e99827Sdillo * checking it for a possible prior instance of an object
101425e99827Sdillo * with our desired parent cnid.
101525e99827Sdillo */
101625e99827Sdillo curnode = lastnode;
101725e99827Sdillo break;
1018547d41caSmaxv } else if (recnum == nd.num_recs-1 && keycompare > 0) {
101925e99827Sdillo /* Descend to child node if we found an exact match, or if
102025e99827Sdillo * this is the last pointer record. */
102125e99827Sdillo curnode = currec.child;
102225e99827Sdillo break;
102325e99827Sdillo }
102425e99827Sdillo
102525e99827Sdillo lastnode = currec.child;
1026547d41caSmaxv } else {
102725e99827Sdillo /*
102825e99827Sdillo * We have now descended down the hierarchy of index nodes into
102925e99827Sdillo * the leaf node that contains the first catalog record with a
103025e99827Sdillo * matching parent CNID. Since all leaf nodes are chained
103125e99827Sdillo * through their flink/blink, we can simply walk forward through
103225e99827Sdillo * this chain, copying every matching non-thread record, until
103325e99827Sdillo * we hit a record with a different parent CNID. At that point,
103425e99827Sdillo * we've retrieved all of our directory's items, if any.
103525e99827Sdillo */
103625e99827Sdillo curnode = nd.flink;
103725e99827Sdillo
1038547d41caSmaxv if (curkey.parent_cnid < in_dir) {
103925e99827Sdillo continue;
1040547d41caSmaxv } else if (curkey.parent_cnid == in_dir) {
104125e99827Sdillo /* Hide files/folders which are supposed to be invisible
104225e99827Sdillo * to users, according to the hfs+ spec. */
104356c3e412Sdillo if (hfslib_is_private_file(&curkey))
104425e99827Sdillo continue;
104525e99827Sdillo
104625e99827Sdillo /* leaftype has now been set to the catalog record type */
104756c3e412Sdillo if (leaftype == HFS_REC_FLDR || leaftype == HFS_REC_FILE)
104825e99827Sdillo {
104925e99827Sdillo (*out_numchildren)++;
105025e99827Sdillo
1051547d41caSmaxv if (out_children != NULL) {
105256c3e412Sdillo ptr = hfslib_realloc(*out_children,
105325e99827Sdillo *out_numchildren *
105456c3e412Sdillo sizeof(hfs_catalog_keyed_record_t), cbargs);
105525e99827Sdillo if (ptr == NULL)
105656c3e412Sdillo HFS_LIBERR("could not allocate child record");
105725e99827Sdillo *out_children = ptr;
105825e99827Sdillo
105925e99827Sdillo memcpy(&((*out_children)[*out_numchildren-1]),
106056c3e412Sdillo &currec, sizeof(hfs_catalog_keyed_record_t));
106125e99827Sdillo }
106225e99827Sdillo
1063547d41caSmaxv if (out_childnames != NULL) {
106456c3e412Sdillo ptr = hfslib_realloc(*out_childnames,
106556c3e412Sdillo *out_numchildren * sizeof(hfs_unistr255_t),
106625e99827Sdillo cbargs);
106725e99827Sdillo if (ptr == NULL)
106856c3e412Sdillo HFS_LIBERR("could not allocate child name");
106925e99827Sdillo *out_childnames = ptr;
107025e99827Sdillo
107125e99827Sdillo memcpy(&((*out_childnames)[*out_numchildren-1]),
107256c3e412Sdillo &curkey.name, sizeof(hfs_unistr255_t));
107325e99827Sdillo }
107425e99827Sdillo }
107525e99827Sdillo } else {
107625e99827Sdillo result = 0;
107725e99827Sdillo /* We have just now passed the last item in the desired
107825e99827Sdillo * folder (or the folder was empty), so exit. */
107925e99827Sdillo goto exit;
108025e99827Sdillo }
108125e99827Sdillo }
108225e99827Sdillo }
108325e99827Sdillo }
108425e99827Sdillo
108525e99827Sdillo result = 0;
108625e99827Sdillo goto exit;
108725e99827Sdillo
108825e99827Sdillo error:
108925e99827Sdillo if (out_children != NULL && *out_children != NULL)
109056c3e412Sdillo hfslib_free(*out_children, cbargs);
109125e99827Sdillo if (out_childnames != NULL && *out_childnames != NULL)
109256c3e412Sdillo hfslib_free(*out_childnames, cbargs);
109325e99827Sdillo /* FALLTHROUGH */
109425e99827Sdillo
109525e99827Sdillo exit:
109625e99827Sdillo if (extents != NULL)
109756c3e412Sdillo hfslib_free(extents, cbargs);
109856c3e412Sdillo hfslib_free_recs(&recs, &recsizes, &nd.num_recs, cbargs);
109925e99827Sdillo if (buffer != NULL)
110056c3e412Sdillo hfslib_free(buffer, cbargs);
110125e99827Sdillo return result;
110225e99827Sdillo }
110325e99827Sdillo
110425e99827Sdillo int
hfslib_is_journal_clean(hfs_volume * in_vol)110556c3e412Sdillo hfslib_is_journal_clean(hfs_volume* in_vol)
110625e99827Sdillo {
110725e99827Sdillo if (in_vol == NULL)
110825e99827Sdillo return 0;
110925e99827Sdillo
111025e99827Sdillo /* return true if no journal */
111156c3e412Sdillo if (!(in_vol->vh.attributes & (1<<HFS_VOL_JOURNALED)))
111225e99827Sdillo return 1;
111325e99827Sdillo
111425e99827Sdillo return (in_vol->jh.start == in_vol->jh.end);
111525e99827Sdillo }
111625e99827Sdillo
111725e99827Sdillo /*
111856c3e412Sdillo * hfslib_is_private_file()
111925e99827Sdillo *
112025e99827Sdillo * Given a file/folder's key and parent CNID, determines if it should be hidden
112125e99827Sdillo * from the user (e.g., the journal header file or the HFS+ Private Data folder)
112225e99827Sdillo */
112325e99827Sdillo int
hfslib_is_private_file(hfs_catalog_key_t * filekey)112456c3e412Sdillo hfslib_is_private_file(hfs_catalog_key_t *filekey)
112525e99827Sdillo {
112656c3e412Sdillo hfs_catalog_key_t* curkey = NULL;
112725e99827Sdillo int i = 0;
112825e99827Sdillo
112925e99827Sdillo /*
113025e99827Sdillo * According to the HFS+ spec to date, all special objects are located in
113125e99827Sdillo * the root directory of the volume, so don't bother going further if the
113225e99827Sdillo * requested object is not.
113325e99827Sdillo */
113456c3e412Sdillo if (filekey->parent_cnid != HFS_CNID_ROOT_FOLDER)
113525e99827Sdillo return 0;
113625e99827Sdillo
1137547d41caSmaxv while ((curkey = hfs_gPrivateObjectKeys[i]) != NULL) {
113825e99827Sdillo /* XXX Always use binary compare here, or use volume's specific key
113925e99827Sdillo * XXX comparison routine? */
1140547d41caSmaxv if (filekey->name.length == curkey->name.length &&
1141547d41caSmaxv memcmp(filekey->name.unicode, curkey->name.unicode,
114225e99827Sdillo 2 * curkey->name.length) == 0)
114325e99827Sdillo return 1;
114425e99827Sdillo i++;
114525e99827Sdillo }
114625e99827Sdillo
114725e99827Sdillo return 0;
114825e99827Sdillo }
114925e99827Sdillo
115025e99827Sdillo
115125e99827Sdillo /* bool
115256c3e412Sdillo hfslib_is_journal_valid(hfs_volume* in_vol)
115325e99827Sdillo {
115425e99827Sdillo - check magic numbers
115525e99827Sdillo - check Other Things
115625e99827Sdillo }*/
115725e99827Sdillo
115825e99827Sdillo #if 0
115925e99827Sdillo #pragma mark -
116025e99827Sdillo #pragma mark Major Structures
116125e99827Sdillo #endif
116225e99827Sdillo
116325e99827Sdillo /*
116456c3e412Sdillo * hfslib_read_volume_header()
116525e99827Sdillo *
116625e99827Sdillo * Reads in_bytes, formats the data appropriately, and places the result
116725e99827Sdillo * in out_header, which is assumed to be previously allocated. Returns number
116825e99827Sdillo * of bytes read, 0 if failed.
116925e99827Sdillo */
117025e99827Sdillo
117125e99827Sdillo size_t
hfslib_read_volume_header(void * in_bytes,hfs_volume_header_t * out_header)117256c3e412Sdillo hfslib_read_volume_header(void* in_bytes, hfs_volume_header_t* out_header)
117325e99827Sdillo {
117425e99827Sdillo void* ptr;
117525e99827Sdillo size_t last_bytes_read;
117625e99827Sdillo int i;
117725e99827Sdillo
117825e99827Sdillo if (in_bytes == NULL || out_header == NULL)
117925e99827Sdillo return 0;
118025e99827Sdillo
118125e99827Sdillo ptr = in_bytes;
118225e99827Sdillo
118325e99827Sdillo out_header->signature = be16tohp(&ptr);
118425e99827Sdillo out_header->version = be16tohp(&ptr);
118525e99827Sdillo out_header->attributes = be32tohp(&ptr);
118625e99827Sdillo out_header->last_mounting_version = be32tohp(&ptr);
118725e99827Sdillo out_header->journal_info_block = be32tohp(&ptr);
118825e99827Sdillo
118925e99827Sdillo out_header->date_created = be32tohp(&ptr);
119025e99827Sdillo out_header->date_modified = be32tohp(&ptr);
119125e99827Sdillo out_header->date_backedup = be32tohp(&ptr);
119225e99827Sdillo out_header->date_checked = be32tohp(&ptr);
119325e99827Sdillo
119425e99827Sdillo out_header->file_count = be32tohp(&ptr);
119525e99827Sdillo out_header->folder_count = be32tohp(&ptr);
119625e99827Sdillo
119725e99827Sdillo out_header->block_size = be32tohp(&ptr);
119825e99827Sdillo out_header->total_blocks = be32tohp(&ptr);
119925e99827Sdillo out_header->free_blocks = be32tohp(&ptr);
120025e99827Sdillo out_header->next_alloc_block = be32tohp(&ptr);
120125e99827Sdillo out_header->rsrc_clump_size = be32tohp(&ptr);
120225e99827Sdillo out_header->data_clump_size = be32tohp(&ptr);
120325e99827Sdillo out_header->next_cnid = be32tohp(&ptr);
120425e99827Sdillo
120525e99827Sdillo out_header->write_count = be32tohp(&ptr);
120625e99827Sdillo out_header->encodings = be64tohp(&ptr);
120725e99827Sdillo
120825e99827Sdillo for (i =0 ; i < 8; i++)
120925e99827Sdillo out_header->finder_info[i] = be32tohp(&ptr);
121025e99827Sdillo
121156c3e412Sdillo if ((last_bytes_read = hfslib_read_fork_descriptor(ptr,
121225e99827Sdillo &out_header->allocation_file)) == 0)
121325e99827Sdillo return 0;
121425e99827Sdillo ptr = (uint8_t*)ptr + last_bytes_read;
121525e99827Sdillo
121656c3e412Sdillo if ((last_bytes_read = hfslib_read_fork_descriptor(ptr,
121725e99827Sdillo &out_header->extents_file)) == 0)
121825e99827Sdillo return 0;
121925e99827Sdillo ptr = (uint8_t*)ptr + last_bytes_read;
122025e99827Sdillo
122156c3e412Sdillo if ((last_bytes_read = hfslib_read_fork_descriptor(ptr,
122225e99827Sdillo &out_header->catalog_file)) == 0)
122325e99827Sdillo return 0;
122425e99827Sdillo ptr = (uint8_t*)ptr + last_bytes_read;
122525e99827Sdillo
122656c3e412Sdillo if ((last_bytes_read = hfslib_read_fork_descriptor(ptr,
122725e99827Sdillo &out_header->attributes_file)) == 0)
122825e99827Sdillo return 0;
122925e99827Sdillo ptr = (uint8_t*)ptr + last_bytes_read;
123025e99827Sdillo
123156c3e412Sdillo if ((last_bytes_read = hfslib_read_fork_descriptor(ptr,
123225e99827Sdillo &out_header->startup_file)) == 0)
123325e99827Sdillo return 0;
123425e99827Sdillo ptr = (uint8_t*)ptr + last_bytes_read;
123525e99827Sdillo
123625e99827Sdillo return ((uint8_t*)ptr - (uint8_t*)in_bytes);
123725e99827Sdillo }
123825e99827Sdillo
123925e99827Sdillo /*
124041627b2cSdillo * hfsplib_read_master_directory_block()
124141627b2cSdillo *
124241627b2cSdillo * Reads in_bytes, formats the data appropriately, and places the result
124341627b2cSdillo * in out_header, which is assumed to be previously allocated. Returns numb
124441627b2cSdillo er
124541627b2cSdillo * of bytes read, 0 if failed.
124641627b2cSdillo */
124741627b2cSdillo
124841627b2cSdillo size_t
hfslib_read_master_directory_block(void * in_bytes,hfs_hfs_master_directory_block_t * out_mdr)124941627b2cSdillo hfslib_read_master_directory_block(void* in_bytes,
125041627b2cSdillo hfs_hfs_master_directory_block_t* out_mdr)
125141627b2cSdillo {
125241627b2cSdillo void* ptr;
125341627b2cSdillo int i;
125441627b2cSdillo
125541627b2cSdillo if (in_bytes == NULL || out_mdr == NULL)
125641627b2cSdillo return 0;
125741627b2cSdillo
125841627b2cSdillo ptr = in_bytes;
125941627b2cSdillo
126041627b2cSdillo out_mdr->signature = be16tohp(&ptr);
126141627b2cSdillo
126241627b2cSdillo out_mdr->date_created = be32tohp(&ptr);
126341627b2cSdillo out_mdr->date_modified = be32tohp(&ptr);
126441627b2cSdillo
126541627b2cSdillo out_mdr->attributes = be16tohp(&ptr);
126641627b2cSdillo out_mdr->root_file_count = be16tohp(&ptr);
126741627b2cSdillo out_mdr->volume_bitmap = be16tohp(&ptr);
126841627b2cSdillo
126941627b2cSdillo out_mdr->next_alloc_block = be16tohp(&ptr);
127041627b2cSdillo out_mdr->total_blocks = be16tohp(&ptr);
127141627b2cSdillo out_mdr->block_size = be32tohp(&ptr);
127241627b2cSdillo
127341627b2cSdillo out_mdr->clump_size = be32tohp(&ptr);
127441627b2cSdillo out_mdr->first_block = be16tohp(&ptr);
127541627b2cSdillo out_mdr->next_cnid = be32tohp(&ptr);
127641627b2cSdillo out_mdr->free_blocks = be16tohp(&ptr);
127741627b2cSdillo
127841627b2cSdillo memcpy(out_mdr->volume_name, ptr, 28);
127941627b2cSdillo ptr = (char *)ptr + 28;
128041627b2cSdillo
128141627b2cSdillo out_mdr->date_backedup = be32tohp(&ptr);
128241627b2cSdillo out_mdr->backup_seqnum = be16tohp(&ptr);
128341627b2cSdillo
128441627b2cSdillo out_mdr->write_count = be32tohp(&ptr);
128541627b2cSdillo
128641627b2cSdillo out_mdr->extents_clump_size = be32tohp(&ptr);
128741627b2cSdillo out_mdr->catalog_clump_size = be32tohp(&ptr);
128841627b2cSdillo
128941627b2cSdillo out_mdr->root_folder_count = be16tohp(&ptr);
129041627b2cSdillo out_mdr->file_count = be32tohp(&ptr);
129141627b2cSdillo out_mdr->folder_count = be32tohp(&ptr);
129241627b2cSdillo
129341627b2cSdillo for (i = 0; i < 8; i++)
129441627b2cSdillo out_mdr->finder_info[i] = be32tohp(&ptr);
129541627b2cSdillo
129641627b2cSdillo out_mdr->embedded_signature = be16tohp(&ptr);
129741627b2cSdillo out_mdr->embedded_extent.start_block = be16tohp(&ptr);
129841627b2cSdillo out_mdr->embedded_extent.block_count = be16tohp(&ptr);
129941627b2cSdillo
130041627b2cSdillo out_mdr->extents_size = be32tohp(&ptr);
1301547d41caSmaxv for (i = 0; i < 3; i++) {
130241627b2cSdillo out_mdr->extents_extents[i].start_block = be16tohp(&ptr);
130341627b2cSdillo out_mdr->extents_extents[i].block_count = be16tohp(&ptr);
130441627b2cSdillo }
130541627b2cSdillo
130641627b2cSdillo out_mdr->catalog_size = be32tohp(&ptr);
1307547d41caSmaxv for (i = 0; i < 3; i++) {
130841627b2cSdillo out_mdr->catalog_extents[i].start_block = be16tohp(&ptr);
130941627b2cSdillo out_mdr->catalog_extents[i].block_count = be16tohp(&ptr);
131041627b2cSdillo }
131141627b2cSdillo
131241627b2cSdillo return ((uint8_t*)ptr - (uint8_t*)in_bytes);
131341627b2cSdillo }
131441627b2cSdillo
131541627b2cSdillo /*
131656c3e412Sdillo * hfslib_reada_node()
131725e99827Sdillo *
131825e99827Sdillo * Given the pointer to and size of a buffer containing the entire, raw
131925e99827Sdillo * contents of any b-tree node from the disk, this function will:
132025e99827Sdillo *
132125e99827Sdillo * 1. determine the type of node and read its contents
132225e99827Sdillo * 2. allocate memory for each record and fill it appropriately
132325e99827Sdillo * 3. set out_record_ptrs_array to point to an array (which it allocates)
132425e99827Sdillo * which has out_node_descriptor->num_recs many pointers to the
132525e99827Sdillo * records themselves
132625e99827Sdillo * 4. allocate out_record_ptr_sizes_array and fill it with the sizes of
132725e99827Sdillo * each record
132825e99827Sdillo * 5. return the number of bytes read (i.e., the size of the node)
132925e99827Sdillo * or 0 on failure
133025e99827Sdillo *
133125e99827Sdillo * out_node_descriptor must be allocated by the caller and may not be NULL.
133225e99827Sdillo *
133325e99827Sdillo * out_record_ptrs_array and out_record_ptr_sizes_array must both be specified,
133425e99827Sdillo * or both be NULL if the caller is not interested in reading the records.
133525e99827Sdillo *
133625e99827Sdillo * out_record_ptr_sizes_array may be NULL if the caller is not interested in
133725e99827Sdillo * reading the records, but must not be NULL if out_record_ptrs_array is not.
133825e99827Sdillo *
133956c3e412Sdillo * in_parent_file is HFS_CATALOG_FILE, HFS_EXTENTS_FILE, or
134056c3e412Sdillo * HFS_ATTRIBUTES_FILE, depending on the special file in which this node
134125e99827Sdillo * resides.
134225e99827Sdillo *
134325e99827Sdillo * inout_volume must have its catnodesize or extnodesize field (depending on
134425e99827Sdillo * the parent file) set to the correct value if this is an index, leaf, or map
134525e99827Sdillo * node. If this is a header node, the field will be set to its correct value.
134625e99827Sdillo */
134725e99827Sdillo size_t
hfslib_reada_node(void * in_bytes,hfs_node_descriptor_t * out_node_descriptor,void ** out_record_ptrs_array[],uint16_t * out_record_ptr_sizes_array[],hfs_btree_file_type in_parent_file,hfs_volume * inout_volume,hfs_callback_args * cbargs)134856c3e412Sdillo hfslib_reada_node(void* in_bytes,
134956c3e412Sdillo hfs_node_descriptor_t* out_node_descriptor,
135025e99827Sdillo void** out_record_ptrs_array[],
135125e99827Sdillo uint16_t* out_record_ptr_sizes_array[],
135256c3e412Sdillo hfs_btree_file_type in_parent_file,
135356c3e412Sdillo hfs_volume* inout_volume,
135456c3e412Sdillo hfs_callback_args* cbargs)
135525e99827Sdillo {
135625e99827Sdillo void* ptr;
135725e99827Sdillo uint16_t* rec_offsets;
135825e99827Sdillo size_t last_bytes_read;
135925e99827Sdillo uint16_t nodesize;
136025e99827Sdillo uint16_t numrecords;
136125e99827Sdillo uint16_t free_space_offset; /* offset to free space in node */
136225e99827Sdillo int keysizefieldsize;
136325e99827Sdillo int i;
136425e99827Sdillo
136525e99827Sdillo numrecords = 0;
136625e99827Sdillo rec_offsets = NULL;
136725e99827Sdillo if (out_record_ptrs_array != NULL)
136825e99827Sdillo *out_record_ptrs_array = NULL;
136925e99827Sdillo if (out_record_ptr_sizes_array != NULL)
137025e99827Sdillo *out_record_ptr_sizes_array = NULL;
137125e99827Sdillo
137225e99827Sdillo if (in_bytes == NULL || inout_volume == NULL || out_node_descriptor == NULL
137325e99827Sdillo || (out_record_ptrs_array == NULL && out_record_ptr_sizes_array != NULL)
137425e99827Sdillo || (out_record_ptrs_array != NULL && out_record_ptr_sizes_array == NULL) )
137525e99827Sdillo goto error;
137625e99827Sdillo
137725e99827Sdillo ptr = in_bytes;
137825e99827Sdillo
137925e99827Sdillo out_node_descriptor->flink = be32tohp(&ptr);
138025e99827Sdillo out_node_descriptor->blink = be32tohp(&ptr);
138125e99827Sdillo out_node_descriptor->kind = *(((int8_t*)ptr));
138225e99827Sdillo ptr = (uint8_t*)ptr + 1;
138325e99827Sdillo out_node_descriptor->height = *(((uint8_t*)ptr));
138425e99827Sdillo ptr = (uint8_t*)ptr + 1;
138525e99827Sdillo out_node_descriptor->num_recs = be16tohp(&ptr);
138625e99827Sdillo out_node_descriptor->reserved = be16tohp(&ptr);
138725e99827Sdillo
138825e99827Sdillo numrecords = out_node_descriptor->num_recs;
138925e99827Sdillo
139025e99827Sdillo /*
139125e99827Sdillo * To go any further, we will need to know the size of this node, as well
139225e99827Sdillo * as the width of keyed records' key_len parameters for this btree. If
139325e99827Sdillo * this is an index, leaf, or map node, inout_volume already has the node
139425e99827Sdillo * size set in its catnodesize or extnodesize field and the key length set
139525e99827Sdillo * in the catkeysizefieldsize or extkeysizefieldsize for catalog files and
139625e99827Sdillo * extent files, respectively. However, if this is a header node, this
139725e99827Sdillo * information has not yet been determined, so this is the place to do it.
139825e99827Sdillo */
139956c3e412Sdillo if (out_node_descriptor->kind == HFS_HEADERNODE)
140025e99827Sdillo {
140156c3e412Sdillo hfs_header_record_t hr;
140225e99827Sdillo void* header_rec_offset[1];
140325e99827Sdillo uint16_t header_rec_size[1];
140425e99827Sdillo
140525e99827Sdillo /* sanity check to ensure this is a good header node */
140625e99827Sdillo if (numrecords != 3)
140756c3e412Sdillo HFS_LIBERR("header node does not have exactly 3 records");
140825e99827Sdillo
140925e99827Sdillo header_rec_offset[0] = ptr;
141056c3e412Sdillo header_rec_size[0] = sizeof(hfs_header_record_t);
141125e99827Sdillo
141256c3e412Sdillo last_bytes_read = hfslib_read_header_node(header_rec_offset,
141325e99827Sdillo header_rec_size, 1, &hr, NULL, NULL);
141425e99827Sdillo if (last_bytes_read == 0)
141556c3e412Sdillo HFS_LIBERR("could not read header node");
141625e99827Sdillo
141725e99827Sdillo switch(in_parent_file)
141825e99827Sdillo {
141956c3e412Sdillo case HFS_CATALOG_FILE:
142025e99827Sdillo inout_volume->chr.node_size = hr.node_size;
142125e99827Sdillo inout_volume->catkeysizefieldsize =
142256c3e412Sdillo (hr.attributes & HFS_BIG_KEYS_MASK) ?
142325e99827Sdillo sizeof(uint16_t):sizeof(uint8_t);
142425e99827Sdillo break;
142525e99827Sdillo
142656c3e412Sdillo case HFS_EXTENTS_FILE:
142725e99827Sdillo inout_volume->ehr.node_size = hr.node_size;
142825e99827Sdillo inout_volume->extkeysizefieldsize =
142956c3e412Sdillo (hr.attributes & HFS_BIG_KEYS_MASK) ?
143025e99827Sdillo sizeof(uint16_t):sizeof(uint8_t);
143125e99827Sdillo break;
143225e99827Sdillo
143356c3e412Sdillo case HFS_ATTRIBUTES_FILE:
143425e99827Sdillo default:
143556c3e412Sdillo HFS_LIBERR("invalid parent file type specified");
143625e99827Sdillo /* NOTREACHED */
143725e99827Sdillo }
143825e99827Sdillo }
143925e99827Sdillo
144025e99827Sdillo switch (in_parent_file)
144125e99827Sdillo {
144256c3e412Sdillo case HFS_CATALOG_FILE:
144325e99827Sdillo nodesize = inout_volume->chr.node_size;
144425e99827Sdillo keysizefieldsize = inout_volume->catkeysizefieldsize;
144525e99827Sdillo break;
144625e99827Sdillo
144756c3e412Sdillo case HFS_EXTENTS_FILE:
144825e99827Sdillo nodesize = inout_volume->ehr.node_size;
144925e99827Sdillo keysizefieldsize = inout_volume->extkeysizefieldsize;
145025e99827Sdillo break;
145125e99827Sdillo
145256c3e412Sdillo case HFS_ATTRIBUTES_FILE:
145325e99827Sdillo default:
145456c3e412Sdillo HFS_LIBERR("invalid parent file type specified");
145525e99827Sdillo /* NOTREACHED */
145625e99827Sdillo }
145725e99827Sdillo
145825e99827Sdillo /*
145925e99827Sdillo * Don't care about records so just exit after getting the node descriptor.
146025e99827Sdillo * Note: This happens after the header node code, and not before it, in
146125e99827Sdillo * case the caller calls this function and ignores the record data just to
146225e99827Sdillo * get at the node descriptor, but then tries to call it again on a non-
146325e99827Sdillo * header node without first setting inout_volume->cat/extnodesize.
146425e99827Sdillo */
146525e99827Sdillo if (out_record_ptrs_array == NULL)
146625e99827Sdillo return ((uint8_t*)ptr - (uint8_t*)in_bytes);
146725e99827Sdillo
146856c3e412Sdillo rec_offsets = hfslib_malloc(numrecords * sizeof(uint16_t), cbargs);
146925e99827Sdillo *out_record_ptr_sizes_array =
147056c3e412Sdillo hfslib_malloc(numrecords * sizeof(uint16_t), cbargs);
147125e99827Sdillo if (rec_offsets == NULL || *out_record_ptr_sizes_array == NULL)
147256c3e412Sdillo HFS_LIBERR("could not allocate node record offsets");
147325e99827Sdillo
147456c3e412Sdillo *out_record_ptrs_array = hfslib_malloc(numrecords * sizeof(void*), cbargs);
147525e99827Sdillo if (*out_record_ptrs_array == NULL)
147656c3e412Sdillo HFS_LIBERR("could not allocate node records");
147725e99827Sdillo
147856c3e412Sdillo last_bytes_read = hfslib_reada_node_offsets((uint8_t*)in_bytes + nodesize -
1479f9833f67Sriastradh numrecords * sizeof(uint16_t), rec_offsets, numrecords);
148025e99827Sdillo if (last_bytes_read == 0)
148156c3e412Sdillo HFS_LIBERR("could not read node record offsets");
148225e99827Sdillo
148325e99827Sdillo /* The size of the last record (i.e. the first one listed in the offsets)
148425e99827Sdillo * must be determined using the offset to the node's free space. */
148525e99827Sdillo free_space_offset = be16toh(*(uint16_t*)((uint8_t*)in_bytes + nodesize -
148625e99827Sdillo (numrecords+1) * sizeof(uint16_t)));
148725e99827Sdillo
148825e99827Sdillo (*out_record_ptr_sizes_array)[numrecords-1] =
148925e99827Sdillo free_space_offset - rec_offsets[0];
1490547d41caSmaxv for (i = 1; i < numrecords; i++) {
149125e99827Sdillo (*out_record_ptr_sizes_array)[numrecords-i-1] =
149225e99827Sdillo rec_offsets[i-1] - rec_offsets[i];
149325e99827Sdillo }
149425e99827Sdillo
149525e99827Sdillo for (i = 0; i < numrecords; i++)
149625e99827Sdillo {
149725e99827Sdillo (*out_record_ptrs_array)[i] =
149856c3e412Sdillo hfslib_malloc((*out_record_ptr_sizes_array)[i], cbargs);
149925e99827Sdillo
150025e99827Sdillo if ((*out_record_ptrs_array)[i] == NULL)
150156c3e412Sdillo HFS_LIBERR("could not allocate node record #%i",i);
150225e99827Sdillo
150325e99827Sdillo /*
150425e99827Sdillo * If this is a keyed node (i.e., a leaf or index node), there are two
150525e99827Sdillo * boundary rules that each record must obey:
150625e99827Sdillo *
150725e99827Sdillo * 1. A pad byte must be placed between the key and data if the
150825e99827Sdillo * size of the key plus the size of the key_len field is odd.
150925e99827Sdillo *
151025e99827Sdillo * 2. A pad byte must be placed after the data if the data size
151125e99827Sdillo * is odd.
151225e99827Sdillo *
151325e99827Sdillo * So in the first case we increment the starting point of the data
151425e99827Sdillo * and correspondingly decrement the record size. In the second case
151525e99827Sdillo * we decrement the record size.
151625e99827Sdillo */
151756c3e412Sdillo if (out_node_descriptor->kind == HFS_LEAFNODE ||
151856c3e412Sdillo out_node_descriptor->kind == HFS_INDEXNODE)
151925e99827Sdillo {
152056c3e412Sdillo hfs_catalog_key_t reckey;
152125e99827Sdillo uint16_t rectype;
152225e99827Sdillo
152325e99827Sdillo rectype = out_node_descriptor->kind;
152456c3e412Sdillo last_bytes_read = hfslib_read_catalog_keyed_record(ptr, NULL,
152525e99827Sdillo &rectype, &reckey, inout_volume);
152625e99827Sdillo if (last_bytes_read == 0)
152756c3e412Sdillo HFS_LIBERR("could not read node record");
152825e99827Sdillo
1529547d41caSmaxv if ((reckey.key_len + keysizefieldsize) % 2 == 1) {
153025e99827Sdillo ptr = (uint8_t*)ptr + 1;
153125e99827Sdillo (*out_record_ptr_sizes_array)[i]--;
153225e99827Sdillo }
153325e99827Sdillo
153425e99827Sdillo if ((*out_record_ptr_sizes_array)[i] % 2 == 1)
153525e99827Sdillo (*out_record_ptr_sizes_array)[i]--;
153625e99827Sdillo }
153725e99827Sdillo
153825e99827Sdillo memcpy((*out_record_ptrs_array)[i], ptr,
153925e99827Sdillo (*out_record_ptr_sizes_array)[i]);
154025e99827Sdillo ptr = (uint8_t*)ptr + (*out_record_ptr_sizes_array)[i];
154125e99827Sdillo }
154225e99827Sdillo
154325e99827Sdillo goto exit;
154425e99827Sdillo
154525e99827Sdillo error:
154656c3e412Sdillo hfslib_free_recs(out_record_ptrs_array, out_record_ptr_sizes_array,
154725e99827Sdillo &numrecords, cbargs);
154825e99827Sdillo
154925e99827Sdillo ptr = in_bytes;
155025e99827Sdillo
155156c3e412Sdillo /* warn("error occurred in hfslib_reada_node()"); */
155225e99827Sdillo
155325e99827Sdillo /* FALLTHROUGH */
155425e99827Sdillo
155525e99827Sdillo exit:
155625e99827Sdillo if (rec_offsets != NULL)
155756c3e412Sdillo hfslib_free(rec_offsets, cbargs);
155825e99827Sdillo return ((uint8_t*)ptr - (uint8_t*)in_bytes);
155925e99827Sdillo }
156025e99827Sdillo
156125e99827Sdillo /*
156256c3e412Sdillo * hfslib_reada_node_offsets()
156325e99827Sdillo *
156425e99827Sdillo * Sets out_offset_array to contain the offsets to each record in the node,
156525e99827Sdillo * in reverse order. Does not read the free space offset.
156625e99827Sdillo */
156725e99827Sdillo size_t
hfslib_reada_node_offsets(void * in_bytes,uint16_t * out_offset_array,uint16_t numrecords)1568f9833f67Sriastradh hfslib_reada_node_offsets(void* in_bytes, uint16_t* out_offset_array,
1569f9833f67Sriastradh uint16_t numrecords)
157025e99827Sdillo {
157125e99827Sdillo void* ptr;
157225e99827Sdillo
157325e99827Sdillo if (in_bytes == NULL || out_offset_array == NULL)
157425e99827Sdillo return 0;
157525e99827Sdillo
157625e99827Sdillo ptr = in_bytes;
157725e99827Sdillo
157825e99827Sdillo /*
157925e99827Sdillo * The offset for record 0 (which is the very last offset in the node) is
158025e99827Sdillo * always equal to 14, the size of the node descriptor. So, once we hit
158125e99827Sdillo * offset=14, we know this is the last offset. In this way, we don't need
158225e99827Sdillo * to know the number of records beforehand.
158325e99827Sdillo */
1584547d41caSmaxv do {
1585f9833f67Sriastradh if (numrecords-- == 0)
1586f9833f67Sriastradh return 0;
158725e99827Sdillo *out_offset_array = be16tohp(&ptr);
15886ecb13cdSriastradh } while (*out_offset_array++ != (uint16_t)14);
158925e99827Sdillo
159025e99827Sdillo return ((uint8_t*)ptr - (uint8_t*)in_bytes);
159125e99827Sdillo }
159225e99827Sdillo
159356c3e412Sdillo /* hfslib_read_header_node()
159425e99827Sdillo *
159525e99827Sdillo * out_header_record and/or out_map_record may be NULL if the caller doesn't
159625e99827Sdillo * care about their contents.
159725e99827Sdillo */
159825e99827Sdillo size_t
hfslib_read_header_node(void ** in_recs,uint16_t * in_rec_sizes,uint16_t in_num_recs,hfs_header_record_t * out_hr,void * out_userdata,void * out_map)159956c3e412Sdillo hfslib_read_header_node(void** in_recs,
160025e99827Sdillo uint16_t* in_rec_sizes,
160125e99827Sdillo uint16_t in_num_recs,
160256c3e412Sdillo hfs_header_record_t* out_hr,
160325e99827Sdillo void* out_userdata,
160425e99827Sdillo void* out_map)
160525e99827Sdillo {
160625e99827Sdillo void* ptr;
160725e99827Sdillo int i;
160825e99827Sdillo
16094b586f4eSjoerg KASSERT(out_hr != NULL);
16104b586f4eSjoerg
161125e99827Sdillo if (in_recs == NULL || in_rec_sizes == NULL)
161225e99827Sdillo return 0;
161325e99827Sdillo
161425e99827Sdillo ptr = in_recs[0];
161525e99827Sdillo out_hr->tree_depth = be16tohp(&ptr);
161625e99827Sdillo out_hr->root_node = be32tohp(&ptr);
161725e99827Sdillo out_hr->leaf_recs = be32tohp(&ptr);
161825e99827Sdillo out_hr->first_leaf = be32tohp(&ptr);
161925e99827Sdillo out_hr->last_leaf = be32tohp(&ptr);
162025e99827Sdillo out_hr->node_size = be16tohp(&ptr);
162125e99827Sdillo out_hr->max_key_len = be16tohp(&ptr);
162225e99827Sdillo out_hr->total_nodes = be32tohp(&ptr);
162325e99827Sdillo out_hr->free_nodes = be32tohp(&ptr);
162425e99827Sdillo out_hr->reserved = be16tohp(&ptr);
162525e99827Sdillo out_hr->clump_size = be32tohp(&ptr);
162625e99827Sdillo out_hr->btree_type = *(((uint8_t*)ptr));
162725e99827Sdillo ptr = (uint8_t*)ptr + 1;
162825e99827Sdillo out_hr->keycomp_type = *(((uint8_t*)ptr));
162925e99827Sdillo ptr = (uint8_t*)ptr + 1;
163025e99827Sdillo out_hr->attributes = be32tohp(&ptr);
163125e99827Sdillo for (i = 0; i < 16; i++)
163225e99827Sdillo out_hr->reserved2[i] = be32tohp(&ptr);
163325e99827Sdillo
1634547d41caSmaxv if (out_userdata != NULL) {
163525e99827Sdillo memcpy(out_userdata, in_recs[1], in_rec_sizes[1]);
163625e99827Sdillo }
163725e99827Sdillo ptr = (uint8_t*)ptr + in_rec_sizes[1]; /* size of user data record */
163825e99827Sdillo
1639547d41caSmaxv if (out_map != NULL) {
164025e99827Sdillo memcpy(out_map, in_recs[2], in_rec_sizes[2]);
164125e99827Sdillo }
164225e99827Sdillo ptr = (uint8_t*)ptr + in_rec_sizes[2]; /* size of map record */
164325e99827Sdillo
164425e99827Sdillo return ((uint8_t*)ptr - (uint8_t*)in_recs[0]);
164525e99827Sdillo }
164625e99827Sdillo
164725e99827Sdillo /*
164856c3e412Sdillo * hfslib_read_catalog_keyed_record()
164925e99827Sdillo *
165056c3e412Sdillo * out_recdata can be NULL. inout_rectype must be set to either HFS_LEAFNODE
165156c3e412Sdillo * or HFS_INDEXNODE upon calling this function, and will be set by the
165256c3e412Sdillo * function to one of HFS_REC_FLDR, HFS_REC_FILE, HFS_REC_FLDR_THREAD, or
165356c3e412Sdillo * HFS_REC_FLDR_THREAD upon return if the node is a leaf node. If it is an
165425e99827Sdillo * index node, inout_rectype will not be changed.
165525e99827Sdillo */
165625e99827Sdillo size_t
hfslib_read_catalog_keyed_record(void * in_bytes,hfs_catalog_keyed_record_t * out_recdata,int16_t * inout_rectype,hfs_catalog_key_t * out_key,hfs_volume * in_volume)165756c3e412Sdillo hfslib_read_catalog_keyed_record(
165825e99827Sdillo void* in_bytes,
165956c3e412Sdillo hfs_catalog_keyed_record_t* out_recdata,
166025e99827Sdillo int16_t* inout_rectype,
166156c3e412Sdillo hfs_catalog_key_t* out_key,
166256c3e412Sdillo hfs_volume* in_volume)
166325e99827Sdillo {
166425e99827Sdillo void* ptr;
166525e99827Sdillo size_t last_bytes_read;
166625e99827Sdillo
166725e99827Sdillo if (in_bytes == NULL || out_key == NULL || inout_rectype == NULL)
166825e99827Sdillo return 0;
166925e99827Sdillo
167025e99827Sdillo ptr = in_bytes;
167125e99827Sdillo
167225e99827Sdillo /* For HFS+, the key length is always a 2-byte number. This is indicated
167356c3e412Sdillo * by the HFS_BIG_KEYS_MASK bit in the attributes field of the catalog
167425e99827Sdillo * header record. However, we just assume this bit is set, since all HFS+
167525e99827Sdillo * volumes should have it set anyway. */
167625e99827Sdillo if (in_volume->catkeysizefieldsize == sizeof(uint16_t))
167725e99827Sdillo out_key->key_len = be16tohp(&ptr);
167825e99827Sdillo else if (in_volume->catkeysizefieldsize == sizeof(uint8_t)) {
167925e99827Sdillo out_key->key_len = *(((uint8_t*)ptr));
168025e99827Sdillo ptr = (uint8_t*)ptr + 1;
168125e99827Sdillo }
168225e99827Sdillo
168325e99827Sdillo out_key->parent_cnid = be32tohp(&ptr);
168425e99827Sdillo
168556c3e412Sdillo last_bytes_read = hfslib_read_unistr255(ptr, &out_key->name);
168625e99827Sdillo if (last_bytes_read == 0)
168725e99827Sdillo return 0;
168825e99827Sdillo ptr = (uint8_t*)ptr + last_bytes_read;
168925e99827Sdillo
169025e99827Sdillo /* don't waste time if the user just wanted the key and/or record type */
1691547d41caSmaxv if (out_recdata == NULL) {
169256c3e412Sdillo if (*inout_rectype == HFS_LEAFNODE)
169325e99827Sdillo *inout_rectype = be16tohp(&ptr);
169456c3e412Sdillo else if (*inout_rectype != HFS_INDEXNODE)
169525e99827Sdillo return 0; /* should not happen if we were given valid arguments */
169625e99827Sdillo
169725e99827Sdillo return ((uint8_t*)ptr - (uint8_t*)in_bytes);
169825e99827Sdillo }
169925e99827Sdillo
1700547d41caSmaxv if (*inout_rectype == HFS_INDEXNODE) {
170125e99827Sdillo out_recdata->child = be32tohp(&ptr);
1702547d41caSmaxv } else {
170325e99827Sdillo /* first need to determine what kind of record this is */
170425e99827Sdillo *inout_rectype = be16tohp(&ptr);
170525e99827Sdillo out_recdata->type = *inout_rectype;
170625e99827Sdillo
170725e99827Sdillo switch(out_recdata->type)
170825e99827Sdillo {
170956c3e412Sdillo case HFS_REC_FLDR:
171025e99827Sdillo {
171125e99827Sdillo out_recdata->folder.flags = be16tohp(&ptr);
171225e99827Sdillo out_recdata->folder.valence = be32tohp(&ptr);
171325e99827Sdillo out_recdata->folder.cnid = be32tohp(&ptr);
171425e99827Sdillo out_recdata->folder.date_created = be32tohp(&ptr);
171525e99827Sdillo out_recdata->folder.date_content_mod = be32tohp(&ptr);
171625e99827Sdillo out_recdata->folder.date_attrib_mod = be32tohp(&ptr);
171725e99827Sdillo out_recdata->folder.date_accessed = be32tohp(&ptr);
171825e99827Sdillo out_recdata->folder.date_backedup = be32tohp(&ptr);
171925e99827Sdillo
172056c3e412Sdillo last_bytes_read = hfslib_read_bsd_data(ptr,
172125e99827Sdillo &out_recdata->folder.bsd);
172225e99827Sdillo if (last_bytes_read == 0)
172325e99827Sdillo return 0;
172425e99827Sdillo ptr = (uint8_t*)ptr + last_bytes_read;
172525e99827Sdillo
172656c3e412Sdillo last_bytes_read = hfslib_read_folder_userinfo(ptr,
172725e99827Sdillo &out_recdata->folder.user_info);
172825e99827Sdillo if (last_bytes_read == 0)
172925e99827Sdillo return 0;
173025e99827Sdillo ptr = (uint8_t*)ptr + last_bytes_read;
173125e99827Sdillo
173256c3e412Sdillo last_bytes_read = hfslib_read_folder_finderinfo(ptr,
173325e99827Sdillo &out_recdata->folder.finder_info);
173425e99827Sdillo if (last_bytes_read == 0)
173525e99827Sdillo return 0;
173625e99827Sdillo ptr = (uint8_t*)ptr + last_bytes_read;
173725e99827Sdillo
173825e99827Sdillo out_recdata->folder.text_encoding = be32tohp(&ptr);
173925e99827Sdillo out_recdata->folder.reserved = be32tohp(&ptr);
174025e99827Sdillo }
174125e99827Sdillo break;
174225e99827Sdillo
174356c3e412Sdillo case HFS_REC_FILE:
174425e99827Sdillo {
174525e99827Sdillo out_recdata->file.flags = be16tohp(&ptr);
174625e99827Sdillo out_recdata->file.reserved = be32tohp(&ptr);
174725e99827Sdillo out_recdata->file.cnid = be32tohp(&ptr);
174825e99827Sdillo out_recdata->file.date_created = be32tohp(&ptr);
174925e99827Sdillo out_recdata->file.date_content_mod = be32tohp(&ptr);
175025e99827Sdillo out_recdata->file.date_attrib_mod = be32tohp(&ptr);
175125e99827Sdillo out_recdata->file.date_accessed = be32tohp(&ptr);
175225e99827Sdillo out_recdata->file.date_backedup = be32tohp(&ptr);
175325e99827Sdillo
175456c3e412Sdillo last_bytes_read = hfslib_read_bsd_data(ptr,
175525e99827Sdillo &out_recdata->file.bsd);
175625e99827Sdillo if (last_bytes_read == 0)
175725e99827Sdillo return 0;
175825e99827Sdillo ptr = (uint8_t*)ptr + last_bytes_read;
175925e99827Sdillo
176056c3e412Sdillo last_bytes_read = hfslib_read_file_userinfo(ptr,
176125e99827Sdillo &out_recdata->file.user_info);
176225e99827Sdillo if (last_bytes_read == 0)
176325e99827Sdillo return 0;
176425e99827Sdillo ptr = (uint8_t*)ptr + last_bytes_read;
176525e99827Sdillo
176656c3e412Sdillo last_bytes_read = hfslib_read_file_finderinfo(ptr,
176725e99827Sdillo &out_recdata->file.finder_info);
176825e99827Sdillo if (last_bytes_read == 0)
176925e99827Sdillo return 0;
177025e99827Sdillo ptr = (uint8_t*)ptr + last_bytes_read;
177125e99827Sdillo
177225e99827Sdillo out_recdata->file.text_encoding = be32tohp(&ptr);
177325e99827Sdillo out_recdata->file.reserved2 = be32tohp(&ptr);
177425e99827Sdillo
177556c3e412Sdillo last_bytes_read = hfslib_read_fork_descriptor(ptr,
177625e99827Sdillo &out_recdata->file.data_fork);
177725e99827Sdillo if (last_bytes_read == 0)
177825e99827Sdillo return 0;
177925e99827Sdillo ptr = (uint8_t*)ptr + last_bytes_read;
178025e99827Sdillo
178156c3e412Sdillo last_bytes_read = hfslib_read_fork_descriptor(ptr,
178225e99827Sdillo &out_recdata->file.rsrc_fork);
178325e99827Sdillo if (last_bytes_read == 0)
178425e99827Sdillo return 0;
178525e99827Sdillo ptr = (uint8_t*)ptr + last_bytes_read;
178625e99827Sdillo }
178725e99827Sdillo break;
178825e99827Sdillo
178956c3e412Sdillo case HFS_REC_FLDR_THREAD:
179056c3e412Sdillo case HFS_REC_FILE_THREAD:
179125e99827Sdillo {
179225e99827Sdillo out_recdata->thread.reserved = be16tohp(&ptr);
179325e99827Sdillo out_recdata->thread.parent_cnid = be32tohp(&ptr);
179425e99827Sdillo
179556c3e412Sdillo last_bytes_read = hfslib_read_unistr255(ptr,
179625e99827Sdillo &out_recdata->thread.name);
179725e99827Sdillo if (last_bytes_read == 0)
179825e99827Sdillo return 0;
179925e99827Sdillo ptr = (uint8_t*)ptr + last_bytes_read;
180025e99827Sdillo }
180125e99827Sdillo break;
180225e99827Sdillo
180325e99827Sdillo default:
180425e99827Sdillo return 1;
180525e99827Sdillo /* NOTREACHED */
180625e99827Sdillo }
180725e99827Sdillo }
180825e99827Sdillo
180925e99827Sdillo return ((uint8_t*)ptr - (uint8_t*)in_bytes);
181025e99827Sdillo }
181125e99827Sdillo
181225e99827Sdillo /* out_rec may be NULL */
181325e99827Sdillo size_t
hfslib_read_extent_record(void * in_bytes,hfs_extent_record_t * out_rec,hfs_node_kind in_nodekind,hfs_extent_key_t * out_key,hfs_volume * in_volume)181456c3e412Sdillo hfslib_read_extent_record(
181525e99827Sdillo void* in_bytes,
181656c3e412Sdillo hfs_extent_record_t* out_rec,
181756c3e412Sdillo hfs_node_kind in_nodekind,
181856c3e412Sdillo hfs_extent_key_t* out_key,
181956c3e412Sdillo hfs_volume* in_volume)
182025e99827Sdillo {
182125e99827Sdillo void* ptr;
182225e99827Sdillo size_t last_bytes_read;
182325e99827Sdillo
182425e99827Sdillo if (in_bytes == NULL || out_key == NULL
182556c3e412Sdillo || (in_nodekind!=HFS_LEAFNODE && in_nodekind!=HFS_INDEXNODE))
182625e99827Sdillo return 0;
182725e99827Sdillo
182825e99827Sdillo ptr = in_bytes;
182925e99827Sdillo
183025e99827Sdillo /* For HFS+, the key length is always a 2-byte number. This is indicated
183156c3e412Sdillo * by the HFS_BIG_KEYS_MASK bit in the attributes field of the extent
183225e99827Sdillo * overflow header record. However, we just assume this bit is set, since
183325e99827Sdillo * all HFS+ volumes should have it set anyway. */
183425e99827Sdillo if (in_volume->extkeysizefieldsize == sizeof(uint16_t))
183525e99827Sdillo out_key->key_length = be16tohp(&ptr);
183625e99827Sdillo else if (in_volume->extkeysizefieldsize == sizeof(uint8_t)) {
183725e99827Sdillo out_key->key_length = *(((uint8_t*)ptr));
183825e99827Sdillo ptr = (uint8_t*)ptr + 1;
183925e99827Sdillo }
184025e99827Sdillo
184125e99827Sdillo out_key->fork_type = *(((uint8_t*)ptr));
184225e99827Sdillo ptr = (uint8_t*)ptr + 1;
184325e99827Sdillo out_key->padding = *(((uint8_t*)ptr));
184425e99827Sdillo ptr = (uint8_t*)ptr + 1;
184525e99827Sdillo out_key->file_cnid = be32tohp(&ptr);
184625e99827Sdillo out_key->start_block = be32tohp(&ptr);
184725e99827Sdillo
184825e99827Sdillo /* don't waste time if the user just wanted the key */
184925e99827Sdillo if (out_rec == NULL)
185025e99827Sdillo return ((uint8_t*)ptr - (uint8_t*)in_bytes);
185125e99827Sdillo
1852547d41caSmaxv if (in_nodekind == HFS_LEAFNODE) {
185356c3e412Sdillo last_bytes_read = hfslib_read_extent_descriptors(ptr, out_rec);
185425e99827Sdillo if (last_bytes_read == 0)
185525e99827Sdillo return 0;
185625e99827Sdillo ptr = (uint8_t*)ptr + last_bytes_read;
1857547d41caSmaxv } else {
185825e99827Sdillo /* XXX: this is completely bogus */
185925e99827Sdillo /* (uint32_t*)*out_rec = be32tohp(&ptr); */
186025e99827Sdillo uint32_t *ptr_32 = (uint32_t *)out_rec;
186125e99827Sdillo *ptr_32 = be32tohp(&ptr);
186225e99827Sdillo /* (*out_rec)[0].start_block = be32tohp(&ptr); */
186325e99827Sdillo }
186425e99827Sdillo
186525e99827Sdillo return ((uint8_t*)ptr - (uint8_t*)in_bytes);
186625e99827Sdillo }
186725e99827Sdillo
186825e99827Sdillo void
hfslib_free_recs(void *** inout_node_recs,uint16_t ** inout_rec_sizes,uint16_t * inout_num_recs,hfs_callback_args * cbargs)186956c3e412Sdillo hfslib_free_recs(
187025e99827Sdillo void*** inout_node_recs,
187125e99827Sdillo uint16_t** inout_rec_sizes,
187225e99827Sdillo uint16_t* inout_num_recs,
187356c3e412Sdillo hfs_callback_args* cbargs)
187425e99827Sdillo {
187525e99827Sdillo uint16_t i;
187625e99827Sdillo
187725e99827Sdillo if (inout_num_recs == NULL || *inout_num_recs == 0)
187825e99827Sdillo return;
187925e99827Sdillo
1880547d41caSmaxv if (inout_node_recs != NULL && *inout_node_recs != NULL) {
1881547d41caSmaxv for (i = 0 ; i < *inout_num_recs; i++) {
1882547d41caSmaxv if ((*inout_node_recs)[i] != NULL) {
188356c3e412Sdillo hfslib_free((*inout_node_recs)[i], cbargs);
188425e99827Sdillo (*inout_node_recs)[i] = NULL;
188525e99827Sdillo }
188625e99827Sdillo }
188756c3e412Sdillo hfslib_free(*inout_node_recs, cbargs);
188825e99827Sdillo *inout_node_recs = NULL;
188925e99827Sdillo }
189025e99827Sdillo
1891547d41caSmaxv if (inout_rec_sizes != NULL && *inout_rec_sizes != NULL) {
189256c3e412Sdillo hfslib_free(*inout_rec_sizes, cbargs);
189325e99827Sdillo *inout_rec_sizes = NULL;
189425e99827Sdillo }
189525e99827Sdillo
189625e99827Sdillo *inout_num_recs = 0;
189725e99827Sdillo }
189825e99827Sdillo
189925e99827Sdillo #if 0
190025e99827Sdillo #pragma mark -
190125e99827Sdillo #pragma mark Individual Fields
190225e99827Sdillo #endif
190325e99827Sdillo
190425e99827Sdillo size_t
hfslib_read_fork_descriptor(void * in_bytes,hfs_fork_t * out_forkdata)190556c3e412Sdillo hfslib_read_fork_descriptor(void* in_bytes, hfs_fork_t* out_forkdata)
190625e99827Sdillo {
190725e99827Sdillo void* ptr;
190825e99827Sdillo size_t last_bytes_read;
190925e99827Sdillo
191025e99827Sdillo if (in_bytes == NULL || out_forkdata == NULL)
191125e99827Sdillo return 0;
191225e99827Sdillo
191325e99827Sdillo ptr = in_bytes;
191425e99827Sdillo
191525e99827Sdillo out_forkdata->logical_size = be64tohp(&ptr);
191625e99827Sdillo out_forkdata->clump_size = be32tohp(&ptr);
191725e99827Sdillo out_forkdata->total_blocks = be32tohp(&ptr);
191825e99827Sdillo
191956c3e412Sdillo if ((last_bytes_read = hfslib_read_extent_descriptors(ptr,
192025e99827Sdillo &out_forkdata->extents)) == 0)
192125e99827Sdillo return 0;
192225e99827Sdillo ptr = (uint8_t*)ptr + last_bytes_read;
192325e99827Sdillo
192425e99827Sdillo return ((uint8_t*)ptr - (uint8_t*)in_bytes);
192525e99827Sdillo }
192625e99827Sdillo
192725e99827Sdillo size_t
hfslib_read_extent_descriptors(void * in_bytes,hfs_extent_record_t * out_extentrecord)192856c3e412Sdillo hfslib_read_extent_descriptors(
192925e99827Sdillo void* in_bytes,
193056c3e412Sdillo hfs_extent_record_t* out_extentrecord)
193125e99827Sdillo {
193225e99827Sdillo void* ptr;
193325e99827Sdillo int i;
193425e99827Sdillo
193525e99827Sdillo if (in_bytes == NULL || out_extentrecord == NULL)
193625e99827Sdillo return 0;
193725e99827Sdillo
193825e99827Sdillo ptr = in_bytes;
193925e99827Sdillo
1940547d41caSmaxv for (i = 0; i < 8; i++) {
194156c3e412Sdillo (((hfs_extent_descriptor_t*)*out_extentrecord)[i]).start_block =
194225e99827Sdillo be32tohp(&ptr);
194356c3e412Sdillo (((hfs_extent_descriptor_t*)*out_extentrecord)[i]).block_count =
194425e99827Sdillo be32tohp(&ptr);
194525e99827Sdillo }
194625e99827Sdillo
194725e99827Sdillo return ((uint8_t*)ptr - (uint8_t*)in_bytes);
194825e99827Sdillo }
194925e99827Sdillo
195025e99827Sdillo size_t
hfslib_read_unistr255(void * in_bytes,hfs_unistr255_t * out_string)195156c3e412Sdillo hfslib_read_unistr255(void* in_bytes, hfs_unistr255_t* out_string)
195225e99827Sdillo {
195325e99827Sdillo void* ptr;
195425e99827Sdillo uint16_t i, length;
195525e99827Sdillo
195625e99827Sdillo if (in_bytes == NULL || out_string == NULL)
195725e99827Sdillo return 0;
195825e99827Sdillo
195925e99827Sdillo ptr = in_bytes;
196025e99827Sdillo
196125e99827Sdillo length = be16tohp(&ptr);
196225e99827Sdillo if (length > 255)
196325e99827Sdillo length = 255; /* hfs+ folder/file names have a limit of 255 chars */
196425e99827Sdillo out_string->length = length;
196525e99827Sdillo
1966547d41caSmaxv for (i = 0; i < length; i++) {
196725e99827Sdillo out_string->unicode[i] = be16tohp(&ptr);
196825e99827Sdillo }
196925e99827Sdillo
197025e99827Sdillo return ((uint8_t*)ptr - (uint8_t*)in_bytes);
197125e99827Sdillo }
197225e99827Sdillo
197325e99827Sdillo size_t
hfslib_read_bsd_data(void * in_bytes,hfs_bsd_data_t * out_perms)197456c3e412Sdillo hfslib_read_bsd_data(void* in_bytes, hfs_bsd_data_t* out_perms)
197525e99827Sdillo {
197625e99827Sdillo void* ptr;
197725e99827Sdillo
197825e99827Sdillo if (in_bytes == NULL || out_perms == NULL)
197925e99827Sdillo return 0;
198025e99827Sdillo
198125e99827Sdillo ptr = in_bytes;
198225e99827Sdillo
198325e99827Sdillo out_perms->owner_id = be32tohp(&ptr);
198425e99827Sdillo out_perms->group_id = be32tohp(&ptr);
198525e99827Sdillo out_perms->admin_flags = *(((uint8_t*)ptr));
198625e99827Sdillo ptr = (uint8_t*)ptr + 1;
198725e99827Sdillo out_perms->owner_flags = *(((uint8_t*)ptr));
198825e99827Sdillo ptr = (uint8_t*)ptr + 1;
198925e99827Sdillo out_perms->file_mode = be16tohp(&ptr);
199025e99827Sdillo out_perms->special.inode_num = be32tohp(&ptr); /* this field is a union */
199125e99827Sdillo
199225e99827Sdillo return ((uint8_t*)ptr - (uint8_t*)in_bytes);
199325e99827Sdillo }
199425e99827Sdillo
199525e99827Sdillo size_t
hfslib_read_file_userinfo(void * in_bytes,hfs_macos_file_info_t * out_info)199656c3e412Sdillo hfslib_read_file_userinfo(void* in_bytes, hfs_macos_file_info_t* out_info)
199725e99827Sdillo {
199825e99827Sdillo void* ptr;
199925e99827Sdillo
200025e99827Sdillo if (in_bytes == NULL || out_info == NULL)
200125e99827Sdillo return 0;
200225e99827Sdillo
200325e99827Sdillo ptr = in_bytes;
200425e99827Sdillo
200525e99827Sdillo out_info->file_type = be32tohp(&ptr);
200625e99827Sdillo out_info->file_creator = be32tohp(&ptr);
200725e99827Sdillo out_info->finder_flags = be16tohp(&ptr);
200825e99827Sdillo out_info->location.v = be16tohp(&ptr);
200925e99827Sdillo out_info->location.h = be16tohp(&ptr);
201025e99827Sdillo out_info->reserved = be16tohp(&ptr);
201125e99827Sdillo
201225e99827Sdillo return ((uint8_t*)ptr - (uint8_t*)in_bytes);
201325e99827Sdillo }
201425e99827Sdillo
201525e99827Sdillo size_t
hfslib_read_file_finderinfo(void * in_bytes,hfs_macos_extended_file_info_t * out_info)201656c3e412Sdillo hfslib_read_file_finderinfo(
201725e99827Sdillo void* in_bytes,
201856c3e412Sdillo hfs_macos_extended_file_info_t* out_info)
201925e99827Sdillo {
202025e99827Sdillo void* ptr;
202125e99827Sdillo
202225e99827Sdillo if (in_bytes == NULL || out_info == NULL)
202325e99827Sdillo return 0;
202425e99827Sdillo
202525e99827Sdillo ptr = in_bytes;
202625e99827Sdillo
202725e99827Sdillo #if 0
202825e99827Sdillo #pragma warn Fill in with real code!
202925e99827Sdillo #endif
203025e99827Sdillo /* FIXME: Fill in with real code! */
203125e99827Sdillo memset(out_info, 0, sizeof(*out_info));
203256c3e412Sdillo ptr = (uint8_t*)ptr + sizeof(hfs_macos_extended_file_info_t);
203325e99827Sdillo
203425e99827Sdillo return ((uint8_t*)ptr - (uint8_t*)in_bytes);
203525e99827Sdillo }
203625e99827Sdillo
203725e99827Sdillo size_t
hfslib_read_folder_userinfo(void * in_bytes,hfs_macos_folder_info_t * out_info)203856c3e412Sdillo hfslib_read_folder_userinfo(void* in_bytes, hfs_macos_folder_info_t* out_info)
203925e99827Sdillo {
204025e99827Sdillo void* ptr;
204125e99827Sdillo
204225e99827Sdillo if (in_bytes == NULL || out_info == NULL)
204325e99827Sdillo return 0;
204425e99827Sdillo
204525e99827Sdillo ptr = in_bytes;
204625e99827Sdillo
204725e99827Sdillo #if 0
204825e99827Sdillo #pragma warn Fill in with real code!
204925e99827Sdillo #endif
205025e99827Sdillo /* FIXME: Fill in with real code! */
205125e99827Sdillo memset(out_info, 0, sizeof(*out_info));
205256c3e412Sdillo ptr = (uint8_t*)ptr + sizeof(hfs_macos_folder_info_t);
205325e99827Sdillo
205425e99827Sdillo return ((uint8_t*)ptr - (uint8_t*)in_bytes);
205525e99827Sdillo }
205625e99827Sdillo
205725e99827Sdillo size_t
hfslib_read_folder_finderinfo(void * in_bytes,hfs_macos_extended_folder_info_t * out_info)205856c3e412Sdillo hfslib_read_folder_finderinfo(
205925e99827Sdillo void* in_bytes,
206056c3e412Sdillo hfs_macos_extended_folder_info_t* out_info)
206125e99827Sdillo {
206225e99827Sdillo void* ptr;
206325e99827Sdillo
206425e99827Sdillo if (in_bytes == NULL || out_info == NULL)
206525e99827Sdillo return 0;
206625e99827Sdillo
206725e99827Sdillo ptr = in_bytes;
206825e99827Sdillo
206925e99827Sdillo #if 0
207025e99827Sdillo #pragma warn Fill in with real code!
207125e99827Sdillo #endif
207225e99827Sdillo /* FIXME: Fill in with real code! */
207325e99827Sdillo memset(out_info, 0, sizeof(*out_info));
207456c3e412Sdillo ptr = (uint8_t*)ptr + sizeof(hfs_macos_extended_folder_info_t);
207525e99827Sdillo
207625e99827Sdillo return ((uint8_t*)ptr - (uint8_t*)in_bytes);
207725e99827Sdillo }
207825e99827Sdillo
207925e99827Sdillo size_t
hfslib_read_journal_info(void * in_bytes,hfs_journal_info_t * out_info)208056c3e412Sdillo hfslib_read_journal_info(void* in_bytes, hfs_journal_info_t* out_info)
208125e99827Sdillo {
208225e99827Sdillo void* ptr;
208325e99827Sdillo int i;
208425e99827Sdillo
208525e99827Sdillo if (in_bytes == NULL || out_info == NULL)
208625e99827Sdillo return 0;
208725e99827Sdillo
208825e99827Sdillo ptr = in_bytes;
208925e99827Sdillo
209025e99827Sdillo out_info->flags = be32tohp(&ptr);
2091547d41caSmaxv for (i = 0; i < 8; i++) {
209225e99827Sdillo out_info->device_signature[i] = be32tohp(&ptr);
209325e99827Sdillo }
209425e99827Sdillo out_info->offset = be64tohp(&ptr);
209525e99827Sdillo out_info->size = be64tohp(&ptr);
2096547d41caSmaxv for (i = 0; i < 32; i++) {
209725e99827Sdillo out_info->reserved[i] = be64tohp(&ptr);
209825e99827Sdillo }
209925e99827Sdillo
210025e99827Sdillo return ((uint8_t*)ptr - (uint8_t*)in_bytes);
210125e99827Sdillo }
210225e99827Sdillo
210325e99827Sdillo size_t
hfslib_read_journal_header(void * in_bytes,hfs_journal_header_t * out_header)210456c3e412Sdillo hfslib_read_journal_header(void* in_bytes, hfs_journal_header_t* out_header)
210525e99827Sdillo {
210625e99827Sdillo void* ptr;
210725e99827Sdillo
210825e99827Sdillo if (in_bytes == NULL || out_header == NULL)
210925e99827Sdillo return 0;
211025e99827Sdillo
211125e99827Sdillo ptr = in_bytes;
211225e99827Sdillo
211325e99827Sdillo out_header->magic = be32tohp(&ptr);
211425e99827Sdillo out_header->endian = be32tohp(&ptr);
211525e99827Sdillo out_header->start = be64tohp(&ptr);
211625e99827Sdillo out_header->end = be64tohp(&ptr);
211725e99827Sdillo out_header->size = be64tohp(&ptr);
211825e99827Sdillo out_header->blocklist_header_size = be32tohp(&ptr);
211925e99827Sdillo out_header->checksum = be32tohp(&ptr);
212025e99827Sdillo out_header->journal_header_size = be32tohp(&ptr);
212125e99827Sdillo
212225e99827Sdillo return ((uint8_t*)ptr - (uint8_t*)in_bytes);
212325e99827Sdillo }
212425e99827Sdillo
212525e99827Sdillo #if 0
212625e99827Sdillo #pragma mark -
212725e99827Sdillo #pragma mark Disk Access
212825e99827Sdillo #endif
212925e99827Sdillo
213025e99827Sdillo /*
213156c3e412Sdillo * hfslib_readd_with_extents()
213225e99827Sdillo *
213325e99827Sdillo * This function reads the contents of a file from the volume, given an array
213425e99827Sdillo * of extent descriptors which specify where every extent of the file is
213525e99827Sdillo * located (in addition to the usual pread() arguments). out_bytes is presumed
213625e99827Sdillo * to exist and be large enough to hold in_length number of bytes. Returns 0
213725e99827Sdillo * on success.
213825e99827Sdillo */
213925e99827Sdillo int
hfslib_readd_with_extents(hfs_volume * in_vol,void * out_bytes,uint64_t * out_bytesread,uint64_t in_length,uint64_t in_offset,hfs_extent_descriptor_t in_extents[],uint16_t in_numextents,hfs_callback_args * cbargs)214056c3e412Sdillo hfslib_readd_with_extents(
214156c3e412Sdillo hfs_volume* in_vol,
214225e99827Sdillo void* out_bytes,
214325e99827Sdillo uint64_t* out_bytesread,
214425e99827Sdillo uint64_t in_length,
214525e99827Sdillo uint64_t in_offset,
214656c3e412Sdillo hfs_extent_descriptor_t in_extents[],
214725e99827Sdillo uint16_t in_numextents,
214856c3e412Sdillo hfs_callback_args* cbargs)
214925e99827Sdillo {
215025e99827Sdillo uint64_t ext_length, last_offset;
215125e99827Sdillo uint16_t i;
215225e99827Sdillo int error;
215325e99827Sdillo
2154547d41caSmaxv if (in_vol == NULL || out_bytes == NULL || in_extents == NULL ||
2155547d41caSmaxv in_numextents == 0 || out_bytesread == NULL)
215625e99827Sdillo return -1;
215725e99827Sdillo
215825e99827Sdillo *out_bytesread = 0;
215925e99827Sdillo last_offset = 0;
216025e99827Sdillo
216125e99827Sdillo for (i = 0; i < in_numextents; i++)
216225e99827Sdillo {
216325e99827Sdillo if (in_extents[i].block_count == 0)
216425e99827Sdillo continue;
216525e99827Sdillo
216625e99827Sdillo ext_length = in_extents[i].block_count * in_vol->vh.block_size;
216725e99827Sdillo
216825e99827Sdillo if (in_offset < last_offset+ext_length
216925e99827Sdillo && in_offset+in_length >= last_offset)
217025e99827Sdillo {
217125e99827Sdillo uint64_t isect_start, isect_end;
217225e99827Sdillo
217325e99827Sdillo isect_start = max(in_offset, last_offset);
217425e99827Sdillo isect_end = min(in_offset+in_length, last_offset+ext_length);
217556c3e412Sdillo error = hfslib_readd(in_vol, out_bytes, isect_end-isect_start,
217625e99827Sdillo isect_start - last_offset + (uint64_t)in_extents[i].start_block
217725e99827Sdillo * in_vol->vh.block_size, cbargs);
217825e99827Sdillo
217925e99827Sdillo if (error != 0)
218025e99827Sdillo return error;
218125e99827Sdillo
218225e99827Sdillo *out_bytesread += isect_end-isect_start;
218325e99827Sdillo out_bytes = (uint8_t*)out_bytes + isect_end-isect_start;
218425e99827Sdillo }
218525e99827Sdillo
218625e99827Sdillo last_offset += ext_length;
218725e99827Sdillo }
218825e99827Sdillo
218925e99827Sdillo return 0;
219025e99827Sdillo }
219125e99827Sdillo
219225e99827Sdillo #if 0
219325e99827Sdillo #pragma mark -
219425e99827Sdillo #pragma mark Callback Wrappers
219525e99827Sdillo #endif
219625e99827Sdillo
219725e99827Sdillo void
hfslib_error(const char * in_format,const char * in_file,int in_line,...)219856c3e412Sdillo hfslib_error(const char* in_format, const char* in_file, int in_line, ...)
219925e99827Sdillo {
220025e99827Sdillo va_list ap;
220125e99827Sdillo
220225e99827Sdillo if (in_format == NULL)
220325e99827Sdillo return;
220425e99827Sdillo
2205547d41caSmaxv if (hfs_gcb.error != NULL) {
220625e99827Sdillo va_start(ap, in_line);
220756c3e412Sdillo hfs_gcb.error(in_format, in_file, in_line, ap);
220825e99827Sdillo va_end(ap);
220925e99827Sdillo }
221025e99827Sdillo }
221125e99827Sdillo
221225e99827Sdillo void*
hfslib_malloc(size_t size,hfs_callback_args * cbargs)221356c3e412Sdillo hfslib_malloc(size_t size, hfs_callback_args* cbargs)
221425e99827Sdillo {
221556c3e412Sdillo if (hfs_gcb.allocmem != NULL)
221656c3e412Sdillo return hfs_gcb.allocmem(size, cbargs);
221725e99827Sdillo
221825e99827Sdillo return NULL;
221925e99827Sdillo }
222025e99827Sdillo
222125e99827Sdillo void*
hfslib_realloc(void * ptr,size_t size,hfs_callback_args * cbargs)222256c3e412Sdillo hfslib_realloc(void* ptr, size_t size, hfs_callback_args* cbargs)
222325e99827Sdillo {
222456c3e412Sdillo if (hfs_gcb.reallocmem != NULL)
222556c3e412Sdillo return hfs_gcb.reallocmem(ptr, size, cbargs);
222625e99827Sdillo
222725e99827Sdillo return NULL;
222825e99827Sdillo }
222925e99827Sdillo
223025e99827Sdillo void
hfslib_free(void * ptr,hfs_callback_args * cbargs)223156c3e412Sdillo hfslib_free(void* ptr, hfs_callback_args* cbargs)
223225e99827Sdillo {
223356c3e412Sdillo if (hfs_gcb.freemem != NULL && ptr != NULL)
223456c3e412Sdillo hfs_gcb.freemem(ptr, cbargs);
223525e99827Sdillo }
223625e99827Sdillo
223725e99827Sdillo int
hfslib_openvoldevice(hfs_volume * in_vol,const char * in_device,hfs_callback_args * cbargs)223856c3e412Sdillo hfslib_openvoldevice(
223956c3e412Sdillo hfs_volume* in_vol,
224025e99827Sdillo const char* in_device,
224156c3e412Sdillo hfs_callback_args* cbargs)
224225e99827Sdillo {
224356c3e412Sdillo if (hfs_gcb.openvol != NULL && in_device != NULL)
224441627b2cSdillo return hfs_gcb.openvol(in_vol, in_device, cbargs);
224525e99827Sdillo
224625e99827Sdillo return 1;
224725e99827Sdillo }
224825e99827Sdillo
224925e99827Sdillo void
hfslib_closevoldevice(hfs_volume * in_vol,hfs_callback_args * cbargs)225056c3e412Sdillo hfslib_closevoldevice(hfs_volume* in_vol, hfs_callback_args* cbargs)
225125e99827Sdillo {
225256c3e412Sdillo if (hfs_gcb.closevol != NULL)
225356c3e412Sdillo hfs_gcb.closevol(in_vol, cbargs);
225425e99827Sdillo }
225525e99827Sdillo
225625e99827Sdillo int
hfslib_readd(hfs_volume * in_vol,void * out_bytes,uint64_t in_length,uint64_t in_offset,hfs_callback_args * cbargs)225756c3e412Sdillo hfslib_readd(
225856c3e412Sdillo hfs_volume* in_vol,
225925e99827Sdillo void* out_bytes,
226025e99827Sdillo uint64_t in_length,
226125e99827Sdillo uint64_t in_offset,
226256c3e412Sdillo hfs_callback_args* cbargs)
226325e99827Sdillo {
226425e99827Sdillo if (in_vol == NULL || out_bytes == NULL)
226525e99827Sdillo return -1;
226625e99827Sdillo
226756c3e412Sdillo if (hfs_gcb.read != NULL)
226856c3e412Sdillo return hfs_gcb.read(in_vol, out_bytes, in_length, in_offset, cbargs);
226925e99827Sdillo
227025e99827Sdillo return -1;
227125e99827Sdillo }
227225e99827Sdillo
227325e99827Sdillo #if 0
227425e99827Sdillo #pragma mark -
227525e99827Sdillo #pragma mark Other
227625e99827Sdillo #endif
227725e99827Sdillo
227825e99827Sdillo /* returns key length */
227925e99827Sdillo uint16_t
hfslib_make_catalog_key(hfs_cnid_t in_parent_cnid,uint16_t in_name_len,unichar_t * in_unicode,hfs_catalog_key_t * out_key)228056c3e412Sdillo hfslib_make_catalog_key(
228156c3e412Sdillo hfs_cnid_t in_parent_cnid,
228225e99827Sdillo uint16_t in_name_len,
228325e99827Sdillo unichar_t* in_unicode,
228456c3e412Sdillo hfs_catalog_key_t* out_key)
228525e99827Sdillo {
2286547d41caSmaxv if (in_parent_cnid == 0 || (in_name_len > 0 && in_unicode == NULL) ||
2287547d41caSmaxv out_key == 0)
228825e99827Sdillo return 0;
228925e99827Sdillo
229025e99827Sdillo if (in_name_len > 255)
229125e99827Sdillo in_name_len = 255;
229225e99827Sdillo
229325e99827Sdillo out_key->key_len = 6 + 2 * in_name_len;
229425e99827Sdillo out_key->parent_cnid = in_parent_cnid;
229525e99827Sdillo out_key->name.length = in_name_len;
229625e99827Sdillo if (in_name_len > 0)
229725e99827Sdillo memcpy(&out_key->name.unicode, in_unicode, in_name_len*2);
229825e99827Sdillo
229925e99827Sdillo return out_key->key_len;
230025e99827Sdillo }
230125e99827Sdillo
230225e99827Sdillo /* returns key length */
230325e99827Sdillo uint16_t
hfslib_make_extent_key(hfs_cnid_t in_cnid,uint8_t in_forktype,uint32_t in_startblock,hfs_extent_key_t * out_key)230456c3e412Sdillo hfslib_make_extent_key(
230556c3e412Sdillo hfs_cnid_t in_cnid,
230625e99827Sdillo uint8_t in_forktype,
230725e99827Sdillo uint32_t in_startblock,
230856c3e412Sdillo hfs_extent_key_t* out_key)
230925e99827Sdillo {
231025e99827Sdillo if (in_cnid == 0 || out_key == 0)
231125e99827Sdillo return 0;
231225e99827Sdillo
231356c3e412Sdillo out_key->key_length = HFS_MAX_EXT_KEY_LEN;
231425e99827Sdillo out_key->fork_type = in_forktype;
231525e99827Sdillo out_key->padding = 0;
231625e99827Sdillo out_key->file_cnid = in_cnid;
231725e99827Sdillo out_key->start_block = in_startblock;
231825e99827Sdillo
231925e99827Sdillo return out_key->key_length;
232025e99827Sdillo }
232125e99827Sdillo
232225e99827Sdillo /* case-folding */
232325e99827Sdillo int
hfslib_compare_catalog_keys_cf(const void * ap,const void * bp)232456c3e412Sdillo hfslib_compare_catalog_keys_cf (
232525e99827Sdillo const void *ap,
232625e99827Sdillo const void *bp)
232725e99827Sdillo {
232856c3e412Sdillo const hfs_catalog_key_t *a, *b;
232925e99827Sdillo unichar_t ac, bc; /* current character from a, b */
233025e99827Sdillo unichar_t lc; /* lowercase version of current character */
233125e99827Sdillo uint8_t apos, bpos; /* current character indices */
233225e99827Sdillo
233356c3e412Sdillo a = (const hfs_catalog_key_t*)ap;
233456c3e412Sdillo b = (const hfs_catalog_key_t*)bp;
233525e99827Sdillo
2336547d41caSmaxv if (a->parent_cnid != b->parent_cnid) {
233725e99827Sdillo return (a->parent_cnid - b->parent_cnid);
2338547d41caSmaxv } else {
233925e99827Sdillo /*
234025e99827Sdillo * The following code implements the pseudocode suggested by
234125e99827Sdillo * the HFS+ technote.
234225e99827Sdillo */
234325e99827Sdillo
234425e99827Sdillo /*
234525e99827Sdillo * XXX These need to be revised to be endian-independent!
234625e99827Sdillo */
234725e99827Sdillo #define hbyte(x) ((x) >> 8)
234825e99827Sdillo #define lbyte(x) ((x) & 0x00FF)
234925e99827Sdillo
235025e99827Sdillo apos = bpos = 0;
235125e99827Sdillo while (1)
235225e99827Sdillo {
235325e99827Sdillo /* get next valid character from a */
235425e99827Sdillo for (lc = 0; lc == 0 && apos < a->name.length; apos++) {
235525e99827Sdillo ac = a->name.unicode[apos];
235656c3e412Sdillo lc = hfs_gcft[hbyte(ac)];
235725e99827Sdillo if (lc == 0)
235825e99827Sdillo lc = ac;
235925e99827Sdillo else
236056c3e412Sdillo lc = hfs_gcft[lc + lbyte(ac)];
236125e99827Sdillo };
236225e99827Sdillo ac = lc;
236325e99827Sdillo
236425e99827Sdillo /* get next valid character from b */
236525e99827Sdillo for (lc = 0; lc == 0 && bpos < b->name.length; bpos++) {
236625e99827Sdillo bc = b->name.unicode[bpos];
236756c3e412Sdillo lc = hfs_gcft[hbyte(bc)];
236825e99827Sdillo if (lc == 0)
236925e99827Sdillo lc = bc;
237025e99827Sdillo else
237156c3e412Sdillo lc = hfs_gcft[lc + lbyte(bc)];
237225e99827Sdillo };
237325e99827Sdillo bc = lc;
237425e99827Sdillo
237525e99827Sdillo /* on end of string ac/bc are 0, otherwise > 0 */
237625e99827Sdillo if (ac != bc || (ac == 0 && bc == 0))
237725e99827Sdillo return ac - bc;
237825e99827Sdillo }
237925e99827Sdillo #undef hbyte
238025e99827Sdillo #undef lbyte
238125e99827Sdillo }
238225e99827Sdillo }
238325e99827Sdillo
238425e99827Sdillo /* binary compare (i.e., not case folding) */
238525e99827Sdillo int
hfslib_compare_catalog_keys_bc(const void * ap,const void * bp)238656c3e412Sdillo hfslib_compare_catalog_keys_bc (
2387ffb79aacSsevan const void *ap,
2388ffb79aacSsevan const void *bp)
238925e99827Sdillo {
2390ffb79aacSsevan int c;
2391ffb79aacSsevan const hfs_catalog_key_t *a, *b;
2392ffb79aacSsevan
2393ffb79aacSsevan a = (const hfs_catalog_key_t *) ap;
2394ffb79aacSsevan b = (const hfs_catalog_key_t *) bp;
2395ffb79aacSsevan
2396ffb79aacSsevan if (a->parent_cnid == b->parent_cnid)
239725e99827Sdillo {
2398ffb79aacSsevan if (a->name.length == 0 && b->name.length == 0)
239925e99827Sdillo return 0;
240025e99827Sdillo
2401ffb79aacSsevan if (a->name.length == 0)
240225e99827Sdillo return -1;
2403ffb79aacSsevan if (b->name.length == 0)
240425e99827Sdillo return 1;
240525e99827Sdillo
240625e99827Sdillo /* FIXME: This does a byte-per-byte comparison, whereas the HFS spec
240725e99827Sdillo * mandates a uint16_t chunk comparison. */
2408ffb79aacSsevan c = memcmp(a->name.unicode, b->name.unicode,
2409ffb79aacSsevan sizeof(unichar_t)*min(a->name.length, b->name.length));
2410ffb79aacSsevan if (c != 0)
2411ffb79aacSsevan return c;
2412ffb79aacSsevan else
2413ffb79aacSsevan return (a->name.length - b->name.length);
2414547d41caSmaxv } else {
2415ffb79aacSsevan return (a->parent_cnid - b->parent_cnid);
241625e99827Sdillo }
241725e99827Sdillo }
241825e99827Sdillo
241925e99827Sdillo int
hfslib_compare_extent_keys(const void * ap,const void * bp)242056c3e412Sdillo hfslib_compare_extent_keys (
2421ffb79aacSsevan const void *ap,
2422ffb79aacSsevan const void *bp)
242325e99827Sdillo {
242425e99827Sdillo /*
242525e99827Sdillo * Comparison order, in descending importance:
242625e99827Sdillo *
242725e99827Sdillo * CNID -> fork type -> start block
242825e99827Sdillo */
242925e99827Sdillo
2430ffb79aacSsevan const hfs_extent_key_t *a, *b;
2431ffb79aacSsevan a = (const hfs_extent_key_t *) ap;
2432ffb79aacSsevan b = (const hfs_extent_key_t *) bp;
2433ffb79aacSsevan
2434ffb79aacSsevan if (a->file_cnid == b->file_cnid)
243525e99827Sdillo {
2436ffb79aacSsevan if (a->fork_type == b->fork_type)
243725e99827Sdillo {
2438ffb79aacSsevan if (a->start_block == b->start_block)
243925e99827Sdillo {
244025e99827Sdillo return 0;
2441547d41caSmaxv } else {
2442ffb79aacSsevan return (a->start_block - b->start_block);
244325e99827Sdillo }
2444547d41caSmaxv } else {
2445ffb79aacSsevan return (a->fork_type - b->fork_type);
244625e99827Sdillo }
2447547d41caSmaxv } else {
2448ffb79aacSsevan return (a->file_cnid - b->file_cnid);
244925e99827Sdillo }
245025e99827Sdillo }
245125e99827Sdillo
245225e99827Sdillo /* 1+10 tables of 16 rows and 16 columns, each 2 bytes wide = 5632 bytes */
245325e99827Sdillo int
hfslib_create_casefolding_table(void)245456c3e412Sdillo hfslib_create_casefolding_table(void)
245525e99827Sdillo {
245656c3e412Sdillo hfs_callback_args cbargs;
245725e99827Sdillo unichar_t* t; /* convenience */
245825e99827Sdillo uint16_t s; /* current subtable * 256 */
245925e99827Sdillo uint16_t i; /* current subtable index (0 to 255) */
246025e99827Sdillo
246156c3e412Sdillo if (hfs_gcft != NULL)
246225e99827Sdillo return 0; /* no sweat, table already exists */
246325e99827Sdillo
246456c3e412Sdillo hfslib_init_cbargs(&cbargs);
246556c3e412Sdillo hfs_gcft = hfslib_malloc(5632, &cbargs);
246656c3e412Sdillo if (hfs_gcft == NULL)
246756c3e412Sdillo HFS_LIBERR("could not allocate case folding table");
246825e99827Sdillo
246956c3e412Sdillo t = hfs_gcft; /* easier to type :) */
247025e99827Sdillo
247125e99827Sdillo /*
247225e99827Sdillo * high byte indices
247325e99827Sdillo */
247425e99827Sdillo s = 0 * 256;
247525e99827Sdillo memset(t, 0x00, 512);
247625e99827Sdillo t[s+ 0] = 0x0100;
247725e99827Sdillo t[s+ 1] = 0x0200;
247825e99827Sdillo t[s+ 3] = 0x0300;
247925e99827Sdillo t[s+ 4] = 0x0400;
248025e99827Sdillo t[s+ 5] = 0x0500;
248125e99827Sdillo t[s+ 16] = 0x0600;
248225e99827Sdillo t[s+ 32] = 0x0700;
248325e99827Sdillo t[s+ 33] = 0x0800;
248425e99827Sdillo t[s+254] = 0x0900;
248525e99827Sdillo t[s+255] = 0x0a00;
248625e99827Sdillo
248725e99827Sdillo /*
248825e99827Sdillo * table 1 (high byte 0x00)
248925e99827Sdillo */
249025e99827Sdillo s = 1 * 256;
249125e99827Sdillo for (i = 0; i < 65; i++)
249225e99827Sdillo t[s+i] = i;
249325e99827Sdillo t[s+ 0] = 0xffff;
249425e99827Sdillo for (i = 65; i < 91; i++)
249525e99827Sdillo t[s+i] = i + 0x20;
249625e99827Sdillo for (i = 91; i < 256; i++)
249725e99827Sdillo t[s+i] = i;
249825e99827Sdillo t[s+198] = 0x00e6;
249925e99827Sdillo t[s+208] = 0x00f0;
250025e99827Sdillo t[s+216] = 0x00f8;
250125e99827Sdillo t[s+222] = 0x00fe;
250225e99827Sdillo
250325e99827Sdillo /*
250425e99827Sdillo * table 2 (high byte 0x01)
250525e99827Sdillo */
250625e99827Sdillo s = 2 * 256;
250725e99827Sdillo for (i = 0; i < 256; i++)
250825e99827Sdillo t[s+i] = i + 0x0100;
250925e99827Sdillo t[s+ 16] = 0x0111;
251025e99827Sdillo t[s+ 38] = 0x0127;
251125e99827Sdillo t[s+ 50] = 0x0133;
251225e99827Sdillo t[s+ 63] = 0x0140;
251325e99827Sdillo t[s+ 65] = 0x0142;
251425e99827Sdillo t[s+ 74] = 0x014b;
251525e99827Sdillo t[s+ 82] = 0x0153;
251625e99827Sdillo t[s+102] = 0x0167;
251725e99827Sdillo t[s+129] = 0x0253;
251825e99827Sdillo t[s+130] = 0x0183;
251925e99827Sdillo t[s+132] = 0x0185;
252025e99827Sdillo t[s+134] = 0x0254;
252125e99827Sdillo t[s+135] = 0x0188;
252225e99827Sdillo t[s+137] = 0x0256;
252325e99827Sdillo t[s+138] = 0x0257;
252425e99827Sdillo t[s+139] = 0x018c;
252525e99827Sdillo t[s+142] = 0x01dd;
252625e99827Sdillo t[s+143] = 0x0259;
252725e99827Sdillo t[s+144] = 0x025b;
252825e99827Sdillo t[s+145] = 0x0192;
252925e99827Sdillo t[s+147] = 0x0260;
253025e99827Sdillo t[s+148] = 0x0263;
253125e99827Sdillo t[s+150] = 0x0269;
253225e99827Sdillo t[s+151] = 0x0268;
253325e99827Sdillo t[s+152] = 0x0199;
253425e99827Sdillo t[s+156] = 0x026f;
253525e99827Sdillo t[s+157] = 0x0272;
253625e99827Sdillo t[s+159] = 0x0275;
253725e99827Sdillo t[s+162] = 0x01a3;
253825e99827Sdillo t[s+164] = 0x01a5;
253925e99827Sdillo t[s+167] = 0x01a8;
254025e99827Sdillo t[s+169] = 0x0283;
254125e99827Sdillo t[s+172] = 0x01ad;
254225e99827Sdillo t[s+174] = 0x0288;
254325e99827Sdillo t[s+177] = 0x028a;
254425e99827Sdillo t[s+178] = 0x028b;
254525e99827Sdillo t[s+179] = 0x01b4;
254625e99827Sdillo t[s+181] = 0x01b6;
254725e99827Sdillo t[s+183] = 0x0292;
254825e99827Sdillo t[s+184] = 0x01b9;
254925e99827Sdillo t[s+188] = 0x01bd;
255025e99827Sdillo t[s+196] = 0x01c6;
255125e99827Sdillo t[s+197] = 0x01c6;
255225e99827Sdillo t[s+199] = 0x01c9;
255325e99827Sdillo t[s+200] = 0x01c9;
255425e99827Sdillo t[s+202] = 0x01cc;
255525e99827Sdillo t[s+203] = 0x01cc;
255625e99827Sdillo t[s+228] = 0x01e5;
255725e99827Sdillo t[s+241] = 0x01f3;
255825e99827Sdillo t[s+242] = 0x01f3;
255925e99827Sdillo
256025e99827Sdillo /*
256125e99827Sdillo * table 3 (high byte 0x03)
256225e99827Sdillo */
256325e99827Sdillo s = 3 * 256;
256425e99827Sdillo for (i = 0; i < 145; i++)
256525e99827Sdillo t[s+i] = i + 0x0300;
256625e99827Sdillo for (i = 145; i < 170; i++)
256725e99827Sdillo t[s+i] = i + 0x0320;
256825e99827Sdillo t[s+162] = 0x03a2;
256925e99827Sdillo for (i = 170; i < 256; i++)
257025e99827Sdillo t[s+i] = i + 0x0300;
257125e99827Sdillo
257225e99827Sdillo for (i = 226; i < 239; i += 2)
257325e99827Sdillo t[s+i] = i + 0x0301;
257425e99827Sdillo
257525e99827Sdillo /*
257625e99827Sdillo * table 4 (high byte 0x04)
257725e99827Sdillo */
257825e99827Sdillo s = 4 * 256;
257925e99827Sdillo for (i = 0; i < 16; i++)
258025e99827Sdillo t[s+i] = i + 0x0400;
258125e99827Sdillo t[s+ 2] = 0x0452;
258225e99827Sdillo t[s+ 4] = 0x0454;
258325e99827Sdillo t[s+ 5] = 0x0455;
258425e99827Sdillo t[s+ 6] = 0x0456;
258525e99827Sdillo t[s+ 8] = 0x0458;
258625e99827Sdillo t[s+ 9] = 0x0459;
258725e99827Sdillo t[s+ 10] = 0x045a;
258825e99827Sdillo t[s+ 11] = 0x045b;
258925e99827Sdillo t[s+ 15] = 0x045f;
259025e99827Sdillo
259125e99827Sdillo for (i = 16; i < 48; i++)
259225e99827Sdillo t[s+i] = i + 0x0420;
259325e99827Sdillo t[s+ 25] = 0x0419;
259425e99827Sdillo for (i = 48; i < 256; i++)
259525e99827Sdillo t[s+i] = i + 0x0400;
259625e99827Sdillo t[s+195] = 0x04c4;
259725e99827Sdillo t[s+199] = 0x04c8;
259825e99827Sdillo t[s+203] = 0x04cc;
259925e99827Sdillo
260025e99827Sdillo for (i = 96; i < 129; i += 2)
260125e99827Sdillo t[s+i] = i + 0x0401;
260225e99827Sdillo t[s+118] = 0x0476;
260325e99827Sdillo for (i = 144; i < 191; i += 2)
260425e99827Sdillo t[s+i] = i + 0x0401;
260525e99827Sdillo
260625e99827Sdillo /*
260725e99827Sdillo * table 5 (high byte 0x05)
260825e99827Sdillo */
260925e99827Sdillo s = 5 * 256;
261025e99827Sdillo for (i = 0; i < 49; i++)
261125e99827Sdillo t[s+i] = i + 0x0500;
261225e99827Sdillo for (i = 49; i < 87; i++)
261325e99827Sdillo t[s+i] = i + 0x0530;
261425e99827Sdillo for (i = 87; i < 256; i++)
261525e99827Sdillo t[s+i] = i + 0x0500;
261625e99827Sdillo
261725e99827Sdillo /*
261825e99827Sdillo * table 6 (high byte 0x10)
261925e99827Sdillo */
262025e99827Sdillo s = 6 * 256;
262125e99827Sdillo for (i = 0; i < 160; i++)
262225e99827Sdillo t[s+i] = i + 0x1000;
262325e99827Sdillo for (i = 160; i < 198; i++)
262425e99827Sdillo t[s+i] = i + 0x1030;
262525e99827Sdillo for (i = 198; i < 256; i++)
262625e99827Sdillo t[s+i] = i + 0x1000;
262725e99827Sdillo
262825e99827Sdillo /*
262925e99827Sdillo * table 7 (high byte 0x20)
263025e99827Sdillo */
263125e99827Sdillo s = 7 * 256;
263225e99827Sdillo for (i = 0; i < 256; i++)
263325e99827Sdillo t[s+i] = i + 0x2000;
263425e99827Sdillo {
263525e99827Sdillo uint8_t zi[15] = { 12, 13, 14, 15,
263625e99827Sdillo 42, 43, 44, 45, 46,
263725e99827Sdillo 106, 107, 108, 109, 110, 111};
263825e99827Sdillo
263925e99827Sdillo for (i = 0; i < 15; i++)
264025e99827Sdillo t[s+zi[i]] = 0x0000;
264125e99827Sdillo }
264225e99827Sdillo
264325e99827Sdillo /*
264425e99827Sdillo * table 8 (high byte 0x21)
264525e99827Sdillo */
264625e99827Sdillo s = 8 * 256;
264725e99827Sdillo for (i = 0; i < 96; i++)
264825e99827Sdillo t[s+i] = i + 0x2100;
264925e99827Sdillo for (i = 96; i < 112; i++)
265025e99827Sdillo t[s+i] = i + 0x2110;
265125e99827Sdillo for (i = 112; i < 256; i++)
265225e99827Sdillo t[s+i] = i + 0x2100;
265325e99827Sdillo
265425e99827Sdillo /*
265525e99827Sdillo * table 9 (high byte 0xFE)
265625e99827Sdillo */
265725e99827Sdillo s = 9 * 256;
265825e99827Sdillo for (i = 0; i < 256; i++)
265925e99827Sdillo t[s+i] = i + 0xFE00;
266025e99827Sdillo t[s+255] = 0x0000;
266125e99827Sdillo
266225e99827Sdillo /*
266325e99827Sdillo * table 10 (high byte 0xFF)
266425e99827Sdillo */
266525e99827Sdillo s = 10 * 256;
266625e99827Sdillo for (i = 0; i < 33; i++)
266725e99827Sdillo t[s+i] = i + 0xFF00;
266825e99827Sdillo for (i = 33; i < 59; i++)
266925e99827Sdillo t[s+i] = i + 0xFF20;
267025e99827Sdillo for (i = 59; i < 256; i++)
267125e99827Sdillo t[s+i] = i + 0xFF00;
267225e99827Sdillo
267325e99827Sdillo return 0;
267425e99827Sdillo
267525e99827Sdillo error:
267625e99827Sdillo return 1;
267725e99827Sdillo }
267825e99827Sdillo
267925e99827Sdillo int
hfslib_get_hardlink(hfs_volume * vol,uint32_t inode_num,hfs_catalog_keyed_record_t * rec,hfs_callback_args * cbargs)268056c3e412Sdillo hfslib_get_hardlink(hfs_volume *vol, uint32_t inode_num,
268156c3e412Sdillo hfs_catalog_keyed_record_t *rec,
268256c3e412Sdillo hfs_callback_args *cbargs)
268325e99827Sdillo {
268456c3e412Sdillo hfs_catalog_keyed_record_t metadata;
268556c3e412Sdillo hfs_catalog_key_t key;
268625e99827Sdillo char name[16];
268725e99827Sdillo unichar_t name_uni[16];
268825e99827Sdillo int i, len;
268925e99827Sdillo
269025e99827Sdillo /* XXX: cache this */
269156c3e412Sdillo if (hfslib_find_catalog_record_with_key(vol,
269256c3e412Sdillo &hfs_gMetadataDirectoryKey,
269325e99827Sdillo &metadata, cbargs) != 0
269456c3e412Sdillo || metadata.type != HFS_REC_FLDR)
269525e99827Sdillo return -1;
269625e99827Sdillo
269725e99827Sdillo len = snprintf(name, sizeof(name), "iNode%d", inode_num);
269825e99827Sdillo for (i = 0; i < len; i++)
269925e99827Sdillo name_uni[i] = name[i];
270025e99827Sdillo
270156c3e412Sdillo if (hfslib_make_catalog_key(metadata.folder.cnid, len, name_uni,
270225e99827Sdillo &key) == 0)
270325e99827Sdillo return -1;
270425e99827Sdillo
270556c3e412Sdillo return hfslib_find_catalog_record_with_key(vol, &key, rec, cbargs);
270625e99827Sdillo }
2707