Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openhackware / src / libfs / hfs.c
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 }