VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_hfs.c

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 41.9 KB
Line 
1/* $Id: fsw_hfs.c 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * fsw_hfs.c - HFS file system driver code, see
4 *
5 * https://developer.apple.com/legacy/library/technotes/tn/tn1150.html
6 * (formerly http://developer.apple.com/technotes/tn/tn1150.html)
7 *
8 * Current limitations:
9 * - Doesn't support permissions
10 * - Complete Unicode case-insensitiveness disabled (large tables)
11 * - No links
12 * - Only supports pure HFS+ (i.e. no HFS, or HFS+ embedded to HFS)
13 */
14
15/*
16 * Copyright (C) 2010-2023 Oracle and/or its affiliates.
17 *
18 * This file is part of VirtualBox base platform packages, as
19 * available from https://www.virtualbox.org.
20 *
21 * This program is free software; you can redistribute it and/or
22 * modify it under the terms of the GNU General Public License
23 * as published by the Free Software Foundation, in version 3 of the
24 * License.
25 *
26 * This program is distributed in the hope that it will be useful, but
27 * WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
29 * General Public License for more details.
30 *
31 * You should have received a copy of the GNU General Public License
32 * along with this program; if not, see <https://www.gnu.org/licenses>.
33 *
34 * The contents of this file may alternatively be used under the terms
35 * of the Common Development and Distribution License Version 1.0
36 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
37 * in the VirtualBox distribution, in which case the provisions of the
38 * CDDL are applicable instead of those of the GPL.
39 *
40 * You may elect to license modified versions of this file under the
41 * terms and conditions of either the GPL or the CDDL or both.
42 *
43 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
44 */
45
46#include "fsw_hfs.h"
47
48#ifdef HOST_POSIX
49#include <assert.h>
50#define DPRINT(x) printf(x)
51#define DPRINT2(x,y) printf(x,y)
52#define BP(msg) do { printf("ERROR: %s", msg); assert(0); } while (0)
53#elif defined DEBUG_LEVEL
54#define CONCAT(x,y) x##y
55#define DPRINT(x) Print(CONCAT(L,x))
56#define DPRINT2(x,y) Print(CONCAT(L,x), y)
57#define BP(msg) DPRINT(msg)
58#else
59#include <Library/PrintLib.h>
60#define DPRINT(x) do { } while (0)
61#define DPRINT2(x,y) do { } while (0)
62#define BP(msg) do { } while (0)
63#endif
64
65// functions
66#if 0
67void dump_str(fsw_u16* p, fsw_u32 len, int swap)
68{
69 int i;
70
71 for (i=0; i<len; i++)
72 {
73 fprintf(stderr, "%c", swap ? be16_to_cpu(p[i]) : p[i]);
74 }
75 fprintf(stderr, "\n");
76}
77#endif
78
79static fsw_status_t fsw_hfs_volume_mount(struct fsw_hfs_volume *vol);
80static void fsw_hfs_volume_free(struct fsw_hfs_volume *vol);
81static fsw_status_t fsw_hfs_volume_stat(struct fsw_hfs_volume *vol, struct fsw_volume_stat *sb);
82
83static fsw_status_t fsw_hfs_dnode_fill(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno);
84static void fsw_hfs_dnode_free(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno);
85static fsw_status_t fsw_hfs_dnode_stat(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
86 struct fsw_dnode_stat *sb);
87static fsw_status_t fsw_hfs_get_extent(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
88 struct fsw_extent *extent);
89
90static fsw_status_t fsw_hfs_dir_lookup(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
91 struct fsw_string *lookup_name, struct fsw_hfs_dnode **child_dno);
92static fsw_status_t fsw_hfs_dir_read(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
93 struct fsw_shandle *shand, struct fsw_hfs_dnode **child_dno);
94#if 0
95static fsw_status_t fsw_hfs_read_dirrec(struct fsw_shandle *shand, struct hfs_dirrec_buffer *dirrec_buffer);
96#endif
97
98static fsw_status_t fsw_hfs_readlink(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
99 struct fsw_string *link);
100
101//
102// Dispatch Table
103//
104
105struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(hfs) = {
106 { FSW_STRING_TYPE_ISO88591, 4, 4, "hfs" },
107 sizeof(struct fsw_hfs_volume),
108 sizeof(struct fsw_hfs_dnode),
109
110 fsw_hfs_volume_mount,
111 fsw_hfs_volume_free,
112 fsw_hfs_volume_stat,
113 fsw_hfs_dnode_fill,
114 fsw_hfs_dnode_free,
115 fsw_hfs_dnode_stat,
116 fsw_hfs_get_extent,
117 fsw_hfs_dir_lookup,
118 fsw_hfs_dir_read,
119 fsw_hfs_readlink,
120};
121
122static fsw_s32
123fsw_hfs_read_block (struct fsw_hfs_dnode * dno,
124 fsw_u32 log_bno,
125 fsw_u32 off,
126 fsw_s32 len,
127 fsw_u8 * buf)
128{
129 fsw_status_t status;
130 struct fsw_extent extent;
131 fsw_u32 phys_bno;
132 fsw_u8* buffer;
133
134 extent.log_start = log_bno;
135 status = fsw_hfs_get_extent(dno->g.vol, dno, &extent);
136 if (status)
137 return status;
138
139 phys_bno = extent.phys_start;
140 status = fsw_block_get(dno->g.vol, phys_bno, 0, (void **)&buffer);
141 if (status)
142 return status;
143
144 fsw_memcpy(buf, buffer + off, len);
145
146 fsw_block_release(dno->g.vol, phys_bno, buffer);
147
148 return FSW_SUCCESS;
149
150}
151
152/* Read data from HFS file. */
153static fsw_s32
154fsw_hfs_read_file (struct fsw_hfs_dnode * dno,
155 fsw_u64 pos,
156 fsw_s32 len,
157 fsw_u8 * buf)
158{
159
160 fsw_status_t status;
161 fsw_u32 log_bno;
162 fsw_u32 block_size_bits = dno->g.vol->block_size_shift;
163 fsw_u32 block_size = (1 << block_size_bits);
164 fsw_u32 block_size_mask = block_size - 1;
165 fsw_s32 read = 0;
166
167 while (len > 0)
168 {
169 fsw_u32 off = (fsw_u32)(pos & block_size_mask);
170 fsw_s32 next_len = len;
171
172 log_bno = (fsw_u32)RShiftU64(pos, block_size_bits);
173
174 if ( next_len >= 0
175 && (fsw_u32)next_len > block_size)
176 next_len = block_size;
177 status = fsw_hfs_read_block(dno, log_bno, off, next_len, buf);
178 if (status)
179 return -1;
180 buf += next_len;
181 pos += next_len;
182 len -= next_len;
183 read += next_len;
184 }
185
186 return read;
187}
188
189
190static fsw_s32
191fsw_hfs_compute_shift(fsw_u32 size)
192{
193 fsw_s32 i;
194
195 for (i=0; i<32; i++)
196 {
197 if ((size >> i) == 0)
198 return i - 1;
199 }
200
201 BP("BUG\n");
202 return 0;
203}
204
205/**
206 * Mount an HFS+ volume. Reads the superblock and constructs the
207 * root directory dnode.
208 */
209
210static fsw_status_t fsw_hfs_volume_mount(struct fsw_hfs_volume *vol)
211{
212 fsw_status_t status, rv;
213 void *buffer = NULL;
214 HFSPlusVolumeHeader *voldesc;
215 fsw_u32 blockno;
216 struct fsw_string s;
217
218 rv = FSW_UNSUPPORTED;
219
220 vol->primary_voldesc = NULL;
221 fsw_set_blocksize(vol, HFS_BLOCKSIZE, HFS_BLOCKSIZE);
222 blockno = HFS_SUPERBLOCK_BLOCKNO;
223
224#define CHECK(s) \
225 if (status) { \
226 rv = status; \
227 break; \
228 }
229
230 vol->emb_block_off = 0;
231 vol->hfs_kind = 0;
232 do {
233 fsw_u16 signature;
234 BTHeaderRec tree_header;
235 fsw_s32 r;
236 fsw_u32 block_size;
237
238 status = fsw_block_get(vol, blockno, 0, &buffer);
239 CHECK(status);
240 voldesc = (HFSPlusVolumeHeader *)buffer;
241 signature = be16_to_cpu(voldesc->signature);
242
243 if ((signature == kHFSPlusSigWord) || (signature == kHFSXSigWord))
244 {
245 if (vol->hfs_kind == 0)
246 {
247 DPRINT("found HFS+\n");
248 vol->hfs_kind = FSW_HFS_PLUS;
249 }
250 }
251 else if (signature == kHFSSigWord)
252 {
253 HFSMasterDirectoryBlock* mdb = (HFSMasterDirectoryBlock*)buffer;
254
255 if (be16_to_cpu(mdb->drEmbedSigWord) == kHFSPlusSigWord)
256 {
257 DPRINT("found HFS+ inside HFS, untested\n");
258 vol->hfs_kind = FSW_HFS_PLUS_EMB;
259 vol->emb_block_off = be32_to_cpu(mdb->drEmbedExtent.startBlock);
260 blockno += vol->emb_block_off;
261 /* retry */
262 continue;
263 }
264 else
265 {
266 DPRINT("found plain HFS, unsupported\n");
267 vol->hfs_kind = FSW_HFS_PLAIN;
268 }
269 rv = FSW_UNSUPPORTED;
270 break;
271 }
272 else
273 {
274 rv = FSW_UNSUPPORTED;
275 break;
276 }
277
278 status = fsw_memdup((void **)&vol->primary_voldesc, voldesc,
279 sizeof(*voldesc));
280 CHECK(status);
281
282
283 block_size = be32_to_cpu(voldesc->blockSize);
284 vol->block_size_shift = fsw_hfs_compute_shift(block_size);
285
286 fsw_block_release(vol, blockno, buffer);
287 buffer = NULL;
288 voldesc = NULL;
289 fsw_set_blocksize(vol, block_size, block_size);
290
291 /* get volume name */
292 s.type = FSW_STRING_TYPE_ISO88591;
293 s.size = s.len = kHFSMaxVolumeNameChars;
294 s.data = "HFS+ volume\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; /* Otherwise buffer overflow reading beyond the end of the buffer. */
295 status = fsw_strdup_coerce(&vol->g.label, vol->g.host_string_type, &s);
296 CHECK(status);
297
298 /* Setup catalog dnode */
299 status = fsw_dnode_create_root(vol, kHFSCatalogFileID, &vol->catalog_tree.file);
300 CHECK(status);
301 fsw_memcpy (vol->catalog_tree.file->extents,
302 vol->primary_voldesc->catalogFile.extents,
303 sizeof vol->catalog_tree.file->extents);
304 vol->catalog_tree.file->g.size =
305 be64_to_cpu(vol->primary_voldesc->catalogFile.logicalSize);
306
307 /* Setup extents overflow file */
308 status = fsw_dnode_create_root(vol, kHFSExtentsFileID, &vol->extents_tree.file);
309 fsw_memcpy (vol->extents_tree.file->extents,
310 vol->primary_voldesc->extentsFile.extents,
311 sizeof vol->extents_tree.file->extents);
312 vol->extents_tree.file->g.size =
313 be64_to_cpu(vol->primary_voldesc->extentsFile.logicalSize);
314
315 /* Setup the root dnode */
316 status = fsw_dnode_create_root(vol, kHFSRootFolderID, &vol->g.root);
317 CHECK(status);
318
319 /*
320 * Read catalog file, we know that first record is in the first node, right after
321 * the node descriptor.
322 */
323 r = fsw_hfs_read_file(vol->catalog_tree.file,
324 sizeof (BTNodeDescriptor),
325 sizeof (BTHeaderRec), (fsw_u8 *) &tree_header);
326 if (r <= 0)
327 {
328 status = FSW_VOLUME_CORRUPTED;
329 break;
330 }
331 vol->case_sensitive =
332 (signature == kHFSXSigWord) &&
333 (tree_header.keyCompareType == kHFSBinaryCompare);
334 vol->catalog_tree.root_node = be32_to_cpu (tree_header.rootNode);
335 vol->catalog_tree.node_size = be16_to_cpu (tree_header.nodeSize);
336
337 /* Read extents overflow file */
338 r = fsw_hfs_read_file(vol->extents_tree.file,
339 sizeof (BTNodeDescriptor),
340 sizeof (BTHeaderRec), (fsw_u8 *) &tree_header);
341 if (r <= 0)
342 {
343 status = FSW_VOLUME_CORRUPTED;
344 break;
345 }
346
347 vol->extents_tree.root_node = be32_to_cpu (tree_header.rootNode);
348 vol->extents_tree.node_size = be16_to_cpu (tree_header.nodeSize);
349
350 rv = FSW_SUCCESS;
351 } while (0);
352
353#undef CHECK
354
355
356 if (buffer != NULL)
357 fsw_block_release(vol, blockno, buffer);
358
359 return rv;
360}
361
362/**
363 * Free the volume data structure. Called by the core after an unmount or after
364 * an unsuccessful mount to release the memory used by the file system type specific
365 * part of the volume structure.
366 */
367
368static void fsw_hfs_volume_free(struct fsw_hfs_volume *vol)
369{
370 if (vol->primary_voldesc)
371 {
372 fsw_free(vol->primary_voldesc);
373 vol->primary_voldesc = NULL;
374 }
375}
376
377/**
378 * Get in-depth information on a volume.
379 */
380
381static fsw_status_t fsw_hfs_volume_stat(struct fsw_hfs_volume *vol, struct fsw_volume_stat *sb)
382{
383 sb->total_bytes = be32_to_cpu(vol->primary_voldesc->totalBlocks) << vol->block_size_shift;
384 sb->free_bytes = be32_to_cpu(vol->primary_voldesc->freeBlocks) << vol->block_size_shift;
385 return FSW_SUCCESS;
386}
387
388/**
389 * Get full information on a dnode from disk. This function is called by the core
390 * whenever it needs to access fields in the dnode structure that may not
391 * be filled immediately upon creation of the dnode.
392 */
393
394static fsw_status_t fsw_hfs_dnode_fill(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno)
395{
396 return FSW_SUCCESS;
397}
398
399/**
400 * Free the dnode data structure. Called by the core when deallocating a dnode
401 * structure to release the memory used by the file system type specific part
402 * of the dnode structure.
403 */
404
405static void fsw_hfs_dnode_free(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno)
406{
407}
408
409static fsw_u32 mac_to_posix(fsw_u32 mac_time)
410{
411 /* Mac time is 1904 year based */
412 return mac_time ? mac_time - 2082844800 : 0;
413}
414
415/**
416 * Get in-depth information on a dnode. The core makes sure that fsw_hfs_dnode_fill
417 * has been called on the dnode before this function is called. Note that some
418 * data is not directly stored into the structure, but passed to a host-specific
419 * callback that converts it to the host-specific format.
420 */
421
422static fsw_status_t fsw_hfs_dnode_stat(struct fsw_hfs_volume *vol,
423 struct fsw_hfs_dnode *dno,
424 struct fsw_dnode_stat *sb)
425{
426 sb->used_bytes = dno->used_bytes;
427 sb->store_time_posix(sb, FSW_DNODE_STAT_CTIME, mac_to_posix(dno->ctime));
428 sb->store_time_posix(sb, FSW_DNODE_STAT_MTIME, mac_to_posix(dno->mtime));
429 sb->store_time_posix(sb, FSW_DNODE_STAT_ATIME, 0);
430 sb->store_attr_posix(sb, 0700);
431
432 return FSW_SUCCESS;
433}
434
435static int
436fsw_hfs_find_block(HFSPlusExtentRecord * exts,
437 fsw_u32 * lbno,
438 fsw_u32 * pbno)
439{
440 int i;
441 fsw_u32 cur_lbno = *lbno;
442
443 for (i = 0; i < 8; i++)
444 {
445 fsw_u32 start = be32_to_cpu ((*exts)[i].startBlock);
446 fsw_u32 count = be32_to_cpu ((*exts)[i].blockCount);
447
448 if (cur_lbno < count)
449 {
450 *pbno = start + cur_lbno;
451 return 1;
452 }
453
454 cur_lbno -= count;
455 }
456
457 *lbno = cur_lbno;
458
459 return 0;
460}
461
462/* Find record offset, numbering starts from the end */
463static fsw_u32
464fsw_hfs_btree_recoffset (struct fsw_hfs_btree * btree,
465 BTNodeDescriptor * node,
466 fsw_u32 index)
467{
468 fsw_u8 *cnode = (fsw_u8 *) node;
469 fsw_u16 *recptr;
470 recptr = (fsw_u16 *) (cnode+btree->node_size - index * 2 - 2);
471 return be16_to_cpu(*recptr);
472}
473
474/* Pointer to the key inside node */
475static BTreeKey *
476fsw_hfs_btree_rec (struct fsw_hfs_btree * btree,
477 BTNodeDescriptor * node,
478 fsw_u32 index)
479{
480 fsw_u8 *cnode = (fsw_u8 *) node;
481 fsw_u32 offset;
482 offset = fsw_hfs_btree_recoffset (btree, node, index);
483 return (BTreeKey *) (cnode + offset);
484}
485
486
487static fsw_status_t
488fsw_hfs_btree_search (struct fsw_hfs_btree * btree,
489 BTreeKey * key,
490 int (*compare_keys) (BTreeKey* key1, BTreeKey* key2),
491 BTNodeDescriptor ** result,
492 fsw_u32 * key_offset)
493{
494 BTNodeDescriptor* node;
495 fsw_u32 currnode;
496 fsw_u32 rec;
497 fsw_status_t status;
498 fsw_u8* buffer = NULL;
499
500 currnode = btree->root_node;
501 status = fsw_alloc(btree->node_size, &buffer);
502 if (status)
503 return status;
504 node = (BTNodeDescriptor*)buffer;
505
506 while (1)
507 {
508 int cmp = 0;
509 int match;
510 fsw_u32 count;
511
512 readnode:
513 match = 0;
514 /* Read a node. */
515 if (fsw_hfs_read_file (btree->file,
516 (fsw_u64)currnode * btree->node_size,
517 btree->node_size, buffer) <= 0)
518 {
519 status = FSW_VOLUME_CORRUPTED;
520 break;
521 }
522
523 if (be16_to_cpu(*(fsw_u16*)(buffer + btree->node_size - 2)) != sizeof(BTNodeDescriptor))
524 BP("corrupted node\n");
525
526 count = be16_to_cpu (node->numRecords);
527
528#if 1
529 for (rec = 0; rec < count; rec++)
530 {
531 BTreeKey *currkey;
532
533 currkey = fsw_hfs_btree_rec (btree, node, rec);
534 cmp = compare_keys (currkey, key);
535 //fprintf(stderr, "rec=%d cmp=%d kind=%d \n", rec, cmp, node->kind);
536
537 /* Leaf node. */
538 if (node->kind == kBTLeafNode)
539 {
540 if (cmp == 0)
541 {
542 /* Found! */
543 *result = node;
544 *key_offset = rec;
545
546 status = FSW_SUCCESS;
547 goto done;
548 }
549 }
550 else if (node->kind == kBTIndexNode)
551 {
552 fsw_u32 *pointer;
553
554 if (cmp > 0)
555 break;
556
557 pointer = (fsw_u32 *) ((char *) currkey
558 + be16_to_cpu (currkey->length16)
559 + 2);
560 currnode = be32_to_cpu (*pointer);
561 match = 1;
562 }
563 }
564
565 if (node->kind == kBTLeafNode && cmp < 0 && node->fLink)
566 {
567 currnode = be32_to_cpu(node->fLink);
568 goto readnode;
569 }
570 else if (!match)
571 {
572 status = FSW_NOT_FOUND;
573 break;
574 }
575#else
576 /* Perform binary search */
577 fsw_u32 lower = 0;
578 fsw_u32 upper = count - 1;
579 fsw_s32 cmp = -1;
580 BTreeKey *currkey = NULL;
581
582 if (count == 0)
583 {
584 status = FSW_NOT_FOUND;
585 goto done;
586 }
587
588 while (lower <= upper)
589 {
590 fsw_u32 index = (lower + upper) / 2;
591
592 currkey = fsw_hfs_btree_rec (btree, node, index);
593
594 cmp = compare_keys (currkey, key);
595 if (cmp < 0) upper = index - 1;
596 if (cmp > 0) lower = index + 1;
597 if (cmp == 0)
598 {
599 /* Found! */
600 *result = node;
601 *key_offset = rec;
602
603 status = FSW_SUCCESS;
604 goto done;
605 }
606 }
607
608 if (cmp < 0)
609 currkey = fsw_hfs_btree_rec (btree, node, upper);
610
611 if (node->kind == kBTIndexNode && currkey)
612 {
613 fsw_u32 *pointer;
614
615 pointer = (fsw_u32 *) ((char *) currkey
616 + be16_to_cpu (currkey->length16)
617 + 2);
618 currnode = be32_to_cpu (*pointer);
619 }
620 else
621 {
622 status = FSW_NOT_FOUND;
623 break;
624 }
625#endif
626 }
627
628
629 done:
630 if (buffer != NULL && status != FSW_SUCCESS)
631 fsw_free(buffer);
632
633 return status;
634}
635
636typedef struct
637{
638 fsw_u32 id;
639 fsw_u32 type;
640 struct fsw_string * name;
641 fsw_u64 size;
642 fsw_u64 used;
643 fsw_u32 ctime;
644 fsw_u32 mtime;
645 fsw_u32 node_num;
646 HFSPlusExtentRecord extents;
647} file_info_t;
648
649typedef struct
650{
651 fsw_u32 cur_pos; /* current position */
652 fsw_u32 parent;
653 struct fsw_hfs_volume * vol;
654
655 struct fsw_shandle * shandle; /* this one track iterator's state */
656 file_info_t file_info;
657} visitor_parameter_t;
658
659static void hfs_fill_info(struct fsw_hfs_volume *vol, HFSPlusCatalogKey *file_key, file_info_t *file_info)
660{
661 fsw_u8 * base;
662 fsw_u16 rec_type;
663
664 /* for plain HFS "-(keySize & 1)" would be needed */
665 base = (fsw_u8*)file_key + be16_to_cpu(file_key->keyLength) + 2;
666 rec_type = be16_to_cpu(*(fsw_u16*)base);
667
668 /** @todo read additional info */
669 switch (rec_type)
670 {
671 case kHFSPlusFolderRecord:
672 {
673 HFSPlusCatalogFolder* info = (HFSPlusCatalogFolder*)base;
674
675 file_info->id = be32_to_cpu(info->folderID);
676 file_info->type = FSW_DNODE_TYPE_DIR;
677 /** @todo return number of elements, maybe use smth else */
678 file_info->size = be32_to_cpu(info->valence);
679 file_info->used = be32_to_cpu(info->valence);
680 file_info->ctime = be32_to_cpu(info->createDate);
681 file_info->mtime = be32_to_cpu(info->contentModDate);
682 break;
683 }
684 case kHFSPlusFileRecord:
685 {
686 HFSPlusCatalogFile* info = (HFSPlusCatalogFile*)base;
687 uint32_t creator = be32_to_cpu(info->userInfo.fdCreator);
688 uint32_t crtype = be32_to_cpu(info->userInfo.fdType);
689
690 file_info->id = be32_to_cpu(info->fileID);
691 file_info->type = FSW_DNODE_TYPE_FILE;
692 file_info->size = be64_to_cpu(info->dataFork.logicalSize);
693 file_info->used = LShiftU64(be32_to_cpu(info->dataFork.totalBlocks), vol->block_size_shift);
694 file_info->ctime = be32_to_cpu(info->createDate);
695 file_info->mtime = be32_to_cpu(info->contentModDate);
696 fsw_memcpy(&file_info->extents, &info->dataFork.extents,
697 sizeof file_info->extents);
698 if (creator == kHFSPlusCreator && crtype == kHardLinkFileType)
699 {
700 /* Only hard links currently supported. */
701 file_info->type = FSW_DNODE_TYPE_SYMLINK;
702 file_info->node_num = be32_to_cpu(info->bsdInfo.special.iNodeNum);
703 }
704 break;
705 }
706 case kHFSPlusFolderThreadRecord:
707 case kHFSPlusFileThreadRecord:
708 {
709 /* Do nothing. */
710 break;
711 }
712 default:
713 BP("unknown file type\n");
714 file_info->type = FSW_DNODE_TYPE_UNKNOWN;
715
716 break;
717 }
718}
719
720static int
721fsw_hfs_btree_visit_node(BTreeKey *record, void* param)
722{
723 visitor_parameter_t* vp = (visitor_parameter_t*)param;
724 fsw_u8* base = (fsw_u8*)record->rawData + be16_to_cpu(record->length16) + 2;
725 fsw_u16 rec_type = be16_to_cpu(*(fsw_u16*)base);
726 struct HFSPlusCatalogKey* cat_key = (HFSPlusCatalogKey*)record;
727 fsw_u16 name_len;
728 fsw_u16 *name_ptr;
729 fsw_u32 i;
730 struct fsw_string * file_name;
731
732 if (be32_to_cpu(cat_key->parentID) != vp->parent)
733 return -1;
734
735 /* not smth we care about */
736 if (vp->shandle->pos != vp->cur_pos++)
737 return 0;
738
739 if (rec_type == kHFSPlusFolderThreadRecord || rec_type == kHFSPlusFileThreadRecord)
740 {
741 vp->shandle->pos++;
742 return 0;
743 }
744
745 hfs_fill_info(vp->vol, cat_key, &vp->file_info);
746
747 name_len = be16_to_cpu(cat_key->nodeName.length);
748
749 file_name = vp->file_info.name;
750 file_name->len = name_len;
751 fsw_memdup(&file_name->data, &cat_key->nodeName.unicode[0], 2*name_len);
752 file_name->size = 2*name_len;
753 file_name->type = FSW_STRING_TYPE_UTF16;
754 name_ptr = (fsw_u16*)file_name->data;
755 for (i=0; i<name_len; i++)
756 {
757 name_ptr[i] = be16_to_cpu(name_ptr[i]);
758 }
759 vp->shandle->pos++;
760
761 return 1;
762}
763
764static fsw_status_t
765fsw_hfs_btree_iterate_node (struct fsw_hfs_btree * btree,
766 BTNodeDescriptor * first_node,
767 fsw_u32 first_rec,
768 int (*callback) (BTreeKey *record, void* param),
769 void * param)
770{
771 fsw_status_t status;
772 /* We modify node, so make a copy */
773 BTNodeDescriptor* node = first_node;
774 fsw_u8* buffer = NULL;
775
776 status = fsw_alloc(btree->node_size, &buffer);
777 if (status)
778 return status;
779
780 while (1)
781 {
782 fsw_u32 i;
783 fsw_u32 count = be16_to_cpu(node->numRecords);
784 fsw_u32 next_node;
785
786 /* Iterate over all records in this node. */
787 for (i = first_rec; i < count; i++)
788 {
789 int rv = callback(fsw_hfs_btree_rec (btree, node, i), param);
790
791 switch (rv)
792 {
793 case 1:
794 status = FSW_SUCCESS;
795 goto done;
796 case -1:
797 status = FSW_NOT_FOUND;
798 goto done;
799 }
800 /* if callback returned 0 - continue */
801 }
802
803 next_node = be32_to_cpu(node->fLink);
804
805 if (!next_node)
806 {
807 status = FSW_NOT_FOUND;
808 break;
809 }
810
811 if (fsw_hfs_read_file (btree->file,
812 next_node * btree->node_size,
813 btree->node_size, buffer) <= 0)
814 {
815 status = FSW_VOLUME_CORRUPTED;
816 return 1;
817 }
818
819 node = (BTNodeDescriptor*)buffer;
820 first_rec = 0;
821 }
822 done:
823 if (buffer)
824 fsw_free(buffer);
825
826 return status;
827}
828
829#if 0
830void deb(fsw_u16* p, int len, int swap)
831{
832 int i;
833 for (i=0; i<len; i++)
834 {
835 printf("%c", swap ? be16_to_cpu(p[i]) : p[i]);
836 }
837 printf("\n");
838}
839#endif
840
841static int
842fsw_hfs_cmp_extkey(BTreeKey* key1, BTreeKey* key2)
843{
844 HFSPlusExtentKey* ekey1 = (HFSPlusExtentKey*)key1;
845 HFSPlusExtentKey* ekey2 = (HFSPlusExtentKey*)key2;
846 int result;
847
848 /* First key is read from the FS data, second is in-memory in CPU endianess */
849 result = be32_to_cpu(ekey1->fileID) - ekey2->fileID;
850
851 if (result)
852 return result;
853
854 result = ekey1->forkType - ekey2->forkType;
855
856 if (result)
857 return result;
858
859 result = be32_to_cpu(ekey1->startBlock) - ekey2->startBlock;
860 return result;
861}
862
863static int
864fsw_hfs_cmp_catkey (BTreeKey *key1, BTreeKey *key2)
865{
866 HFSPlusCatalogKey *ckey1 = (HFSPlusCatalogKey*)key1;
867 HFSPlusCatalogKey *ckey2 = (HFSPlusCatalogKey*)key2;
868
869 int apos, bpos, lc;
870 fsw_u16 ac, bc;
871 fsw_u32 parentId1;
872 int key1Len;
873 fsw_u16 *p1;
874 fsw_u16 *p2;
875
876 parentId1 = be32_to_cpu(ckey1->parentID);
877
878 if (parentId1 > ckey2->parentID)
879 return 1;
880 if (parentId1 < ckey2->parentID)
881 return -1;
882
883 p1 = &ckey1->nodeName.unicode[0];
884 p2 = &ckey2->nodeName.unicode[0];
885 key1Len = be16_to_cpu (ckey1->nodeName.length);
886 apos = bpos = 0;
887
888 while(1)
889 {
890 /* get next valid character from ckey1 */
891 for (lc = 0; lc == 0 && apos < key1Len; apos++) {
892 ac = be16_to_cpu(p1[apos]);
893 lc = ac;
894 };
895 ac = (fsw_u16)lc;
896
897 /* get next valid character from ckey2 */
898 for (lc = 0; lc == 0 && bpos < ckey2->nodeName.length; bpos++) {
899 bc = p2[bpos];
900 lc = bc;
901 };
902 bc = (fsw_u16)lc;
903
904 if (ac != bc || (ac == 0 && bc == 0))
905 return ac - bc;
906 }
907}
908
909static int
910fsw_hfs_cmpi_catkey (BTreeKey *key1, BTreeKey *key2)
911{
912 HFSPlusCatalogKey *ckey1 = (HFSPlusCatalogKey*)key1;
913 HFSPlusCatalogKey *ckey2 = (HFSPlusCatalogKey*)key2;
914
915 int apos, bpos, lc;
916 fsw_u16 ac, bc;
917 fsw_u32 parentId1;
918 int key1Len;
919 fsw_u16 *p1;
920 fsw_u16 *p2;
921
922 parentId1 = be32_to_cpu(ckey1->parentID);
923
924 if (parentId1 > ckey2->parentID)
925 return 1;
926 if (parentId1 < ckey2->parentID)
927 return -1;
928
929 key1Len = be16_to_cpu (ckey1->nodeName.length);
930
931 if (key1Len == 0 && ckey2->nodeName.length == 0)
932 return 0;
933
934 p1 = &ckey1->nodeName.unicode[0];
935 p2 = &ckey2->nodeName.unicode[0];
936
937 apos = bpos = 0;
938
939 while(1)
940 {
941 /* get next valid (non-zero) character from ckey1 */
942 for (lc = 0; lc == 0 && apos < key1Len; apos++) {
943 ac = be16_to_cpu(p1[apos]);
944 lc = fsw_to_lower(ac); /* NB: 0x0000 is translated to 0xffff */
945 };
946 ac = (fsw_u16)lc;
947
948 /* get next valid (non-zero) character from ckey2 */
949 for (lc = 0; lc == 0 && bpos < ckey2->nodeName.length; bpos++) {
950 bc = p2[bpos];
951 lc = fsw_to_lower(bc); /* NB: 0x0000 is translated to 0xffff */
952 };
953 bc = (fsw_u16)lc;
954
955 if (ac != bc || (ac == 0 && bc == 0))
956 return ac - bc;
957 }
958}
959
960/**
961 * Retrieve file data mapping information. This function is called by the core when
962 * fsw_shandle_read needs to know where on the disk the required piece of the file's
963 * data can be found. The core makes sure that fsw_hfs_dnode_fill has been called
964 * on the dnode before. Our task here is to get the physical disk block number for
965 * the requested logical block number.
966 */
967
968static fsw_status_t fsw_hfs_get_extent(struct fsw_hfs_volume * vol,
969 struct fsw_hfs_dnode * dno,
970 struct fsw_extent * extent)
971{
972 fsw_status_t status;
973 fsw_u32 lbno;
974 HFSPlusExtentRecord *exts;
975 BTNodeDescriptor *node = NULL;
976
977 extent->type = FSW_EXTENT_TYPE_PHYSBLOCK;
978 extent->log_count = 1;
979 lbno = extent->log_start;
980
981 /* we only care about data forks atm, do we? */
982 exts = &dno->extents;
983
984 while (1)
985 {
986 struct HFSPlusExtentKey* key;
987 struct HFSPlusExtentKey overflowkey;
988 fsw_u32 ptr;
989 fsw_u32 phys_bno;
990
991 if (fsw_hfs_find_block(exts, &lbno, &phys_bno))
992 {
993 extent->phys_start = phys_bno + vol->emb_block_off;
994 status = FSW_SUCCESS;
995 break;
996 }
997
998
999 /* Find appropriate overflow record */
1000 overflowkey.fileID = dno->g.dnode_id;
1001 overflowkey.startBlock = extent->log_start - lbno;
1002
1003 if (node != NULL)
1004 {
1005 fsw_free(node);
1006 node = NULL;
1007 }
1008
1009 status = fsw_hfs_btree_search (&vol->extents_tree,
1010 (BTreeKey*)&overflowkey,
1011 fsw_hfs_cmp_extkey,
1012 &node, &ptr);
1013 if (status)
1014 break;
1015
1016 key = (struct HFSPlusExtentKey *)
1017 fsw_hfs_btree_rec (&vol->extents_tree, node, ptr);
1018 exts = (HFSPlusExtentRecord*) (key + 1);
1019 }
1020
1021 if (node != NULL)
1022 fsw_free(node);
1023
1024 return status;
1025}
1026
1027static const fsw_u16* g_blacklist[] =
1028{
1029 //L"AppleIntelCPUPowerManagement.kext",
1030 NULL
1031};
1032
1033
1034//#define HFS_FILE_INJECTION
1035
1036#ifdef HFS_FILE_INJECTION
1037static struct
1038{
1039 const fsw_u16* path;
1040 const fsw_u16* name;
1041} g_injectList[] =
1042{
1043 {
1044 L"/System/Library/Extensions",
1045 L"ApplePS2Controller.kext"
1046 },
1047 {
1048 NULL,
1049 NULL
1050 }
1051};
1052#endif
1053
1054static fsw_status_t
1055create_hfs_dnode(struct fsw_hfs_dnode * dno,
1056 file_info_t * file_info,
1057 struct fsw_hfs_dnode ** child_dno_out)
1058{
1059 fsw_status_t status;
1060 struct fsw_hfs_dnode * baby;
1061
1062 status = fsw_dnode_create(dno, file_info->id, file_info->type,
1063 file_info->name, &baby);
1064 if (status)
1065 return status;
1066
1067 baby->g.size = file_info->size;
1068 baby->used_bytes = file_info->used;
1069 baby->ctime = file_info->ctime;
1070 baby->mtime = file_info->mtime;
1071 baby->node_num = file_info->node_num;
1072
1073
1074 /* Fill-in extents info */
1075 if (file_info->type == FSW_DNODE_TYPE_FILE)
1076 {
1077 fsw_memcpy(baby->extents, &file_info->extents, sizeof file_info->extents);
1078 }
1079
1080 *child_dno_out = baby;
1081
1082 return FSW_SUCCESS;
1083}
1084
1085
1086/**
1087 * Lookup a directory's child dnode by name. This function is called on a directory
1088 * to retrieve the directory entry with the given name. A dnode is constructed for
1089 * this entry and returned. The core makes sure that fsw_hfs_dnode_fill has been called
1090 * and the dnode is actually a directory.
1091 */
1092
1093static fsw_status_t fsw_hfs_dir_lookup(struct fsw_hfs_volume * vol,
1094 struct fsw_hfs_dnode * dno,
1095 struct fsw_string * lookup_name,
1096 struct fsw_hfs_dnode ** child_dno_out)
1097{
1098 fsw_status_t status;
1099 struct HFSPlusCatalogKey catkey;
1100 fsw_u32 ptr;
1101 BTNodeDescriptor * node = NULL;
1102 struct fsw_string rec_name;
1103 int free_data = 0, i;
1104 HFSPlusCatalogKey* file_key;
1105 file_info_t file_info;
1106
1107
1108 fsw_memzero(&file_info, sizeof file_info);
1109 file_info.name = &rec_name;
1110
1111 catkey.parentID = dno->g.dnode_id;
1112 catkey.nodeName.length = (fsw_u16)lookup_name->len;
1113
1114 /* no need to allocate anything */
1115 if (lookup_name->type == FSW_STRING_TYPE_UTF16)
1116 {
1117 fsw_memcpy(catkey.nodeName.unicode, lookup_name->data, lookup_name->size);
1118 rec_name = *lookup_name;
1119 } else
1120 {
1121 status = fsw_strdup_coerce(&rec_name, FSW_STRING_TYPE_UTF16, lookup_name);
1122 /* nothing allocated so far */
1123 if (status)
1124 goto done;
1125 free_data = 1;
1126 fsw_memcpy(catkey.nodeName.unicode, rec_name.data, rec_name.size);
1127 }
1128
1129 /* Dirty hack: blacklisting of certain files on FS driver level */
1130 for (i = 0; g_blacklist[i]; i++)
1131 {
1132 if (fsw_memeq(g_blacklist[i], catkey.nodeName.unicode, catkey.nodeName.length*2))
1133 {
1134 DPRINT2("Blacklisted %s\n", g_blacklist[i]);
1135 status = FSW_NOT_FOUND;
1136 goto done;
1137 }
1138 }
1139
1140#ifdef HFS_FILE_INJECTION
1141 if (fsw_hfs_inject(vol,
1142 dno,
1143 catkey.nodeName.unicode,
1144 catkey.nodeName.length,
1145 &file_info))
1146 {
1147 status = FSW_SUCCESS;
1148 goto create;
1149 }
1150#endif
1151
1152 catkey.keyLength = (fsw_u16)(6 + rec_name.len);
1153
1154 status = fsw_hfs_btree_search (&vol->catalog_tree,
1155 (BTreeKey*)&catkey,
1156 vol->case_sensitive ?
1157 fsw_hfs_cmp_catkey : fsw_hfs_cmpi_catkey,
1158 &node, &ptr);
1159 if (status)
1160 goto done;
1161
1162 file_key = (HFSPlusCatalogKey *)fsw_hfs_btree_rec (&vol->catalog_tree, node, ptr);
1163 hfs_fill_info(vol, file_key, &file_info);
1164
1165#ifdef HFS_FILE_INJECTION
1166create:
1167#endif
1168 status = create_hfs_dnode(dno, &file_info, child_dno_out);
1169 if (status)
1170 goto done;
1171
1172done:
1173
1174 if (node != NULL)
1175 fsw_free(node);
1176
1177 if (free_data)
1178 fsw_strfree(&rec_name);
1179
1180 return status;
1181}
1182
1183/**
1184 * Get the next directory entry when reading a directory. This function is called during
1185 * directory iteration to retrieve the next directory entry. A dnode is constructed for
1186 * the entry and returned. The core makes sure that fsw_hfs_dnode_fill has been called
1187 * and the dnode is actually a directory. The shandle provided by the caller is used to
1188 * record the position in the directory between calls.
1189 */
1190
1191static fsw_status_t fsw_hfs_dir_read(struct fsw_hfs_volume *vol,
1192 struct fsw_hfs_dnode *dno,
1193 struct fsw_shandle *shand,
1194 struct fsw_hfs_dnode **child_dno_out)
1195{
1196 fsw_status_t status;
1197 struct HFSPlusCatalogKey catkey;
1198 fsw_u32 ptr;
1199 BTNodeDescriptor * node = NULL;
1200
1201 visitor_parameter_t param;
1202 struct fsw_string rec_name;
1203
1204 catkey.parentID = dno->g.dnode_id;
1205 catkey.nodeName.length = 0;
1206
1207 fsw_memzero(&param, sizeof(param));
1208
1209 rec_name.type = FSW_STRING_TYPE_EMPTY;
1210 param.file_info.name = &rec_name;
1211
1212 status = fsw_hfs_btree_search (&vol->catalog_tree,
1213 (BTreeKey*)&catkey,
1214 vol->case_sensitive ?
1215 fsw_hfs_cmp_catkey : fsw_hfs_cmpi_catkey,
1216 &node, &ptr);
1217 if (status)
1218 goto done;
1219
1220 /* Iterator updates shand state */
1221 param.vol = vol;
1222 param.shandle = shand;
1223 param.parent = dno->g.dnode_id;
1224 param.cur_pos = 0;
1225 status = fsw_hfs_btree_iterate_node (&vol->catalog_tree,
1226 node,
1227 ptr,
1228 fsw_hfs_btree_visit_node,
1229 &param);
1230 if (status)
1231 goto done;
1232
1233 status = create_hfs_dnode(dno, &param.file_info, child_dno_out);
1234
1235 if (status)
1236 goto done;
1237
1238 done:
1239 fsw_strfree(&rec_name);
1240
1241 return status;
1242}
1243
1244static const char hfs_priv_prefix[] = "/\0\0\0\0HFS+ Private Data/" HFS_INODE_PREFIX;
1245
1246/**
1247 * Get the target path of a symbolic link. This function is called when a symbolic
1248 * link needs to be resolved. The core makes sure that the fsw_hfs_dnode_fill has been
1249 * called on the dnode and that it really is a symlink.
1250 *
1251 */
1252static fsw_status_t fsw_hfs_readlink(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
1253 struct fsw_string *link_target)
1254{
1255 fsw_status_t status;
1256
1257 if (dno->node_num)
1258 {
1259 struct fsw_string tgt;
1260
1261 DPRINT2("hfs_readlink: %d\n", dno->node_num);
1262 tgt.type = FSW_STRING_TYPE_ISO88591;
1263 tgt.size = sizeof(hfs_priv_prefix) + 10;
1264 tgt.len = tgt.size - 1;
1265 status = fsw_alloc(tgt.size, &tgt.data);
1266 if (!status)
1267 {
1268 char *str = tgt.data;
1269 fsw_memcpy(tgt.data, hfs_priv_prefix, sizeof(hfs_priv_prefix)); // null chars here!
1270#ifdef HOST_POSIX
1271 tgt.len = sprintf(&str[sizeof(hfs_priv_prefix) - 1], "%d", dno->node_num);
1272#else
1273 tgt.len = (int)AsciiSPrint(&str[sizeof(hfs_priv_prefix) - 1], tgt.len, "%d", dno->node_num);
1274#endif
1275 tgt.len += sizeof(hfs_priv_prefix) - 1;
1276 status = fsw_strdup_coerce(link_target, vol->g.host_string_type, &tgt);
1277 fsw_strfree(&tgt);
1278 }
1279 return status;
1280 }
1281
1282 return FSW_UNSUPPORTED;
1283}
1284
1285static int fsw_hfs_btree_find_id(BTreeKey *record, void* param)
1286{
1287 visitor_parameter_t *vp = (visitor_parameter_t*)param;
1288 fsw_u8 *base = (fsw_u8*)record->rawData + be16_to_cpu(record->length16) + 2;
1289 fsw_u16 rec_type = be16_to_cpu(*(fsw_u16*)base);
1290 struct HFSPlusCatalogKey *cat_key = (HFSPlusCatalogKey*)record;
1291 fsw_u16 name_len;
1292 fsw_u16 *name_ptr;
1293 fsw_u16 *old_ptr;
1294 int i;
1295 struct fsw_string *file_name;
1296 struct fsw_string new_name;
1297
1298 if (be32_to_cpu(cat_key->parentID) != vp->parent)
1299 return -1;
1300
1301 if (!vp->cur_pos)
1302 vp->cur_pos = be32_to_cpu(cat_key->parentID);
1303
1304 /* Not what we're looking for. */
1305 if (vp->file_info.id != vp->cur_pos++)
1306 return 0;
1307
1308 if (rec_type == kHFSPlusFolderThreadRecord || rec_type == kHFSPlusFileThreadRecord)
1309 {
1310 HFSPlusCatalogThread *thread;
1311
1312 thread = (HFSPlusCatalogThread *)base;
1313 vp->file_info.id = be32_to_cpu(thread->parentID);
1314
1315 name_len = be16_to_cpu(thread->nodeName.length);
1316
1317 file_name = vp->file_info.name;
1318
1319 new_name.len = name_len + 1 + file_name->len;
1320 new_name.size = sizeof(fsw_u16) * new_name.len;
1321 fsw_alloc(new_name.size, &new_name.data);
1322 name_ptr = (fsw_u16*)new_name.data;
1323 /* Tack on path separator. */
1324#ifdef HOST_POSIX
1325 name_ptr[0] = L'/';
1326#else
1327 name_ptr[0] = L'\\';
1328#endif
1329 /* Copy over + swap the new path component. */
1330 for (i = 0; i < name_len; i++)
1331 name_ptr[i + 1] = be16_to_cpu(thread->nodeName.unicode[i]);
1332 if (file_name->len) {
1333 /* Tack on the previous path. */
1334 old_ptr = (fsw_u16*)file_name->data;
1335 for (++i; i < new_name.len; i++ )
1336 name_ptr[i] = *old_ptr++;
1337 }
1338
1339 fsw_free(file_name->data);
1340 file_name->len = new_name.len;
1341 file_name->size = new_name.size;
1342 file_name->data = new_name.data;
1343 file_name->type = FSW_STRING_TYPE_UTF16;
1344
1345 /* This was it, stop iterating. */
1346 return 1;
1347 }
1348
1349 return 0;
1350}
1351
1352/**
1353 * Obtain the full path of a file given its CNID (Catalog Node ID), i.e.
1354 * file or folder ID.
1355 *
1356 */
1357static fsw_status_t fsw_hfs_get_path_from_cnid(struct fsw_hfs_volume *vol, fsw_u32 cnid, struct fsw_string *path)
1358{
1359 fsw_status_t status = FSW_UNSUPPORTED;
1360 fsw_u32 ptr;
1361 BTNodeDescriptor *node = NULL;
1362 struct HFSPlusCatalogKey catkey;
1363 visitor_parameter_t param;
1364 struct fsw_string rec_name;
1365
1366 /* The CNID must be a valid user node ID. */
1367 if (cnid < kHFSFirstUserCatalogNodeID)
1368 goto done;
1369
1370 fsw_memzero(&param, sizeof(param));
1371 fsw_memzero(&rec_name, sizeof(rec_name));
1372
1373 catkey.parentID = cnid;
1374 catkey.nodeName.length = 0;
1375
1376 param.vol = vol;
1377 param.shandle = NULL;
1378 param.file_info.id = cnid;
1379 param.parent = cnid;
1380 param.cur_pos = 0;
1381
1382 do {
1383 rec_name.type = FSW_STRING_TYPE_EMPTY;
1384 param.file_info.name = &rec_name;
1385
1386 status = fsw_hfs_btree_search(&vol->catalog_tree, (BTreeKey*)&catkey,
1387 vol->case_sensitive ? fsw_hfs_cmp_catkey : fsw_hfs_cmpi_catkey,
1388 &node, &ptr);
1389 if (status)
1390 goto done;
1391
1392 status = fsw_hfs_btree_iterate_node(&vol->catalog_tree, node, ptr,
1393 fsw_hfs_btree_find_id, &param);
1394 if (status)
1395 goto done;
1396
1397 param.parent = param.file_info.id;
1398 param.cur_pos = 0;
1399
1400 catkey.parentID = param.file_info.id;
1401 catkey.nodeName.length = 0;
1402 } while (catkey.parentID >= kHFSFirstUserCatalogNodeID);
1403
1404 /* If everything worked out , the final parent ID will be the root folder ID. */
1405 if (catkey.parentID == kHFSRootFolderID)
1406 {
1407 *path = *param.file_info.name;
1408 status = FSW_SUCCESS;
1409 }
1410 else
1411 status = FSW_NOT_FOUND;
1412
1413done:
1414 return status;
1415}
1416
1417/**
1418 * Get the path of the HFS+ blessed file, if any.
1419 *
1420 */
1421/*static*/ fsw_status_t fsw_hfs_get_blessed_file(struct fsw_hfs_volume *vol, struct fsw_string *path)
1422{
1423 fsw_status_t status = FSW_UNSUPPORTED;
1424 fsw_u32 bfile_id;
1425 fsw_u32 *finderinfo;
1426
1427 finderinfo = (fsw_u32 *)&vol->primary_voldesc->finderInfo;
1428 bfile_id = finderinfo[1];
1429 bfile_id = be32_to_cpu(bfile_id);
1430
1431 DPRINT2("Blessed file ID: %u\n", bfile_id);
1432
1433 status = fsw_hfs_get_path_from_cnid(vol, bfile_id, path);
1434#ifdef HOST_POSIX
1435 if (!status)
1436 {
1437 fsw_u16 *name_ptr;
1438 int i;
1439
1440 printf("Blessed file: ");
1441 name_ptr = (fsw_u16*)path->data;
1442 for (i = 0; i < path->len; i++)
1443 printf("%c", name_ptr[i]);
1444 printf("\n");
1445 }
1446#endif
1447
1448 return status;
1449}
1450
1451// EOF
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use