OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
fsw_hfsplus.c
Go to the documentation of this file.
1
17#include "fsw_hfsplus.h"
18
19// --------------------------------------------------------
20// HFS+ FSW Methods declaration
21//
22
23/* Mount an HFS+ volume. Read volume header (equivalent of superblock),
24 * and set up dnodes for the root folder and B-Tree file(s).
25 * Return FSW_SUCCESS or error code.
26 */
27static fsw_status_t
28fsw_hfsplus_vol_mount(struct fsw_hfsplus_volume *v);
29
30/* Free the volume data structure. Called by the core after an unmount or
31 * unsuccessful mount, to release the memory used by the file system type
32 * specific part of the volume structure.
33 */
34static void
35fsw_hfsplus_vol_free(struct fsw_hfsplus_volume *v);
36
37/* Get in-depth information on a volume.
38 */
39static fsw_status_t
40fsw_hfsplus_vol_stat(struct fsw_hfsplus_volume *v, struct fsw_volume_stat *s);
41
42/* Get full information on a dnode from disk. This function is called by
43 * the core whenever it needs to access fields in the dnode structure that
44 * may not be filled immediately upon creation of the dnode.
45 */
46static fsw_status_t
47fsw_hfsplus_dno_fill(struct fsw_hfsplus_volume *v, struct fsw_hfsplus_dnode *d);
48
49/* Free the dnode data structure. Called by the core when deallocating a dnode
50 * structure to release the memory used by the file system type specific part
51 * of the dnode structure.
52 */
53static void
54fsw_hfsplus_dno_free(struct fsw_hfsplus_volume *v, struct fsw_hfsplus_dnode *d);
55
56/* Get in-depth dnode information. The core ensures fsw_hfsplus_dno_fill()
57 * has been called on the dnode before this function is called. Note that some
58 * data is not directly stored into the structure, but passed to a host-specific
59 * callback that converts it to the host-specific format.
60 */
61static fsw_status_t
62fsw_hfsplus_dno_stat(struct fsw_hfsplus_volume *v, struct fsw_hfsplus_dnode *d,
63 struct fsw_dnode_stat *s);
64
65/* Retrieve file data mapping information. This function is called by
66 * the core when fsw_shandle_read needs to know where on the disk the
67 * required piece of the file's data can be found. The core makes sure
68 * that fsw_hfsplus_dno_fill has been called on the dnode before.
69 * Our task here is to get the physical disk block number for the
70 * requested logical block number.
71 * NOTE: logical and physical block sizes are the same (see mount method).
72 */
73static fsw_status_t
74fsw_hfsplus_get_ext(struct fsw_hfsplus_volume *v, struct fsw_hfsplus_dnode *d,
75 struct fsw_extent *e);
76
77
78/* Lookup a directory's child dnode by name. This function is called on a
79 * directory to retrieve the directory entry with the given name. A dnode
80 * is constructed for this entry and returned. The core makes sure that
81 * fsw_hfsplus_dno_fill has been called and the dnode is actually a directory.
82 */
83static fsw_status_t
84fsw_hfsplus_dir_get(struct fsw_hfsplus_volume *v, struct fsw_hfsplus_dnode *d,
85 struct fsw_string *name, struct fsw_hfsplus_dnode **d_out);
86
87/* Get the next directory entry when reading a directory. This function is
88 * called during directory iteration to retrieve the next directory entry.
89 * A dnode is constructed for the entry and returned. The core makes sure
90 * that fsw_hfsplus_dno_fill has been called and the dnode is actually a
91 * directory. The shandle provided by the caller is used to record the
92 * position in the directory between calls.
93 */
94static fsw_status_t
95fsw_hfsplus_dir_read(struct fsw_hfsplus_volume *v, struct fsw_hfsplus_dnode *d,
96 struct fsw_shandle *sh, struct fsw_hfsplus_dnode **d_out);
97
98/* Get the target path of a symbolic link. This function is called when a
99 * symbolic link needs to be resolved. The core makes sure that the
100 * fsw_hfsplus_dno_fill has been called on the dnode and that it really is a
101 * symlink.
102 */
103static fsw_status_t
104fsw_hfsplus_readlink(struct fsw_hfsplus_volume *v, struct fsw_hfsplus_dnode *d,
105 struct fsw_string *lnk_tgt);
113static fsw_status_t
114fsw_hfsplus_get_bless_info(struct fsw_hfsplus_volume *vol, /* in */
115 fsw_u32 bless_type, /* in */
116 struct fsw_hfsplus_dnode **dno_out /* out */);
117
122 { FSW_STRING_TYPE_ISO88591, 4, 4, "hfsplus" },
123 sizeof(struct fsw_hfsplus_volume), sizeof(struct fsw_hfsplus_dnode),
124 fsw_hfsplus_vol_mount, fsw_hfsplus_vol_free, fsw_hfsplus_vol_stat,
125 fsw_hfsplus_dno_fill, fsw_hfsplus_dno_free, fsw_hfsplus_dno_stat,
126 fsw_hfsplus_get_ext, fsw_hfsplus_dir_get, fsw_hfsplus_dir_read,
127 fsw_hfsplus_readlink, fsw_hfsplus_get_bless_info
128};
129
130// -------------------------------------------------------------------
131// Other declarations
132
133/* Given dnode 'd' and offset 'pos' into the data file it represents,
134 * retrieve 'len' bytes of data into buffer 'buf';
135 * Return FSW_SUCCESS or error code.
136 */
137static fsw_status_t
138fsw_hfsplus_read(struct fsw_hfsplus_dnode *d, fsw_u64 pos,
139 fsw_u32 len, void *buf);
140
141/* Given the volume being mounted ('v'), and the ID & fork data of the B-Tree
142 * file being set up ('dn_id' and 'f', respectively), populate a cached,
143 * in-memory record of the B-Tree file at the location pointed to by 'btp';
144 * Return FSW_SUCCESS or error code.
145 */
146static fsw_status_t
147fsw_hfsplus_btf_setup(struct fsw_hfsplus_volume *v,
148 fsw_u32 dn_id, HFSPlusForkData *f,
149 struct fsw_hfsplus_dnode **btp);
150
151/* HFS+ to Posix timestamp conversion
152 */
153static fsw_u32
154fsw_hfsplus_posix_time(fsw_u32 t);
155
156/* Given a B-Tree node pointed to by 'btnode', with node size 'size',
157 * locate the record given by its record number 'rnum';
158 * Return a pointer to the B-Tree key at the beginning of the record.
159 */
160static HFSPlusBTKey *
161fsw_hfsplus_btnode_get_rec(BTNodeDescriptor* btnode, fsw_u16 size, fsw_u32 rnum);
162
163/* Given a B-Tree record pointer 'k', return a pointer to the data
164 * immediately following the key record; IOW, skip the key record which
165 * prefixes the record data payload.
166 */
167static void *
168fsw_hfsplus_bt_rec_skip_key(HFSPlusBTKey *k);
169
170/* Return the child node number immediately following the key record 'k' of
171 * an index node
172 */
173static fsw_u32
174fsw_hfsplus_bt_idx_get_child(HFSPlusBTKey *k);
175
185static fsw_status_t
186fsw_hfsplus_dnode_create_minimal(struct fsw_hfsplus_volume *v /* in */,
187 fsw_u32 parent_id /* in */,
188 fsw_u32 dnode_id /* in */,
189 struct fsw_string *name /* in */,
190 struct fsw_hfsplus_dnode **d_out /* out */);
191
199static void
200fsw_hfsplus_dnode_complete(HFSPlusCatalogRecord *rec /* in */,
201 struct fsw_hfsplus_dnode *parent /* in */,
202 struct fsw_hfsplus_dnode *d_out /* out */);
203
212static fsw_status_t
213fsw_hfsplus_dnode_create_full(HFSPlusCatalogRecord *rec /* in */,
214 struct fsw_hfsplus_dnode *parent /* in */,
215 struct fsw_string *name /* in */,
216 struct fsw_hfsplus_dnode **d_out /* out */);
217
225static int
226fsw_hfsplus_thread_cmp(HFSPlusBTKey *tk /* in */, HFSPlusBTKey *sk /* in */);
227
235static int
236fsw_hfsplus_cat_cmp(HFSPlusBTKey *tk /* in */, HFSPlusBTKey *sk /* in */);
237
238
246static fsw_status_t
247fsw_hfsplus_fswstr2unistr(HFSUniStr255* t /* out */,
248 struct fsw_string* src /* in */);
249
250/* Search an HFS+ special file's B-Tree (given by 'bt'), for a search key
251 * matching 'sk', using comparison procedure 'k_cmp' to determine when a key
252 * match occurs;
253 * Finish by filling a caller-provided B-Tree node buffer ('btnode'), and returning
254 * record number of the matching record inside 'btnode', via 'rec_num';
255 * On error, set fsw_status_t return code acoordingly.
256 *
257 * NOTE: A HFS+ volume has a few "special" files, linked directly from the
258 * volume header. For the purpose of this driver, we mainly care about
259 * two of them: the "catalog" and "extents" files. All of these files
260 * are organized as B-Tree structures. This means that, overlaid on
261 * top of the linear span of each file there is an array of nodes of
262 * a given size (node_size), internally cross-linked with "pointers"
263 * to parent/child/sibling nodes, which are essentially the "index"
264 * (or 'node-number') of the target node in this overlaid array.
265 * Ultimately, (node-number * node-size) is a byte offset into the
266 * file, to the location where the referenced node's data begins.
267 * Each B-Tree file's "dnode" information is available in the HFS+
268 * volume header. The node at the very beginning of each file (at
269 * index or node-number == 0) contains a "header node", which provides
270 * the 'node-number' of the B-Tree's "root" node, as well as the
271 * 'node-size' of all nodes in that B-Tree file.
272 */
273static fsw_status_t
274fsw_hfsplus_bt_search(struct fsw_hfsplus_dnode *bt, /* in */
275 HFSPlusBTKey *sk, /* in */
276 k_cmp_t k_cmp, /* in */
277 BTNodeDescriptor *btnode, /* out */
278 fsw_u32 *rec_num /* out */);
279
280/* Compare unsigned integers 'a' and 'b';
281 * Return -1/0/1 if 'a' is less/equal/greater than 'b'.
282 */
283static int
284fsw_hfsplus_int_cmp(fsw_u32 a, fsw_u32 b);
285
286/* Basic latin unicode lowercase
287 */
288static fsw_u16
289fsw_hfsplus_ucblatin_tolower(fsw_u16 c);
290
300static fsw_status_t
301fsw_hfsplus_btree_get_rec(struct fsw_hfsplus_dnode *bt, /* in */
302 fsw_u32 parent_id, /* in */
303 BTNodeDescriptor *btnode, /* in */ /* out */
304 fsw_u32 *rec_num, /* in */ /* out */
305 fsw_u64 *rec_skip /* in */ /* out */);
306
315static fsw_status_t
316fsw_hfsplus_dnid2thread(struct fsw_hfsplus_volume *v /* in */,
317 fsw_u32 dnid /* in */,
318 BTNodeDescriptor *btnode /* in */ /* out */,
319 HFSPlusCatalogThread **thread_out /* out */);
320
330static fsw_status_t
331fsw_hfsplus_thread2dnode(struct fsw_hfsplus_volume *v /* in */,
332 HFSPlusCatalogThread *thread /* in */,
333 BTNodeDescriptor *btnode /* in */ /* out */,
334 struct fsw_hfsplus_dnode **d_out /* out */);
335
344static fsw_status_t
345fsw_hfsplus_dnid2dnode(struct fsw_hfsplus_volume *v /* in */,
346 fsw_u32 dnid /* in */,
347 struct fsw_hfsplus_dnode **d_out /* out */);
355static fsw_status_t
356fsw_hfsplus_bless_type2dnid(struct fsw_hfsplus_volume *vol, /* in */
357 fsw_u32 bless_type, /* in */
358 fsw_u32 *dnid /* out */);
359
367static fsw_status_t
368fsw_hfsplus_itoa(fsw_u32 num, char** dest, int* len);
369
379static fsw_status_t
380fsw_hfsplus_sconcat(const char *const s1, int len1, const char *const s2, int len2, char **dest);
381
382// ---------------------------------------------------------------------
383
384
385static fsw_status_t
386fsw_hfsplus_read(struct fsw_hfsplus_dnode *d, fsw_u64 pos,
387 fsw_u32 len, void *buf)
388{
389 struct fsw_shandle sh;
390 fsw_u32 buflen;
391 fsw_status_t status;
392
393 status = fsw_shandle_open(d, &sh);
394 if (status)
395 return status;
396
397 sh.pos = pos;
398 buflen = len;
399 status = fsw_shandle_read(&sh, &buflen, buf);
400 if (!status && buflen != len)
401 status = FSW_IO_ERROR;
402
404 return status;
405}
406
407static fsw_status_t
408fsw_hfsplus_btf_setup(struct fsw_hfsplus_volume *v,
409 fsw_u32 dn_id, HFSPlusForkData *f,
410 struct fsw_hfsplus_dnode **btp)
411{
412 BTHeaderRec hdr_rec;
413 fsw_status_t status;
414
415 status = fsw_dnode_create_root(v, dn_id, btp);
416 if (status)
417 return status;
418
419 (*btp)->g.size = fsw_u64_be_swap(f->logicalSize);
420 fsw_memcpy((*btp)->extents, f->extents, sizeof(HFSPlusExtentRecord));
421
422 // read header record (from node 0, immediately past the node descriptor)
423 status = fsw_hfsplus_read(*btp, sizeof(BTNodeDescriptor),
424 sizeof(BTHeaderRec), &hdr_rec);
425 if (status)
426 return status;
427
428 // grab root node index and node size from header record
429 (*btp)->bt_root = fsw_u32_be_swap(hdr_rec.rootNode);
430 (*btp)->bt_ndsz = fsw_u16_be_swap(hdr_rec.nodeSize);
431
432 return FSW_SUCCESS;
433}
434
435static fsw_status_t
436fsw_hfsplus_vol_mount(struct fsw_hfsplus_volume *v)
437{
438 void *buf;
439 fsw_u32 bs;
440 BTNodeDescriptor *btnode;
441 HFSPlusCatalogThread *thread;
442 struct fsw_string label;
443 fsw_status_t status;
444
445 // allocate memory for vol. header
446 status = fsw_alloc(sizeof(HFSPlusVolumeHeader), &v->vh);
447 if (status)
448 return status;
449
450 // read vol. header into buffer
452 status = fsw_block_get(v, kMasterDirectoryBlock, 0, &buf);
453 if (status)
454 return status;
455 fsw_memcpy(v->vh, buf, sizeof(HFSPlusVolumeHeader));
457
458 // check vol. header
459 if (fsw_u16_be_swap(v->vh->signature) != kHFSPlusSigWord)
460 return FSW_UNSUPPORTED;
461
462 // use block size specified by vol. header
463 bs = fsw_u32_be_swap(v->vh->blockSize);
464 fsw_set_blocksize(v, bs, bs);
465
466 // set up catalog B-Tree file:
467 status = fsw_hfsplus_btf_setup(v, kHFSCatalogFileID, &v->vh->catalogFile,
468 &v->catf);
469 if (status)
470 return status;
471
472 // set up root folder:
474 if (status)
475 return status;
476
477 // Get volume label from kHFSRootFolderID thread record
478 // Not-readed volume label is not fatal error,
479 // we can proceed without it leaving label empty
480 status = fsw_alloc(v->catf->bt_ndsz, &btnode);
481 if (!status) {
482 status = fsw_hfsplus_dnid2thread(v, kHFSRootFolderID, btnode, &thread);
483 if (status)
484 goto label_read_fail;
485
486 label.len = fsw_u16_be_swap(thread->nodeName.length);
487 label.size = sizeof(fsw_u16) * label.len;
488 label.data = thread->nodeName.unicode;
490
491 status = fsw_strdup_coerce(&v->g.label, FSW_STRING_TYPE_UTF16, &label);
492 if (status)
493 goto label_read_fail;
494
495 fsw_free(btnode);
496 }
497
498 return FSW_SUCCESS;
499
500// If volume label reading failed we leave it empty and return SUCCESS status
501label_read_fail:
502 fsw_free(btnode);
504 return FSW_SUCCESS;
505
506}
507
508static void
509fsw_hfsplus_vol_free(struct fsw_hfsplus_volume *v)
510{
511 if (v->vh)
512 fsw_free(v->vh);
513 if (v->catf)
514 fsw_dnode_release((struct fsw_dnode *)v->catf);
515}
516
517static fsw_status_t
518fsw_hfsplus_vol_stat(struct fsw_hfsplus_volume *v, struct fsw_volume_stat *s)
519{
520 fsw_u32 bs = fsw_u32_be_swap(v->vh->blockSize);
521
522 s->total_bytes = bs * fsw_u32_be_swap(v->vh->totalBlocks);
523 s->free_bytes = bs * fsw_u32_be_swap(v->vh->freeBlocks);
524
525 return FSW_SUCCESS;
526}
527
528static fsw_status_t
529fsw_hfsplus_dno_fill(struct fsw_hfsplus_volume *v, struct fsw_hfsplus_dnode *d)
530{
531 fsw_status_t status;
532 struct fsw_hfsplus_dnode *parent;
533 HFSPlusCatalogKey sk, *tk;
535 fsw_u32 rec_num;
536 BTNodeDescriptor *btnode;
537
538 // pre-allocate bt-node buffer for use by search function:
539 status = fsw_alloc(v->catf->bt_ndsz, &btnode);
540 if (status) {
541 return status;
542 }
543
544 sk.parentID = d->parent_id;
545 status = fsw_hfsplus_fswstr2unistr(&(sk.nodeName), &(d->g.name));
546 if (status) {
547 goto done;
548 }
549
550 status = fsw_hfsplus_bt_search(v->catf,
551 (HFSPlusBTKey *)&sk,
552 fsw_hfsplus_cat_cmp,
553 btnode, &rec_num);
554
555 tk = (HFSPlusCatalogKey *) fsw_hfsplus_btnode_get_rec(btnode, v->catf->bt_ndsz, rec_num);
556 rec = (HFSPlusCatalogRecord *) fsw_hfsplus_bt_rec_skip_key((HFSPlusBTKey *)tk);
557
558 status = fsw_hfsplus_dnid2dnode(v, d->parent_id, &parent);
559 if (status) {
560 goto done;
561 }
562
563 fsw_hfsplus_dnode_complete(rec, parent, d);
564
565done:
566 fsw_free(btnode);
567
568 return status;
569}
570
571static void
572fsw_hfsplus_dno_free(struct fsw_hfsplus_volume *v, struct fsw_hfsplus_dnode *d)
573{
574 // NOTE: not applicable to HFS+ dnodes!
575 return;
576}
577
578static fsw_u32
579fsw_hfsplus_posix_time(fsw_u32 t)
580{
581 // t is in seconds since midnight, January 1, 1904, GMT
582 return (t > 2082844800) ? t - 2082844800 : 0;
583}
584
585static fsw_status_t
586fsw_hfsplus_dno_stat(struct fsw_hfsplus_volume *v, struct fsw_hfsplus_dnode *d,
587 struct fsw_dnode_stat *s)
588{
589 s->used_bytes = d->g.size;
590 s->store_attr_posix(s, 0500);
591 s->store_time_posix(s, FSW_DNODE_STAT_CTIME, fsw_hfsplus_posix_time(d->ct));
592 s->store_time_posix(s, FSW_DNODE_STAT_MTIME, fsw_hfsplus_posix_time(d->mt));
593 s->store_time_posix(s, FSW_DNODE_STAT_ATIME, fsw_hfsplus_posix_time(d->at));
594
595 return FSW_SUCCESS;
596}
597
598static HFSPlusBTKey *
599fsw_hfsplus_btnode_get_rec(BTNodeDescriptor* btnode, fsw_u16 size, fsw_u32 rnum)
600{
601 fsw_u16 *off = (fsw_u16 *) ((fsw_u8 *) btnode + size) - 1 - rnum;
602 return (HFSPlusBTKey *)((fsw_u8 *)btnode + fsw_u16_be_swap(*off));
603}
604
605static void *
606fsw_hfsplus_bt_rec_skip_key(HFSPlusBTKey *k)
607{
608 return (fsw_u8 *)k + sizeof(k->keyLength) + fsw_u16_be_swap(k->keyLength);
609}
610
611static fsw_u32
612fsw_hfsplus_bt_idx_get_child(HFSPlusBTKey *k)
613{
614 fsw_u32 *child;
615 child = (fsw_u32 *)fsw_hfsplus_bt_rec_skip_key(k);
616 return fsw_u32_be_swap(*child);
617}
618
619static fsw_status_t
620fsw_hfsplus_bt_search(struct fsw_hfsplus_dnode *bt,
621 HFSPlusBTKey *sk,
622 k_cmp_t k_cmp,
623 BTNodeDescriptor *btnode,
624 fsw_u32 *rec_num)
625{
626 fsw_u32 node;
627 fsw_u16 rec, lo, hi;
628 HFSPlusBTKey *tk; // trial key
629 int cmp;
630 fsw_status_t status;
631
632 // start searching from the B-Tree root node:
633 node = bt->bt_root;
634
635 for (;;) {
636 // load data for current node into caller-provided buffer 'btnode'
637 status = fsw_hfsplus_read(bt, (fsw_u64)node * bt->bt_ndsz,
638 bt->bt_ndsz, btnode);
639 if (status)
640 return status;
641
642 // sanity check: record 0 located immediately after node descriptor
643 if ((fsw_u8 *)btnode + sizeof(BTNodeDescriptor) !=
644 (fsw_u8 *)fsw_hfsplus_btnode_get_rec(btnode, bt->bt_ndsz, 0))
646
647 // search records within current node
648 lo = 0;
649 hi = fsw_u16_be_swap(btnode->numRecords) - 1;
650 while (lo <= hi) {
651 // access record data, then compare to search key 'sk'
652 rec = (lo + hi) >> 1;
653 tk = fsw_hfsplus_btnode_get_rec(btnode, bt->bt_ndsz, rec);
654 cmp = k_cmp(tk, sk);
655
656 if (cmp < 0) // (tk < sk)
657 lo = rec + 1;
658 else if (cmp > 0) // (tk > sk)
659 hi = rec - 1;
660 else { // (tk == sk)
661 if (btnode->kind != kBTLeafNode) {
662 hi = rec;
663 break;
664 }
665
666 *rec_num = rec;
667 return FSW_SUCCESS;
668 }
669 }
670
671 // NOTE: following the binary search, 'hi' now points at the
672 // record with the largest 'tk' for which (tk <= sk)
673
674 if (btnode->kind != kBTIndexNode)
675 break;
676
677 // on an index node, so descend to child
678 tk = fsw_hfsplus_btnode_get_rec(btnode, bt->bt_ndsz, hi);
679 node = fsw_hfsplus_bt_idx_get_child(tk);
680 }
681
682 // search key 'sk' not found
683 return FSW_NOT_FOUND;
684}
685
686
687static int
688fsw_hfsplus_int_cmp(fsw_u32 a, fsw_u32 b)
689{
690 return (a < b) ? -1 : (a > b) ? 1 : 0;
691}
692
693static fsw_u16
694fsw_hfsplus_ucblatin_tolower(fsw_u16 c)
695{
696 if (c == 0)
697 return 0xFFFF;
698 if (c == 0x00C6 || c == 0x00D0 || c == 0x00D8 || c == 0x00DE ||
699 (c >= 0x0041 && c <= 0x005A))
700 return c + 0x0020;
701 return c;
702}
703
704static int
705fsw_hfsplus_thread_cmp(HFSPlusBTKey *tk, HFSPlusBTKey *sk)
706{
707 int ret;
708 // NOTE: all 'tk' fields are stored as big-endian values and must be
709 // converted to CPU endianness before any comparison to corresponding
710 // fields in 'sk'.
711
712 // Here is enough to compare parent's IDs and
713 // check if the name is an empty string
714 ret = fsw_hfsplus_int_cmp(fsw_u32_be_swap(tk->catKey.parentID), sk->catKey.parentID);
715 if (ret)
716 return ret;
717
718 // NOTE:
719 // When failing name length check there's no reason of continuing B-Tree traverse
720 // because we can have only one child of 'thread' type (with an empty name), and it
721 // should be the 1st record. But let the search traverse be stopped
722 // later on parents comparison for simplicity
723 return tk->catKey.nodeName.length > 0;
724}
725
726static int
727fsw_hfsplus_cat_cmp(HFSPlusBTKey *tk, HFSPlusBTKey *sk)
728{
729 fsw_u16 *t_str, *s_str;
730 fsw_u16 t_len, s_len;
731 fsw_u16 t_char, s_char;
732 int ret;
733
734 // NOTE: all 'tk' fields are stored as big-endian values and must be
735 // converted to CPU endianness before any comparison to corresponding
736 // fields in 'sk'.
737
738 // compare parent IDs: if unequal, we're done!
739 ret = fsw_hfsplus_int_cmp(fsw_u32_be_swap(tk->catKey.parentID),
740 sk->catKey.parentID);
741 if (ret)
742 return ret;
743
744 // unicode string pointers and lengths:
745 t_len = fsw_u16_be_swap(tk->catKey.nodeName.length);
746 t_str = tk->catKey.nodeName.unicode;
747 s_len = sk->catKey.nodeName.length;
748 s_str = sk->catKey.nodeName.unicode;
749
750 for (;;) {
751 // start by assuming strings are empty:
752 t_char = s_char = 0;
753
754 // find next valid char from on-disk key string:
755 while (t_char == 0 && t_len > 0) {
756 t_char = fsw_hfsplus_ucblatin_tolower(fsw_u16_be_swap(*t_str));
757 t_len--;
758 t_str++;
759 }
760
761 // find next valid char from memory key string:
762 while (s_char == 0 && s_len > 0) {
763 s_char = fsw_hfsplus_ucblatin_tolower(*s_str);
764 s_len--;
765 s_str++;
766 }
767
768 // stop if difference or both strings exhausted:
769 ret = fsw_hfsplus_int_cmp(t_char, s_char);
770 if (ret || s_char == 0)
771 break;
772 }
773
774 return ret;
775}
776
777static fsw_status_t
778fsw_hfsplus_get_ext(struct fsw_hfsplus_volume *v, struct fsw_hfsplus_dnode *d,
779 struct fsw_extent *e)
780{
781 fsw_u32 off, bc;
783 int i;
784
785 // set initial offset to provided starting logical block number:
786 off = e->log_start;
787
788 // start with dnode's initial extent record:
789 er = &d->extents;
790
791 // search extent record:
792 for (i = 0; i < kHFSPlusExtentDensity; i++) {
793 // get block count for current extent descriptor:
794 bc = fsw_u32_be_swap((*er)[i].blockCount);
795
796 // have we exhausted all available extents?
797 if (bc == 0)
798 return FSW_NOT_FOUND;
799
800 // offset is relative to current extent's physical startBlock:
801 if (off < bc) {
803 e->phys_start = fsw_u32_be_swap((*er)[i].startBlock) + off;
804 e->log_count = bc - off;
805 return FSW_SUCCESS;
806 }
807
808 // update offset to NEXT extent descriptor:
809 off -= bc;
810 }
811
812 // FIXME: more than 8 fragments not yet supported!
813 FSW_MSG_ASSERT((FSW_MSGSTR("FswHfsPlus: get_ext: got_here\n")));
814
815 return FSW_UNSUPPORTED;
816}
817
818static fsw_status_t
819fsw_hfsplus_fswstr2unistr(HFSUniStr255* t, struct fsw_string* src)
820{
821 fsw_status_t status;
822 struct fsw_string ws;
823
824 status = fsw_strdup_coerce(&ws, FSW_STRING_TYPE_UTF16, src);
825 if (status == FSW_SUCCESS) {
826 t->length = (fsw_u16) fsw_strlen(&ws);
827 if (t->length > 0) {
828 fsw_memcpy(t->unicode, fsw_strdata(&ws), fsw_strsize(&ws));
829 }
830 }
831 fsw_strfree (&ws);
832 return status;
833}
834
835static fsw_status_t
836fsw_hfsplus_btree_get_rec(struct fsw_hfsplus_dnode *bt,
837 fsw_u32 parent_id,
838 BTNodeDescriptor *btnode,
839 fsw_u32 *rec_num,
840 fsw_u64 *rec_skip)
841{
842 fsw_status_t status;
843 fsw_u32 btnode_next;
844 fsw_u32 num_records;
845 fsw_u32 counter;
846 HFSPlusBTKey *tk;
848 fsw_u32 i;
849
850 counter = 0;
851 for (;;) {
852 status = FSW_NOT_FOUND;
853 num_records = fsw_u16_be_swap(btnode->numRecords);
854
855 for (i = *rec_num; i < num_records; ++i) {
856 tk = fsw_hfsplus_btnode_get_rec(btnode, bt->bt_ndsz, i);
857
858 if (fsw_u32_be_swap(((HFSPlusCatalogKey*)(tk))->parentID) != parent_id) {
859 return status;
860 }
861
862 if (counter++ != *rec_skip) {
863 continue;
864 }
865
866 rec = fsw_hfsplus_bt_rec_skip_key(tk);
867 ++(*rec_skip);
868 switch (fsw_u16_be_swap(rec->recordType)) {
871 *rec_num = i;
872 return FSW_SUCCESS;
873 break;
874
877 default:
878 break;
879 }
880 }
881
882 btnode_next = fsw_u32_be_swap(btnode->fLink);
883 if (btnode_next == 0) {
884 return status;
885 }
886
887 status = fsw_hfsplus_read(bt, (fsw_u64) btnode_next * bt->bt_ndsz,
888 bt->bt_ndsz, btnode);
889 *rec_num = 0;
890 if (status) {
891 return status;
892 }
893 }
894
895}
896
897static fsw_status_t
898fsw_hfsplus_dnode_create_minimal(struct fsw_hfsplus_volume *v,
899 fsw_u32 parent_id,
900 fsw_u32 dnode_id,
901 struct fsw_string *name,
902 struct fsw_hfsplus_dnode **d_out)
903{
904 fsw_status_t status;
905
906 status = fsw_dnode_create(v, NULL, dnode_id, FSW_DNODE_TYPE_UNKNOWN, name, d_out);
907 if (!status) {
908 (*d_out)->parent_id = parent_id;
909 }
910 return status;
911}
912
913static void
914fsw_hfsplus_dnode_complete(HFSPlusCatalogRecord *rec,
915 struct fsw_hfsplus_dnode *parent,
916 struct fsw_hfsplus_dnode *d_out)
917{
918
919 // figure out type of child dnode:
920 switch (fsw_u16_be_swap(rec->recordType)) {
922 d_out->g.type = FSW_DNODE_TYPE_DIR;
923
924 d_out->ct = fsw_u32_be_swap(rec->folderRecord.createDate);
925 d_out->mt = fsw_u32_be_swap(rec->folderRecord.contentModDate);
926 d_out->at = fsw_u32_be_swap(rec->folderRecord.accessDate);
927 break;
928
930 d_out->g.type = FSW_DNODE_TYPE_FILE;
931 d_out->g.size = fsw_u64_be_swap(rec->fileRecord.dataFork.logicalSize);
932
934
935 d_out->ct = fsw_u32_be_swap(rec->fileRecord.createDate);
936 d_out->mt = fsw_u32_be_swap(rec->fileRecord.contentModDate);
937 d_out->at = fsw_u32_be_swap(rec->fileRecord.accessDate);
938
939 d_out->fd_type = fsw_u32_be_swap(rec->fileRecord.userInfo.fdType);
940 d_out->fd_creator = fsw_u32_be_swap(rec->fileRecord.userInfo.fdCreator);
941
942 if ((d_out->fd_creator == kHFSPlusSymlinkCreator && d_out->fd_type == kHFSPlusSymlinkType) ||
944
946 d_out->inode_num = fsw_u32_be_swap (rec->fileRecord.permissions.special.iNodeNum);
947 }
948 break;
949
950 default:
952
953 d_out->ct = 0;
954 d_out->mt = 0;
955 d_out->at = 0;
956 break;
957 }
958
959 d_out->g.parent = parent;
960 fsw_dnode_retain(&parent->g);
961
962 // mark dnode as complete
964}
965
966static fsw_status_t
967fsw_hfsplus_dnode_create_full(HFSPlusCatalogRecord *rec,
968 struct fsw_hfsplus_dnode *parent,
969 struct fsw_string *name,
970 struct fsw_hfsplus_dnode **d_out)
971{
972 fsw_status_t status;
973 fsw_u32 dnid;
974
975 switch (fsw_u16_be_swap(rec->recordType)) {
977 dnid = fsw_u32_be_swap(rec->folderRecord.folderID);
978 break;
980 dnid = fsw_u32_be_swap(rec->fileRecord.fileID);
981 break;
982 default:
983 dnid = 0;
984 break;
985 }
986
987 status = fsw_hfsplus_dnode_create_minimal(parent->g.vol, parent->g.dnode_id, dnid, name, d_out);
988
989 if (!status) {
990 fsw_hfsplus_dnode_complete(rec, parent, *d_out);
991 }
992 return status;
993}
994
995static fsw_status_t
996fsw_hfsplus_dir_get(struct fsw_hfsplus_volume *v, struct fsw_hfsplus_dnode *d,
997 struct fsw_string *name, struct fsw_hfsplus_dnode **d_out)
998{
999 BTNodeDescriptor *btnode;
1000 HFSPlusCatalogKey sk, *tk;
1002 fsw_status_t status;
1003 fsw_u32 rec_num;
1004 fsw_u32 i;
1005
1006 // search catalog file for child named by 'name':
1007 sk.parentID = d->g.dnode_id;
1008 status = fsw_hfsplus_fswstr2unistr(&(sk.nodeName), name);
1009
1010 if (status)
1011 return status;
1012
1013 FSW_MSG_DEBUG((FSW_MSGSTR("FswHfsPlus: dir_get: parent=%d name: "), d->g.dnode_id));
1014 for (i = 0; i < sk.nodeName.length; i++)
1015 FSW_MSG_DEBUG((FSW_MSGSTR("%c"), ((fsw_u16 *)sk.nodeName.unicode)[i]));
1016 FSW_MSG_DEBUG((FSW_MSGSTR("\n")));
1017
1018 // pre-allocate bt-node buffer for use by search function:
1019 status = fsw_alloc(v->catf->bt_ndsz, &btnode);
1020 if (status) {
1021 return status;
1022 }
1023
1024 status = fsw_hfsplus_bt_search(v->catf,
1025 (HFSPlusBTKey *)&sk,
1026 fsw_hfsplus_cat_cmp,
1027 btnode,
1028 &rec_num);
1029 if (status) {
1030 goto done;
1031 }
1032
1033 tk = (HFSPlusCatalogKey *)fsw_hfsplus_btnode_get_rec(btnode, v->catf->bt_ndsz, rec_num);
1034 rec = fsw_hfsplus_bt_rec_skip_key((HFSPlusBTKey *)tk);
1035 status = fsw_hfsplus_dnode_create_full(rec, d, name, d_out);
1036
1037done:
1038 fsw_free(btnode);
1039 return status;
1040}
1041
1042static fsw_status_t
1043fsw_hfsplus_dir_read(struct fsw_hfsplus_volume *v, struct fsw_hfsplus_dnode *d,
1044 struct fsw_shandle *sh, struct fsw_hfsplus_dnode **d_out)
1045{
1046 BTNodeDescriptor *btnode;
1047 HFSPlusCatalogKey sk, *tk;
1049 struct fsw_string name;
1050 fsw_u32 rec_num;
1051 int i;
1052 fsw_status_t status;
1053
1054 FSW_MSG_DEBUG((FSW_MSGSTR("FswHfsPlus: dir_read.1: parent=%ld, sh->pos=%ld\n"), d->g.dnode_id, sh->pos));
1055
1056 // pre-allocate bt-node buffer for use by search function:
1057 status = fsw_alloc(v->catf->bt_ndsz, &btnode);
1058 if (status) {
1059 return status;
1060 }
1061
1062 // search catalog file for first child of 'd' (a.k.a. "./"):
1063 sk.parentID = d->g.dnode_id;
1064 sk.nodeName.length = 0;
1065 // NOTE: keyLength not used in search, setting only for completeness:
1066
1067 sk.keyLength = sizeof(sk.parentID) + sizeof(sk.nodeName.length);
1068 status = fsw_hfsplus_bt_search(v->catf,
1069 (HFSPlusBTKey *)&sk,
1070 fsw_hfsplus_cat_cmp,
1071 btnode, &rec_num);
1072 if (status) {
1073 goto done;
1074 }
1075
1076 status = fsw_hfsplus_btree_get_rec(v->catf,
1077 sk.parentID,
1078 btnode,
1079 &rec_num,
1080 &sh->pos);
1081 if (status) {
1082 goto done;
1083 }
1084
1085 tk = (HFSPlusCatalogKey *)fsw_hfsplus_btnode_get_rec(btnode, v->catf->bt_ndsz, rec_num);
1086 rec = fsw_hfsplus_bt_rec_skip_key((HFSPlusBTKey *)tk);
1087
1088 // Fill child name
1090 name.len = fsw_u16_be_swap(tk->nodeName.length);
1091 name.size = name.len * 2;
1092 status = fsw_alloc(name.size, &name.data);
1093 if (status) {
1094 goto done;
1095 }
1096
1097 FSW_MSG_DEBUG((FSW_MSGSTR("FswHfsPlus: dir_read.2: child name: ")));
1098 for (i = 0; i < name.len; i++) {
1099 ((fsw_u16 *) name.data)[i] = fsw_u16_be_swap(tk->nodeName.unicode[i]);
1100 FSW_MSG_DEBUG((FSW_MSGSTR("%c"), ((fsw_u16 *) name.data)[i]));
1101 }
1102 FSW_MSG_DEBUG((FSW_MSGSTR("\n")));
1103
1104 status = fsw_hfsplus_dnode_create_full(rec, d, &name, d_out);
1105 fsw_strfree(&name);
1106
1107done:
1108 fsw_free(btnode);
1109 return status;
1110}
1111
1112static fsw_status_t
1113fsw_hfsplus_itoa(fsw_u32 num, char** dest, int* len)
1114{
1115 fsw_status_t status;
1116 int i, j;
1117 int num_copy;
1118 char c;
1119
1120 (*len) = 0;
1121
1122 // Pre-calculating string length
1123 num_copy = num;
1124 do {
1125 ++(*len);
1126 } while ((num_copy /= 10) > 0);
1127
1128 // Allocating memory for the string
1129 status = fsw_alloc_zero(sizeof(char) * (*len), (void **) dest);
1130 if (status) {
1131 return status;
1132 }
1133
1134 // Converting
1135 i = 0;
1136 do {
1137 (*dest)[i++] = num % 10 + '0';
1138 } while ((num /= 10) > 0);
1139
1140 // Reversing the string
1141 for (i = 0, j = *len - 1; i < j; i++, j--) {
1142 c = (*dest)[i];
1143 (*dest)[i] = (*dest)[j];
1144 (*dest)[j] = c;
1145 }
1146 return status;
1147}
1148
1149static fsw_status_t
1150fsw_hfsplus_sconcat(const char *const s1, int len1, const char *const s2, int len2, char **dest)
1151{
1152 int i;
1153 fsw_status_t status;
1154
1155 status = fsw_alloc_zero(sizeof(char) * (len1 + len2), (void **) dest);
1156 if (status) {
1157 return status;
1158 }
1159
1160 for (i = 0; i < len1; ++i) {
1161 (*dest)[i] = s1[i];
1162 }
1163
1164 for (i = 0; i < len2; ++i) {
1165 (*dest)[i + len1] = s2[i];
1166 }
1167 return status;
1168}
1169
1170static fsw_status_t
1171fsw_hfsplus_readlink(struct fsw_hfsplus_volume *v, struct fsw_hfsplus_dnode *d,
1172 struct fsw_string *lnk_tgt)
1173{
1174 // Note:
1175 // We assume the size = length * sizeof(char)
1176 // And NO strings are null-terminated
1177
1178 static const char hlink_prefix[] = "/\0\0\0\0HFS+ Private Data/iNode";
1179 static const int hlink_prefix_len = 28;
1180
1181 fsw_status_t status;
1182 char *buf;
1183 int buf_len;
1184
1186 status = fsw_hfsplus_itoa(d->inode_num, &buf, &buf_len);
1187 if (status) {
1188 return status;
1189 }
1190
1191 status = fsw_hfsplus_sconcat(hlink_prefix, hlink_prefix_len, buf, buf_len, (char**) &lnk_tgt->data);
1192 if (status) {
1193 return status;
1194 }
1195
1196 lnk_tgt->type = FSW_STRING_TYPE_ISO88591;
1197 lnk_tgt->size = (hlink_prefix_len + buf_len) * sizeof(char);
1198 lnk_tgt->len = hlink_prefix_len + buf_len;
1199 fsw_free(buf);
1200
1201 FSW_MSG_DEBUG((FSW_MSGSTR("FswHfsPlus: readlink: inode no: %d\n"), d->g.dnode_id));
1202 return FSW_SUCCESS;
1204 return fsw_dnode_readlink_data(d, lnk_tgt);
1205 }
1206 return FSW_UNSUPPORTED;
1207}
1208
1209static fsw_status_t
1210fsw_hfsplus_dnid2thread(struct fsw_hfsplus_volume *v, fsw_u32 dnid,
1211 BTNodeDescriptor *btnode, HFSPlusCatalogThread **thread_out)
1212{
1213 fsw_status_t status;
1214 HFSPlusCatalogKey sk, *tk;
1215 fsw_u32 rec_num;
1216
1217 // Known parent id is enough to find a thread
1218 sk.parentID = dnid;
1219 status = fsw_hfsplus_bt_search(v->catf,
1220 (HFSPlusBTKey *)&sk,
1221 fsw_hfsplus_thread_cmp,
1222 btnode, &rec_num);
1223 if (status) {
1224 return status;
1225 }
1226
1227 tk = (HFSPlusCatalogKey *) fsw_hfsplus_btnode_get_rec(btnode, v->catf->bt_ndsz, rec_num);
1228 *thread_out = (HFSPlusCatalogThread *) fsw_hfsplus_bt_rec_skip_key((HFSPlusBTKey *)tk);
1229 return FSW_SUCCESS;
1230}
1231
1232static fsw_status_t
1233fsw_hfsplus_thread2dnode(struct fsw_hfsplus_volume *v, HFSPlusCatalogThread *thread,
1234 BTNodeDescriptor *btnode, struct fsw_hfsplus_dnode **d_out)
1235{
1236 fsw_status_t status;
1237 struct fsw_string name;
1238 fsw_u32 rec_num;
1239 HFSPlusCatalogKey sk, *tk;
1241
1242 // Prepare search key
1243 sk.parentID = fsw_u32_be_swap(thread->parentID);
1244
1245 name.len = fsw_u16_be_swap(thread->nodeName.length);
1246 name.size = sizeof(fsw_u16) * name.len;
1247 name.data = thread->nodeName.unicode;
1249
1250 status = fsw_hfsplus_fswstr2unistr(&(sk.nodeName), &name);
1251 if (status) {
1252 return status;
1253 }
1254
1255 // Try to find btree node by its parent id and name
1256 status = fsw_hfsplus_bt_search(v->catf,
1257 (HFSPlusBTKey *)&sk,
1258 fsw_hfsplus_cat_cmp,
1259 btnode, &rec_num);
1260 if (status) {
1261 return status;
1262 }
1263
1264 tk = (HFSPlusCatalogKey *) fsw_hfsplus_btnode_get_rec(btnode, v->catf->bt_ndsz, rec_num);
1265 rec = (HFSPlusCatalogRecord *) fsw_hfsplus_bt_rec_skip_key((HFSPlusBTKey *)tk);
1266
1267 // Just a sanity check
1268 switch (fsw_u16_be_swap(rec->recordType)) {
1270 case kHFSPlusFileRecord:
1271 break;
1272 default:
1273 return FSW_NOT_FOUND;
1274 }
1275
1276 // We have same dnode id field position
1277 // for file (rec->fileRecord.fileID)
1278 // and folder (rec->folderRecord.folderID), so use one of them
1279 status = fsw_hfsplus_dnode_create_minimal(v,
1280 fsw_u32_be_swap(thread->parentID),
1281 fsw_u32_be_swap(rec->folderRecord.folderID),
1282 &name, d_out);
1283 if (status) {
1284 return status;
1285 }
1286
1287 return status;
1288}
1289
1290static fsw_status_t
1291fsw_hfsplus_dnid2dnode(struct fsw_hfsplus_volume *v, fsw_u32 dnid, struct fsw_hfsplus_dnode **d_out)
1292{
1293 fsw_status_t status;
1294 BTNodeDescriptor *btnode_thread, *btnode_dnode;
1295 HFSPlusCatalogThread *thread;
1296
1297 status = fsw_alloc(v->catf->bt_ndsz, &btnode_thread);
1298 if (status) {
1299 return status;
1300 }
1301
1302 status = fsw_alloc(v->catf->bt_ndsz, &btnode_dnode);
1303 if (status) {
1304 goto free_btnode_thread;
1305 }
1306
1307 status = fsw_hfsplus_dnid2thread(v, dnid, btnode_thread, &thread);
1308 if (status) {
1309 goto free_all;
1310 }
1311
1312 status = fsw_hfsplus_thread2dnode(v, thread, btnode_dnode, d_out);
1313
1314free_all:
1315 fsw_free(btnode_dnode);
1316
1317free_btnode_thread:
1318 fsw_free(btnode_thread);
1319
1320 return status;
1321}
1322
1323static fsw_status_t
1324fsw_hfsplus_bless_type2dnid(struct fsw_hfsplus_volume *vol,
1325 fsw_u32 bless_type,
1326 fsw_u32 *dnid)
1327{
1328 HFSPlusVolumeFinderInfo *finderInfo;
1329
1330 finderInfo = (HFSPlusVolumeFinderInfo*) &vol->vh->finderInfo;
1331 switch (bless_type) {
1333 *dnid = fsw_u32_be_swap(finderInfo->blessedSystemFileID);
1334 break;
1336 *dnid = fsw_u32_be_swap(finderInfo->blessedSystemFolderID);
1337 break;
1339 *dnid = fsw_u32_be_swap(finderInfo->blessedOSXFolderID);
1340 break;
1341 default:
1342 return FSW_NOT_FOUND;
1343 break;
1344 }
1345
1346 return FSW_SUCCESS;
1347}
1348
1349static fsw_status_t
1350fsw_hfsplus_get_bless_info(struct fsw_hfsplus_volume *vol,
1351 fsw_u32 bless_type,
1352 struct fsw_hfsplus_dnode **dno_out) {
1353 fsw_status_t status;
1354 fsw_u32 dnid;
1355
1356 status = fsw_hfsplus_bless_type2dnid(vol, bless_type, &dnid);
1357 if (status)
1358 return status;
1359
1360 status = fsw_hfsplus_dnid2dnode(vol, dnid, dno_out);
1361 return status;
1362}
1363
UINT32 size
#define FSW_MSG_ASSERT(params)
Definition fsw_base.h:62
#define FSW_MSG_DEBUG(params)
Definition fsw_base.h:70
fsw_status_t fsw_shandle_read(struct fsw_shandle *shand, fsw_u32 *buffer_size_inout, void *buffer_in)
Definition fsw_core.c:860
fsw_status_t fsw_block_get(struct VOLSTRUCTNAME *vol, fsw_u32 phys_bno, fsw_u32 cache_level, void **buffer_out)
Definition fsw_core.c:179
fsw_status_t fsw_dnode_create_root(struct fsw_volume *vol, fsw_u32 dnode_id, struct fsw_dnode **dno_out)
Definition fsw_core.c:323
void fsw_shandle_close(struct fsw_shandle *shand)
Definition fsw_core.c:848
void fsw_set_blocksize(struct fsw_volume *vol, fsw_u32 phys_blocksize, fsw_u32 log_blocksize)
Definition fsw_core.c:145
fsw_status_t fsw_shandle_open(struct fsw_dnode *dno, struct fsw_shandle *shand)
Definition fsw_core.c:822
void fsw_block_release(struct VOLSTRUCTNAME *vol, fsw_u32 phys_bno, void *buffer)
Definition fsw_core.c:267
fsw_status_t fsw_dnode_readlink_data(struct fsw_dnode *dno, struct fsw_string *link_target)
Definition fsw_core.c:720
fsw_status_t fsw_dnode_create(struct fsw_volume *vol, struct fsw_dnode *parent_dno, fsw_u32 dnode_id, int type, struct fsw_string *name, struct fsw_dnode **dno_out)
Definition fsw_core.c:372
void fsw_dnode_release(struct fsw_dnode *dno)
Definition fsw_core.c:442
void fsw_dnode_retain(struct fsw_dnode *dno)
Definition fsw_core.c:430
void fsw_dnode_mkcomplete(struct fsw_dnode *dno)
Definition fsw_core.c:420
int fsw_status_t
Definition fsw_core.h:153
void fsw_strfree(struct fsw_string *s)
Definition fsw_lib.c:310
@ FSW_DNODE_TYPE_SYMLINK
Definition fsw_core.h:267
@ FSW_DNODE_TYPE_FILE
Definition fsw_core.h:265
@ FSW_DNODE_TYPE_UNKNOWN
Definition fsw_core.h:264
@ FSW_DNODE_TYPE_DIR
Definition fsw_core.h:266
int fsw_strsize(struct fsw_string *s)
Definition fsw_lib.c:89
#define FSW_FSTYPE_TABLE_NAME(t)
Definition fsw_core.h:53
int fsw_strlen(struct fsw_string *s)
Definition fsw_lib.c:79
@ FSW_EXTENT_TYPE_PHYSBLOCK
Definition fsw_core.h:296
fsw_status_t fsw_strdup_coerce(struct fsw_string *dest, int type, struct fsw_string *src)
Definition fsw_lib.c:190
@ FSW_UNSUPPORTED
Definition fsw_core.h:162
@ FSW_NOT_FOUND
Definition fsw_core.h:163
@ FSW_SUCCESS
Definition fsw_core.h:159
@ FSW_VOLUME_CORRUPTED
Definition fsw_core.h:164
@ FSW_IO_ERROR
Definition fsw_core.h:161
void * fsw_strdata(struct fsw_string *s)
Definition fsw_lib.c:100
fsw_status_t fsw_alloc_zero(int len, void **ptr_out)
Definition fsw_lib.c:49
#define FSW_STRING_TYPE_UTF16_BE
Definition fsw_core.h:197
@ BLESSED_TYPE_SYSTEM_FILE
Definition fsw_core.h:272
@ BLESSED_TYPE_SYSTEM_FOLDER
Definition fsw_core.h:273
@ BLESSED_TYPE_OSX_FOLDER
Definition fsw_core.h:274
@ FSW_DNODE_STAT_ATIME
Definition fsw_core.h:338
@ FSW_DNODE_STAT_CTIME
Definition fsw_core.h:336
@ FSW_DNODE_STAT_MTIME
Definition fsw_core.h:337
@ FSW_STRING_TYPE_ISO88591
Definition fsw_core.h:186
@ FSW_STRING_TYPE_EMPTY
Definition fsw_core.h:185
@ FSW_STRING_TYPE_UTF16
Definition fsw_core.h:188
#define fsw_memcpy(dest, src, size)
UINT16 fsw_u16
UINT32 fsw_u32
UINT64 fsw_u64
#define fsw_free(ptr)
#define fsw_alloc(size, ptrptr)
UINT8 fsw_u8
#define FSW_MSGSTR(s)
#define kHFSPlusFileThreadRecord
Definition fsw_hfsplus.h:58
int(* k_cmp_t)(HFSPlusBTKey *, HFSPlusBTKey *)
#define kMasterDirectoryBlock
Definition fsw_hfsplus.h:32
#define kHFSBlockSize
Definition fsw_hfsplus.h:31
#define kBTLeafNode
Definition fsw_hfsplus.h:66
HFSPlusExtentDescriptor HFSPlusExtentRecord[kHFSPlusExtentDensity]
Definition fsw_hfsplus.h:83
#define kBTIndexNode
Definition fsw_hfsplus.h:67
#define kHFSPlusExtentDensity
Definition fsw_hfsplus.h:38
#define kHFSRootFolderID
Definition fsw_hfsplus.h:44
#define kHFSPlusHFSPlusCreator
Definition fsw_hfsplus.h:60
#define kHFSPlusSymlinkType
Definition fsw_hfsplus.h:64
#define kHFSPlusFolderThreadRecord
Definition fsw_hfsplus.h:57
#define kHFSPlusSigWord
Definition fsw_hfsplus.h:34
#define kHFSPlusFolderRecord
Definition fsw_hfsplus.h:55
#define kHFSPlusFileRecord
Definition fsw_hfsplus.h:56
#define kHFSPlusSymlinkCreator
Definition fsw_hfsplus.h:61
#define kHFSCatalogFileID
Definition fsw_hfsplus.h:46
#define kHFSPlusHardlinkType
Definition fsw_hfsplus.h:63
fsw_u16 nodeSize
fsw_u32 rootNode
fsw_u32 fdCreator
fsw_u32 fdType
union HFSPlusBSDInfo::@127 special
HFSPlusBSDInfo permissions
FndrFileInfo userInfo
HFSPlusForkData dataFork
HFSUniStr255 nodeName
HFSUniStr255 nodeName
HFSPlusExtentRecord extents
Definition fsw_hfsplus.h:90
fsw_u64 logicalSize
Definition fsw_hfsplus.h:87
HFSPlusForkData catalogFile
fsw_u8 finderInfo[32]
fsw_u16 unicode[kHFSPlusMaxFileNameChars]
Definition fsw_hfsplus.h:73
fsw_u16 length
Definition fsw_hfsplus.h:72
void(* store_attr_posix)(struct fsw_dnode_stat *sb, fsw_u16 posix_mode)
Callbock for storing a Posix-style file mode.
Definition fsw_core.h:328
void(* store_time_posix)(struct fsw_dnode_stat *sb, int which, fsw_u32 posix_time)
Callback for storing a Posix-style timestamp.
Definition fsw_core.h:327
fsw_u64 used_bytes
Bytes actually used by the file on disk.
Definition fsw_core.h:326
struct VOLSTRUCTNAME * vol
The volume this dnode belongs to.
Definition fsw_core.h:247
fsw_u32 dnode_id
Unique id number (usually the inode number)
Definition fsw_core.h:251
fsw_u64 size
Data size in bytes.
Definition fsw_core.h:253
struct DNODESTRUCTNAME * parent
Parent directory dnode.
Definition fsw_core.h:248
int type
Type of the dnode - file, dir, symlink, special.
Definition fsw_core.h:252
struct fsw_string name
Name of this item in the parent directory.
Definition fsw_core.h:249
int type
Type of extent specification.
Definition fsw_core.h:282
fsw_u32 log_count
Logical block count.
Definition fsw_core.h:284
fsw_u32 log_start
Starting logical block number.
Definition fsw_core.h:283
fsw_u32 phys_start
Starting physical block number (for FSW_EXTENT_TYPE_PHYSBLOCK only)
Definition fsw_core.h:285
struct fsw_dnode g
HFSPlusExtentRecord extents
struct fsw_volume g
HFSPlusVolumeHeader * vh
struct fsw_hfsplus_dnode * catf
fsw_u64 pos
Current file pointer in bytes.
Definition fsw_core.h:308
void * data
Data pointer (may be NULL if type is EMPTY or len is zero)
Definition fsw_core.h:177
int len
Length in characters.
Definition fsw_core.h:175
int size
Total data size in bytes.
Definition fsw_core.h:176
int type
Encoding of the string - empty, ISO-8859-1, UTF8, UTF16.
Definition fsw_core.h:174
fsw_u64 free_bytes
Bytes still available for storing file data.
Definition fsw_core.h:318
fsw_u64 total_bytes
Total size of data area size in bytes.
Definition fsw_core.h:317
struct fsw_string label
Volume label.
Definition fsw_core.h:226
struct DNODESTRUCTNAME * root
Root directory dnode.
Definition fsw_core.h:225
fsw_u16 keyLength
HFSPlusCatalogKey catKey
HFSPlusCatalogFolder folderRecord
HFSPlusCatalogFile fileRecord