4 * Open Hack'Ware BIOS HFS file system management
6 * Copyright (c) 2004-2005 Jocelyn Mayer
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License V2
10 * as published by the Free Software Foundation
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * Major rework and debug by Thayne Harbaugh <thayne@realmsys.com>
32 #if defined (DEBUG_HFS)
33 #define HFS_DPRINTF(fmt, args...) \
34 do { dprintf("%s: " fmt, __func__ , ##args); } while (0)
36 #define HFS_DPRINTF(fmt, args...) \
39 #define HFS_ERROR(fmt, args...) \
40 do { dprintf("HFS ERROR in %s: " fmt, __func__ , ##args); } while (0)
42 /* HFS/HFS+ common definitions */
43 #define HFS_SECTOR_SIZE 512
44 #define HFS_VOLHEAD_SECTOR 2
45 #define HFS_NODE_SIZE 0x200
48 #define HFS_VOLHEAD_SIG 0x4244
50 #define HFSPLUS_VOLHEAD_SIG 0x482b
52 /* HFS+ filesystem support */
55 HFS_ROOT_PARENT
= 1, /* Parent of root folder */
56 HFS_ROOT_FOLDER
= 2, /* root folder */
57 HFS_EXTENT_FILE
= 3, /* file extents file */
58 HFS_CATALOG_FILE
= 4, /* catalog file */
59 HFS_BBLOCS_FILE
= 5, /* badblocks file */
60 HFS_ALLOC_FILE
= 6, /* allocation file (HFSplus) */
61 HFS_STARTUP_FILE
= 7, /* startup file (HFSplus) */
62 HFS_ATTR_FILE
= 8, /* attribute file (HFSplus) */
63 HFS_BEXTENT_FILE
= 15, /* file extents temporary file */
64 HFS_FIRST_USERID
= 16,
67 typedef uint32_t HFS_cnid_t
;
69 static inline HFS_cnid_t
HFS_get_cnid (HFS_cnid_t
*cnidp
)
71 return get_be32(cnidp
);
74 typedef uint16_t HFSP_unichr_t
;
76 static inline HFSP_unichr_t
HFSP_get_unichr (HFSP_unichr_t
*chrp
)
78 return get_be16(chrp
);
81 /* A single contiguous area of a file */
82 typedef struct HFSP_extent_t HFSP_extent_t
;
83 struct HFSP_extent_t
{
86 } __attribute__ ((packed
));
88 static inline HFSP_extent_t
*HFSP_get_extent (HFSP_extent_t
*extp
)
90 extp
->start_block
= get_be32(&extp
->start_block
);
91 extp
->block_count
= get_be32(&extp
->block_count
);
96 /* Information for a "Fork" in a file */
97 typedef struct HFSP_fork_t HFSP_fork_t
;
102 uint32_t total_blocks
;
104 HFSP_extent_t extents
[8];
106 } __attribute__ ((packed
));
108 static inline HFSP_fork_t
*HFSP_get_fork (HFSP_fork_t
*forkp
)
112 forkp
->total_size
= get_be64(&forkp
->total_size
);
113 forkp
->clump_size
= get_be32(&forkp
->clump_size
);
114 forkp
->total_blocks
= get_be32(&forkp
->total_blocks
);
115 for (i
= 0; i
< 8; i
++) {
116 HFSP_get_extent(&forkp
->extents
[i
]);
122 /* HFS+ Volume Header */
123 typedef struct HFSP_vh_t HFSP_vh_t
;
129 uint32_t last_mount_vers
;
133 uint32_t create_date
;
134 uint32_t modify_date
;
135 uint32_t backup_date
;
136 uint32_t checked_date
;
140 uint32_t folder_count
;
142 uint32_t total_blocks
;
145 uint32_t free_blocks
;
147 uint32_t rsrc_clump_sz
;
148 uint32_t data_clump_sz
;
151 HFS_cnid_t next_cnid
;
152 uint32_t write_count
;
153 uint64_t encodings_bmp
;
156 uint32_t finder_info
[8];
159 HFSP_fork_t alloc_file
;
161 HFSP_fork_t ext_file
;
163 HFSP_fork_t cat_file
;
165 HFSP_fork_t attr_file
;
167 HFSP_fork_t start_file
;
170 } __attribute__ ((packed
));
172 static HFSP_vh_t
*HFSP_read_volhead (part_t
*part
, uint32_t bloc
,
173 uint32_t offset
, void *buffer
, int size
)
178 if (part_seek(part
, bloc
, offset
) == -1)
180 if (part_read(part
, buffer
, size
) < 0)
183 vh
->signature
= get_be16(&vh
->signature
);
184 vh
->version
= get_be16(&vh
->version
);
185 vh
->attributes
= get_be32(&vh
->attributes
);
186 vh
->last_mount_vers
= get_be32(&vh
->last_mount_vers
);
187 vh
->create_date
= get_be32(&vh
->create_date
);
188 vh
->modify_date
= get_be32(&vh
->modify_date
);
189 vh
->backup_date
= get_be32(&vh
->backup_date
);
190 vh
->checked_date
= get_be32(&vh
->checked_date
);
191 vh
->file_count
= get_be32(&vh
->file_count
);
192 vh
->folder_count
= get_be32(&vh
->folder_count
);
193 vh
->blocksize
= get_be32(&vh
->blocksize
);
194 vh
->total_blocks
= get_be32(&vh
->total_blocks
);
195 vh
->free_blocks
= get_be32(&vh
->free_blocks
);
196 vh
->next_alloc
= get_be32(&vh
->next_alloc
);
197 vh
->rsrc_clump_sz
= get_be32(&vh
->rsrc_clump_sz
);
198 vh
->data_clump_sz
= get_be32(&vh
->data_clump_sz
);
199 HFS_get_cnid(&vh
->next_cnid
);
200 vh
->write_count
= get_be32(&vh
->write_count
);
201 vh
->encodings_bmp
= get_be32(&vh
->encodings_bmp
);
202 for (i
= 0; i
< 8; i
++) {
203 vh
->finder_info
[i
] = get_be32(&vh
->finder_info
[i
]);
205 HFSP_get_fork(&vh
->alloc_file
);
206 HFSP_get_fork(&vh
->ext_file
);
207 HFSP_get_fork(&vh
->cat_file
);
208 HFSP_get_fork(&vh
->attr_file
);
209 HFSP_get_fork(&vh
->start_file
);
215 /* A single contiguous area of a file */
216 typedef struct HFS_extent_t HFS_extent_t
;
217 struct HFS_extent_t
{
218 uint16_t start_block
;
219 uint16_t block_count
;
220 } __attribute__ ((packed
));
222 static inline HFS_extent_t
*HFS_get_extent (HFS_extent_t
*extp
)
224 extp
->start_block
= get_be16(&extp
->start_block
);
225 extp
->block_count
= get_be16(&extp
->block_count
);
230 /* HFS Volume Header */
231 typedef struct HFS_vh_t HFS_vh_t
;
235 uint32_t create_date
;
236 uint32_t modify_date
;
238 uint16_t root_file_count
;
239 uint16_t bitmap_start
;
243 uint16_t alloc_blocs
;
248 uint16_t alloc_start
;
249 HFS_cnid_t next_cnid
;
256 uint32_t backup_tmsp
;
258 uint32_t write_count
;
261 uint32_t ext_clump_size
;
263 uint32_t cat_clump_size
;
266 uint16_t root_dir_cnt
;
271 uint32_t finder_info
[8];
275 HFS_extent_t embed_ext
;
279 HFS_extent_t ext_rec
[3];
283 HFS_extent_t cat_rec
[3];
286 } __attribute__(( __packed__
));
288 static HFS_vh_t
*HFS_read_volhead (part_t
*part
, uint32_t bloc
,
289 uint32_t offset
, void *buffer
, int size
)
294 if (part_seek(part
, bloc
, offset
) == -1)
296 if (part_read(part
, buffer
, size
) < 0)
299 vh
->signature
= get_be16(&vh
->signature
);
300 vh
->create_date
= get_be32(&vh
->create_date
);
301 vh
->modify_date
= get_be32(&vh
->modify_date
);
302 vh
->attributes
= get_be16(&vh
->attributes
);
303 vh
->root_file_count
= get_be16(&vh
->root_file_count
);
304 vh
->bitmap_start
= get_be16(&vh
->bitmap_start
);
305 vh
->alloc_ptr
= get_be16(&vh
->alloc_ptr
);
306 vh
->alloc_blocs
= get_be16(&vh
->alloc_blocs
);
307 vh
->alloc_size
= get_be32(&vh
->alloc_size
);
308 vh
->clump_size
= get_be32(&vh
->clump_size
);
309 vh
->alloc_start
= get_be16(&vh
->alloc_start
);
310 HFS_get_cnid(&vh
->next_cnid
);
311 vh
->free_blocs
= get_be16(&vh
->free_blocs
);
312 vh
->backup_tmsp
= get_be32(&vh
->backup_tmsp
);
313 vh
->backup_seq
= get_be16(&vh
->backup_seq
);
314 vh
->write_count
= get_be32(&vh
->write_count
);
315 vh
->ext_clump_size
= get_be32(&vh
->ext_clump_size
);
316 vh
->cat_clump_size
= get_be32(&vh
->cat_clump_size
);
317 vh
->root_dir_cnt
= get_be16(&vh
->root_dir_cnt
);
318 vh
->file_cnt
= get_be32(&vh
->file_cnt
);
319 vh
->dir_cnt
= get_be32(&vh
->dir_cnt
);
320 for (i
= 0; i
< 8; i
++) {
321 vh
->finder_info
[i
] = get_be32(&vh
->finder_info
[i
]);
323 vh
->embed_sig
= get_be16(&vh
->embed_sig
);
324 HFS_get_extent(&vh
->embed_ext
);
325 vh
->ext_size
= get_be16(&vh
->ext_size
);
326 for (i
= 0; i
< 3; i
++) {
327 HFS_get_extent(&vh
->ext_rec
[i
]);
329 vh
->cat_size
= get_be16(&vh
->cat_size
);
330 for (i
= 0; i
< 3; i
++) {
331 HFS_get_extent(&vh
->cat_rec
[i
]);
338 HFS_NODE_LEAF
= 0xFF,
340 HFS_NODE_HEAD
= 0x01,
344 /* HFS B-tree structures */
345 typedef struct HFS_bnode_t HFS_bnode_t
;
353 } __attribute__ ((packed
));
355 static HFS_bnode_t
*HFS_read_Hnode (part_t
*part
, uint32_t bloc
,
356 uint32_t offset
, void *buffer
, int nsize
)
360 if (part_seek(part
, bloc
, offset
) == -1) {
361 HFS_DPRINTF("seek failed\n");
364 if (part_read(part
, buffer
, nsize
) < 0) {
365 HFS_DPRINTF("read failed\n");
368 Hnode
= (void *)buffer
;
369 Hnode
->next
= get_be32(&Hnode
->next
);
370 Hnode
->prev
= get_be32(&Hnode
->prev
);
371 Hnode
->nrecs
= get_be16(&Hnode
->nrecs
);
376 typedef struct HFS_headrec_t HFS_headrec_t
;
377 struct HFS_headrec_t
{
402 } __attribute__ ((packed
));
404 static HFS_headrec_t
*HFS_get_headrec (void *pos
)
406 HFS_headrec_t
*head
= pos
;
408 head
->depth
= get_be16(&head
->depth
);
409 head
->rootnode
= get_be32(&head
->rootnode
);
410 head
->nbleaves
= get_be32(&head
->nbleaves
);
411 head
->firstleaf
= get_be32(&head
->firstleaf
);
412 head
->lastleaf
= get_be32(&head
->lastleaf
);
413 head
->maxkeylen
= get_be16(&head
->maxkeylen
);
414 head
->nbnodes
= get_be32(&head
->nbnodes
);
415 head
->freenodes
= get_be32(&head
->freenodes
);
416 head
->clump_size
= get_be32(&head
->clump_size
);
417 head
->attr
= get_be32(&head
->attr
);
422 typedef struct HFS_catkey_t HFS_catkey_t
;
423 struct HFS_catkey_t
{
428 unsigned char name
[0x1F];
429 } __attribute__ ((packed
));
431 typedef struct HFSP_catkey_t HFSP_catkey_t
;
432 struct HFSP_catkey_t
{
436 HFSP_unichr_t uniname
[255];
437 } __attribute__ ((packed
));
440 HFS_CAT_FOLDER
= 0x0100,
441 HFS_CAT_FILE
= 0x0200,
442 HFS_CAT_FOLDTH
= 0x0300,
443 HFS_CAT_FILETH
= 0x0400,
444 HFSP_CAT_FOLDER
= 0x0001,
445 HFSP_CAT_FILE
= 0x0002,
446 HFSP_CAT_FOLDTH
= 0x0003,
447 HFSP_CAT_FILETH
= 0x0004,
450 typedef struct HFS_win_t HFS_win_t
;
456 } __attribute__ ((packed
));
458 typedef struct HFS_pos_t HFS_pos_t
;
462 } __attribute__ ((packed
));
464 typedef struct HFS_fdir_info_t HFS_fdir_info_t
;
465 struct HFS_fdir_info_t
{
470 } __attribute__ ((packed
));
472 typedef struct HFS_file_info_t HFS_file_info_t
;
473 struct HFS_file_info_t
{
479 } __attribute__ ((packed
));
481 typedef struct HFSP_BSD_info_t HFSP_BSD_info_t
;
482 struct HFSP_BSD_info_t
{
493 } __attribute__ ((packed
));
495 typedef struct HFS_fold_t HFS_fold_t
;
504 HFS_fdir_info_t finder_dir
;
505 uint8_t finder_pad
[16];
507 } __attribute__ ((packed
));
509 typedef struct HFSP_fold_t HFSP_fold_t
;
520 HFSP_BSD_info_t BSD_infos
;
521 HFS_fdir_info_t finder_dir
;
522 uint8_t finder_pad
[16];
525 } __attribute__ ((packed
));
527 typedef struct HFS_file_t HFS_file_t
;
534 HFS_file_info_t finder_file
;
551 uint8_t finder_pad
[16];
555 HFS_extent_t extents
[3];
557 } __attribute__ ((packed
));
559 typedef struct HFSP_file_t HFSP_file_t
;
574 HFSP_BSD_info_t BSD_infos
;
576 HFS_file_info_t finder_file
;
578 uint8_t finder_pad
[16];
583 HFSP_fork_t ressources
;
584 } __attribute__ ((packed
));
586 typedef struct HFS_thread_t HFS_thread_t
;
587 struct HFS_thread_t
{
592 unsigned char name
[32];
593 } __attribute__ ((packed
));
595 typedef struct HFSP_thread_t HFSP_thread_t
;
596 struct HFSP_thread_t
{
601 HFSP_unichr_t uniname
[255];
602 } __attribute__ ((packed
));
604 /* in memory structures */
605 typedef struct hfs_vol_t hfs_vol_t
;
606 typedef struct hfs_btree_t hfs_btree_t
;
607 typedef struct hfs_rec_t hfs_rec_t
;
609 /* Volume/file structures */
610 typedef struct hfs_extent_t
{
615 typedef struct hfs_fork_t
{
618 hfs_extent_t extents
[8];
627 uint32_t embed_offset
;
628 uint32_t start_offset
;
630 hfs_fork_t alloc_file
;
633 hfs_fork_t
*boot_file
;
634 hfs_btree_t
*cat_tree
;
635 hfs_btree_t
*ext_tree
;
638 /* Btree structures */
640 typedef struct hfs_bnode_t
{
649 /* Cached Btree node */
650 typedef struct hfs_cbnode_t hfs_cbnode_t
;
651 struct hfs_cbnode_t
{
666 typedef struct hfs_headrec_t
{
674 typedef struct hfs_idxrec_t
{
677 unsigned char name
[0x20];
680 /* File extent records */
682 typedef struct hfs_extrec_t
{
686 /* Catalog records */
687 typedef struct hfs_catrec_t
{
691 unsigned char name
[0x20];
692 unsigned char finfo
[9];
702 hfs_headrec_t headrec
;
713 hfs_bnode_t
*root_node
;
714 hfs_rec_t
*root_catrec
;
715 hfs_rec_t
*root_extrec
;
719 int (*compare
)(int type
, HFS_cnid_t cnid
,
720 const void *more
, hfs_rec_t
*rec
, int rectype
);
723 /* Unicode to ISO-8859-15, stolen from Linux nls */
724 static unsigned char page00
[256] = {
725 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
726 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
727 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
728 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
729 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
730 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
731 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
732 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
733 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
734 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
735 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
736 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
737 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
738 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
739 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
740 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
742 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
743 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
744 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
745 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
746 0xa0, 0xa1, 0xa2, 0xa3, 0x00, 0xa5, 0x00, 0xa7, /* 0xa0-0xa7 */
747 0x00, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
748 0xb0, 0xb1, 0xb2, 0xb3, 0x00, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
749 0x00, 0xb9, 0xba, 0xbb, 0x00, 0x00, 0x00, 0xbf, /* 0xb8-0xbf */
750 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
751 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
752 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
753 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
754 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */
755 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */
756 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
757 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
760 static unsigned char page01
[256] = {
761 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
762 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
763 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
764 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
765 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
766 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
767 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
768 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
769 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
770 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
771 0x00, 0x00, 0xbc, 0xbd, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
772 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
773 0xa6, 0xa8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
774 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
775 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
776 0xbe, 0x00, 0x00, 0x00, 0x00, 0xb4, 0xb8, 0x00, /* 0x78-0x7f */
779 static unsigned char page20
[256] = {
780 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
781 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
782 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
783 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
784 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
785 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
786 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
787 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
788 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
789 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
790 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
791 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
792 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
793 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
794 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
795 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
797 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
798 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
799 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
800 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
801 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
802 0x00, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
805 static unsigned char *page_uni2charset
[256] = {
806 page00
, page01
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
807 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
809 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
810 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
812 page20
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
813 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
816 static int uni2char (uint16_t uni
, unsigned char *out
)
818 unsigned char *uni2charset
;
819 unsigned char cl
= uni
& 0x00ff;
820 unsigned char ch
= (uni
& 0xff00) >> 8;
822 uni2charset
= page_uni2charset
[ch
];
823 if (uni2charset
&& uni2charset
[cl
])
824 *out
= uni2charset
[cl
];
831 static void hfs_get_str (unsigned char *out
, int len
, uint16_t *hfs_str
)
836 for (i
= 0; i
< len
; i
++) {
837 if (uni2char(*hfs_str
++, &c
) < 0)
844 /* Locate a bloc in the partition given a file and an offset */
845 static uint32_t hfs_get_bloc (hfs_fork_t
*file
, uint32_t bloc
)
848 hfs_extent_t
*extent
;
849 uint32_t abloc
, aoffset
;
852 volume
= file
->volume
;
853 abloc
= bloc
/ volume
->bsize
;
854 aoffset
= bloc
- (abloc
* volume
->bsize
);
855 extent
= file
->extents
;
857 HFS_DPRINTF("Look for bloc %08x => %08x %08x (%08x)\n",
858 bloc
, abloc
, aoffset
, volume
->bsize
);
860 for (i
= 0; i
< 8; i
++) {
862 HFS_DPRINTF("Check extent %d %08x %08x (%08x)\n",
863 i
, extent
->start
, extent
->count
, abloc
);
865 if (extent
->count
== 0)
867 if (abloc
< extent
->count
) {
868 return volume
->start_offset
+ /*volume->embed_offset +*/
869 ((extent
->start
+ abloc
) * volume
->bsize
) + aoffset
;
871 abloc
-= extent
->count
;
874 HFS_ERROR("Block %d not found\n", bloc
);
879 /* Convert HFS/HFS plus extent/fork records to memory structure */
880 static inline void hfs_get_extent (hfs_extent_t
*dst
, HFS_extent_t
*src
)
882 dst
->start
= src
->start_block
;
883 dst
->count
= src
->block_count
;
886 static void hfs_get_fork (hfs_fork_t
*dst
, uint32_t blocs
,
887 HFS_extent_t
*extents
)
891 dst
->nb_blocs
= blocs
;
892 for (i
= 0; i
< 3; i
++) {
893 hfs_get_extent(&dst
->extents
[i
], &extents
[i
]);
895 memset(&dst
->extents
[3], 0, 5 * sizeof(hfs_extent_t
));
898 static inline void hfsp_get_extent (hfs_extent_t
*dst
, HFSP_extent_t
*src
)
900 dst
->start
= src
->start_block
;
901 dst
->count
= src
->block_count
;
904 static void hfsp_get_fork (hfs_fork_t
*dst
, uint32_t blocs
,
905 HFSP_extent_t
*extents
)
909 dst
->nb_blocs
= blocs
;
910 for (i
= 0; i
< 8; i
++) {
911 hfsp_get_extent(&dst
->extents
[i
], &extents
[i
]);
915 static void hfs_dump_fork (hfs_fork_t
*fork
)
919 HFS_DPRINTF("Nb blocs: %d\n", fork
->nb_blocs
);
920 for (i
= 0; i
< 8; i
++) {
921 if (fork
->extents
[i
].count
== 0)
923 HFS_DPRINTF(" extent %d: start: %08x count: %08x\n",
924 i
, fork
->extents
[i
].start
, fork
->extents
[i
].count
);
928 /* Btree nodes cache */
929 static inline void *hfs_brec_get (HFS_bnode_t
*node
, uint32_t nodesize
, int nb
)
933 if (nb
< 1 || nb
> node
->nrecs
) {
934 HFS_ERROR("nb=%d nrec=%d\n", nb
, node
->nrecs
);
937 off
= (void *)((char *)node
+ nodesize
);
939 HFS_DPRINTF("%d => %02x node %p off %p %p %d\n",
940 nb
, *off
, node
, off
, (char *)node
+ nodesize
, nodesize
);
942 return (char *)node
+ *off
;
945 static hfs_bnode_t
*hfs_bnode_get (hfs_btree_t
*tree
, uint32_t location
)
947 unsigned char *buffer
, tmpbuf
[HFS_NODE_SIZE
];
950 HFS_headrec_t
*Hhead
;
951 HFSP_catkey_t
*HPkey
= NULL
;
952 HFS_catkey_t
*Hkey
= NULL
;
953 HFSP_thread_t
*HPthread
;
954 HFS_thread_t
*Hthread
;
963 uint32_t bloc
, offset
, bsize
, *upID
, nsize
;
968 for (cur
= &tree
->cache
; *cur
!= NULL
; cur
= &((*cur
)->next
)) {
969 if ((*cur
)->location
== location
) {
970 HFS_DPRINTF("found node %08x in cache (%08x %08x)\n",
971 location
, (*cur
)->bnode
.prev
, (*cur
)->bnode
.next
);
972 return &(*cur
)->bnode
;
976 /* Not found in cache, get it from disk */
977 head
= &tree
->head_rec
->u
.headrec
;
978 if (tree
->nodesize
!= 0) {
979 nsize
= tree
->nodesize
;
982 nsize
= HFS_NODE_SIZE
;
985 bsize
= part_blocsize(tree
->file
->volume
->part
);
986 bloc
= location
* nsize
/ 512;
987 HFS_DPRINTF("Get node from %08x %08x %p\n",
988 bloc
, nsize
, tree
->file
->volume
->part
);
989 bloc
= hfs_get_bloc(tree
->file
, bloc
);
990 if (bloc
== (uint32_t)-1)
992 HFS_DPRINTF(" => %08x\n", bloc
);
994 offset
= bloc
% bsize
;
999 HFS_DPRINTF(" => %08x %08x (%d)\n", bloc
, offset
, bsize
);
1000 Hnode
= HFS_read_Hnode(tree
->file
->volume
->part
,
1001 bloc
, offset
, buffer
, nsize
);
1002 if (Hnode
== NULL
) {
1003 HFS_DPRINTF("No Hnode !\n");
1006 *cur
= malloc(sizeof(hfs_cbnode_t
) + (Hnode
->nrecs
* sizeof(hfs_rec_t
)));
1009 memset(*cur
, 0, sizeof(hfs_cbnode_t
) + (Hnode
->nrecs
* sizeof(hfs_rec_t
)));
1010 (*cur
)->location
= location
;
1011 node
= &(*cur
)->bnode
;
1013 node
->prev
= Hnode
->prev
;
1014 node
->next
= Hnode
->next
;
1015 node
->type
= Hnode
->type
;
1016 node
->nrecs
= Hnode
->nrecs
;
1017 node
->recs
= (void *)(node
+ 1);
1018 if (tree
->nodesize
== 0 && node
->type
!= HFS_NODE_HEAD
) {
1019 HFS_ERROR("first node should be a header !\n");
1022 if (node
->type
== HFS_NODE_HEAD
) {
1023 Hhead
= HFS_get_headrec(Hnode
+ 1);
1024 nsize
= Hhead
->nodesize
;
1026 nsize
= HFS_NODE_SIZE
;
1027 HFS_DPRINTF("Set node size to %d\n", nsize
);
1028 tree
->nodesize
= nsize
;
1029 tree
->buf
= malloc(nsize
);
1030 if (tree
->buf
== NULL
)
1032 memset(tree
->buf
, 0, nsize
);
1034 Hnode
= HFS_read_Hnode(tree
->file
->volume
->part
,
1035 bloc
, offset
, buffer
, nsize
);
1039 HFS_DPRINTF("New node %08x prev: %08x next: %08x type: %d nrecs: %d\n",
1040 location
, node
->prev
, node
->next
, node
->type
, node
->nrecs
);
1041 is_hfs
= tree
->file
->volume
->type
== FS_TYPE_HFS
;
1042 for (i
= 0; i
< (int)node
->nrecs
; i
++) {
1043 rec
= &node
->recs
[i
];
1046 HFS_recp
= hfs_brec_get(Hnode
, nsize
, i
+ 1);
1047 if (HFS_recp
== NULL
) {
1048 HFS_ERROR("can't get record %d\n", i
+ 1);
1054 upID
= (void *)(((uint32_t)Hkey
+ 2 + Hkey
->len
));
1056 upID
= (void *)(((uint32_t)Hkey
+ 2 + Hkey
->len
) & ~1);
1060 upID
= (void *)(((uint32_t)HPkey
+ 2 + HPkey
->len
) & ~1);
1062 switch (node
->type
) {
1064 HFS_DPRINTF("record %d: leaf %p %p %d\n", i
+ 1, upID
, HFS_recp
,
1065 (char *)upID
- (char *)HFS_recp
);
1066 rec
->type
= tree
->type
;
1067 switch (rec
->type
) {
1069 ptype
= (void *)upID
;
1071 memcpy(rec
->u
.catrec
.name
, Hkey
->name
, Hkey
->nlen
);
1072 rec
->u
.catrec
.name
[Hkey
->nlen
] = '\0';
1073 rec
->u
.catrec
.pid
= Hkey
->pID
;
1075 hfs_get_str(rec
->u
.catrec
.name
,
1076 HPkey
->nlen
, HPkey
->uniname
);
1077 rec
->u
.catrec
.pid
= HPkey
->pID
;
1079 rec
->u
.catrec
.type
= *ptype
;
1080 rec
->u
.catrec
.fork
.volume
= tree
->file
->volume
;
1081 rec
->u
.catrec
.fork
.catrec
= rec
;
1083 case HFS_CAT_FOLDER
:
1084 Hdir
= (void *)ptype
;
1085 rec
->u
.catrec
.ID
= Hdir
->ID
;
1086 HFS_DPRINTF("HFS Catalog folder ID: %08x name '%s' %08x\n",
1087 rec
->u
.catrec
.ID
, rec
->u
.catrec
.name
,
1091 Hfile
= (void *)ptype
;
1092 rec
->u
.catrec
.ID
= Hfile
->ID
;
1093 memcpy(rec
->u
.catrec
.finfo
, &Hfile
->finder_file
, 8);
1094 rec
->u
.catrec
.finfo
[8] = '\0';
1095 for (j
= 0; j
< 3; j
++) {
1096 hfs_get_extent(&rec
->u
.catrec
.fork
.extents
[j
],
1097 &Hfile
->extents
[j
]);
1099 HFS_DPRINTF("Extent %04x %04x => %08x %08x\n",
1100 Hfile
->extents
[j
].start_block
,
1101 Hfile
->extents
[j
].block_count
,
1102 rec
->u
.catrec
.fork
.extents
[j
].start
,
1103 rec
->u
.catrec
.fork
.extents
[j
].count
);
1106 memset(&rec
->u
.catrec
.fork
.extents
[3], 0,
1107 5 * sizeof(hfs_extent_t
));
1108 HFS_DPRINTF("HFS Catalog file ID: %08x name '%s' '%s' %08x\n",
1109 rec
->u
.catrec
.ID
, rec
->u
.catrec
.name
,
1110 rec
->u
.catrec
.finfo
, rec
->u
.catrec
.pid
);
1112 HFS_DPRINTF("Extent %08x %08x\n",
1113 rec
->u
.catrec
.fork
.extents
[0].start
,
1114 rec
->u
.catrec
.fork
.extents
[0].count
);
1117 case HFS_CAT_FOLDTH
:
1118 Hthread
= (void *)ptype
;
1119 strcpy(rec
->u
.catrec
.name
, Hthread
->name
);
1120 rec
->u
.catrec
.ID
= rec
->u
.catrec
.pid
;
1121 rec
->u
.catrec
.pid
= Hthread
->pid
;
1122 HFS_DPRINTF("HFS Catalog folder thread '%s' %08x %08x\n",
1123 rec
->u
.catrec
.name
, rec
->u
.catrec
.ID
,
1126 case HFS_CAT_FILETH
:
1127 Hthread
= (void *)ptype
;
1128 strcpy(rec
->u
.catrec
.name
, Hthread
->name
);
1129 rec
->u
.catrec
.ID
= rec
->u
.catrec
.pid
;
1130 rec
->u
.catrec
.pid
= Hthread
->pid
;
1131 HFS_DPRINTF("HFS Catalog file thread '%s' %08x %08x\n",
1132 rec
->u
.catrec
.name
, rec
->u
.catrec
.ID
,
1135 case HFSP_CAT_FOLDER
:
1136 HPdir
= (void *)ptype
;
1137 rec
->u
.catrec
.ID
= HPdir
->ID
;
1138 HFS_DPRINTF("HFSplus Catalog folder ID: %08x name '%s'\n",
1139 rec
->u
.catrec
.ID
, rec
->u
.catrec
.name
);
1142 HPfile
= (void *)ptype
;
1143 rec
->u
.catrec
.ID
= HPfile
->ID
;
1144 memcpy(rec
->u
.catrec
.finfo
, &HPfile
->finder_file
, 8);
1145 rec
->u
.catrec
.finfo
[8] = '\0';
1146 memcpy(&rec
->u
.catrec
.fork
, &HPfile
->data
,
1147 sizeof(HFSP_fork_t
));
1148 HFS_DPRINTF("HFSPlus Catalog file ID: %08x name '%s' '%s'\n",
1149 rec
->u
.catrec
.ID
, rec
->u
.catrec
.name
,
1150 rec
->u
.catrec
.finfo
);
1151 HFS_DPRINTF("Extent %08x %08x\n",
1152 rec
->u
.catrec
.fork
.extents
[0].start
,
1153 rec
->u
.catrec
.fork
.extents
[0].count
);
1155 case HFSP_CAT_FOLDTH
:
1156 HPthread
= (void *)ptype
;
1157 rec
->u
.catrec
.ID
= rec
->u
.catrec
.pid
;
1158 rec
->u
.catrec
.pid
= HPthread
->pid
;
1159 hfs_get_str(rec
->u
.catrec
.name
,
1160 HPthread
->nlen
, HPthread
->uniname
);
1161 HFS_DPRINTF("HFSplus Catalog folder thread '%s'...\n",
1162 rec
->u
.catrec
.name
);
1164 case HFSP_CAT_FILETH
:
1165 HPthread
= (void *)ptype
;
1166 hfs_get_str(rec
->u
.catrec
.name
,
1167 HPthread
->nlen
, HPthread
->uniname
);
1168 rec
->u
.catrec
.ID
= rec
->u
.catrec
.pid
;
1169 rec
->u
.catrec
.pid
= HPthread
->pid
;
1170 HFS_DPRINTF("HFSplus Catalog file thread '%s'...\n",
1171 rec
->u
.catrec
.name
);
1174 printf("Unknown catalog entry %d %d '%s' %d\n", rec
->type
,
1175 *ptype
, rec
->u
.catrec
.name
, (char *)ptype
- (char *)Hkey
);
1181 HFS_DPRINTF("Extent file entry\n");
1184 HFS_ERROR("Unknown entry\n");
1189 rec
->type
= RECORD_IDX
;
1190 rec
->u
.idxrec
.uid
= *upID
;
1192 rec
->u
.idxrec
.pid
= Hkey
->pID
;
1193 memcpy(rec
->u
.idxrec
.name
, Hkey
->name
, Hkey
->nlen
);
1194 rec
->u
.idxrec
.name
[Hkey
->nlen
] = '\0';
1195 HFS_DPRINTF("HFS IDX record %d parent: %08x up: %08x name '%s'\n",
1196 i
+ 1, rec
->u
.idxrec
.pid
, rec
->u
.idxrec
.uid
,
1197 rec
->u
.idxrec
.name
);
1198 HFS_DPRINTF("uidp : %d %d\n", (char *)upID
- (char *)Hkey
,
1199 (char *)(Hkey
+ 1) - (char *)Hkey
);
1201 rec
->u
.idxrec
.pid
= HPkey
->pID
;
1202 hfs_get_str(rec
->u
.idxrec
.name
,
1203 HPkey
->nlen
, HPkey
->uniname
);
1204 HFS_DPRINTF("HFSplus IDX record %d parent: %08x up: %08x "
1205 "name '%s'\n", i
+ 1, rec
->u
.idxrec
.pid
,
1206 rec
->u
.idxrec
.uid
, rec
->u
.idxrec
.name
);
1210 Hhead
= HFS_get_headrec(HFS_recp
);
1211 rec
->type
= RECORD_HEAD
;
1212 rec
->u
.headrec
.rootnode
= Hhead
->rootnode
;
1213 rec
->u
.headrec
.firstleaf
= Hhead
->firstleaf
;
1214 rec
->u
.headrec
.lastleaf
= Hhead
->lastleaf
;
1215 rec
->u
.headrec
.nodesize
= Hhead
->nodesize
;
1216 HFS_DPRINTF("Header record %d root: %08x first: %08x last: %08x "
1217 "size: %08x\n", i
+ 1, rec
->u
.headrec
.rootnode
,
1218 rec
->u
.headrec
.firstleaf
, rec
->u
.headrec
.lastleaf
,
1219 rec
->u
.headrec
.nodesize
);
1233 static inline hfs_rec_t
*hfs_rec_get (hfs_bnode_t
*node
, int nb
)
1235 if (nb
< 1 || nb
> (int)node
->nrecs
) {
1236 HFS_ERROR("nb: %d min: %d max: %d\n", nb
, 1, node
->nrecs
);
1240 return &node
->recs
[nb
- 1];
1243 static inline hfs_bnode_t
*hfs_bnode_prev (hfs_bnode_t
*cur
)
1245 if (cur
->prev
== 0x00000000)
1248 return hfs_bnode_get(cur
->tree
, cur
->prev
);
1251 static inline hfs_bnode_t
*hfs_bnode_next (hfs_bnode_t
*cur
)
1253 if (cur
->next
== 0x00000000)
1256 return hfs_bnode_get(cur
->tree
, cur
->next
);
1259 unused
static hfs_rec_t
*hfs_rec_prev (hfs_rec_t
*cur
)
1267 curn
= hfs_bnode_prev(curn
);
1270 num
= curn
->nrecs
+ 1;
1273 return hfs_rec_get(curn
, num
- 1);
1276 unused
static hfs_rec_t
*hfs_rec_next (hfs_rec_t
*cur
)
1283 if (num
== (int)curn
->nrecs
) {
1284 curn
= hfs_bnode_next(curn
);
1290 return hfs_rec_get(curn
, num
- 1);
1293 static int hfs_cat_compare (int type
, HFS_cnid_t cnid
,
1294 const void *more
, hfs_rec_t
*rec
, int rectype
);
1296 /* Simplified Btree recurse function from Linux */
1297 static hfs_rec_t
*hfs_rec_find (hfs_btree_t
*tree
,
1298 HFS_cnid_t cnid
, const char *name
, int rectype
)
1306 * This is an ugly scattering of #if, but it's wonderful for debugging
1307 * hfs_rec_find(). If you set this to 1, then the loop will traverse
1308 * and show all of the records in a node before descending the correct
1311 #define DEBUG_HFS_REC_FIND 0
1312 #if DEBUG_HFS_REC_FIND
1316 #endif /* DEBUG_HFS_REC_FIND */
1318 HFS_DPRINTF("look for ID: %08x '%s'\n", cnid
, name
);
1322 for (curn
= tree
->root_node
; curn
!= NULL
;) {
1323 #if DEBUG_HFS_REC_FIND
1327 #endif /* DEBUG_HFS_REC_FIND */
1328 for (i
= curn
->nrecs
; i
!= 0; i
--) {
1329 cur
= hfs_rec_get(curn
, i
);
1331 HFS_ERROR("Cannot get record %d\n", i
);
1334 HFS_DPRINTF("Check record %d %d %p %p %p\n", i
, cur
->type
, cur
,
1335 curn
->tree
->compare
, &hfs_cat_compare
);
1336 ret
= (*curn
->tree
->compare
)(cur
->type
, cnid
, name
, cur
, rectype
);
1337 HFS_DPRINTF("\t%u:%d\n", i
, ret
);
1339 #if !DEBUG_HFS_REC_FIND
1347 #endif /* DEBUG_HFS_REC_FIND */
1350 #if DEBUG_HFS_REC_FIND
1356 #endif /* DEBUG_HFS_REC_FIND */
1357 HFS_DPRINTF("ret=%d HFS_NODE=%02x RECORD=%02x\n",
1358 ret
, curn
->type
, cur
->type
);
1359 if (i
== 0 || /* exhausted all the records */
1360 curn
->type
== HFS_NODE_LEAF
) { /* Can't descend any lower */
1363 HFS_DPRINTF("Recurse to record: %d %08x => %08x\n",
1364 i
, cnid
, cur
->u
.idxrec
.uid
);
1365 curn
= hfs_bnode_get(curn
->tree
, cur
->u
.idxrec
.uid
);
1367 if (ret
!= 0 || curn
== NULL
) {
1368 /* We won't find what we're looking for... */
1369 HFS_DPRINTF("NOT FOUND\n");
1373 if (ret
!= 0 && cur
->u
.catrec
.ID
!= cnid
) {
1374 HFS_ERROR("%d %d\n", cur
->u
.catrec
.ID
, cnid
);
1378 HFS_DPRINTF("found %p %p %d %p\n", cur
, curn
, i
, hfs_rec_get(curn
, i
));
1383 static inline hfs_rec_t
*hfs_get_dir (hfs_btree_t
*tree
, HFS_cnid_t cnid
,
1384 const unsigned char *name
)
1386 return hfs_rec_find(tree
, cnid
, name
, 1);
1389 static hfs_rec_t
*hfs_get_dirfile (hfs_rec_t
*dir
, HFS_cnid_t cnid
,
1390 const unsigned char *name
,
1391 const unsigned char *info
)
1401 for (idx
= dir
->num
+ 1;; idx
++) {
1402 if (idx
> (int)cur
->nrecs
) {
1403 HFS_DPRINTF("Go to next node %08x\n", cur
->next
);
1404 cur
= hfs_bnode_next(cur
);
1406 HFS_ERROR("Node %08x not found\n", cur
->next
);
1411 rec
= hfs_rec_get(cur
, idx
);
1413 HFS_ERROR("Cannot get record %d\n", idx
);
1416 HFS_DPRINTF("Check record %d '%s' '%s' '%s' '%s'\n",
1417 idx
, rec
->u
.catrec
.name
, rec
->u
.catrec
.finfo
, name
, info
);
1418 if (rec
->type
== RECORD_IDX
) {
1421 frec
= &rec
->u
.catrec
;
1422 if (frec
->type
!= HFS_CAT_FILE
&& frec
->type
!= HFS_CAT_FILETH
&&
1423 frec
->type
!= HFSP_CAT_FILE
&& frec
->type
!= HFSP_CAT_FILETH
)
1425 if (frec
->pid
!= cnid
) {
1426 HFS_ERROR("Out of directory %08x %08x\n", cnid
, frec
->pid
);
1429 if (info
!= NULL
&& memcmp(frec
->finfo
, info
, strlen(info
)) != 0)
1431 /* Beware: HFS is case insensitive ! */
1432 if (name
!= NULL
&& strcasecmp(frec
->name
, name
) != 0)
1440 static hfs_btree_t
*hfs_btree_open (hfs_fork_t
*fork
, int type
,
1441 int (*compare
)(int type
,
1449 hfs_headrec_t
*head
;
1453 bloc
= hfs_get_bloc(fork
, 0);
1454 if (bloc
== (uint32_t)-1)
1456 HFS_DPRINTF("Open btree: bloc=%08x\n", bloc
);
1458 newt
= malloc(sizeof(hfs_btree_t
));
1461 memset(newt
, 0, sizeof(hfs_btree_t
));
1465 newt
->compare
= compare
;
1466 /* Get tree header */
1467 HFS_DPRINTF("Get first node\n");
1468 node
= hfs_bnode_get(newt
, 0);
1470 HFS_ERROR("Cannot get tree head\n");
1473 HFS_DPRINTF("Get first record\n");
1474 rec
= hfs_rec_get(node
, 1);
1476 HFS_ERROR("Cannot get first record\n");
1479 if (rec
->type
!= RECORD_HEAD
) {
1480 HFS_ERROR("Not an header record !\n");
1483 head
= &rec
->u
.headrec
;
1484 newt
->head_rec
= rec
;
1486 HFS_DPRINTF("Get root entry node: %08x\n", head
->rootnode
);
1487 newt
->root_node
= hfs_bnode_get(newt
, head
->rootnode
);
1488 if (newt
->root_node
== NULL
)
1490 /* Get root directory record */
1491 HFS_DPRINTF("Get root folder record\n");
1492 newt
->root_catrec
= hfs_get_dir(newt
, HFS_ROOT_FOLDER
, "");
1493 HFS_DPRINTF("Found root folder record: %p\n", newt
->root_catrec
);
1494 if (newt
->root_catrec
== NULL
)
1500 static int hfs_cat_compare (int type
, HFS_cnid_t cnid
,
1501 const void *more
, hfs_rec_t
*rec
, int rectype
)
1503 hfs_idxrec_t
*idxrec
;
1504 hfs_catrec_t
*catrec
;
1505 const unsigned char *name
;
1509 if (type
== RECORD_IDX
) {
1510 idxrec
= &rec
->u
.idxrec
;
1512 name
= idxrec
->name
;
1515 catrec
= &rec
->u
.catrec
;
1516 name
= catrec
->name
;
1517 if (type
!= RECORD_IDX
&&
1518 (catrec
->type
== HFS_CAT_FOLDTH
||
1519 catrec
->type
== HFS_CAT_FILETH
||
1520 catrec
->type
== HFSP_CAT_FOLDTH
||
1521 catrec
->type
== HFSP_CAT_FILETH
)) {
1522 HFS_DPRINTF("CHECK FOLDER %08x %08x!\n", catrec
->ID
, catrec
->pid
);
1528 HFS_DPRINTF("Compare cnid (%08x '%s') vs (%08x '%s') %08x %d\n",
1529 cnid
, (char *)more
, id
, name
, catrec
->type
, rectype
);
1532 * Always diff Record_IDXs, but diff RECORDS_CATs iff they match the type
1533 * being looked for: THREAD vs NON-THREAD (rectype).
1537 if (ret
== 0 && type
!= RECORD_IDX
) {
1538 /* out on a leaf - don't compare different types */
1540 (catrec
->type
== HFS_CAT_FILE
||
1541 catrec
->type
== HFS_CAT_FOLDER
||
1542 catrec
->type
== HFSP_CAT_FILE
||
1543 catrec
->type
== HFSP_CAT_FOLDER
)) {
1544 /* looking for thread and this is a file/folder - keep looking */
1546 } else if (!rectype
&&
1547 (catrec
->type
== HFS_CAT_FILETH
||
1548 catrec
->type
== HFS_CAT_FOLDTH
||
1549 catrec
->type
== HFSP_CAT_FILETH
||
1550 catrec
->type
== HFSP_CAT_FOLDTH
)) {
1551 /* looking for file/folder and this is a thread - keep looking */
1557 /* Apparently there is still a match - further constrain it by
1558 * checking if the name matches. Name matchs should be
1559 * skipped if we're looking for a thread and we've reached a
1560 * leaf record (that case will match solely on the record
1561 * type and the cnid which has already been done).
1563 (type
== RECORD_IDX
||
1565 (catrec
->type
== HFS_CAT_FILE
||
1566 catrec
->type
== HFS_CAT_FOLDER
||
1567 catrec
->type
== HFSP_CAT_FILE
||
1568 catrec
->type
== HFSP_CAT_FOLDER
)))) {
1569 /* HFS is case insensitive - HFSP *can* be case sensitive */
1570 ret
= strcasecmp(more
, name
);
1573 HFS_DPRINTF("ret %d catrec %p catrec->type %08x\n",
1574 ret
, catrec
, catrec
? catrec
->type
: 0);
1578 static hfs_btree_t
*hfs_cat_open (hfs_vol_t
*volume
)
1580 HFS_DPRINTF("Open HFS catalog\n");
1581 return hfs_btree_open(&volume
->cat_file
, RECORD_CAT
, &hfs_cat_compare
);
1584 unused
static int hfs_ext_compare (unused
int type
, unused HFS_cnid_t cnid
,
1585 unused
const void *more
,
1586 unused hfs_rec_t
*rec
)
1592 static hfs_btree_t
*hfs_ext_open (unused hfs_vol_t
*volume
)
1594 HFS_DPRINTF("Open HFS extents file\n");
1596 return hfs_btree_open(&volume
->ext_file
, RECORD_EXT
, &hfs_ext_compare
);
1602 static void hfs_map_boot_file (part_t
*part
, hfs_vol_t
*volume
,
1603 uint32_t *boot_start
, uint32_t *boot_offset
,
1604 uint32_t *boot_size
)
1606 uint32_t bloc
, size
;
1608 /* Now, patch the partition to register the boot file
1609 * XXX: we "know" that only one extent is used...
1610 * this may not be true if booting from a hard drive...
1612 volume
->boot_file
->volume
= volume
;
1613 bloc
= hfs_get_bloc(volume
->boot_file
, 0);
1614 if (bloc
== (uint32_t)(-1)) {
1615 printf("Cannot get boot file start bloc\n");
1618 size
= volume
->boot_file
->extents
[0].count
* volume
->bsize
;
1619 // printf("Map boot file bloc 0 to %08x\n", bloc);
1620 part_set_boot_file(part
, bloc
, 0, size
);
1626 static inode_t
*fs_hfs_get_inode (inode_t
*parent
, const unsigned char *name
)
1629 hfs_fork_t
*pfile
, *file
;
1630 hfs_rec_t
*catrec
, *extrec
;
1634 pfile
= parent
->private;
1635 HFS_DPRINTF("Get inode '%s' %p %p %p %08x\n", name
, pfile
, pfile
->catrec
,
1636 pfile
->catrec
->node
->tree
, pfile
->catrec
->u
.catrec
.pid
);
1637 catrec
= hfs_rec_find(pfile
->catrec
->node
->tree
,
1638 pfile
->catrec
->u
.catrec
.ID
, name
, 0);
1640 extrec
= hfs_rec_find(pfile
->extrec
->node
->tree
,
1641 pfile
->extrec
->u
.extrec
.pid
, name
, 0);
1645 if (catrec
== NULL
/* || extrec == NULL */)
1647 new = malloc(sizeof(inode_t
));
1650 memset(new, 0, sizeof(inode_t
));
1652 file
= &catrec
->u
.catrec
.fork
;
1653 new->private = file
;
1655 for (i
= 0; i
< 8; i
++) {
1656 if (file
->extents
[i
].count
== 0)
1658 size
+= file
->extents
[i
].count
;
1660 size
*= file
->volume
->bsize
;
1661 new->size
.bloc
= size
;
1662 new->size
.offset
= 0;
1663 HFS_DPRINTF("File: '%s'\n", name
);
1664 hfs_dump_fork(new->private);
1669 static void fs_hfs_put_inode (unused inode_t
*inode
)
1673 static uint32_t fs_hfs_map_bloc (inode_t
*inode
, uint32_t bloc
)
1675 return hfs_get_bloc(inode
->private, bloc
);
1678 static inode_t
*fs_hfs_get_special_inode (fs_t
*fs
, int type
)
1681 inode_t
*bfile
, *bdir
, *cur
;
1682 hfs_rec_t
*drec
, *rec
;
1684 uint32_t boot_start
, boot_size
, boot_offset
;
1687 volume
= fs
->private;
1690 if (fs
->root
== NULL
) {
1691 volume
->cat_tree
= hfs_cat_open(volume
);
1692 volume
->ext_tree
= hfs_ext_open(volume
);
1693 if (volume
->cat_tree
== NULL
/*|| volume->ext_tree == NULL*/) {
1694 HFS_ERROR("Can't open volume catalog/extent files\n");
1697 cur
= malloc(sizeof(inode_t
));
1700 memset(cur
, 0, sizeof(inode_t
));
1701 cur
->flags
= INODE_TYPE_DIR
;
1702 cur
->private = &volume
->cat_tree
->root_catrec
->u
.catrec
.fork
;
1709 if (fs
->bootfile
!= NULL
)
1710 return fs
->bootfile
;
1713 if (fs
->bootdir
!= NULL
)
1715 if (volume
->boot_file
!= NULL
) {
1716 bfile
= malloc(sizeof(inode_t
));
1719 memset(bfile
, 0, sizeof(inode_t
));
1720 fs
->bootfile
= bfile
;
1721 rec
= volume
->boot_file
->catrec
;
1722 bfile
->name
= strdup(rec
->u
.catrec
.name
);
1723 if (bfile
->name
== NULL
) {
1725 fs
->bootfile
= NULL
;
1728 bfile
->private = volume
->boot_file
;
1729 bfile
->flags
= INODE_TYPE_FILE
| INODE_FLAG_EXEC
| INODE_FLAG_BOOT
;
1730 fs
->bootdir
= fs
->root
;
1731 hfs_map_boot_file(fs
->part
, volume
,
1732 &boot_start
, &boot_offset
, &boot_size
);
1738 HFS_DPRINTF("Look for boot file (%d)\n", volume
->boot_id
);
1739 if (volume
->boot_file
== NULL
||
1740 volume
->boot_file
->extents
[0].count
== 0) {
1741 if (volume
->boot_id
!= 0x00000000) {
1742 /* Try to find regular MacOS bootfile */
1743 drec
= hfs_get_dir(volume
->cat_tree
, volume
->boot_id
, "");
1745 HFS_ERROR("Didn't find boot directory %d\n", volume
->boot_id
);
1748 HFS_DPRINTF("Found boot directory '%s'\n", drec
->u
.catrec
.name
);
1749 rec
= hfs_get_dirfile(drec
, volume
->boot_id
, NULL
, "tbxi");
1751 /* Try NetBSD boot */
1752 drec
= hfs_get_dir(volume
->cat_tree
, HFS_ROOT_FOLDER
, "");
1755 rec
= hfs_get_dirfile(drec
, HFS_ROOT_FOLDER
, "ofwboot", NULL
);
1757 rec
= hfs_get_dirfile(drec
, HFS_ROOT_FOLDER
,
1758 "ofwboot.xcf", NULL
);
1760 rec
= hfs_get_dirfile(drec
, HFS_ROOT_FOLDER
,
1761 "ofwboot.elf", NULL
);
1765 volume
->boot_id
= rec
->u
.catrec
.pid
;
1766 drec
= hfs_get_dir(volume
->cat_tree
, volume
->boot_id
, "");
1770 HFS_ERROR("Didn't find boot file\n");
1773 volume
->boot_file
= &rec
->u
.catrec
.fork
;
1774 hfs_map_boot_file(fs
->part
, volume
,
1775 &boot_start
, &boot_offset
, &boot_size
);
1776 HFS_DPRINTF("boot file mapped: %08x-%08x %08x\n",
1777 boot_start
, boot_offset
, boot_size
);
1779 hfs_treat_boot_file(fs
->part
, volume
,
1780 &boot_start
, &boot_offset
, &boot_size
);
1782 HFS_DPRINTF("Dump boot file\n");
1783 hfs_dump_fork(volume
->boot_file
);
1784 HFS_DPRINTF("boot file mapped: %08x-%08x %08x\n",
1785 boot_start
, boot_offset
, boot_size
);
1787 drec
= hfs_get_dir(volume
->cat_tree
, HFS_ROOT_FOLDER
, "");
1791 rec
= volume
->boot_file
->catrec
;
1792 fork
= volume
->boot_file
;
1793 HFS_DPRINTF("boot file: %p '%s' boot dir: %p '%s'\n",
1794 rec
, rec
->u
.catrec
.name
, drec
, drec
->u
.catrec
.name
);
1795 bfile
= malloc(sizeof(inode_t
));
1798 memset(bfile
, 0, sizeof(inode_t
));
1799 fs
->bootfile
= bfile
;
1800 bfile
->name
= strdup(rec
->u
.catrec
.name
);
1801 if (bfile
->name
== NULL
) {
1805 bfile
->private = fork
;
1806 bfile
->flags
= INODE_TYPE_FILE
| INODE_FLAG_EXEC
| INODE_FLAG_BOOT
;
1807 bfile
->size
.bloc
= boot_size
/ part_blocsize(volume
->part
);
1808 bfile
->size
.offset
= boot_size
% part_blocsize(volume
->part
);
1809 HFS_DPRINTF("%s: look for parent ID: %08x\n", __func__
, volume
->boot_id
);
1812 if (type
== FILE_BOOT
) {
1815 for (id
= volume
->boot_id
; id
!= HFS_ROOT_FOLDER
;
1816 id
= drec
->u
.catrec
.pid
) {
1817 drec
= hfs_get_dir(volume
->cat_tree
, id
, "");
1820 bdir
= malloc(sizeof(inode_t
));
1823 memset(bdir
, 0, sizeof(inode_t
));
1824 if (id
== volume
->boot_id
) {
1825 if (type
== FILE_BOOTDIR
)
1829 bdir
->name
= strdup(drec
->u
.catrec
.name
);
1830 if (bdir
->name
== NULL
) {
1834 bdir
->private = &drec
->u
.catrec
.fork
;
1835 bdir
->flags
= INODE_TYPE_DIR
;
1836 bfile
->parent
= bdir
;
1837 HFS_DPRINTF("%s: cache '%s' into '%s'\n",
1838 __func__
, bfile
->name
, bdir
->name
);
1839 fs_cache_add_inode(bdir
, bfile
);
1842 bfile
->parent
= fs
->root
;
1843 HFS_DPRINTF("%s: cache '%s' into root dir\n", __func__
, bfile
->name
);
1844 fs_cache_add_inode(fs
->root
, bfile
);
1848 if (type
== FILE_BOOTDIR
)
1852 HFS_DPRINTF("boot file: %p '%s' boot dir: %p '%s'\n",
1853 fs
->bootfile
, fs
->bootfile
->name
,
1854 fs
->bootdir
, fs
->bootdir
->name
);
1855 HFS_DPRINTF("boot fork %p rec %p %p %08x\n",
1856 bfile
->private, rec
, rec
->u
.catrec
.fork
.catrec
,
1858 HFS_DPRINTF("boot dir fork %p rec %p %p %08x %08x\n",
1859 bdir
->private, drec
, drec
->u
.catrec
.fork
.catrec
,
1860 drec
->u
.catrec
.ID
, volume
->boot_id
);
1861 HFS_DPRINTF("FS cat tree: %p\n", volume
->cat_tree
);
1866 static fs_ops_t hfs_fs_ops
= {
1870 &fs_hfs_get_special_inode
,
1873 int fs_hfs_probe (part_t
*part
, uint32_t *size
,
1874 fs_ops_t
**fs_ops
, unsigned char **name
,
1877 unsigned char buffer
[512];
1881 uint32_t embed_offset
= 0, boot_id
;
1884 hfs_vh
= HFS_read_volhead(part
, HFS_VOLHEAD_SECTOR
, 0, buffer
, 512);
1886 if (hfs_vh
== NULL
) {
1887 DPRINTF("Can't read HFS volume header\n");
1891 if (hfs_vh
->signature
== HFS_VOLHEAD_SIG
) {
1893 printf("HFS volume\n");
1894 if (hfs_vh
->embed_sig
== HFSPLUS_VOLHEAD_SIG
) {
1895 embed_offset
= hfs_vh
->embed_ext
.start_block
*
1896 hfs_vh
->alloc_size
/ HFS_SECTOR_SIZE
;
1897 embed_offset
+= hfs_vh
->alloc_start
;
1898 printf("HFSplus embedded volume offset=%08x\n", embed_offset
);
1899 hfsp_vh
= HFSP_read_volhead(part
,
1900 HFS_VOLHEAD_SECTOR
+ embed_offset
,
1904 boot_id
= hfs_vh
->finder_info
[0];
1905 DPRINTF("HFS boot id : %d %04x\n", boot_id
, boot_id
);
1906 volume
= malloc(sizeof(hfs_vol_t
));
1909 memset(volume
, 0, sizeof(hfs_vol_t
));
1910 HFS_DPRINTF("sig: %x %x %x\n", hfs_vh
->signature
,
1911 hfs_vh
->embed_sig
, HFSPLUS_VOLHEAD_SIG
);
1912 HFS_DPRINTF("cr: %08x mod: %08x attr: %04x count: %04x\n",
1913 hfs_vh
->create_date
, hfs_vh
->modify_date
,
1914 hfs_vh
->attributes
, hfs_vh
->root_file_count
);
1915 HFS_DPRINTF("alloc ptr: %04x blocs: %04x size: %08x bmap %04x\n",
1916 hfs_vh
->alloc_ptr
, hfs_vh
->alloc_blocs
, hfs_vh
->alloc_size
,
1917 hfs_vh
->bitmap_start
);
1918 volume
->bsize
= hfs_vh
->alloc_size
/ HFS_SECTOR_SIZE
;
1919 volume
->start_offset
= hfs_vh
->alloc_start
;
1921 volume
->alloc_file
.volume
= volume
;
1922 volume
->alloc_file
.nb_blocs
= hfs_vh
->alloc_size
* volume
->bsize
;
1923 volume
->alloc_file
.extents
[0].start
= 0;
1924 volume
->alloc_file
.extents
[0].count
= hfs_vh
->alloc_size
;
1926 volume
->cat_file
.volume
= volume
;
1927 hfs_get_fork(&volume
->cat_file
, hfs_vh
->cat_size
, hfs_vh
->cat_rec
);
1929 volume
->ext_file
.volume
= volume
;
1930 hfs_get_fork(&volume
->ext_file
, hfs_vh
->ext_size
, hfs_vh
->ext_rec
);
1931 *size
= hfs_vh
->alloc_blocs
* volume
->bsize
;
1932 *name
= strdup(hfs_vh
->label
);
1937 hfsp_vh
= HFSP_read_volhead(part
, HFS_VOLHEAD_SECTOR
, 0, buffer
, 512);
1939 if (hfsp_vh
== NULL
) {
1940 DPRINTF("Can't read HFS+ volume header\n");
1943 if (hfsp_vh
->signature
!= HFSPLUS_VOLHEAD_SIG
) {
1944 DPRINTF("Bad HFS+ signature %02x %02x\n",
1945 hfsp_vh
->signature
, HFSPLUS_VOLHEAD_SIG
);
1949 printf("HFSplus volume\n");
1950 volume
= malloc(sizeof(hfs_vol_t
));
1953 memset(volume
, 0, sizeof(hfs_vol_t
));
1954 volume
->embed_offset
= embed_offset
;
1955 volume
->start_offset
= embed_offset
;
1956 volume
->bsize
= hfsp_vh
->blocksize
/ HFS_SECTOR_SIZE
;
1957 // volume->bsize = 2048;
1959 HFS_DPRINTF("Boot file: %d %d\n",
1960 hfsp_vh
->start_file
.total_blocks
,
1961 hfsp_vh
->start_file
.extents
[0].block_count
);
1962 if (hfsp_vh
->start_file
.total_blocks
!= 0) {
1963 volume
->boot_file
= malloc(sizeof(hfs_fork_t
));
1964 memset(volume
->boot_file
, 0, sizeof(hfs_fork_t
));
1965 volume
->boot_file
->volume
= volume
;
1966 hfsp_get_fork(volume
->boot_file
,
1967 hfsp_vh
->start_file
.total_blocks
,
1968 hfsp_vh
->start_file
.extents
);
1971 boot_id
= hfsp_vh
->finder_info
[0];
1973 DPRINTF("HFS+ boot id : %d %04x %d\n", boot_id
, boot_id
,
1974 hfsp_vh
->start_file
.total_blocks
);
1976 volume
->cat_file
.volume
= volume
;
1977 hfsp_get_fork(&volume
->cat_file
,
1978 hfsp_vh
->cat_file
.total_blocks
,
1979 hfsp_vh
->cat_file
.extents
);
1981 volume
->ext_file
.volume
= volume
;
1982 hfsp_get_fork(&volume
->ext_file
,
1983 hfsp_vh
->ext_file
.total_blocks
,
1984 hfsp_vh
->ext_file
.extents
);
1985 *size
= hfsp_vh
->total_blocks
* volume
->bsize
;
1986 type
= FS_TYPE_HFSP
;
1988 volume
->boot_id
= boot_id
;
1989 volume
->type
= type
;
1990 HFS_DPRINTF("%s volume: type: %d bsize: %d start_offset: %d\n",
1991 type
== FS_TYPE_HFS
? "HFS" : "HFSplus",
1992 volume
->type
, volume
->bsize
, volume
->start_offset
);
1993 HFS_DPRINTF("Catalog file:\n");
1994 hfs_dump_fork(&volume
->cat_file
);
1995 HFS_DPRINTF("Extents file:\n");
1996 hfs_dump_fork(&volume
->ext_file
);
1997 if (volume
->boot_file
!= NULL
) {
1998 HFS_DPRINTF("Boot file:\n");
1999 hfs_dump_fork(volume
->boot_file
);
2001 *fs_ops
= &hfs_fs_ops
;
2002 HFS_DPRINTF("Set part to %p\n", part
);
2003 volume
->part
= part
;