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