Import of openhackware-0.4.1
[openhackware.git] / src / libfs / hfs.c
blobb2420ebe8afd392ee893ba81c6b84d9eb1fcf1f8
1 /*
2 * <hfs.c>
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
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * Major rework and debug by Thayne Harbaugh <thayne@realmsys.com>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include "bios.h"
27 #include "libfs.h"
29 //#define DEBUG_HFS 1
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)
42 /* HFS/HFS+ common definitions */
43 #define HFS_SECTOR_SIZE 512
44 #define HFS_VOLHEAD_SECTOR 2
45 #define HFS_NODE_SIZE 0x200
47 /* HFS signature */
48 #define HFS_VOLHEAD_SIG 0x4244
49 /* HFS+ signature */
50 #define HFSPLUS_VOLHEAD_SIG 0x482b
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,
67 typedef uint32_t HFS_cnid_t;
69 static inline HFS_cnid_t HFS_get_cnid (HFS_cnid_t *cnidp)
71 return get_be32(cnidp);
74 typedef uint16_t HFSP_unichr_t;
76 static inline HFSP_unichr_t HFSP_get_unichr (HFSP_unichr_t *chrp)
78 return get_be16(chrp);
81 /* A single contiguous area of a file */
82 typedef struct HFSP_extent_t HFSP_extent_t;
83 struct HFSP_extent_t {
84 uint32_t start_block;
85 uint32_t block_count;
86 } __attribute__ ((packed));
88 static inline HFSP_extent_t *HFSP_get_extent (HFSP_extent_t *extp)
90 extp->start_block = get_be32(&extp->start_block);
91 extp->block_count = get_be32(&extp->block_count);
93 return extp;
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));
108 static inline HFSP_fork_t *HFSP_get_fork (HFSP_fork_t *forkp)
110 int i;
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]);
119 return forkp;
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;
132 /* 0x010 */
133 uint32_t create_date;
134 uint32_t modify_date;
135 uint32_t backup_date;
136 uint32_t checked_date;
138 /* 0x020 */
139 uint32_t file_count;
140 uint32_t folder_count;
141 uint32_t blocksize;
142 uint32_t total_blocks;
144 /* 0x030 */
145 uint32_t free_blocks;
146 uint32_t next_alloc;
147 uint32_t rsrc_clump_sz;
148 uint32_t data_clump_sz;
150 /* 0x040 */
151 HFS_cnid_t next_cnid;
152 uint32_t write_count;
153 uint64_t encodings_bmp;
155 /* 0x050 */
156 uint32_t finder_info[8];
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));
172 static HFSP_vh_t *HFSP_read_volhead (part_t *part, uint32_t bloc,
173 uint32_t offset, void *buffer, int size)
175 HFSP_vh_t *vh;
176 int i;
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]);
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);
211 return vh;
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));
222 static inline HFS_extent_t *HFS_get_extent (HFS_extent_t *extp)
224 extp->start_block = get_be16(&extp->start_block);
225 extp->block_count = get_be16(&extp->block_count);
227 return extp;
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;
241 /* 0x010 */
242 uint16_t alloc_ptr;
243 uint16_t alloc_blocs;
244 uint32_t alloc_size;
246 /* 0x018 */
247 uint32_t clump_size;
248 uint16_t alloc_start;
249 HFS_cnid_t next_cnid;
250 uint16_t free_blocs;
252 /* 0x024 */
253 uint8_t label[28];
255 /* 0x040 */
256 uint32_t backup_tmsp;
257 uint16_t backup_seq;
258 uint32_t write_count;
260 /* 0x04A */
261 uint32_t ext_clump_size;
262 /* 0x04E */
263 uint32_t cat_clump_size;
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];
273 /* 0x07C */
274 uint16_t embed_sig;
275 HFS_extent_t embed_ext;
277 /* 0x082 */
278 uint32_t ext_size;
279 HFS_extent_t ext_rec[3];
281 /* 0x092 */
282 uint32_t cat_size;
283 HFS_extent_t cat_rec[3];
285 /* 0x0A2 */
286 } __attribute__(( __packed__ ));
288 static HFS_vh_t *HFS_read_volhead (part_t *part, uint32_t bloc,
289 uint32_t offset, void *buffer, int size)
291 HFS_vh_t *vh;
292 int i;
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]);
323 vh->embed_sig = get_be16(&vh->embed_sig);
324 HFS_get_extent(&vh->embed_ext);
325 vh->ext_size = get_be16(&vh->ext_size);
326 for (i = 0; i < 3; i++) {
327 HFS_get_extent(&vh->ext_rec[i]);
329 vh->cat_size = get_be16(&vh->cat_size);
330 for (i = 0; i < 3; i++) {
331 HFS_get_extent(&vh->cat_rec[i]);
334 return vh;
337 enum {
338 HFS_NODE_LEAF = 0xFF,
339 HFS_NODE_IDX = 0x00,
340 HFS_NODE_HEAD = 0x01,
341 HFS_NODE_MAP = 0x02,
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));
355 static HFS_bnode_t *HFS_read_Hnode (part_t *part, uint32_t bloc,
356 uint32_t offset, void *buffer, int nsize)
358 HFS_bnode_t *Hnode;
360 if (part_seek(part, bloc, offset) == -1) {
361 HFS_DPRINTF("seek failed\n");
362 return NULL;
364 if (part_read(part, buffer, nsize) < 0) {
365 HFS_DPRINTF("read failed\n");
366 return NULL;
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);
373 return Hnode;
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));
404 static HFS_headrec_t *HFS_get_headrec (void *pos)
406 HFS_headrec_t *head = pos;
408 head->depth = get_be16(&head->depth);
409 head->rootnode = get_be32(&head->rootnode);
410 head->nbleaves = get_be32(&head->nbleaves);
411 head->firstleaf = get_be32(&head->firstleaf);
412 head->lastleaf = get_be32(&head->lastleaf);
413 head->maxkeylen = get_be16(&head->maxkeylen);
414 head->nbnodes = get_be32(&head->nbnodes);
415 head->freenodes = get_be32(&head->freenodes);
416 head->clump_size = get_be32(&head->clump_size);
417 head->attr = get_be32(&head->attr);
419 return head;
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));
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));
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,
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));
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));
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));
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));
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));
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));
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));
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));
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));
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));
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));
604 /* in memory structures */
605 typedef struct hfs_vol_t hfs_vol_t;
606 typedef struct hfs_btree_t hfs_btree_t;
607 typedef struct hfs_rec_t hfs_rec_t;
609 /* Volume/file structures */
610 typedef struct hfs_extent_t {
611 uint32_t start;
612 uint32_t count;
613 } hfs_extent_t;
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;
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;
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;
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;
657 /* Bnode records */
658 enum {
659 RECORD_HEAD = 0,
660 RECORD_IDX,
661 RECORD_CAT,
662 RECORD_EXT,
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;
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;
680 /* File extent records */
681 /* TODO */
682 typedef struct hfs_extrec_t {
683 HFS_cnid_t ID;
684 } hfs_extrec_t;
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;
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;
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);
723 /* Unicode to ISO-8859-15, stolen from Linux nls */
724 static unsigned char page00[256] = {
725 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
726 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
727 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
728 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
729 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
730 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
731 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
732 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
733 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
734 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
735 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
736 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
737 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
738 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
739 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
740 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
742 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
743 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
744 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
745 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
746 0xa0, 0xa1, 0xa2, 0xa3, 0x00, 0xa5, 0x00, 0xa7, /* 0xa0-0xa7 */
747 0x00, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
748 0xb0, 0xb1, 0xb2, 0xb3, 0x00, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
749 0x00, 0xb9, 0xba, 0xbb, 0x00, 0x00, 0x00, 0xbf, /* 0xb8-0xbf */
750 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
751 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
752 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
753 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
754 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */
755 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */
756 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
757 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
760 static unsigned char page01[256] = {
761 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
762 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
763 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
764 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
765 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
766 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
767 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
768 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
769 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
770 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
771 0x00, 0x00, 0xbc, 0xbd, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
772 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
773 0xa6, 0xa8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
774 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
775 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
776 0xbe, 0x00, 0x00, 0x00, 0x00, 0xb4, 0xb8, 0x00, /* 0x78-0x7f */
779 static unsigned char page20[256] = {
780 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
781 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
782 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
783 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
784 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
785 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
786 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
787 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
788 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
789 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
790 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
791 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
792 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
793 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
794 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
795 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
797 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
798 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
799 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
800 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
801 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
802 0x00, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
805 static unsigned char *page_uni2charset[256] = {
806 page00, page01, NULL, NULL, NULL, NULL, NULL, NULL,
807 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
809 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
810 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
812 page20, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
813 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
816 static int uni2char (uint16_t uni, unsigned char *out)
818 unsigned char *uni2charset;
819 unsigned char cl = uni & 0x00ff;
820 unsigned char ch = (uni & 0xff00) >> 8;
822 uni2charset = page_uni2charset[ch];
823 if (uni2charset && uni2charset[cl])
824 *out = uni2charset[cl];
825 else
826 return -1;
828 return 0;
831 static void hfs_get_str (unsigned char *out, int len, uint16_t *hfs_str)
833 int i;
834 char c;
836 for (i = 0; i < len; i++) {
837 if (uni2char(*hfs_str++, &c) < 0)
838 c = '?';
839 out[i] = c;
841 out[i] = '\0';
844 /* Locate a bloc in the partition given a file and an offset */
845 static uint32_t hfs_get_bloc (hfs_fork_t *file, uint32_t bloc)
847 hfs_vol_t *volume;
848 hfs_extent_t *extent;
849 uint32_t abloc, aoffset;
850 int i;
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;
871 abloc -= extent->count;
872 extent++;
874 HFS_ERROR("Block %d not found\n", bloc);
876 return -1;
879 /* Convert HFS/HFS plus extent/fork records to memory structure */
880 static inline void hfs_get_extent (hfs_extent_t *dst, HFS_extent_t *src)
882 dst->start = src->start_block;
883 dst->count = src->block_count;
886 static void hfs_get_fork (hfs_fork_t *dst, uint32_t blocs,
887 HFS_extent_t *extents)
889 int i;
891 dst->nb_blocs = blocs;
892 for (i = 0; i < 3; i++) {
893 hfs_get_extent(&dst->extents[i], &extents[i]);
895 memset(&dst->extents[3], 0, 5 * sizeof(hfs_extent_t));
898 static inline void hfsp_get_extent (hfs_extent_t *dst, HFSP_extent_t *src)
900 dst->start = src->start_block;
901 dst->count = src->block_count;
904 static void hfsp_get_fork (hfs_fork_t *dst, uint32_t blocs,
905 HFSP_extent_t *extents)
907 int i;
909 dst->nb_blocs = blocs;
910 for (i = 0; i < 8; i++) {
911 hfsp_get_extent(&dst->extents[i], &extents[i]);
915 static void hfs_dump_fork (hfs_fork_t *fork)
917 int i;
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);
928 /* Btree nodes cache */
929 static inline void *hfs_brec_get (HFS_bnode_t *node, uint32_t nodesize, int nb)
931 uint16_t *off;
933 if (nb < 1 || nb > node->nrecs) {
934 HFS_ERROR("nb=%d nrec=%d\n", nb, node->nrecs);
935 return NULL;
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);
942 return (char *)node + *off;
945 static hfs_bnode_t *hfs_bnode_get (hfs_btree_t *tree, uint32_t location)
947 unsigned char *buffer, tmpbuf[HFS_NODE_SIZE];
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;
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;
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;
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;
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;
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;
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;
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);
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;
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
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;
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;
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);
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;
1229 out:
1230 return node;
1233 static inline hfs_rec_t *hfs_rec_get (hfs_bnode_t *node, int nb)
1235 if (nb < 1 || nb > (int)node->nrecs) {
1236 HFS_ERROR("nb: %d min: %d max: %d\n", nb, 1, node->nrecs);
1237 return NULL;
1240 return &node->recs[nb - 1];
1243 static inline hfs_bnode_t *hfs_bnode_prev (hfs_bnode_t *cur)
1245 if (cur->prev == 0x00000000)
1246 return NULL;
1248 return hfs_bnode_get(cur->tree, cur->prev);
1251 static inline hfs_bnode_t *hfs_bnode_next (hfs_bnode_t *cur)
1253 if (cur->next == 0x00000000)
1254 return NULL;
1256 return hfs_bnode_get(cur->tree, cur->next);
1259 unused static hfs_rec_t *hfs_rec_prev (hfs_rec_t *cur)
1261 hfs_bnode_t *curn;
1262 int num;
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;
1273 return hfs_rec_get(curn, num - 1);
1276 unused static hfs_rec_t *hfs_rec_next (hfs_rec_t *cur)
1278 hfs_bnode_t *curn;
1279 int num;
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;
1290 return hfs_rec_get(curn, num - 1);
1293 static int hfs_cat_compare (int type, HFS_cnid_t cnid,
1294 const void *more, hfs_rec_t *rec, int rectype);
1296 /* Simplified Btree recurse function from Linux */
1297 static hfs_rec_t *hfs_rec_find (hfs_btree_t *tree,
1298 HFS_cnid_t cnid, const char *name, int rectype)
1300 hfs_bnode_t *curn;
1301 hfs_rec_t *cur;
1302 unsigned int i;
1303 int ret;
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.
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 */
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;
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;
1347 #endif /* DEBUG_HFS_REC_FIND */
1350 #if DEBUG_HFS_REC_FIND
1351 if (idx) {
1352 i = idx;
1353 ret = idx_ret;
1354 cur = idx_cur;
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;
1363 HFS_DPRINTF("Recurse to record: %d %08x => %08x\n",
1364 i, cnid, cur->u.idxrec.uid);
1365 curn = hfs_bnode_get(curn->tree, cur->u.idxrec.uid);
1367 if (ret != 0 || curn == NULL) {
1368 /* We won't find what we're looking for... */
1369 HFS_DPRINTF("NOT FOUND\n");
1370 return NULL;
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;
1377 #endif
1378 HFS_DPRINTF("found %p %p %d %p\n", cur, curn, i, hfs_rec_get(curn, i));
1380 return cur;
1383 static inline hfs_rec_t *hfs_get_dir (hfs_btree_t *tree, HFS_cnid_t cnid,
1384 const unsigned char *name)
1386 return hfs_rec_find(tree, cnid, name, 1);
1389 static hfs_rec_t *hfs_get_dirfile (hfs_rec_t *dir, HFS_cnid_t cnid,
1390 const unsigned char *name,
1391 const unsigned char *info)
1393 hfs_btree_t *tree;
1394 hfs_bnode_t *cur;
1395 hfs_rec_t *rec;
1396 hfs_catrec_t *frec;
1397 int idx;
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;
1409 idx = 1;
1411 rec = hfs_rec_get(cur, idx);
1412 if (rec == NULL) {
1413 HFS_ERROR("Cannot get record %d\n", idx);
1414 return NULL;
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;
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;
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;
1437 return NULL;
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))
1447 hfs_bnode_t *node;
1448 hfs_rec_t *rec;
1449 hfs_headrec_t *head;
1450 hfs_btree_t *newt;
1451 uint32_t bloc;
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;
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;
1479 if (rec->type != RECORD_HEAD) {
1480 HFS_ERROR("Not an header record !\n");
1481 return NULL;
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;
1497 return newt;
1500 static int hfs_cat_compare (int type, HFS_cnid_t cnid,
1501 const void *more, hfs_rec_t *rec, int rectype)
1503 hfs_idxrec_t *idxrec;
1504 hfs_catrec_t *catrec;
1505 const unsigned char *name;
1506 HFS_cnid_t id;
1507 int ret;
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;
1528 HFS_DPRINTF("Compare cnid (%08x '%s') vs (%08x '%s') %08x %d\n",
1529 cnid, (char *)more, id, name, catrec->type, rectype);
1532 * Always diff Record_IDXs, but diff RECORDS_CATs iff they match the type
1533 * being looked for: THREAD vs NON-THREAD (rectype).
1535 ret = cnid - id;
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;
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).
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);
1573 HFS_DPRINTF("ret %d catrec %p catrec->type %08x\n",
1574 ret, catrec, catrec ? catrec->type : 0);
1575 return ret;
1578 static hfs_btree_t *hfs_cat_open (hfs_vol_t *volume)
1580 HFS_DPRINTF("Open HFS catalog\n");
1581 return hfs_btree_open(&volume->cat_file, RECORD_CAT, &hfs_cat_compare);
1584 unused static int hfs_ext_compare (unused int type, unused HFS_cnid_t cnid,
1585 unused const void *more,
1586 unused hfs_rec_t *rec)
1588 /* TODO */
1589 return -1;
1592 static hfs_btree_t *hfs_ext_open (unused hfs_vol_t *volume)
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
1602 static void hfs_map_boot_file (part_t *part, hfs_vol_t *volume,
1603 uint32_t *boot_start, uint32_t *boot_offset,
1604 uint32_t *boot_size)
1606 uint32_t bloc, size;
1608 /* Now, patch the partition to register the boot file
1609 * XXX: we "know" that only one extent is used...
1610 * this may not be true if booting from a hard drive...
1612 volume->boot_file->volume = volume;
1613 bloc = hfs_get_bloc(volume->boot_file, 0);
1614 if (bloc == (uint32_t)(-1)) {
1615 printf("Cannot get boot file start bloc\n");
1616 return;
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;
1626 static inode_t *fs_hfs_get_inode (inode_t *parent, const unsigned char *name)
1628 inode_t *new;
1629 hfs_fork_t *pfile, *file;
1630 hfs_rec_t *catrec, *extrec;
1631 uint32_t size;
1632 int i;
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;
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);
1666 return new;
1669 static void fs_hfs_put_inode (unused inode_t *inode)
1673 static uint32_t fs_hfs_map_bloc (inode_t *inode, uint32_t bloc)
1675 return hfs_get_bloc(inode->private, bloc);
1678 static inode_t *fs_hfs_get_special_inode (fs_t *fs, int type)
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;
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;
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;
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;
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);
1734 break;
1735 default:
1736 return NULL;
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;
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);
1764 if (rec != NULL) {
1765 volume->boot_id = rec->u.catrec.pid;
1766 drec = hfs_get_dir(volume->cat_tree, volume->boot_id, "");
1769 if (rec == NULL) {
1770 HFS_ERROR("Didn't find boot file\n");
1771 return NULL;
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;
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;
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;
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;
1829 bdir->name = strdup(drec->u.catrec.name);
1830 if (bdir->name == NULL) {
1831 free(bdir);
1832 return NULL;
1834 bdir->private = &drec->u.catrec.fork;
1835 bdir->flags = INODE_TYPE_DIR;
1836 bfile->parent = bdir;
1837 HFS_DPRINTF("%s: cache '%s' into '%s'\n",
1838 __func__, bfile->name, bdir->name);
1839 fs_cache_add_inode(bdir, bfile);
1840 bfile = bdir;
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;
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);
1863 return cur;
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,
1873 int fs_hfs_probe (part_t *part, uint32_t *size,
1874 fs_ops_t **fs_ops, unsigned char **name,
1875 void **private)
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;
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;
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;
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;
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;
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];
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;
1988 volume->boot_id = boot_id;
1989 volume->type = type;
1990 HFS_DPRINTF("%s volume: type: %d bsize: %d start_offset: %d\n",
1991 type == FS_TYPE_HFS ? "HFS" : "HFSplus",
1992 volume->type, volume->bsize, volume->start_offset);
1993 HFS_DPRINTF("Catalog file:\n");
1994 hfs_dump_fork(&volume->cat_file);
1995 HFS_DPRINTF("Extents file:\n");
1996 hfs_dump_fork(&volume->ext_file);
1997 if (volume->boot_file != NULL) {
1998 HFS_DPRINTF("Boot file:\n");
1999 hfs_dump_fork(volume->boot_file);
2001 *fs_ops = &hfs_fs_ops;
2002 HFS_DPRINTF("Set part to %p\n", part);
2003 volume->part = part;
2004 *private = volume;
2006 return type;