~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to roms/openhackware/src/libfs/hfs.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * <hfs.c>
 
3
 *
 
4
 * Open Hack'Ware BIOS HFS file system management
 
5
 * 
 
6
 * Copyright (c) 2004-2005 Jocelyn Mayer
 
7
 * 
 
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
 
11
 *
 
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.
 
16
 *
 
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
 
20
 *
 
21
 * Major rework and debug by Thayne Harbaugh <thayne@realmsys.com>
 
22
 */
 
23
 
 
24
#include <stdlib.h>
 
25
#include <stdio.h>
 
26
#include "bios.h"
 
27
#include "libfs.h"
 
28
 
 
29
//#define DEBUG_HFS 1
 
30
 
 
31
/* HFS / HFSplus */
 
32
#if defined (DEBUG_HFS)
 
33
#define HFS_DPRINTF(fmt, args...) \
 
34
do { dprintf("%s: " fmt, __func__ , ##args); } while (0)
 
35
#else
 
36
#define HFS_DPRINTF(fmt, args...) \
 
37
do { } while (0)
 
38
#endif
 
39
#define HFS_ERROR(fmt, args...) \
 
40
do { dprintf("HFS ERROR in %s: " fmt, __func__ , ##args); } while (0)
 
41
 
 
42
/* HFS/HFS+ common definitions */
 
43
#define HFS_SECTOR_SIZE        512
 
44
#define HFS_VOLHEAD_SECTOR       2
 
45
#define HFS_NODE_SIZE          0x200
 
46
 
 
47
/* HFS signature */
 
48
#define HFS_VOLHEAD_SIG         0x4244
 
49
/* HFS+ signature */
 
50
#define HFSPLUS_VOLHEAD_SIG     0x482b
 
51
 
 
52
/* HFS+ filesystem support */
 
53
/* Files CNID */
 
54
enum {
 
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,
 
65
};
 
66
 
 
67
typedef uint32_t HFS_cnid_t;
 
68
 
 
69
static inline HFS_cnid_t HFS_get_cnid (HFS_cnid_t *cnidp)
 
70
{
 
71
    return get_be32(cnidp);
 
72
}
 
73
 
 
74
typedef uint16_t HFSP_unichr_t;
 
75
 
 
76
static inline HFSP_unichr_t HFSP_get_unichr (HFSP_unichr_t *chrp)
 
77
{
 
78
    return get_be16(chrp);
 
79
}
 
80
 
 
81
/* A single contiguous area of a file */
 
82
typedef struct HFSP_extent_t HFSP_extent_t;
 
83
struct HFSP_extent_t {
 
84
    uint32_t start_block;
 
85
    uint32_t block_count;
 
86
} __attribute__ ((packed));
 
87
 
 
88
static inline HFSP_extent_t *HFSP_get_extent (HFSP_extent_t *extp)
 
89
{
 
90
    extp->start_block = get_be32(&extp->start_block);
 
91
    extp->block_count = get_be32(&extp->block_count);
 
92
 
 
93
    return extp;
 
94
}
 
95
 
 
96
/* Information for a "Fork" in a file */
 
97
typedef struct HFSP_fork_t HFSP_fork_t;
 
98
struct HFSP_fork_t {
 
99
    /* 0x00 */
 
100
    uint64_t total_size;
 
101
    uint32_t clump_size;
 
102
    uint32_t total_blocks;
 
103
    /* 0x10 */
 
104
    HFSP_extent_t extents[8];
 
105
    /* 0x50 */
 
106
} __attribute__ ((packed));
 
107
 
 
108
static inline HFSP_fork_t *HFSP_get_fork (HFSP_fork_t *forkp)
 
109
{
 
110
    int i;
 
111
 
 
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]);
 
117
    }
 
118
 
 
119
    return forkp;
 
120
}
 
121
 
 
122
/* HFS+ Volume Header */
 
123
typedef struct HFSP_vh_t HFSP_vh_t;
 
124
struct HFSP_vh_t {
 
125
    /* 0x000 */
 
126
    uint16_t signature;
 
127
    uint16_t version;
 
128
    uint32_t attributes;
 
129
    uint32_t last_mount_vers;
 
130
    uint32_t reserved;
 
131
    
 
132
    /* 0x010 */
 
133
    uint32_t create_date;
 
134
    uint32_t modify_date;
 
135
    uint32_t backup_date;
 
136
    uint32_t checked_date;
 
137
    
 
138
    /* 0x020 */
 
139
    uint32_t file_count;
 
140
    uint32_t folder_count;
 
141
    uint32_t blocksize;
 
142
    uint32_t total_blocks;
 
143
 
 
144
    /* 0x030 */
 
145
    uint32_t free_blocks;
 
146
    uint32_t next_alloc;
 
147
    uint32_t rsrc_clump_sz;
 
148
    uint32_t data_clump_sz;
 
149
 
 
150
    /* 0x040 */
 
151
    HFS_cnid_t next_cnid;
 
152
    uint32_t write_count;
 
153
    uint64_t encodings_bmp;
 
154
    
 
155
    /* 0x050 */
 
156
    uint32_t finder_info[8];
 
157
    
 
158
    /* 0x070 */
 
159
    HFSP_fork_t alloc_file;
 
160
    /* 0x0C0 */
 
161
    HFSP_fork_t ext_file;
 
162
    /* 0x110 */
 
163
    HFSP_fork_t cat_file;
 
164
    /* 0x160 */
 
165
    HFSP_fork_t attr_file;
 
166
    /* 0x1B0 */
 
167
    HFSP_fork_t start_file;
 
168
    /* 0x1F0 */
 
169
    uint8_t pad[16];
 
170
} __attribute__ ((packed));
 
171
 
 
172
static HFSP_vh_t *HFSP_read_volhead (part_t *part, uint32_t bloc,
 
173
                                     uint32_t offset, void *buffer, int size)
 
174
{
 
175
    HFSP_vh_t *vh;
 
176
    int i;
 
177
    
 
178
    if (part_seek(part, bloc, offset) == -1)
 
179
        return NULL;
 
180
    if (part_read(part, buffer, size) < 0)
 
181
        return NULL;
 
182
    vh = buffer;
 
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]);
 
204
    }
 
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);
 
210
 
 
211
    return vh;
 
212
}
 
213
 
 
214
/* HFS support */
 
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));
 
221
 
 
222
static inline HFS_extent_t *HFS_get_extent (HFS_extent_t *extp)
 
223
{
 
224
    extp->start_block = get_be16(&extp->start_block);
 
225
    extp->block_count = get_be16(&extp->block_count);
 
226
 
 
227
    return extp;
 
228
}
 
229
 
 
230
/* HFS Volume Header */
 
231
typedef struct HFS_vh_t HFS_vh_t;
 
