VirtualBox

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

Last change on this file since 93115 was 93115, checked in by vboxsync, 2 years ago

scm --update-copyright-year

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

© 2023 Oracle
ContactPrivacy policyTerms of Use