/* * VasEBoot -- GRand Unified Bootloader * Copyright (C) 2005,2006,2007,2008,2009,2012,2013 Free Software Foundation, Inc. * * VasEBoot is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * VasEBoot is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with VasEBoot. If not, see . */ #include #include #define VasEBoot_HFSPLUS_MAGIC 0x482B #define VasEBoot_HFSPLUSX_MAGIC 0x4858 #define VasEBoot_HFSPLUS_SBLOCK 2 /* A HFS+ extent. */ struct VasEBoot_hfsplus_extent { /* The first block of a file on disk. */ VasEBoot_uint32_t start; /* The amount of blocks described by this extent. */ VasEBoot_uint32_t count; } VasEBoot_PACKED; /* The descriptor of a fork. */ struct VasEBoot_hfsplus_forkdata { VasEBoot_uint64_t size; VasEBoot_uint32_t clumpsize; VasEBoot_uint32_t blocks; struct VasEBoot_hfsplus_extent extents[8]; } VasEBoot_PACKED; /* The HFS+ Volume Header. */ struct VasEBoot_hfsplus_volheader { VasEBoot_uint16_t magic; VasEBoot_uint16_t version; VasEBoot_uint32_t attributes; VasEBoot_uint8_t unused1[12]; VasEBoot_uint32_t utime; VasEBoot_uint8_t unused2[16]; VasEBoot_uint32_t blksize; VasEBoot_uint8_t unused3[36]; VasEBoot_uint32_t ppc_bootdir; VasEBoot_uint32_t intel_bootfile; /* Folder opened when disk is mounted. Unused by VasEBoot. */ VasEBoot_uint32_t showfolder; VasEBoot_uint32_t os9folder; VasEBoot_uint8_t unused4[4]; VasEBoot_uint32_t osxfolder; VasEBoot_uint64_t num_serial; struct VasEBoot_hfsplus_forkdata allocations_file; struct VasEBoot_hfsplus_forkdata extents_file; struct VasEBoot_hfsplus_forkdata catalog_file; struct VasEBoot_hfsplus_forkdata attr_file; struct VasEBoot_hfsplus_forkdata startup_file; } VasEBoot_PACKED; struct VasEBoot_hfsplus_compress_index { VasEBoot_uint32_t start; VasEBoot_uint32_t size; }; struct VasEBoot_hfsplus_file { struct VasEBoot_hfsplus_data *data; struct VasEBoot_hfsplus_extent extents[8]; struct VasEBoot_hfsplus_extent resource_extents[8]; VasEBoot_uint64_t size; VasEBoot_uint64_t resource_size; VasEBoot_uint32_t fileid; VasEBoot_int32_t mtime; int compressed; char *cbuf; void *file; struct VasEBoot_hfsplus_compress_index *compress_index; VasEBoot_uint32_t cbuf_block; VasEBoot_uint32_t compress_index_size; }; struct VasEBoot_hfsplus_btree { VasEBoot_uint32_t root; VasEBoot_size_t nodesize; /* Catalog file node. */ struct VasEBoot_hfsplus_file file; }; /* Information about a "mounted" HFS+ filesystem. */ struct VasEBoot_hfsplus_data { struct VasEBoot_hfsplus_volheader volheader; VasEBoot_disk_t disk; unsigned int log2blksize; struct VasEBoot_hfsplus_btree catalog_tree; struct VasEBoot_hfsplus_btree extoverflow_tree; struct VasEBoot_hfsplus_btree attr_tree; struct VasEBoot_hfsplus_file dirroot; struct VasEBoot_hfsplus_file opened_file; /* This is the offset into the physical disk for an embedded HFS+ filesystem (one inside a plain HFS wrapper). */ VasEBoot_disk_addr_t embedded_offset; int case_sensitive; }; /* Internal representation of a catalog key. */ struct VasEBoot_hfsplus_catkey_internal { VasEBoot_uint32_t parent; const VasEBoot_uint16_t *name; VasEBoot_size_t namelen; }; /* Internal representation of an extent overflow key. */ struct VasEBoot_hfsplus_extkey_internal { VasEBoot_uint32_t fileid; VasEBoot_uint32_t start; VasEBoot_uint8_t type; }; struct VasEBoot_hfsplus_attrkey { VasEBoot_uint16_t keylen; VasEBoot_uint16_t unknown1[1]; VasEBoot_uint32_t cnid; VasEBoot_uint16_t unknown2[2]; VasEBoot_uint16_t namelen; VasEBoot_uint16_t name[0]; } VasEBoot_PACKED; struct VasEBoot_hfsplus_attrkey_internal { VasEBoot_uint32_t cnid; const VasEBoot_uint16_t *name; VasEBoot_size_t namelen; }; struct VasEBoot_hfsplus_key_internal { union { struct VasEBoot_hfsplus_extkey_internal extkey; struct VasEBoot_hfsplus_catkey_internal catkey; struct VasEBoot_hfsplus_attrkey_internal attrkey; }; }; /* The on disk layout of a catalog key. */ struct VasEBoot_hfsplus_catkey { VasEBoot_uint16_t keylen; VasEBoot_uint32_t parent; VasEBoot_uint16_t namelen; VasEBoot_uint16_t name[0]; } VasEBoot_PACKED; /* The on disk layout of an extent overflow file key. */ struct VasEBoot_hfsplus_extkey { VasEBoot_uint16_t keylen; VasEBoot_uint8_t type; VasEBoot_uint8_t unused; VasEBoot_uint32_t fileid; VasEBoot_uint32_t start; } VasEBoot_PACKED; struct VasEBoot_hfsplus_key { union { struct VasEBoot_hfsplus_extkey extkey; struct VasEBoot_hfsplus_catkey catkey; struct VasEBoot_hfsplus_attrkey attrkey; VasEBoot_uint16_t keylen; }; } VasEBoot_PACKED; struct VasEBoot_hfsplus_btnode { VasEBoot_uint32_t next; VasEBoot_uint32_t prev; VasEBoot_int8_t type; VasEBoot_uint8_t height; VasEBoot_uint16_t count; VasEBoot_uint16_t unused; } VasEBoot_PACKED; /* Return the offset of the record with the index INDEX, in the node NODE which is part of the B+ tree BTREE. */ static inline VasEBoot_uint16_t VasEBoot_hfsplus_btree_recoffset (struct VasEBoot_hfsplus_btree *btree, struct VasEBoot_hfsplus_btnode *node, unsigned index) { char *cnode = (char *) node; void *recptr; if (btree->nodesize < index * sizeof (VasEBoot_uint16_t) + 2) index = 0; recptr = (&cnode[btree->nodesize - index * sizeof (VasEBoot_uint16_t) - 2]); return VasEBoot_be_to_cpu16 (VasEBoot_get_unaligned16 (recptr)); } /* Return a pointer to the record with the index INDEX, in the node NODE which is part of the B+ tree BTREE. */ static inline struct VasEBoot_hfsplus_key * VasEBoot_hfsplus_btree_recptr (struct VasEBoot_hfsplus_btree *btree, struct VasEBoot_hfsplus_btnode *node, unsigned index) { char *cnode = (char *) node; VasEBoot_uint16_t offset; offset = VasEBoot_hfsplus_btree_recoffset (btree, node, index); if (offset > btree->nodesize - sizeof (struct VasEBoot_hfsplus_key)) offset = 0; return (struct VasEBoot_hfsplus_key *) &cnode[offset]; } extern VasEBoot_err_t (*VasEBoot_hfsplus_open_compressed) (struct VasEBoot_hfsplus_file *node); extern VasEBoot_ssize_t (*VasEBoot_hfsplus_read_compressed) (struct VasEBoot_hfsplus_file *node, VasEBoot_off_t pos, VasEBoot_size_t len, char *buf); VasEBoot_ssize_t VasEBoot_hfsplus_read_file (struct VasEBoot_hfsplus_file *node, VasEBoot_disk_read_hook_t read_hook, void *read_hook_data, VasEBoot_off_t pos, VasEBoot_size_t len, char *buf); VasEBoot_err_t VasEBoot_hfsplus_btree_search (struct VasEBoot_hfsplus_btree *btree, struct VasEBoot_hfsplus_key_internal *key, int (*compare_keys) (struct VasEBoot_hfsplus_key *keya, struct VasEBoot_hfsplus_key_internal *keyb), struct VasEBoot_hfsplus_btnode **matchnode, VasEBoot_off_t *keyoffset); VasEBoot_err_t VasEBoot_mac_bless_inode (VasEBoot_device_t dev, VasEBoot_uint32_t inode, int is_dir, int intel); VasEBoot_err_t VasEBoot_mac_bless_file (VasEBoot_device_t dev, const char *path_in, int intel);