232
struct HFS_vh_t {
 
233
    /* 0x000 */
 
234
    uint16_t signature;
 
235
    uint32_t create_date;
 
236
    uint32_t modify_date;
 
237
    uint16_t attributes;
 
238
    uint16_t root_file_count;
 
239
    uint16_t bitmap_start;
 
240
 
 
241
    /* 0x010 */
 
242
    uint16_t alloc_ptr;
 
243
    uint16_t alloc_blocs;
 
244
    uint32_t alloc_size;
 
245
 
 
246
    /* 0x018 */
 
247
    uint32_t clump_size;
 
248
    uint16_t alloc_start;
 
249
    HFS_cnid_t next_cnid;
 
250
    uint16_t free_blocs;
 
251
 
 
252
    /* 0x024 */
 
253
    uint8_t  label[28];
 
254
 
 
255
    /* 0x040 */
 
256
    uint32_t backup_tmsp;
 
257
    uint16_t backup_seq;
 
258
    uint32_t write_count;
 
259
 
 
260
    /* 0x04A */
 
261
    uint32_t ext_clump_size;
 
262
    /* 0x04E */
 
263
    uint32_t cat_clump_size;
 
264
 
 
265
    /* 0x052 */
 
266
    uint16_t root_dir_cnt;
 
267
    /* 0x054 */
 
268
    uint32_t file_cnt;
 
269
    uint32_t dir_cnt;
 
270
    /* 0x05C */
 
271
    uint32_t finder_info[8];
 
272
 
 
273
    /* 0x07C */
 
274
    uint16_t embed_sig;
 
275
    HFS_extent_t embed_ext;
 
276
 
 
277
    /* 0x082 */
 
278
    uint32_t ext_size;
 
279
    HFS_extent_t ext_rec[3];
 
280
 
 
281
    /* 0x092 */
 
282
    uint32_t cat_size;
 
283
    HFS_extent_t cat_rec[3];
 
284
 
 
285
    /* 0x0A2 */
 
286
} __attribute__(( __packed__ ));
 
287
 
 
288
static HFS_vh_t *HFS_read_volhead (part_t *part, uint32_t bloc,
 
289
                                   uint32_t offset, void *buffer, int size)
 
290
{
 
291
    HFS_vh_t *vh;
 
292
    int i;
 
293
    
 
294
    if (part_seek(part, bloc, offset) == -1)
 
295
        return NULL;
 
296
    if (part_read(part, buffer, size) < 0)
 
297
        return NULL;
 
298
    vh = buffer;
 
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]);
 
322
    }
 
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]);
 
328
    }
 
329
    vh->cat_size = get_be16(&vh->cat_size);
 
330
    for (i = 0; i < 3; i++) {
 
331
        HFS_get_extent(&vh->cat_rec[i]);
 
332
    }
 
333
 
 
334
    return vh;
 
335
}
 
336
 
 
337
enum {
 
338
    HFS_NODE_LEAF = 0xFF,
 
339
    HFS_NODE_IDX  = 0x00,
 
340
    HFS_NODE_HEAD = 0x01,
 
341
    HFS_NODE_MAP  = 0x02,
 
342
};
 
343
 
 
344
/* HFS B-tree structures */
 
345
typedef struct HFS_bnode_t HFS_bnode_t;
 
346
struct HFS_bnode_t {
 
347
    uint32_t next;
 
348
    uint32_t prev;
 
349
    uint8_t  type;
 
350
    uint8_t  height;
 
351
    uint16_t nrecs;
 
352
    uint16_t pad;
 
353
} __attribute__ ((packed));
 
354
 
 
355
static HFS_bnode_t *HFS_read_Hnode (part_t *part, uint32_t bloc,
 
356
                                    uint32_t offset, void *buffer, int nsize)
 
357
{
 
358
    HFS_bnode_t *Hnode;
 
359
    
 
360
    if (part_seek(part, bloc, offset) == -1) {
 
361
        HFS_DPRINTF("seek failed\n");
 
362
        return NULL;
 
363
    }
 
364
    if (part_read(part, buffer, nsize) < 0) {
 
365
        HFS_DPRINTF("read failed\n");
 
366
        return NULL;
 
367
    }
 
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);
 
372
 
 
373
    return Hnode;
 
374
}
 
375
 
 
376
typedef struct HFS_headrec_t HFS_headrec_t;
 
377
struct HFS_headrec_t {
 
378
    /* 0x00 */
 
379
    uint16_t depth;
 
380
    uint32_t rootnode;
 
381
    /* 0x06 */
 
382
    uint32_t nbleaves;
 
383
    uint32_t firstleaf;
 
384
    /* 0x0E */
 
385
    uint32_t lastleaf;
 
386
    uint16_t nodesize;
 
387
    /* 0x14 */
 
388
    uint16_t maxkeylen;
 
389
    uint32_t nbnodes;
 
390
    /* 0x18 */
 
391
    uint32_t freenodes;
 
392
    uint16_t pad0;
 
393
    /* 0x1E */
 
394
    uint32_t clump_size;
 
395
    uint8_t  type;
 
396
    uint8_t  pad1;
 
397
    /* 0x24 */
 
398
    uint32_t attr;
 
399
    /* 0x28 */
 
400
    uint32_t pad2[16];
 
401
    /* 0x68 */
 
402
} __attribute__ ((packed));
 
403
 
 
404
static HFS_headrec_t *HFS_get_headrec (void *pos)
 
405
{
 
406
    HFS_headrec_t *head = pos;
 
407
 
 
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);
 
418
 
 
419
    return head;
 
420
}
 
421
 
 
422
typedef struct HFS_catkey_t HFS_catkey_t;
 
423
struct HFS_catkey_t {
 
424
    uint8_t len;
 
425
    uint8_t pad;
 
426
    HFS_cnid_t pID;
 
427
    uint8_t nlen;
 
428
    unsigned char name[0x1F];
 
429
} __attribute__ ((packed));
 
430
 
 
431
typedef struct HFSP_catkey_t HFSP_catkey_t;
 
432
struct HFSP_catkey_t {
 
433
    uint16_t len;
 
434
    HFS_cnid_t pID;
 
435
    uint16_t nlen;
 
436
    HFSP_unichr_t uniname[255];
 
437
} __attribute__ ((packed));
 
438
 
 
439
enum {
 
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,
 
448
};
 
449
 
 
450
typedef struct HFS_win_t HFS_win_t;
 
451
struct HFS_win_t {
 
452
    uint16_t top;
 
453
    uint16_t left;
 
454
    uint16_t bot;
 
455
    uint16_t right;
 
456
}  __attribute__ ((packed));
 
457
 
 
458
typedef struct HFS_pos_t HFS_pos_t;
 
459
struct HFS_pos_t {
 
460
    uint16_t y;
 
461
    uint16_t x;
 
462
} __attribute__ ((packed));
 
463
 
 
464
typedef struct HFS_fdir_info_t HFS_fdir_info_t;
 
465
struct HFS_fdir_info_t {
 
466
    HFS_win_t win;
 
467
    uint16_t  flags;
 
468
    HFS_pos_t pos;
 
469
    uint16_t  pad;
 
470
} __attribute__ ((packed));
 
471
 
 
472
typedef struct HFS_file_info_t HFS_file_info_t;
 
473
struct HFS_file_info_t {
 
474
    uint32_t  ftype;
 
475
    uint32_t  owner;
 
476
    uint16_t  flags;
 
477
    HFS_pos_t pos;
 
478
    uint16_t  pad;
 
479
} __attribute__ ((packed));
 
480
 
 
481
typedef struct HFSP_BSD_info_t HFSP_BSD_info_t;
 
482
struct HFSP_BSD_info_t {
 
483
    uint32_t owner;
 
484
    uint32_t group;
 
485
    uint8_t aflags;
 
486
    uint8_t oflags;
 
487
    uint16_t mode;
 
488
    union {
 
489
        uint32_t inum;
 
490
        uint32_t lcount;
 
491
        uint32_t device;
 
492
    } u;
 
493
} __attribute__ ((packed));
 
