]> code.delx.au - refind/blob - filesystems/fsw_hfs.c
Previous commit broke loading of EFI drivers with SB active; fix it.
[refind] / filesystems / fsw_hfs.c
1 /* $Id: fsw_hfs.c 33540 2010-10-28 09:27:05Z vboxsync $ */
2 /** @file
3 * fsw_hfs.c - HFS file system driver code, see
4 *
5 * http://developer.apple.com/technotes/tn/tn1150.html
6 *
7 * Current limitations:
8 * - Doesn't support permissions
9 * - Complete Unicode case-insensitiveness disabled (large tables)
10 * - No links
11 * - Only supports pure HFS+ (i.e. no HFS, or HFS+ embedded to HFS)
12 */
13
14 /*
15 * Copyright (C) 2010 Oracle Corporation
16 *
17 * This file is part of VirtualBox Open Source Edition (OSE), as
18 * available from http://www.virtualbox.org. This file is free software;
19 * you can redistribute it and/or modify it under the terms of the GNU
20 * General Public License (GPL) as published by the Free Software
21 * Foundation, in version 2 as it comes in the "COPYING" file of the
22 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
23 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
24 */
25
26 #include "fsw_hfs.h"
27
28 #ifdef HOST_POSIX
29 #define DPRINT(x) printf(x)
30 #define DPRINT2(x,y) printf(x,y)
31 #define BP(msg) do { printf("ERROR: %s", msg); asm("int3"); } while (0)
32 #else
33 #define CONCAT(x,y) x##y
34 #define DPRINT(x) Print(CONCAT(L,x))
35 #define DPRINT2(x,y) Print(CONCAT(L,x), y)
36 #define BP(msg) DPRINT(msg)
37 #endif
38
39 // functions
40 #if 0
41 void dump_str(fsw_u16* p, fsw_u32 len, int swap)
42 {
43 int i;
44
45 for (i=0; i<len; i++)
46 {
47 fprintf(stderr, "%c", swap ? be16_to_cpu(p[i]) : p[i]);
48 }
49 fprintf(stderr, "\n");
50 }
51 #endif
52
53 static fsw_status_t fsw_hfs_volume_mount(struct fsw_hfs_volume *vol);
54 static void fsw_hfs_volume_free(struct fsw_hfs_volume *vol);
55 static fsw_status_t fsw_hfs_volume_stat(struct fsw_hfs_volume *vol, struct fsw_volume_stat *sb);
56
57 static fsw_status_t fsw_hfs_dnode_fill(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno);
58 static void fsw_hfs_dnode_free(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno);
59 static fsw_status_t fsw_hfs_dnode_stat(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
60 struct fsw_dnode_stat *sb);
61 static fsw_status_t fsw_hfs_get_extent(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
62 struct fsw_extent *extent);
63
64 static fsw_status_t fsw_hfs_dir_lookup(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
65 struct fsw_string *lookup_name, struct fsw_hfs_dnode **child_dno);
66 static fsw_status_t fsw_hfs_dir_read(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
67 struct fsw_shandle *shand, struct fsw_hfs_dnode **child_dno);
68 #if 0
69 static fsw_status_t fsw_hfs_read_dirrec(struct fsw_shandle *shand, struct hfs_dirrec_buffer *dirrec_buffer);
70 #endif
71
72 static fsw_status_t fsw_hfs_readlink(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
73 struct fsw_string *link);
74
75 //
76 // Dispatch Table
77 //
78
79 struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(hfs) = {
80 { FSW_STRING_TYPE_ISO88591, 4, 4, "hfs" },
81 sizeof(struct fsw_hfs_volume),
82 sizeof(struct fsw_hfs_dnode),
83
84 fsw_hfs_volume_mount, // volume open
85 fsw_hfs_volume_free, // volume close
86 fsw_hfs_volume_stat, // volume info: total_bytes, free_bytes
87 fsw_hfs_dnode_fill, //return FSW_SUCCESS;
88 fsw_hfs_dnode_free, // empty
89 fsw_hfs_dnode_stat, //size and times
90 fsw_hfs_get_extent, // get the physical disk block number for the requested logical block number
91 fsw_hfs_dir_lookup, //retrieve the directory entry with the given name
92 fsw_hfs_dir_read, // next directory entry when reading a directory
93 fsw_hfs_readlink, // return FSW_UNSUPPORTED;
94 };
95
96 static const fsw_u16 fsw_latin_case_fold[] =
97 {
98 /* 0 */ 0xFFFF, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
99 /* 1 */ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
100 /* 2 */ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
101 /* 3 */ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
102 /* 4 */ 0x0040, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
103 /* 5 */ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
104 /* 6 */ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
105 /* 7 */ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
106 /* 8 */ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
107 /* 9 */ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F,
108 /* A */ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
109 /* B */ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
110 /* C */ 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00E6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
111 /* D */ 0x00F0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, 0x00F8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00FE, 0x00DF,
112 /* E */ 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
113 /* F */ 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF,
114 };
115
116 static fsw_u16 fsw_to_lower(fsw_u16 ch)
117 {
118
119 if (ch < 0x0100)
120 return fsw_latin_case_fold[ch];
121
122 return ch;
123 }
124
125 static fsw_s32
126 fsw_hfs_read_block (struct fsw_hfs_dnode * dno,
127 fsw_u32 log_bno,
128 fsw_u32 off,
129 fsw_s32 len,
130 fsw_u8 * buf)
131 {
132 fsw_status_t status;
133 struct fsw_extent extent;
134 fsw_u32 phys_bno;
135 fsw_u8* buffer;
136
137 extent.log_start = log_bno;
138 status = fsw_hfs_get_extent(dno->g.vol, dno, &extent);
139 if (status)
140 return status;
141
142 phys_bno = extent.phys_start;
143 //Slice - increase cache level from 0 to 3
144 status = fsw_block_get(dno->g.vol, phys_bno, 3, (void **)&buffer);
145 if (status)
146 return status;
147
148 fsw_memcpy(buf, buffer + off, len);
149
150 fsw_block_release(dno->g.vol, phys_bno, buffer);
151
152 return FSW_SUCCESS;
153
154 }
155
156 /* Read data from HFS file. */
157 static fsw_s32
158 fsw_hfs_read_file (struct fsw_hfs_dnode * dno,
159 fsw_u64 pos,
160 fsw_s32 len,
161 fsw_u8 * buf)
162 {
163
164 fsw_status_t status;
165 fsw_u32 log_bno;
166 fsw_u32 block_size_bits = dno->g.vol->block_size_shift;
167 fsw_u32 block_size = (1 << block_size_bits);
168 fsw_u32 block_size_mask = block_size - 1;
169 fsw_s32 read = 0;
170
171 while (len > 0)
172 {
173 fsw_u32 off = (fsw_u32)(pos & block_size_mask);
174 fsw_s32 next_len = len;
175
176 log_bno = (fsw_u32)RShiftU64(pos, block_size_bits);
177
178 if ( next_len >= 0
179 && (fsw_u32)next_len > block_size)
180 next_len = block_size;
181 status = fsw_hfs_read_block(dno, log_bno, off, next_len, buf);
182 if (status)
183 return -1;
184 buf += next_len;
185 pos += next_len;
186 len -= next_len;
187 read += next_len;
188 }
189
190 return read;
191 }
192
193
194 static fsw_s32
195 fsw_hfs_compute_shift(fsw_u32 size)
196 {
197 fsw_s32 i;
198
199 for (i=0; i<32; i++)
200 {
201 if ((size >> i) == 0)
202 return i - 1;
203 }
204
205 // BP("BUG\n");
206 return 0;
207 }
208
209 /**
210 * Mount an HFS+ volume. Reads the superblock and constructs the
211 * root directory dnode.
212 */
213 //algo from Chameleon
214 /*
215 void
216 HFSGetDescription(CICell ih, char *str, long strMaxLen)
217 {
218
219 UInt16 nodeSize;
220 UInt32 firstLeafNode;
221 long long dirIndex;
222 char *name;
223 long flags, time;
224
225 if (HFSInitPartition(ih) == -1) { return; }
226
227 // Fill some crucial data structures by side effect.
228 dirIndex = 0;
229 HFSGetDirEntry(ih, "/", &dirIndex, &name, &flags, &time, 0, 0);
230
231 // Now we can loook up the volume name node.
232 nodeSize = be16_to_cpu(gBTHeaders[kBTreeCatalog]->nodeSize);
233 firstLeafNode = SWAP_BE32(gBTHeaders[kBTreeCatalog]->firstLeafNode);
234
235 dirIndex = (long long) firstLeafNode * nodeSize;
236
237 GetCatalogEntry(&dirIndex, &name, &flags, &time, 0, 0);
238
239 strncpy(str, name, strMaxLen);
240 str[strMaxLen] = '\0';
241 }
242 */
243
244
245 static fsw_status_t fsw_hfs_volume_mount(struct fsw_hfs_volume *vol)
246 {
247 fsw_status_t status, rv;
248 void *buffer = NULL;
249 HFSPlusVolumeHeader *voldesc;
250 fsw_u32 blockno;
251 struct fsw_string s;
252 HFSMasterDirectoryBlock* mdb;
253 fsw_u32 firstLeafNum;
254 fsw_u64 catfOffset;
255 fsw_u8 cbuff[sizeof (BTNodeDescriptor) + sizeof (HFSPlusCatalogKey)];
256
257 rv = FSW_UNSUPPORTED;
258
259 vol->primary_voldesc = NULL;
260 fsw_set_blocksize(vol, HFS_BLOCKSIZE, HFS_BLOCKSIZE);
261 blockno = HFS_SUPERBLOCK_BLOCKNO;
262
263 #define CHECK(s) \
264 if (status) { \
265 rv = status; \
266 break; \
267 }
268
269 vol->emb_block_off = 0;
270 vol->hfs_kind = 0;
271 do {
272 fsw_u16 signature;
273 BTHeaderRec tree_header;
274 fsw_s32 r;
275 fsw_u32 block_size;
276
277 status = fsw_block_get(vol, blockno, 0, &buffer);
278 CHECK(status);
279 voldesc = (HFSPlusVolumeHeader *)buffer;
280 mdb = (HFSMasterDirectoryBlock*)buffer;
281 signature = be16_to_cpu(voldesc->signature);
282
283 if ((signature == kHFSPlusSigWord) || (signature == kHFSXSigWord)) //H+ or HX
284 {
285 if (vol->hfs_kind == 0)
286 {
287 // DPRINT("found HFS+\n");
288 vol->hfs_kind = FSW_HFS_PLUS;
289 }
290 }
291 else if (signature == kHFSSigWord) // 'BD'
292 {
293 if (be16_to_cpu(mdb->drEmbedSigWord) == kHFSPlusSigWord)
294 {
295 DPRINT("found HFS+ inside HFS, untested\n");
296 vol->hfs_kind = FSW_HFS_PLUS_EMB;
297 vol->emb_block_off = be32_to_cpu(mdb->drEmbedExtent.startBlock);
298 blockno += vol->emb_block_off;
299 /* retry */
300 continue;
301 }
302 else
303 {
304 DPRINT("found plain HFS, unsupported\n");
305 vol->hfs_kind = FSW_HFS_PLAIN;
306 }
307 rv = FSW_UNSUPPORTED;
308 break;
309 }
310 else
311 {
312 rv = FSW_UNSUPPORTED;
313 break;
314 }
315
316 status = fsw_memdup((void **)&vol->primary_voldesc, voldesc,
317 sizeof(*voldesc));
318 CHECK(status);
319
320
321 block_size = be32_to_cpu(voldesc->blockSize);
322 vol->block_size_shift = fsw_hfs_compute_shift(block_size);
323
324 fsw_block_release(vol, blockno, buffer);
325 buffer = NULL;
326 voldesc = NULL;
327 fsw_set_blocksize(vol, block_size, block_size);
328
329 /* set default/fallback volume name */
330 s.type = FSW_STRING_TYPE_ISO88591;
331 s.size = s.len = kHFSMaxVolumeNameChars;
332 s.data = "HFS+ volume";
333 status = fsw_strdup_coerce(&vol->g.label, vol->g.host_string_type, &s);
334 CHECK(status);
335
336 /* Setup catalog dnode */
337 status = fsw_dnode_create_root(vol, kHFSCatalogFileID, &vol->catalog_tree.file);
338 CHECK(status);
339 fsw_memcpy (vol->catalog_tree.file->extents,
340 vol->primary_voldesc->catalogFile.extents,
341 sizeof vol->catalog_tree.file->extents);
342 vol->catalog_tree.file->g.size =
343 be64_to_cpu(vol->primary_voldesc->catalogFile.logicalSize);
344
345 /* Setup extents overflow file */
346 status = fsw_dnode_create_root(vol, kHFSExtentsFileID, &vol->extents_tree.file);
347 fsw_memcpy (vol->extents_tree.file->extents,
348 vol->primary_voldesc->extentsFile.extents,
349 sizeof vol->extents_tree.file->extents);
350 vol->extents_tree.file->g.size =
351 be64_to_cpu(vol->primary_voldesc->extentsFile.logicalSize);
352
353 /* Setup the root dnode */
354 status = fsw_dnode_create_root(vol, kHFSRootFolderID, &vol->g.root);
355 CHECK(status);
356
357 /*
358 * Read catalog file, we know that first record is in the first node, right after
359 * the node descriptor.
360 */
361 r = fsw_hfs_read_file(vol->catalog_tree.file,
362 sizeof (BTNodeDescriptor),
363 sizeof (BTHeaderRec), (fsw_u8 *) &tree_header);
364 if (r <= 0)
365 {
366 status = FSW_VOLUME_CORRUPTED;
367 break;
368 }
369 vol->case_sensitive =
370 (signature == kHFSXSigWord) &&
371 (tree_header.keyCompareType == kHFSBinaryCompare);
372 vol->catalog_tree.root_node = be32_to_cpu (tree_header.rootNode);
373 vol->catalog_tree.node_size = be16_to_cpu (tree_header.nodeSize);
374
375 //nms42
376 /* Take Volume Name before tree_header overwritten */
377 firstLeafNum = be32_to_cpu(tree_header.firstLeafNode);
378 catfOffset = firstLeafNum * vol->catalog_tree.node_size;
379
380 r = fsw_hfs_read_file(vol->catalog_tree.file, catfOffset, sizeof (cbuff), cbuff);
381
382 if (r == sizeof (cbuff))
383 {
384 BTNodeDescriptor* btnd;
385 HFSPlusCatalogKey* ck;
386
387 btnd = (BTNodeDescriptor*) cbuff;
388 ck = (HFSPlusCatalogKey*) (cbuff + sizeof(BTNodeDescriptor));
389 if (btnd->kind == kBTLeafNode && be32_to_cpu (ck->parentID) == kHFSRootParentID)
390 {
391 struct fsw_string vn;
392
393 vn.type = FSW_STRING_TYPE_UTF16_BE;
394 vn.len = be16_to_cpu (ck->nodeName.length);
395 vn.size = vn.len * sizeof (fsw_u16);
396 vn.data = ck->nodeName.unicode;
397 fsw_strfree (&vol->g.label);
398 status = fsw_strdup_coerce(&vol->g.label, vol->g.host_string_type, &vn);
399 CHECK(status);
400 } // if
401 } // if
402
403 /* Read extents overflow file */
404 r = fsw_hfs_read_file(vol->extents_tree.file,
405 sizeof (BTNodeDescriptor),
406 sizeof (BTHeaderRec), (fsw_u8 *) &tree_header);
407 if (r <= 0)
408 {
409 status = FSW_VOLUME_CORRUPTED;
410 break;
411 }
412
413 vol->extents_tree.root_node = be32_to_cpu (tree_header.rootNode);
414 vol->extents_tree.node_size = be16_to_cpu (tree_header.nodeSize);
415
416 rv = FSW_SUCCESS;
417 } while (0);
418
419 #undef CHECK
420
421
422 if (buffer != NULL)
423 fsw_block_release(vol, blockno, buffer);
424
425 return rv;
426 }
427 //Here is a method to obtain Volume label from Apple
428 //how to implement it?
429 /*
430 UInt16 nodeSize;
431 UInt32 firstLeafNode;
432 long long dirIndex;
433 char *name;
434 long flags, time;
435 char *nodeBuf, *testKey, *entry;
436
437
438 if (HFSInitPartition(ih) == -1) { return; }
439
440 // Fill some crucial data structures by side effect.
441 dirIndex = 0;
442 HFSGetDirEntry(ih, "/", &dirIndex, &name, &flags, &time, 0, 0);
443
444 // Now we can loook up the volume name node.
445 nodeSize = SWAP_BE16(gBTHeaders[kBTreeCatalog]->nodeSize);
446 firstLeafNode = SWAP_BE32(gBTHeaders[kBTreeCatalog]->firstLeafNode);
447
448 dirIndex = (long long) firstLeafNode * nodeSize;
449 index = (long) (*dirIndex % nodeSize); == 0
450 curNode = (long) (*dirIndex / nodeSize); == firstLeafNode
451
452 //GetCatalogEntry(&dirIndex, &name, &flags, &time, 0, 0);
453 // Read the BTree node and get the record for index.
454 ReadExtent(extent, extentSize, kHFSCatalogFileID,
455 (long long) curNode * nodeSize, nodeSize, nodeBuf, 1);
456 GetBTreeRecord(index, nodeBuf, nodeSize, &testKey, &entry);
457
458 utf_encodestr(((HFSPlusCatalogKey *)testKey)->nodeName.unicode,
459 SWAP_BE16(((HFSPlusCatalogKey *)testKey)->nodeName.length),
460 (u_int8_t *)gTempStr, 256, OSBigEndian);
461
462 *name = gTempStr;
463
464 strncpy(str, name, strMaxLen);
465 str[strMaxLen] = '\0';
466 */
467
468 /**
469 * Free the volume data structure. Called by the core after an unmount or after
470 * an unsuccessful mount to release the memory used by the file system type specific
471 * part of the volume structure.
472 */
473
474 static void fsw_hfs_volume_free(struct fsw_hfs_volume *vol)
475 {
476 if (vol->primary_voldesc)
477 {
478 fsw_free(vol->primary_voldesc);
479 vol->primary_voldesc = NULL;
480 }
481 }
482
483 /**
484 * Get in-depth information on a volume.
485 */
486
487 static fsw_status_t fsw_hfs_volume_stat(struct fsw_hfs_volume *vol, struct fsw_volume_stat *sb)
488 {
489 sb->total_bytes = be32_to_cpu(vol->primary_voldesc->totalBlocks) << vol->block_size_shift;
490 sb->free_bytes = be32_to_cpu(vol->primary_voldesc->freeBlocks) << vol->block_size_shift;
491 return FSW_SUCCESS;
492 }
493
494 /**
495 * Get full information on a dnode from disk. This function is called by the core
496 * whenever it needs to access fields in the dnode structure that may not
497 * be filled immediately upon creation of the dnode.
498 */
499
500 static fsw_status_t fsw_hfs_dnode_fill(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno)
501 {
502 return FSW_SUCCESS;
503 }
504
505 /**
506 * Free the dnode data structure. Called by the core when deallocating a dnode
507 * structure to release the memory used by the file system type specific part
508 * of the dnode structure.
509 */
510
511 static void fsw_hfs_dnode_free(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno)
512 {
513 }
514
515 static fsw_u32 mac_to_posix(fsw_u32 mac_time)
516 {
517 /* Mac time is 1904 year based */
518 return mac_time ? mac_time - 2082844800 : 0;
519 }
520
521 /**
522 * Get in-depth information on a dnode. The core makes sure that fsw_hfs_dnode_fill
523 * has been called on the dnode before this function is called. Note that some
524 * data is not directly stored into the structure, but passed to a host-specific
525 * callback that converts it to the host-specific format.
526 */
527
528 static fsw_status_t fsw_hfs_dnode_stat(struct fsw_hfs_volume *vol,
529 struct fsw_hfs_dnode *dno,
530 struct fsw_dnode_stat *sb)
531 {
532 sb->used_bytes = dno->used_bytes;
533 fsw_store_time_posix(sb, FSW_DNODE_STAT_CTIME, mac_to_posix(dno->ctime));
534 fsw_store_time_posix(sb, FSW_DNODE_STAT_MTIME, mac_to_posix(dno->mtime));
535 fsw_store_time_posix(sb, FSW_DNODE_STAT_ATIME, 0);
536 fsw_store_attr_posix(sb, 0700);
537
538 return FSW_SUCCESS;
539 }
540
541 static int
542 fsw_hfs_find_block(HFSPlusExtentRecord * exts,
543 fsw_u32 * lbno,
544 fsw_u32 * pbno)
545 {
546 int i;
547 fsw_u32 cur_lbno = *lbno;
548
549 for (i = 0; i < 8; i++)
550 {
551 fsw_u32 start = be32_to_cpu ((*exts)[i].startBlock);
552 fsw_u32 count = be32_to_cpu ((*exts)[i].blockCount);
553
554 if (cur_lbno < count)
555 {
556 *pbno = start + cur_lbno;
557 return 1;
558 }
559
560 cur_lbno -= count;
561 }
562
563 *lbno = cur_lbno;
564
565 return 0;
566 }
567
568 /* Find record offset, numbering starts from the end */
569 static fsw_u32
570 fsw_hfs_btree_recoffset (struct fsw_hfs_btree * btree,
571 BTNodeDescriptor * node,
572 fsw_u32 index)
573 {
574 fsw_u8 *cnode = (fsw_u8 *) node;
575 fsw_u16 *recptr;
576 recptr = (fsw_u16 *) (cnode+btree->node_size - index * 2 - 2);
577 return be16_to_cpu(*recptr);
578 }
579
580 /* Pointer to the key inside node */
581 static BTreeKey *
582 fsw_hfs_btree_rec (struct fsw_hfs_btree * btree,
583 BTNodeDescriptor * node,
584 fsw_u32 index)
585 {
586 fsw_u8 *cnode = (fsw_u8 *) node;
587 fsw_u32 offset;
588 offset = fsw_hfs_btree_recoffset (btree, node, index);
589 return (BTreeKey *) (cnode + offset);
590 }
591
592
593 static fsw_status_t
594 fsw_hfs_btree_search (struct fsw_hfs_btree * btree,
595 BTreeKey * key,
596 int (*compare_keys) (BTreeKey* key1, BTreeKey* key2),
597 BTNodeDescriptor ** result,
598 fsw_u32 * key_offset)
599 {
600 BTNodeDescriptor* node;
601 fsw_u32 currnode;
602 fsw_u32 rec;
603 fsw_status_t status;
604 fsw_u8* buffer = NULL;
605
606 currnode = btree->root_node;
607 status = fsw_alloc(btree->node_size, &buffer);
608 if (status)
609 return status;
610 node = (BTNodeDescriptor*)buffer;
611
612 while (1)
613 {
614 int cmp = 0;
615 int match;
616 fsw_u32 count;
617
618 readnode:
619 match = 0;
620 /* Read a node. */
621 if (fsw_hfs_read_file (btree->file,
622 (fsw_u64)currnode * btree->node_size,
623 btree->node_size, buffer) <= 0)
624 {
625 status = FSW_VOLUME_CORRUPTED;
626 break;
627 }
628
629 if (be16_to_cpu(*(fsw_u16*)(buffer + btree->node_size - 2)) != sizeof(BTNodeDescriptor))
630 BP("corrupted node\n");
631
632 count = be16_to_cpu (node->numRecords);
633
634 #if 1
635 for (rec = 0; rec < count; rec++)
636 {
637 BTreeKey *currkey;
638
639 currkey = fsw_hfs_btree_rec (btree, node, rec);
640 cmp = compare_keys (currkey, key);
641 //fprintf(stderr, "rec=%d cmp=%d kind=%d \n", rec, cmp, node->kind);
642
643 /* Leaf node. */
644 if (node->kind == kBTLeafNode)
645 {
646 if (cmp == 0)
647 {
648 /* Found! */
649 *result = node;
650 *key_offset = rec;
651
652 status = FSW_SUCCESS;
653 goto done;
654 }
655 }
656 else if (node->kind == kBTIndexNode)
657 {
658 fsw_u32 *pointer;
659
660 if (cmp > 0)
661 break;
662
663 pointer = (fsw_u32 *) ((char *) currkey
664 + be16_to_cpu (currkey->length16)
665 + 2);
666 currnode = be32_to_cpu (*pointer);
667 match = 1;
668 }
669 }
670
671 if (node->kind == kBTLeafNode && cmp < 0 && node->fLink)
672 {
673 currnode = be32_to_cpu(node->fLink);
674 goto readnode;
675 }
676 else if (!match)
677 {
678 status = FSW_NOT_FOUND;
679 break;
680 }
681 #else
682 /* Perform binary search */
683 fsw_u32 lower = 0;
684 fsw_u32 upper = count - 1;
685 fsw_s32 cmp = -1;
686 BTreeKey *currkey = NULL;
687
688 if (count == 0)
689 {
690 status = FSW_NOT_FOUND;
691 goto done;
692 }
693
694 while (lower <= upper)
695 {
696 fsw_u32 index = (lower + upper) / 2;
697
698 currkey = fsw_hfs_btree_rec (btree, node, index);
699
700 cmp = compare_keys (currkey, key);
701 if (cmp < 0) upper = index - 1;
702 if (cmp > 0) lower = index + 1;
703 if (cmp == 0)
704 {
705 /* Found! */
706 *result = node;
707 *key_offset = rec;
708
709 status = FSW_SUCCESS;
710 goto done;
711 }
712 }
713
714 if (cmp < 0)
715 currkey = fsw_hfs_btree_rec (btree, node, upper);
716
717 if (node->kind == kBTIndexNode && currkey)
718 {
719 fsw_u32 *pointer;
720
721 pointer = (fsw_u32 *) ((char *) currkey
722 + be16_to_cpu (currkey->length16)
723 + 2);
724 currnode = be32_to_cpu (*pointer);
725 }
726 else
727 {
728 status = FSW_NOT_FOUND;
729 break;
730 }
731 #endif
732 }
733
734
735 done:
736 if (buffer != NULL && status != FSW_SUCCESS)
737 fsw_free(buffer);
738
739 return status;
740 }
741 typedef struct
742 {
743 fsw_u32 id;
744 fsw_u32 type;
745 struct fsw_string * name;
746 fsw_u64 size;
747 fsw_u64 used;
748 fsw_u32 ctime;
749 fsw_u32 mtime;
750 HFSPlusExtentRecord extents;
751 } file_info_t;
752
753 typedef struct
754 {
755 fsw_u32 cur_pos; /* current position */
756 fsw_u32 parent;
757 struct fsw_hfs_volume * vol;
758
759 struct fsw_shandle * shandle; /* this one track iterator's state */
760 file_info_t file_info;
761 } visitor_parameter_t;
762
763 static int
764 fsw_hfs_btree_visit_node(BTreeKey *record, void* param)
765 {
766 visitor_parameter_t* vp = (visitor_parameter_t*)param;
767 fsw_u8* base = (fsw_u8*)record->rawData + be16_to_cpu(record->length16) + 2;
768 fsw_u16 rec_type = be16_to_cpu(*(fsw_u16*)base);
769 struct HFSPlusCatalogKey* cat_key = (HFSPlusCatalogKey*)record;
770 fsw_u16 name_len;
771 fsw_u16 *name_ptr;
772 fsw_u32 i;
773 struct fsw_string * file_name;
774
775 if (be32_to_cpu(cat_key->parentID) != vp->parent)
776 return -1;
777
778 /* not smth we care about */
779 if (vp->shandle->pos != vp->cur_pos++)
780 return 0;
781
782 switch (rec_type)
783 {
784 case kHFSPlusFolderRecord:
785 {
786 HFSPlusCatalogFolder* folder_info = (HFSPlusCatalogFolder*)base;
787
788 vp->file_info.id = be32_to_cpu(folder_info->folderID);
789 vp->file_info.type = FSW_DNODE_TYPE_DIR;
790 vp->file_info.size = be32_to_cpu(folder_info->valence);
791 vp->file_info.used = be32_to_cpu(folder_info->valence);
792 vp->file_info.ctime = be32_to_cpu(folder_info->createDate);
793 vp->file_info.mtime = be32_to_cpu(folder_info->contentModDate);
794 break;
795 }
796 case kHFSPlusFileRecord:
797 {
798 HFSPlusCatalogFile* file_info = (HFSPlusCatalogFile*)base;
799
800 vp->file_info.id = be32_to_cpu(file_info->fileID);
801 vp->file_info.type = FSW_DNODE_TYPE_FILE;
802 vp->file_info.size = be64_to_cpu(file_info->dataFork.logicalSize);
803 vp->file_info.used = LShiftU64(be32_to_cpu(file_info->dataFork.totalBlocks),
804 vp->vol->block_size_shift);
805 vp->file_info.ctime = be32_to_cpu(file_info->createDate);
806 vp->file_info.mtime = be32_to_cpu(file_info->contentModDate);
807 fsw_memcpy(&vp->file_info.extents, &file_info->dataFork.extents,
808 sizeof vp->file_info.extents);
809 break;
810 }
811 case kHFSPlusFolderThreadRecord:
812 case kHFSPlusFileThreadRecord:
813 {
814 vp->shandle->pos++;
815 return 0;
816 }
817 default:
818 BP("unknown file type\n");
819 vp->file_info.type = FSW_DNODE_TYPE_UNKNOWN;
820 break;
821 }
822
823 name_len = be16_to_cpu(cat_key->nodeName.length);
824
825 file_name = vp->file_info.name;
826 file_name->len = name_len;
827 fsw_memdup(&file_name->data, &cat_key->nodeName.unicode[0], 2*name_len);
828 file_name->size = 2*name_len;
829 file_name->type = FSW_STRING_TYPE_UTF16;
830 name_ptr = (fsw_u16*)file_name->data;
831 for (i=0; i<name_len; i++)
832 {
833 name_ptr[i] = be16_to_cpu(name_ptr[i]);
834 }
835 vp->shandle->pos++;
836
837 return 1;
838 }
839
840 static fsw_status_t
841 fsw_hfs_btree_iterate_node (struct fsw_hfs_btree * btree,
842 BTNodeDescriptor * first_node,
843 fsw_u32 first_rec,
844 int (*callback) (BTreeKey *record, void* param),
845 void * param)
846 {
847 fsw_status_t status;
848 /* We modify node, so make a copy */
849 BTNodeDescriptor* node = first_node;
850 fsw_u8* buffer = NULL;
851
852 status = fsw_alloc(btree->node_size, &buffer);
853 if (status)
854 return status;
855
856 while (1)
857 {
858 fsw_u32 i;
859 fsw_u32 count = be16_to_cpu(node->numRecords);
860 fsw_u32 next_node;
861
862 /* Iterate over all records in this node. */
863 for (i = first_rec; i < count; i++)
864 {
865 int rv = callback(fsw_hfs_btree_rec (btree, node, i), param);
866
867 switch (rv)
868 {
869 case 1:
870 status = FSW_SUCCESS;
871 goto done;
872 case -1:
873 status = FSW_NOT_FOUND;
874 goto done;
875 }
876 /* if callback returned 0 - continue */
877 }
878
879 next_node = be32_to_cpu(node->fLink);
880
881 if (!next_node)
882 {
883 status = FSW_NOT_FOUND;
884 break;
885 }
886
887 if (fsw_hfs_read_file (btree->file,
888 next_node * btree->node_size,
889 btree->node_size, buffer) <= 0)
890 {
891 status = FSW_VOLUME_CORRUPTED;
892 return 1;
893 }
894
895 node = (BTNodeDescriptor*)buffer;
896 first_rec = 0;
897 }
898 done:
899 if (buffer)
900 fsw_free(buffer);
901
902 return status;
903 }
904
905 #if 0
906 void deb(fsw_u16* p, int len, int swap)
907 {
908 int i;
909 for (i=0; i<len; i++)
910 {
911 printf("%c", swap ? be16_to_cpu(p[i]) : p[i]);
912 }
913 printf("\n");
914 }
915 #endif
916
917 static int
918 fsw_hfs_cmp_extkey(BTreeKey* key1, BTreeKey* key2)
919 {
920 HFSPlusExtentKey* ekey1 = (HFSPlusExtentKey*)key1;
921 HFSPlusExtentKey* ekey2 = (HFSPlusExtentKey*)key2;
922 int result;
923
924 /* First key is read from the FS data, second is in-memory in CPU endianess */
925 result = be32_to_cpu(ekey1->fileID) - ekey2->fileID;
926
927 if (result)
928 return result;
929
930 result = ekey1->forkType - ekey2->forkType;
931
932 if (result)
933 return result;
934
935 result = be32_to_cpu(ekey1->startBlock) - ekey2->startBlock;
936 return result;
937 }
938
939 static int
940 fsw_hfs_cmp_catkey (BTreeKey *key1, BTreeKey *key2)
941 {
942 HFSPlusCatalogKey *ckey1 = (HFSPlusCatalogKey*)key1;
943 HFSPlusCatalogKey *ckey2 = (HFSPlusCatalogKey*)key2;
944
945 int apos, bpos, lc;
946 fsw_u16 ac, bc;
947 fsw_u32 parentId1;
948 int key1Len;
949 fsw_u16 *p1;
950 fsw_u16 *p2;
951
952 parentId1 = be32_to_cpu(ckey1->parentID);
953
954 if (parentId1 > ckey2->parentID)
955 return 1;
956 if (parentId1 < ckey2->parentID)
957 return -1;
958
959 p1 = &ckey1->nodeName.unicode[0];
960 p2 = &ckey2->nodeName.unicode[0];
961 key1Len = be16_to_cpu (ckey1->nodeName.length);
962 apos = bpos = 0;
963
964 while(1)
965 {
966 /* get next valid character from ckey1 */
967 for (lc = 0; lc == 0 && apos < key1Len; apos++) {
968 ac = be16_to_cpu(p1[apos]);
969 lc = ac;
970 };
971 ac = (fsw_u16)lc;
972
973 /* get next valid character from ckey2 */
974 for (lc = 0; lc == 0 && bpos < ckey2->nodeName.length; bpos++) {
975 bc = p2[bpos];
976 lc = bc;
977 };
978 bc = (fsw_u16)lc;
979
980 if (ac != bc || (ac == 0 && bc == 0))
981 return ac - bc;
982 }
983 }
984
985 static int
986 fsw_hfs_cmpi_catkey (BTreeKey *key1, BTreeKey *key2)
987 {
988 HFSPlusCatalogKey *ckey1 = (HFSPlusCatalogKey*)key1;
989 HFSPlusCatalogKey *ckey2 = (HFSPlusCatalogKey*)key2;
990
991 int apos, bpos, lc;
992 fsw_u16 ac, bc;
993 fsw_u32 parentId1;
994 int key1Len;
995 fsw_u16 *p1;
996 fsw_u16 *p2;
997
998 parentId1 = be32_to_cpu(ckey1->parentID);
999
1000 if (parentId1 > ckey2->parentID)
1001 return 1;
1002 if (parentId1 < ckey2->parentID)
1003 return -1;
1004
1005 key1Len = be16_to_cpu (ckey1->nodeName.length);
1006
1007 if (key1Len == 0 && ckey2->nodeName.length == 0)
1008 return 0;
1009
1010 p1 = &ckey1->nodeName.unicode[0];
1011 p2 = &ckey2->nodeName.unicode[0];
1012
1013 apos = bpos = 0;
1014
1015 while(1)
1016 {
1017 /* get next valid character from ckey1 */
1018 for (lc = 0; lc == 0 && apos < key1Len; apos++) {
1019 ac = be16_to_cpu(p1[apos]);
1020 lc = ac ? fsw_to_lower(ac) : 0;
1021 };
1022 ac = (fsw_u16)lc;
1023
1024 /* get next valid character from ckey2 */
1025 for (lc = 0; lc == 0 && bpos < ckey2->nodeName.length; bpos++) {
1026 bc = p2[bpos];
1027 lc = bc ? fsw_to_lower(bc) : 0;
1028 };
1029 bc = (fsw_u16)lc;
1030
1031 if (ac != bc || (ac == 0 && bc == 0))
1032 return ac - bc;
1033 }
1034 }
1035
1036 /**
1037 * Retrieve file data mapping information. This function is called by the core when
1038 * fsw_shandle_read needs to know where on the disk the required piece of the file's
1039 * data can be found. The core makes sure that fsw_hfs_dnode_fill has been called
1040 * on the dnode before. Our task here is to get the physical disk block number for
1041 * the requested logical block number.
1042 */
1043
1044 static fsw_status_t fsw_hfs_get_extent(struct fsw_hfs_volume * vol,
1045 struct fsw_hfs_dnode * dno,
1046 struct fsw_extent * extent)
1047 {
1048 fsw_status_t status;
1049 fsw_u32 lbno;
1050 HFSPlusExtentRecord *exts;
1051 BTNodeDescriptor *node = NULL;
1052
1053 extent->type = FSW_EXTENT_TYPE_PHYSBLOCK;
1054 extent->log_count = 1;
1055 lbno = extent->log_start;
1056
1057 /* we only care about data forks atm, do we? */
1058 exts = &dno->extents;
1059
1060 while (1)
1061 {
1062 struct HFSPlusExtentKey* key;
1063 struct HFSPlusExtentKey overflowkey;
1064 fsw_u32 ptr;
1065 fsw_u32 phys_bno;
1066
1067 if (fsw_hfs_find_block(exts, &lbno, &phys_bno))
1068 {
1069 extent->phys_start = phys_bno + vol->emb_block_off;
1070 status = FSW_SUCCESS;
1071 break;
1072 }
1073
1074
1075 /* Find appropriate overflow record */
1076 overflowkey.fileID = dno->g.dnode_id;
1077 overflowkey.startBlock = extent->log_start - lbno;
1078
1079 if (node != NULL)
1080 {
1081 fsw_free(node);
1082 node = NULL;
1083 }
1084
1085 status = fsw_hfs_btree_search (&vol->extents_tree,
1086 (BTreeKey*)&overflowkey,
1087 fsw_hfs_cmp_extkey,
1088 &node, &ptr);
1089 if (status)
1090 break;
1091
1092 key = (struct HFSPlusExtentKey *)
1093 fsw_hfs_btree_rec (&vol->extents_tree, node, ptr);
1094 exts = (HFSPlusExtentRecord*) (key + 1);
1095 }
1096
1097 if (node != NULL)
1098 fsw_free(node);
1099
1100 return status;
1101 }
1102
1103 static const fsw_u16* g_blacklist[] =
1104 {
1105 //L"AppleIntelCPUPowerManagement.kext",
1106 NULL
1107 };
1108
1109
1110 //#define HFS_FILE_INJECTION
1111
1112 #ifdef HFS_FILE_INJECTION
1113 static struct
1114 {
1115 const fsw_u16* path;
1116 const fsw_u16* name;
1117 } g_injectList[] =
1118 {
1119 {
1120 L"/System/Library/Extensions",
1121 L"ApplePS2Controller.kext"
1122 },
1123 {
1124 NULL,
1125 NULL
1126 }
1127 };
1128 #endif
1129
1130 static fsw_status_t
1131 create_hfs_dnode(struct fsw_hfs_dnode * dno,
1132 file_info_t * file_info,
1133 struct fsw_hfs_dnode ** child_dno_out)
1134 {
1135 fsw_status_t status;
1136 struct fsw_hfs_dnode * baby;
1137
1138 status = fsw_dnode_create(dno, file_info->id, file_info->type,
1139 file_info->name, &baby);
1140 if (status)
1141 return status;
1142
1143 baby->g.size = file_info->size;
1144 baby->used_bytes = file_info->used;
1145 baby->ctime = file_info->ctime;
1146 baby->mtime = file_info->mtime;
1147
1148
1149 /* Fill-in extents info */
1150 if (file_info->type == FSW_DNODE_TYPE_FILE)
1151 {
1152 fsw_memcpy(baby->extents, &file_info->extents, sizeof file_info->extents);
1153 }
1154
1155 *child_dno_out = baby;
1156
1157 return FSW_SUCCESS;
1158 }
1159
1160
1161 /**
1162 * Lookup a directory's child dnode by name. This function is called on a directory
1163 * to retrieve the directory entry with the given name. A dnode is constructed for
1164 * this entry and returned. The core makes sure that fsw_hfs_dnode_fill has been called
1165 * and the dnode is actually a directory.
1166 */
1167
1168 static fsw_status_t fsw_hfs_dir_lookup(struct fsw_hfs_volume * vol,
1169 struct fsw_hfs_dnode * dno,
1170 struct fsw_string * lookup_name,
1171 struct fsw_hfs_dnode ** child_dno_out)
1172 {
1173 fsw_status_t status;
1174 struct HFSPlusCatalogKey catkey;
1175 fsw_u32 ptr;
1176 fsw_u16 rec_type;
1177 BTNodeDescriptor * node = NULL;
1178 struct fsw_string rec_name;
1179 int free_data = 0, i;
1180 HFSPlusCatalogKey* file_key;
1181 file_info_t file_info;
1182 fsw_u8* base;
1183
1184
1185 fsw_memzero(&file_info, sizeof file_info);
1186 file_info.name = &rec_name;
1187
1188 catkey.parentID = dno->g.dnode_id;
1189 catkey.nodeName.length = (fsw_u16)lookup_name->len;
1190
1191 /* no need to allocate anything */
1192 if (lookup_name->type == FSW_STRING_TYPE_UTF16)
1193 {
1194 fsw_memcpy(catkey.nodeName.unicode, lookup_name->data, lookup_name->size);
1195 rec_name = *lookup_name;
1196 } else
1197 {
1198 status = fsw_strdup_coerce(&rec_name, FSW_STRING_TYPE_UTF16, lookup_name);
1199 /* nothing allocated so far */
1200 if (status)
1201 goto done;
1202 free_data = 1;
1203 fsw_memcpy(catkey.nodeName.unicode, rec_name.data, rec_name.size);
1204 }
1205
1206 /* Dirty hack: blacklisting of certain files on FS driver level */
1207 for (i = 0; g_blacklist[i]; i++)
1208 {
1209 if (fsw_memeq(g_blacklist[i], catkey.nodeName.unicode, catkey.nodeName.length*2))
1210 {
1211 DPRINT2("Blacklisted %s\n", g_blacklist[i]);
1212 status = FSW_NOT_FOUND;
1213 goto done;
1214 }
1215 }
1216
1217 #ifdef HFS_FILE_INJECTION
1218 if (fsw_hfs_inject(vol,
1219 dno,
1220 catkey.nodeName.unicode,
1221 catkey.nodeName.length,
1222 &file_info))
1223 {
1224 status = FSW_SUCCESS;
1225 goto create;
1226 }
1227 #endif
1228
1229 catkey.keyLength = (fsw_u16)(5 + rec_name.size);
1230
1231 status = fsw_hfs_btree_search (&vol->catalog_tree,
1232 (BTreeKey*)&catkey,
1233 vol->case_sensitive ?
1234 fsw_hfs_cmp_catkey : fsw_hfs_cmpi_catkey,
1235 &node, &ptr);
1236 if (status)
1237 goto done;
1238
1239 file_key = (HFSPlusCatalogKey *)fsw_hfs_btree_rec (&vol->catalog_tree, node, ptr);
1240 /* for plain HFS "-(keySize & 1)" would be needed */
1241 base = (fsw_u8*)file_key + be16_to_cpu(file_key->keyLength) + 2;
1242 rec_type = be16_to_cpu(*(fsw_u16*)base);
1243
1244 /** @todo: read additional info */
1245 switch (rec_type)
1246 {
1247 case kHFSPlusFolderRecord:
1248 {
1249 HFSPlusCatalogFolder* info = (HFSPlusCatalogFolder*)base;
1250
1251 file_info.id = be32_to_cpu(info->folderID);
1252 file_info.type = FSW_DNODE_TYPE_DIR;
1253 /* @todo: return number of elements, maybe use smth else */
1254 file_info.size = be32_to_cpu(info->valence);
1255 file_info.used = be32_to_cpu(info->valence);
1256 file_info.ctime = be32_to_cpu(info->createDate);
1257 file_info.mtime = be32_to_cpu(info->contentModDate);
1258 break;
1259 }
1260 case kHFSPlusFileRecord:
1261 {
1262 HFSPlusCatalogFile* info = (HFSPlusCatalogFile*)base;
1263
1264 file_info.id = be32_to_cpu(info->fileID);
1265 file_info.type = FSW_DNODE_TYPE_FILE;
1266 file_info.size = be64_to_cpu(info->dataFork.logicalSize);
1267 file_info.used = LShiftU64(be32_to_cpu(info->dataFork.totalBlocks), vol->block_size_shift);
1268 file_info.ctime = be32_to_cpu(info->createDate);
1269 file_info.mtime = be32_to_cpu(info->contentModDate);
1270 fsw_memcpy(&file_info.extents, &info->dataFork.extents,
1271 sizeof file_info.extents);
1272 break;
1273 }
1274 default:
1275 BP("unknown file type\n");
1276 file_info.type = FSW_DNODE_TYPE_UNKNOWN;
1277
1278 break;
1279 }
1280 #ifdef HFS_FILE_INJECTION
1281 create:
1282 #endif
1283 status = create_hfs_dnode(dno, &file_info, child_dno_out);
1284 if (status)
1285 goto done;
1286
1287 done:
1288
1289 if (node != NULL)
1290 fsw_free(node);
1291
1292 if (free_data)
1293 fsw_strfree(&rec_name);
1294
1295 return status;
1296 }
1297
1298 /**
1299 * Get the next directory entry when reading a directory. This function is called during
1300 * directory iteration to retrieve the next directory entry. A dnode is constructed for
1301 * the entry and returned. The core makes sure that fsw_hfs_dnode_fill has been called
1302 * and the dnode is actually a directory. The shandle provided by the caller is used to
1303 * record the position in the directory between calls.
1304 */
1305
1306 static fsw_status_t fsw_hfs_dir_read(struct fsw_hfs_volume *vol,
1307 struct fsw_hfs_dnode *dno,
1308 struct fsw_shandle *shand,
1309 struct fsw_hfs_dnode **child_dno_out)
1310 {
1311 fsw_status_t status;
1312 struct HFSPlusCatalogKey catkey;
1313 fsw_u32 ptr;
1314 BTNodeDescriptor * node = NULL;
1315
1316 visitor_parameter_t param;
1317 struct fsw_string rec_name;
1318
1319 catkey.parentID = dno->g.dnode_id;
1320 catkey.nodeName.length = 0;
1321
1322 fsw_memzero(&param, sizeof(param));
1323
1324 rec_name.type = FSW_STRING_TYPE_EMPTY;
1325 param.file_info.name = &rec_name;
1326
1327 status = fsw_hfs_btree_search (&vol->catalog_tree,
1328 (BTreeKey*)&catkey,
1329 vol->case_sensitive ?
1330 fsw_hfs_cmp_catkey : fsw_hfs_cmpi_catkey,
1331 &node, &ptr);
1332 if (status)
1333 goto done;
1334
1335 /* Iterator updates shand state */
1336 param.vol = vol;
1337 param.shandle = shand;
1338 param.parent = dno->g.dnode_id;
1339 param.cur_pos = 0;
1340 status = fsw_hfs_btree_iterate_node (&vol->catalog_tree,
1341 node,
1342 ptr,
1343 fsw_hfs_btree_visit_node,
1344 &param);
1345 if (status)
1346 goto done;
1347
1348 status = create_hfs_dnode(dno, &param.file_info, child_dno_out);
1349
1350 if (status)
1351 goto done;
1352
1353 done:
1354 fsw_strfree(&rec_name);
1355
1356 return status;
1357 }
1358
1359 /**
1360 * Get the target path of a symbolic link. This function is called when a symbolic
1361 * link needs to be resolved. The core makes sure that the fsw_hfs_dnode_fill has been
1362 * called on the dnode and that it really is a symlink.
1363 *
1364 */
1365 static fsw_status_t fsw_hfs_readlink(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
1366 struct fsw_string *link_target)
1367 {
1368 return FSW_UNSUPPORTED;
1369 }
1370
1371 // EOF