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;