494
 
 
495
typedef struct HFS_fold_t HFS_fold_t;
 
496
struct HFS_fold_t {
 
497
    uint16_t type;
 
498
    uint16_t flags;
 
499
    uint16_t valence;
 
500
    HFS_cnid_t ID;
 
501
    uint32_t created;
 
502
    uint32_t modifd;
 
503
    uint32_t backupd;
 
504
    HFS_fdir_info_t finder_dir;
 
505
    uint8_t  finder_pad[16];
 
506
    uint32_t pad[4];
 
507
} __attribute__ ((packed));
 
508
 
 
509
typedef struct HFSP_fold_t HFSP_fold_t;
 
510
struct HFSP_fold_t {
 
511
    uint16_t type;
 
512
    uint16_t flags;
 
513
    uint32_t valence;
 
514
    HFS_cnid_t ID;
 
515
    uint32_t created;
 
516
    uint32_t modifd;
 
517
    uint32_t attrd;
 
518
    uint32_t accessd;
 
519
    uint32_t attrmd;
 
520
    HFSP_BSD_info_t BSD_infos;
 
521
    HFS_fdir_info_t finder_dir;
 
522
    uint8_t  finder_pad[16];
 
523
    uint32_t encoding;
 
524
    uint32_t pad;
 
525
} __attribute__ ((packed));
 
526
 
 
527
typedef struct HFS_file_t HFS_file_t;
 
528
struct HFS_file_t {
 
529
    /* 0x00 */
 
530
    uint16_t type;
 
531
    uint8_t  flags;
 
532
    uint8_t  ftype;
 
533
    /* 0x04 */
 
534
    HFS_file_info_t finder_file;
 
535
    /* 0x14 */
 
536
    HFS_cnid_t ID;
 
537
    /* 0x18 */
 
538
    uint16_t dstart;
 
539
    uint32_t dlsize;
 
540
    uint32_t dpsize;
 
541
    uint16_t rstart;
 
542
    /* 0x24 */
 
543
    uint32_t rlsize;
 
544
    uint32_t rpsize;
 
545
    /* 0x2C */
 
546
    uint32_t created;
 
547
    /* 0x30 */
 
548
    uint32_t modifd;
 
549
    uint32_t backupd;
 
550
    /* 0x38 */
 
551
    uint8_t  finder_pad[16];
 
552
    /* 0x48 */
 
553
    uint16_t clump_size;
 
554
    /* 0x4C */
 
555
    HFS_extent_t extents[3];
 
556
    /* 0x54 */
 
557
} __attribute__ ((packed));
 
558
 
 
559
typedef struct HFSP_file_t HFSP_file_t;
 
560
struct HFSP_file_t {
 
561
    /* 0x00 */
 
562
    uint16_t type;
 
563
    uint16_t flags;
 
564
    uint32_t pad;
 
565
    /* 0x08 */
 
566
    HFS_cnid_t ID;
 
567
    uint32_t created;
 
568
    /* 0x10 */
 
569
    uint32_t modifd;
 
570
    uint32_t attrd;
 
571
    uint32_t accessd;
 
572
    uint32_t backupd;
 
573
    /* 0x20 */
 
574
    HFSP_BSD_info_t BSD_infos;
 
575
    /* 0x30 */
 
576
    HFS_file_info_t finder_file;
 
577
    /* 0x40 */
 
578
    uint8_t  finder_pad[16];
 
579
    /* 0x50 */
 
580
    uint32_t encoding;
 
581
    uint32_t pad1[3];
 
582
    HFSP_fork_t data;
 
583
    HFSP_fork_t ressources;
 
584
} __attribute__ ((packed));
 
585
 
 
586
typedef struct HFS_thread_t HFS_thread_t;
 
587
struct HFS_thread_t {
 
588
    uint16_t type;
 
589
    uint32_t pad[2];
 
590
    HFS_cnid_t pid;
 
591
    uint8_t pad0;
 
592
    unsigned char name[32];
 
593
} __attribute__ ((packed));
 
594
 
 
595
typedef struct HFSP_thread_t HFSP_thread_t;
 
596
struct HFSP_thread_t {
 
597
    uint16_t type;
 
598
    uint16_t pad;
 
599
    HFS_cnid_t pid;
 
600
    uint16_t nlen;
 
601
    HFSP_unichr_t uniname[255];
 
602
} __attribute__ ((packed));
 
603
 
 
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;
 
608
 
 
609
/* Volume/file structures */
 
610
typedef struct hfs_extent_t {
 
611
    uint32_t start;
 
612
    uint32_t count;
 
613
} hfs_extent_t;
 
614
 
 
615
typedef struct hfs_fork_t {
 
616
    hfs_vol_t *volume;
 
617
    uint32_t nb_blocs;
 
618
    hfs_extent_t extents[8];
 
619
    hfs_rec_t *catrec;
 
620
    hfs_rec_t *extrec;
 
621
} hfs_fork_t;
 
622
 
 
623
struct hfs_vol_t {
 
624
    part_t *part;
 
625
    int type;
 
626
    HFS_cnid_t boot_id;
 
627
    uint32_t embed_offset;
 
628
    uint32_t start_offset;
 
629
    uint32_t bsize;
 
630
    hfs_fork_t alloc_file;
 
631
    hfs_fork_t cat_file;
 
632
    hfs_fork_t ext_file;
 
633
    hfs_fork_t *boot_file;
 
634
    hfs_btree_t *cat_tree;
 
635
    hfs_btree_t *ext_tree;
 
636
};
 
637
 
 
638
/* Btree structures */
 
639
/* Btree node */
 
640
typedef struct hfs_bnode_t {
 
641
    hfs_btree_t *tree;
 
642
    uint32_t prev;
 
643
    uint32_t next;
 
644
    int type;
 
645
    uint32_t nrecs;
 
646
    hfs_rec_t *recs;
 
647
} hfs_bnode_t;
 
648
 
 
649
/* Cached Btree node */
 
650
typedef struct hfs_cbnode_t hfs_cbnode_t;
 
651
struct hfs_cbnode_t {
 
652
    uint32_t location;
 
653
    hfs_cbnode_t *next;
 
654
    hfs_bnode_t bnode;
 
655
};
 
656
 
 
657
/* Bnode records */
 
658
enum {
 
659
    RECORD_HEAD = 0,
 
660
    RECORD_IDX,
 
661
    RECORD_CAT,
 
662
    RECORD_EXT,
 
663
};
 
664
 
 
665
/* Header record */
 
666
typedef struct hfs_headrec_t {
 
667
    uint32_t rootnode;
 
668
    uint32_t firstleaf;
 
669
    uint32_t lastleaf;
 
670
    uint32_t nodesize;
 
671
} hfs_headrec_t;
 
672
 
 
673
/* Index record */
 
674
typedef struct hfs_idxrec_t {
 
675
    HFS_cnid_t pid;
 
676
    HFS_cnid_t uid;
 
677
    unsigned char name[0x20];
 
678
} hfs_idxrec_t;
 
679
 
 
680
/* File extent records */
 
681
/* TODO */
 
682
typedef struct hfs_extrec_t {
 
683
    HFS_cnid_t ID;
 
684
} hfs_extrec_t;
 
685
 
 
686
/* Catalog records */
 
