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;