687
typedef struct hfs_catrec_t {
 
688
    HFS_cnid_t ID;
 
689
    HFS_cnid_t pid;
 
690
    int type;
 
691
    unsigned char name[0x20];
 
692
    unsigned char finfo[9];
 
693
    hfs_fork_t fork;
 
694
} hfs_catrec_t;
 
695
 
 
696
/* Generic record */
 
697
struct hfs_rec_t {
 
698
    hfs_bnode_t *node;
 
699
    int type;
 
700
    int num;
 
701
    union {
 
702
        hfs_headrec_t headrec;
 
703
        hfs_idxrec_t  idxrec;
 
704
        hfs_catrec_t  catrec;
 
705
        hfs_extrec_t  extrec;
 
706
    } u;
 
707
};
 
708
 
 
709
struct hfs_btree_t {
 
710
    hfs_fork_t *file;
 
711
    hfs_cbnode_t *cache;
 
712
    hfs_rec_t *head_rec;
 
713
    hfs_bnode_t *root_node;
 
714
    hfs_rec_t *root_catrec;
 
715
    hfs_rec_t *root_extrec;
 
716
    uint32_t nodesize;
 
717
    unsigned char *buf;
 
718
    int type;
 
719
    int (*compare)(int type, HFS_cnid_t cnid,
 
720
                   const void *more, hfs_rec_t *rec, int rectype);
 
721
};
 
722
 
 
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 */
 
741
 
 
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 */
 
758
};
 
759
 
 
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 */
 
777
};
 
778
 
 
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 */
 
796
 
 
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 */
 
803
};
 
804
 
 
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,
 
808
    
 
809
    NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
 
810
    NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
 
811
    
 
812
    page20, NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
 
813
    NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
 
814
};
 
815
 
 
816
static int uni2char (uint16_t uni, unsigned char *out)
 
817
{
 
818
    unsigned char *uni2charset;
 
819
    unsigned char cl = uni & 0x00ff;
 
820
    unsigned char ch = (uni & 0xff00) >> 8;
 
821
 
 
822
    uni2charset = page_uni2charset[ch];
 
823
    if (uni2charset && uni2charset[cl])
 
824
        *out = uni2charset[cl];
 
825
    else
 
826
        return -1;
 
827
 
 
828
    return 0;
 
829
}
 
830
 
 
831
static void hfs_get_str (unsigned char *out, int len, uint16_t *hfs_str)
 
832
{
 
833
    int i;
 
834
    char c;
 
835
 
 
836
    for (i = 0; i < len; i++) {
 
837
        if (uni2char(*hfs_str++, &c) < 0)
 
838
            c = '?';
 
839
        out[i] = c;
 
840
    }
 
841
    out[i] = '\0';
 
842
}
 
843
 
 
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)
 
846
{
 
847
    hfs_vol_t *volume;
 
848
    hfs_extent_t *extent;
 
849
    uint32_t abloc, aoffset;
 
850
    int i;
 
851
    
 
852
    volume = file->volume;
 
853
    abloc = bloc / volume->bsize;
 
854
    aoffset = bloc - (abloc * volume->bsize);
 
855
    extent = file->extents;
 
856
#if 0
 
857
    HFS_DPRINTF("Look for bloc %08x => %08x %08x (%08x)\n",
 
858
                bloc, abloc, aoffset, volume->bsize);
 
859
#endif
 
860
    for (i = 0; i < 8; i++) {
 
861
#if 0
 
862
        HFS_DPRINTF("Check extent %d %08x %08x (%08x)\n",
 
863
                    i, extent->start, extent->count, abloc);
 
864
#endif
 
865
        if (extent->count == 0)
 
866
            break;
 
867
        if (abloc < extent->count) {
 
868
            return volume->start_offset + /*volume->embed_offset +*/
 
869
                ((extent->start + abloc) * volume->bsize) + aoffset;
 
870
        }
 
871
        abloc -= extent->count;
 
872
        extent++;
 
873
    }
 
874
    HFS_ERROR("Block %d not found\n", bloc);
 
875
 
 
876
    return -1;
 
877
}
 
878
 
 
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)
 
881
{
 
882
    dst->start = src->start_block;
 
883
    dst->count = src->block_count;
 
884
}
 
885
 
 
886
static void hfs_get_fork (hfs_fork_t *dst, uint32_t blocs,
 
887
                          HFS_extent_t *extents)
 
888
{
 
889
    int i;
 
890
 
 
891
    dst->nb_blocs = blocs;
 
892
    for (i = 0; i < 3; i++) {
 
893
        hfs_get_extent(&dst->extents[i], &extents[i]);
 
894
    }
 
895
    memset(&dst->extents[3], 0, 5 * sizeof(hfs_extent_t));
 
896
}
 
897
 
 
898
static inline void hfsp_get_extent (hfs_extent_t *dst, HFSP_extent_t *src)
 
899
{
 
900
    dst->start = src->start_block;
 
901
    dst->count = src->block_count;
 
902
}
 
903
 
 
904
static void hfsp_get_fork (hfs_fork_t *dst, uint32_t blocs,
 
905
                           HFSP_extent_t *extents)
 
906
{
 
907
    int i;
 
908
 
 
909
    dst->nb_blocs = blocs;
 
910
    for (i = 0; i < 8; i++) {
 
911
        hfsp_get_extent(&dst->extents[i], &extents[i]);
 
912
    }
 
913
}
 
914
 
 
915
static void hfs_dump_fork (hfs_fork_t *fork)
 
916
{
 
917
    int i;
 
918
 
 
919
    HFS_DPRINTF("Nb blocs: %d\n", fork->nb_blocs);
 
920
    for (i = 0; i < 8; i++) {
 
921
        if (fork->extents[i].count == 0)
 
922
            break;
 
923
        HFS_DPRINTF("  extent %d: start: %08x count: %08x\n",
 
924
                    i, fork->extents[i].start, fork->extents[i].count);
 
925
    }
 
926
}
 
927
 
 
928
/* Btree nodes cache */
 
929
static inline void *hfs_brec_get (HFS_bnode_t *node, uint32_t nodesize, int nb)
 
930
{
 
931
    uint16_t *off;
 
932
 
 
933
    if (nb < 1 || nb > node->nrecs) {
 
934
        HFS_ERROR("nb=%d nrec=%d\n", nb, node->nrecs);
 
935
        return NULL;
 
936
    }
 
937
    off = (void *)((char *)node + nodesize);
 
938
    off -= nb;
 
939
    HFS_DPRINTF("%d => %02x node %p off %p %p %d\n",
 
940
                nb, *off, node, off, (char *)node + nodesize, nodesize);
 
941
    
 
942
    return (char *)node + *off;
 
943
}
 
944
 
 
945
static hfs_bnode_t *hfs_bnode_get (hfs_btree_t *tree, uint32_t location)
 
946
{
 
947
    unsigned char *buffer, tmpbuf[HFS_NODE_SIZE];
 
948
    void *HFS_recp;
 
949
    HFS_bnode_t *Hnode;
 
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;
 
955
    HFSP_fold_t *HPdir;
 
956
    HFS_fold_t *Hdir;
 
957
    HFSP_file_t *HPfile;
 
958
    HFS_file_t *Hfile;
 
959
    hfs_headrec_t *head;
 
960
    hfs_cbnode_t **cur;
 
961
    hfs_bnode_t *node;
 
962
    hfs_rec_t *rec;
 
963
    uint32_t bloc, offset, bsize, *upID, nsize;
 
964
    uint16_t *ptype;
 
965
    int i, j, is_hfs;
 
966
    
 
967
#if 1
 
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;
 
973
        }
 
974
    }
 
975
#endif
 
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;
 
980
        buffer = tree->buf;
 
981
    } else {
 
982
        nsize = HFS_NODE_SIZE;
 
983
        buffer = tmpbuf;
 
984
    }
 
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)
 
991
        return NULL;
 
992
    HFS_DPRINTF("  => %08x\n", bloc);
 
993
#if 0
 
994
    offset = bloc % bsize;
 
995
    bloc /= bsize;
 
996
#else
 
997
    offset = 0;
 
998
#endif
 
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");
 
1004
        return NULL;
 
1005
    }
 
1006
    *cur = malloc(sizeof(hfs_cbnode_t) + (Hnode->nrecs * sizeof(hfs_rec_t)));
 
1007
    if (*cur == NULL)
 
1008
        return NULL;
 
1009
    memset(*cur, 0, sizeof(hfs_cbnode_t) + (Hnode->nrecs * sizeof(hfs_rec_t)));
 
1010
    (*cur)->location = location;
 
1011
    node = &(*cur)->bnode;
 
1012
    node->tree = tree;
 
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");
 
1020
        return NULL;
 
1021
    }
 
1022
    if (node->type == HFS_NODE_HEAD) {
 
1023
        Hhead = HFS_get_headrec(Hnode + 1);
 
1024
        nsize = Hhead->nodesize;
 
1025
        if (nsize == 0)
 
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)
 
1031
            return NULL;
 
1032
        memset(tree->buf, 0, nsize);
 
1033
        buffer = tree->buf;
 
1034
        Hnode = HFS_read_Hnode(tree->file->volume->part,
 
1035
                               bloc, offset, buffer, nsize);
 
1036
        if (Hnode == NULL)
 
1037
            return NULL;
 
1038
    }
 
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];
 
1044
        rec->node = node;
 
1045
        rec->num = i + 1;
 
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);
 
1049
            continue;
 
1050
        }
 
1051
        if (is_hfs) {
 
1052
            Hkey = HFS_recp;
 
1053
#if 0
 
1054
            upID = (void *)(((uint32_t)Hkey + 2 + Hkey->len));
 
1055
#else
 
1056
            upID = (void *)(((uint32_t)Hkey + 2 + Hkey->len) & ~1);
 
1057
#endif
 
1058
        } else {
 
1059
            HPkey = HFS_recp;
 
1060
            upID = (void *)(((uint32_t)HPkey + 2 + HPkey->len) & ~1);
 
1061
        }
 
1062
        switch (node->type) {
 
1063
        case HFS_NODE_LEAF:
 
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) {
 
1068
            case RECORD_CAT:
 
1069
                ptype = (void *)upID;
 
1070
                if (is_hfs) {
 
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;
 
1074
                } else {
 
1075
                    hfs_get_str(rec->u.catrec.name,
 
1076
                                HPkey->nlen, HPkey->uniname);
 
1077
                    rec->u.catrec.pid = HPkey->pID;
 
1078
                }
 
1079
                rec->u.catrec.type = *ptype;
 
1080
                rec->u.catrec.fork.volume = tree->file->volume;
 
1081
                rec->u.catrec.fork.catrec = rec;
 
1082
                switch (*ptype) {
 
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,
 
1088
                                rec->u.catrec.pid);
 
1089
                    break;
 
1090
                case HFS_CAT_FILE:
 
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]);
 
1098
#if 0
 
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);
 
1104
#endif
 
1105
                    }
 
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);
 
1111
#if 0
 
1112
                    HFS_DPRINTF("Extent %08x %08x\n",
 
1113
                                rec->u.catrec.fork.extents[0].start,
 
1114
                                rec->u.catrec.fork.extents[0].count);
 
1115
#endif
 
1116
                    break;
 
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,
 
1124
                                rec->u.catrec.pid);
 
1125
                    continue;
 
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,
 
1133
                                rec->u.catrec.pid);
 
1134
                    continue;
 
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);
 
1140
                    break;
 
1141
                case HFSP_CAT_FILE:
 
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);
 
1154
                    break;
 
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);
 
1163
                    break;
 
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);
 
1172
                    break;
 
1173
                default:
 
1174
                    printf("Unknown catalog entry %d %d '%s' %d\n", rec->type,
 
1175
                           *ptype, rec->u.catrec.name, (char *)ptype - (char *)Hkey);
 
1176
                    continue;
 
1177
                }
 
1178
                break;
 
1179
            case RECORD_EXT:
 
1180
                /* TODO */
 
1181
                HFS_DPRINTF("Extent file entry\n");
 
1182
                continue;
 
1183
            default:
 
1184
                HFS_ERROR("Unknown entry\n");
 
1185
                continue;
 
1186
            }
 
1187
            break;
 
1188
        case HFS_NODE_IDX:
 
1189
            rec->type = RECORD_IDX;
 
1190
            rec->u.idxrec.uid = *upID;
 
1191
            if (is_hfs) {
 
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);
 
1200
            } else {
 
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);
 
1207
            }
 
1208
            break;
 
1209
        case HFS_NODE_HEAD:
 
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);
 
1220
            node->nrecs = 1;
 
1221
            goto out;
 
1222
        case HFS_NODE_MAP:
 
1223
            /* TODO */
 
1224
        default:
 
1225
            continue;
 
1226
        }
 
1227
    }
 
1228
 
 
1229
 out:
 
1230
    return node;
 
1231
}
 
1232
 
 
1233
static inline hfs_rec_t *hfs_rec_get (hfs_bnode_t *node, int nb)
 
1234
{
 
1235
    if (nb < 1 || nb > (int)node->nrecs) {
 
1236
        HFS_ERROR("nb: %d min: %d max: %d\n", nb, 1, node->nrecs);
 
1237
        return NULL;
 
1238
    }
 
1239
 
 
1240
    return &node->recs[nb - 1];
 
1241
}
 
1242
 
 
1243
static inline hfs_bnode_t *hfs_bnode_prev (hfs_bnode_t *cur)
 
1244
{
 
1245
    if (cur->prev == 0x00000000)
 
1246
        return NULL;
 
1247
 
 
1248
    return hfs_bnode_get(cur->tree, cur->prev);
 
1249
}
 
1250
 
 
1251
static inline hfs_bnode_t *hfs_bnode_next (hfs_bnode_t *cur)
 
1252
{
 
1253
    if (cur->next == 0x00000000)
 
1254
        return NULL;
 
1255
 
 
1256
    return hfs_bnode_get(cur->tree, cur->next);
 
1257
}
 
1258
 
 
1259
unused static hfs_rec_t *hfs_rec_prev (hfs_rec_t *cur)
 
1260
{
 
1261
    hfs_bnode_t *curn;
 
1262
    int num;
 
1263
 
 
1264
    num = cur->num;
 
1265
    curn = cur->node;
 
1266
    if (num == 1) {
 
1267
        curn = hfs_bnode_prev(curn);
 
1268
        if (curn == NULL)
 
1269
            return NULL;
 
1270
        num = curn->nrecs + 1;
 
1271
    }
 
1272
    
 
1273
    return hfs_rec_get(curn, num - 1);
 
1274
}
 
1275
 
 
1276
unused static hfs_rec_t *hfs_rec_next (hfs_rec_t *cur)
 
1277
{
 
1278
    hfs_bnode_t *curn;
 
1279
    int num;
 
1280
 
 
1281
    num = cur->num;
 
1282
    curn = cur->node;
 
1283
    if (num == (int)curn->nrecs) {
 
1284
        curn = hfs_bnode_next(curn);
 
1285
        if (curn == NULL)
 
1286
            return NULL;
 
1287
        num = 1;
 
1288
    }
 
1289
    
 
1290
    return hfs_rec_get(curn, num - 1);
 
1291
}
 
1292
 
 
1293
static int hfs_cat_compare (int type, HFS_cnid_t cnid,
 
1294
                            const void *more, hfs_rec_t *rec, int rectype);
 
1295
 
 
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)
 
1299
{
 
1300
    hfs_bnode_t *curn;
 
1301
    hfs_rec_t *cur;
 
1302
    unsigned int i;
 
1303
    int ret;
 
1304
 
 
1305
    /*
 
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
 
1309
     * record.
 
1310
     */
 
1311
#define DEBUG_HFS_REC_FIND 0
 
1312
#if DEBUG_HFS_REC_FIND
 
1313
    hfs_rec_t *idx_cur;
 
1314
    unsigned int idx;
 
1315
    int idx_ret;
 
1316
#endif /* DEBUG_HFS_REC_FIND */
 
1317
 
 
1318
    HFS_DPRINTF("look for ID: %08x '%s'\n", cnid, name);
 
1319
    cur = NULL;
 
1320
    ret = -1;
 
1321
    i = 0;
 
1322
    for (curn = tree->root_node; curn != NULL;) {
 
1323
#if DEBUG_HFS_REC_FIND
 
1324
        idx = 0;
 
1325
        idx_ret = 0;
 
1326
        idx_cur = NULL;
 
1327
#endif /* DEBUG_HFS_REC_FIND */
 
1328
        for (i = curn->nrecs; i != 0; i--) {
 
1329
            cur = hfs_rec_get(curn, i);
 
1330
            if (cur == NULL) {
 
1331
                HFS_ERROR("Cannot get record %d\n", i);
 
1332
                return NULL;
 
1333
            }
 
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);
 
1338
            if (ret >= 0) {
 
1339
#if !DEBUG_HFS_REC_FIND
 
1340
                break;
 
1341
#else
 
1342
                if (!idx) {
 
1343
                    idx = i;
 
1344
                    idx_ret = ret;
 
1345
                    idx_cur = cur;
 
1346
                }
 
1347
#endif /* DEBUG_HFS_REC_FIND */
 
1348
            }
 
1349
        }
 
1350
#if DEBUG_HFS_REC_FIND
 
1351
        if (idx) {
 
1352
            i = idx;
 
1353
            ret = idx_ret;
 
1354
            cur = idx_cur;
 
1355
        }
 
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 */
 
1361
            break;
 
1362
        }
 
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);
 
1366
    }
 
1367
    if (ret != 0 || curn == NULL) {
 
1368
        /* We won't find what we're looking for... */
 
1369
        HFS_DPRINTF("NOT FOUND\n");
 
1370
        return NULL;
 
1371
    }
 
1372
#if 0
 
1373
    if (ret != 0 && cur->u.catrec.ID != cnid) {
 
1374
        HFS_ERROR("%d %d\n", cur->u.catrec.ID, cnid);
 
1375
        return NULL;
 
1376
    }
 
1377
#endif
 
1378
    HFS_DPRINTF("found %p %p %d %p\n", cur, curn, i, hfs_rec_get(curn, i));
 
1379
    
 
1380
    return cur;
 
1381
}
 
1382
 
 
1383
static inline hfs_rec_t *hfs_get_dir (hfs_btree_t *tree, HFS_cnid_t cnid,
 
1384
                                      const unsigned char *name)
 
1385
{
 
1386
    return hfs_rec_find(tree, cnid, name, 1);
 
1387
}
 
1388
 
 
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)
 
1392
{
 
1393
    hfs_btree_t *tree;
 
1394
    hfs_bnode_t *cur;
 
1395
    hfs_rec_t *rec;
 
1396
    hfs_catrec_t *frec;
 
1397
    int idx;
 
1398
 
 
1399
    cur = dir->node;
 
1400
    tree = cur->tree;
 
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);
 
1405
            if (cur == NULL) {
 
1406
                HFS_ERROR("Node %08x not found\n", cur->next);
 
1407
                break;
 
1408
            }
 
1409
            idx = 1;
 
1410
        }
 
1411
        rec = hfs_rec_get(cur, idx);
 
1412
        if (rec == NULL) {
 
1413
            HFS_ERROR("Cannot get record %d\n", idx);
 
1414
            return NULL;
 
1415
        }
 
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) {
 
1419
            continue;
 
1420
        }
 
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)
 
1424
            continue;
 
1425
        if (frec->pid != cnid) {
 
1426
            HFS_ERROR("Out of directory %08x %08x\n", cnid, frec->pid);
 
1427
            break;
 
1428
        }
 
1429
        if (info != NULL && memcmp(frec->finfo, info, strlen(info)) != 0)
 
1430
            continue;
 
1431
        /* Beware: HFS is case insensitive ! */
 
1432
        if (name != NULL && strcasecmp(frec->name, name) != 0)
 
1433
            continue;
 
1434
        return rec;
 
1435
    }
 
1436
 
 
1437
    return NULL;
 
1438
}
 
1439
 
 
1440
static hfs_btree_t *hfs_btree_open (hfs_fork_t *fork, int type,
 
1441
                                    int (*compare)(int type,
 
1442
                                                   HFS_cnid_t cnid,
 
1443
                                                   const void *more,
 
1444
                                                   hfs_rec_t *rec,
 
1445
                                                   int rectype))
 
1446
{
 
1447
    hfs_bnode_t *node;
 
1448
    hfs_rec_t *rec;
 
1449
    hfs_headrec_t *head;
 
1450
    hfs_btree_t *newt;
 
1451
    uint32_t bloc;
 
1452
 
 
1453
    bloc = hfs_get_bloc(fork, 0);
 
1454
    if (bloc == (uint32_t)-1)
 
1455
        return NULL;
 
1456
    HFS_DPRINTF("Open btree: bloc=%08x\n", bloc);
 
1457
    /* Allocate tree */
 
1458
    newt = malloc(sizeof(hfs_btree_t));
 
1459
    if (newt == NULL)
 
1460
        return NULL;
 
1461
    memset(newt, 0, sizeof(hfs_btree_t));
 
1462
    newt->file = fork;
 
1463
    newt->cache = NULL;
 
1464
    newt->type = type;
 
1465
    newt->compare = compare;
 
1466
    /* Get tree header */
 
1467
    HFS_DPRINTF("Get first node\n");
 
1468
    node = hfs_bnode_get(newt, 0);
 
1469
    if (node == NULL) {
 
1470
        HFS_ERROR("Cannot get tree head\n");
 
1471
        return NULL;
 
1472
    }
 
1473
    HFS_DPRINTF("Get first record\n");
 
1474
    rec = hfs_rec_get(node, 1);
 
1475
    if (rec == NULL) {
 
1476
        HFS_ERROR("Cannot get first record\n");
 
1477
        return NULL;
 
1478
    }
 
1479
    if (rec->type != RECORD_HEAD) {
 
1480
        HFS_ERROR("Not an header record !\n");
 
1481
        return NULL;
 
1482
    }
 
1483
    head = &rec->u.headrec;
 
1484
    newt->head_rec = rec;
 
1485
    /* Get root node */
 
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)
 
1489
        return 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)
 
1495
        return NULL;
 
1496
    
 
1497
    return newt;
 
1498
}
 
1499
 
 
1500
static int hfs_cat_compare (int type, HFS_cnid_t cnid,
 
1501
                            const void *more, hfs_rec_t *rec, int rectype)
 
1502
{
 
1503
    hfs_idxrec_t *idxrec;
 
1504
    hfs_catrec_t *catrec;
 
1505
    const unsigned char *name;
 
1506
    HFS_cnid_t id;
 
1507
    int ret;
 
1508
    
 
1509
    if (type == RECORD_IDX) {
 
1510
        idxrec = &rec->u.idxrec;
 
1511
        id = idxrec->pid;
 
1512
        name = idxrec->name;
 
1513
        catrec = NULL;
 
1514
    } else {
 
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);
 
1523
            id = catrec->ID;
 
1524
        } else {
 
1525
            id = catrec->pid;
 
1526
        }
 
1527
    }
 
1528
    HFS_DPRINTF("Compare cnid (%08x '%s') vs (%08x '%s') %08x %d\n",
 
1529
                cnid, (char *)more, id, name, catrec->type, rectype);
 
1530
    
 
1531
    /*
 
1532
     * Always diff Record_IDXs, but diff RECORDS_CATs iff they match the type
 
1533
     * being looked for: THREAD vs NON-THREAD (rectype).
 
1534
     */
 
1535
    ret = cnid - id;
 
1536
    
 
1537
    if (ret == 0 && type != RECORD_IDX) {
 
1538
        /* out on a leaf - don't compare different types */
 
1539
        if (rectype &&
 
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 */
 
1545
            ret = -1;
 
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 */
 
1552
            ret = -1;
 
1553
        }
 
1554
    }
 
1555
 
 
1556
    if (ret == 0 &&
 
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).
 
1562
        */
 
1563
        (type == RECORD_IDX ||
 
1564
         (!rectype &&
 
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);
 
1571
    }
 
1572
    
 
1573
    HFS_DPRINTF("ret %d catrec %p catrec->type %08x\n",
 
1574
                ret, catrec, catrec ? catrec->type : 0);
 
1575
    return ret;
 
1576
}
 
1577
 
 
1578
static hfs_btree_t *hfs_cat_open (hfs_vol_t *volume)
 
1579
{
 
1580
    HFS_DPRINTF("Open HFS catalog\n");
 
1581
    return hfs_btree_open(&volume->cat_file, RECORD_CAT, &hfs_cat_compare);
 
1582
}
 
1583
 
 
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)
 
1587
{
 
1588
    /* TODO */
 
1589
    return -1;
 
1590
}
 
1591
 
 
1592
static hfs_btree_t *hfs_ext_open (unused hfs_vol_t *volume)
 
1593
{
 
1594
    HFS_DPRINTF("Open HFS extents file\n");
 
1595
#if 0
 
1596
    return hfs_btree_open(&volume->ext_file, RECORD_EXT, &hfs_ext_compare);
 
1597
#else
 
1598
    return NULL;
 
1599
#endif
 
1600
}
 
1601
 
 
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)
 
1605
{
 
1606
    uint32_t bloc, size;
 
1607
 
 
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...
 
1611
     */
 
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");
 
1616
        return;
 
1617
    }
 
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);
 
1621
    *boot_start = bloc;
 
1622
    *boot_size = size;
 
1623
    *boot_offset = 0;
 
1624
}
 
1625
 
 
1626
static inode_t *fs_hfs_get_inode (inode_t *parent, const unsigned char *name)
 
1627
{
 
1628
    inode_t *new;
 
1629
    hfs_fork_t *pfile, *file;
 
1630
    hfs_rec_t *catrec, *extrec;
 
1631
    uint32_t size;
 
1632
    int i;
 
1633
 
 
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);
 
1639
#if 0
 
1640
    extrec = hfs_rec_find(pfile->extrec->node->tree,
 
1641
                          pfile->extrec->u.extrec.pid, name, 0);
 
1642
#else
 
1643
    extrec = NULL;
 
1644
#endif
 
1645
    if (catrec == NULL /* || extrec == NULL */)
 
1646
        return NULL;
 
1647
    new = malloc(sizeof(inode_t));
 
1648
    if (new == NULL)
 
1649
        return NULL;
 
1650
    memset(new, 0, sizeof(inode_t));
 
1651
    new->flags = 0;
 
1652
    file = &catrec->u.catrec.fork;
 
1653
    new->private = file;
 
1654
    size = 0;
 
1655
    for (i = 0; i < 8; i++) {
 
1656
        if (file->extents[i].count == 0)
 
1657
            break;
 
1658
        size += file->extents[i].count;
 
1659
    }
 
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); 
 
1665
   
 
1666
    return new;
 
1667
}
 
1668
 
 
1669
static void fs_hfs_put_inode (unused inode_t *inode)
 
1670
{
 
1671
}
 
1672
 
 
1673
static uint32_t fs_hfs_map_bloc (inode_t *inode, uint32_t bloc)
 
1674
{
 
1675
    return hfs_get_bloc(inode->private, bloc);
 
1676
}
 
1677
 
 
1678
static inode_t *fs_hfs_get_special_inode (fs_t *fs, int type)
 
1679
{
 
1680
    hfs_vol_t *volume;
 
1681
    inode_t *bfile, *bdir, *cur;
 
1682
    hfs_rec_t *drec, *rec;
 
1683
    hfs_fork_t *fork;
 
1684
    uint32_t boot_start, boot_size, boot_offset;
 
1685
    HFS_cnid_t id;
 
1686
 
 
1687
    volume = fs->private;
 
1688
    switch (type) {
 
1689
    case FILE_ROOT:
 
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");
 
1695
                return NULL;
 
1696
            }
 
1697
            cur = malloc(sizeof(inode_t));
 
1698
            if (cur == NULL)
 
1699
                return NULL;
 
1700
            memset(cur, 0, sizeof(inode_t));
 
1701
            cur->flags = INODE_TYPE_DIR;
 
1702
            cur->private = &volume->cat_tree->root_catrec->u.catrec.fork;
 
1703
            cur->parent = NULL;
 
1704
        } else {
 
1705
            cur = fs->root;
 
1706
        }
 
1707
        return cur;
 
1708
    case FILE_BOOT:
 
1709
        if (fs->bootfile != NULL)
 
1710
            return fs->bootfile;
 
1711
        break;
 
1712
    case FILE_BOOTDIR:
 
1713
        if (fs->bootdir != NULL)
 
1714
            return fs->bootdir;
 
1715
        if (volume->boot_file != NULL) {
 
1716
            bfile = malloc(sizeof(inode_t));
 
1717
            if (bfile == NULL)
 
1718
                return NULL;
 
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) {
 
1724
                free(bfile);
 
1725
                fs->bootfile = NULL;
 
1726
                return NULL;
 
1727
            }
 
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);
 
1733
        }
 
1734
        break;
 
1735
    default:
 
1736
        return NULL;
 
1737
    }
 
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, "");
 
1744
            if (drec == NULL) {
 
1745
                HFS_ERROR("Didn't find boot directory %d\n", volume->boot_id);
 
1746
                return NULL;
 
1747
            }
 
1748
            HFS_DPRINTF("Found boot directory '%s'\n", drec->u.catrec.name);
 
1749
            rec = hfs_get_dirfile(drec, volume->boot_id, NULL, "tbxi");
 
1750
        } else {
 
1751
            /* Try NetBSD boot */
 
1752
            drec = hfs_get_dir(volume->cat_tree, HFS_ROOT_FOLDER, "");
 
1753
            if (drec == NULL)
 
1754
                return NULL;
 
1755
            rec = hfs_get_dirfile(drec, HFS_ROOT_FOLDER, "ofwboot", NULL);
 
1756
            if (rec == NULL) {
 
1757
                rec = hfs_get_dirfile(drec, HFS_ROOT_FOLDER,
 
1758
                                      "ofwboot.xcf", NULL);
 
1759
                if (rec == NULL) {
 
1760
                    rec = hfs_get_dirfile(drec, HFS_ROOT_FOLDER,
 
1761
                                          "ofwboot.elf", NULL);
 
1762
                }
 
1763
            }
 
1764
            if (rec != NULL) {
 
1765
                volume->boot_id = rec->u.catrec.pid;
 
1766
                drec = hfs_get_dir(volume->cat_tree, volume->boot_id, "");
 
1767
            }
 
1768
        }
 
1769
        if (rec == NULL) {
 
1770
            HFS_ERROR("Didn't find boot file\n");
 
1771
            return NULL;
 
1772
        }
 
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);
 
1778
#if 0
 
1779
        hfs_treat_boot_file(fs->part, volume,
 
1780
                            &boot_start, &boot_offset, &boot_size);
 
1781
#endif
 
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);
 
1786
    } else {
 
1787
        drec = hfs_get_dir(volume->cat_tree, HFS_ROOT_FOLDER, "");
 
1788
        if (drec == NULL)
 
1789
            return NULL;
 
1790
    }
 
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));
 
1796
    if (bfile == NULL)
 
1797
        return NULL;
 
1798
    memset(bfile, 0, sizeof(inode_t));
 
1799
    fs->bootfile = bfile;
 
1800
    bfile->name = strdup(rec->u.catrec.name);
 
1801
    if (bfile->name == NULL) {
 
1802
        free(bfile);
 
1803
        return NULL;
 
1804
    }
 
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);
 
1810
    bdir = NULL;
 
1811
    cur = NULL;
 
1812
    if (type == FILE_BOOT) {
 
1813
        cur = bfile;
 
1814
    }
 
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, "");
 
1818
        if (drec == NULL)
 
1819
            return NULL;
 
1820
        bdir = malloc(sizeof(inode_t));
 
1821
        if (bdir == NULL)
 
1822
            return NULL;
 
1823
        memset(bdir, 0, sizeof(inode_t));
 
1824
        if (id == volume->boot_id) {
 
1825
            if (type == FILE_BOOTDIR)
 
1826
                cur = bdir;
 
1827
            fs->bootdir = bdir;
 
1828
        }
 
1829
        bdir->name = strdup(drec->u.catrec.name);
 
1830
        if (bdir->name == NULL) {
 
1831
            free(bdir);
 
1832
            return NULL;
 
1833
        }
 
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);
 
1840
        bfile = bdir;
 
1841
    }
 
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);
 
1845
    if (bdir == NULL) {
 
1846
        bdir = fs->root;
 
1847
        fs->bootdir = bdir;
 
1848
        if (type == FILE_BOOTDIR)
 
1849
            cur = bdir;
 
1850
    }
 
1851
    cur->fs = fs;
 
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,
 
1857
                rec->u.catrec.ID);
 
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);
 
1862
 
 
1863
    return cur;
 
1864
}
 
1865
 
 
1866
static fs_ops_t hfs_fs_ops = {
 
1867
    &fs_hfs_get_inode,
 
1868
    &fs_hfs_put_inode,
 
1869
    &fs_hfs_map_bloc,
 
1870
    &fs_hfs_get_special_inode,
 
1871
};
 
1872
 
 
1873
int fs_hfs_probe (part_t *part, uint32_t *size,
 
1874
                  fs_ops_t **fs_ops, unsigned char **name,
 
1875
                  void **private)
 
1876
{
 
1877
    unsigned char buffer[512];
 
1878
    HFSP_vh_t *hfsp_vh;
 
1879
    HFS_vh_t *hfs_vh;
 
1880
    hfs_vol_t *volume;
 
1881
    uint32_t embed_offset = 0, boot_id;
 
1882
    int type;
 
1883
 
 
1884
    hfs_vh = HFS_read_volhead(part, HFS_VOLHEAD_SECTOR, 0, buffer, 512);
 
1885
    hfsp_vh = NULL;
 
1886
    if (hfs_vh == NULL) {
 
1887
        DPRINTF("Can't read HFS volume header\n");
 
1888
        return -1;
 
1889
    }
 
1890
    type = -1;
 
1891
    if (hfs_vh->signature == HFS_VOLHEAD_SIG) {
 
1892
        /* HFS volume */
 
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,
 
1901
                                        0, buffer, 512);
 
1902
            goto handle_hfsp;
 
1903
        }
 
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));
 
1907
        if (volume == NULL)
 
1908
            return -1;
 
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;
 
1920
        /* Alloc file */
 
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;
 
1925
        /* Catalog file */
 
1926
        volume->cat_file.volume = volume;
 
1927
        hfs_get_fork(&volume->cat_file, hfs_vh->cat_size, hfs_vh->cat_rec);
 
1928
        /* Extents file */
 
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);
 
1933
        if (*name == NULL)
 
1934
            return -1;
 
1935
        type = FS_TYPE_HFS;
 
1936
    } else {
 
1937
        hfsp_vh = HFSP_read_volhead(part, HFS_VOLHEAD_SECTOR, 0, buffer, 512);
 
1938
    handle_hfsp:
 
1939
        if (hfsp_vh == NULL) {
 
1940
            DPRINTF("Can't read HFS+ volume header\n");
 
1941
            return -1;
 
1942
        }
 
1943
        if (hfsp_vh->signature != HFSPLUS_VOLHEAD_SIG) {
 
1944
            DPRINTF("Bad HFS+ signature %02x %02x\n",
 
1945
                    hfsp_vh->signature, HFSPLUS_VOLHEAD_SIG);
 
1946
            return -1;
 
1947
        }
 
1948
        /* HFS+ volume */
 
1949
        printf("HFSplus volume\n");
 
1950
        volume = malloc(sizeof(hfs_vol_t));
 
1951
        if (volume == NULL)
 
1952
            return -1;
 
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;
 
1958
        /* Boot file */
 
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);
 
1969
            boot_id = 2;
 
1970
        } else {
 
1971
            boot_id = hfsp_vh->finder_info[0];
 
1972
        }
 
1973
            DPRINTF("HFS+ boot id : %d %04x %d\n", boot_id, boot_id,
 
1974
                    hfsp_vh->start_file.total_blocks);
 
1975
        /* Catalog file */
 
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);
 
1980
        /* Extents file */
 
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;
 
1987
    }
 
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);
 
2000
    }
 
2001
    *fs_ops = &hfs_fs_ops;
 
2002
    HFS_DPRINTF("Set part to %p\n", part);
 
2003
    volume->part = part;
 
2004
    *private = volume;
 
2005
 
 
2006
    return type;
 
2007
}