/* * GRUB -- GRand Unified Bootloader * Copyright (C) 2005,2006,2007,2008,2009,2012,2013 Free Software Foundation, Inc. * * GRUB 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. * * GRUB 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 GRUB. If not, see . */ #include #include #define GRUB_HFSPLUS_MAGIC 0x482B #define GRUB_HFSPLUSX_MAGIC 0x4858 #define GRUB_HFSPLUS_SBLOCK 2 /* A HFS+ extent. */ struct grub_hfsplus_extent { /* The first block of a file on disk. */ grub_uint32_t start; /* The amount of blocks described by this extent. */ grub_uint32_t count; } GRUB_PACKED; /* The descriptor of a fork. */ struct grub_hfsplus_forkdata { grub_uint64_t size; grub_uint32_t clumpsize; grub_uint32_t blocks; struct grub_hfsplus_extent extents[8]; } GRUB_PACKED; /* The HFS+ Volume Header. */ struct grub_hfsplus_volheader { grub_uint16_t magic; grub_uint16_t version; grub_uint32_t attributes; grub_uint8_t unused1[12]; grub_uint32_t utime; grub_uint8_t unused2[16]; grub_uint32_t blksize; grub_uint8_t unused3[36]; grub_uint32_t ppc_bootdir; grub_uint32_t intel_bootfile; /* Folder opened when disk is mounted. Unused by GRUB. */ grub_uint32_t showfolder; grub_uint32_t os9folder; grub_uint8_t unused4[4]; grub_uint32_t osxfolder; grub_uint64_t num_serial; struct grub_hfsplus_forkdata allocations_file; struct grub_hfsplus_forkdata extents_file; struct grub_hfsplus_forkdata catalog_file; struct grub_hfsplus_forkdata attr_file; struct grub_hfsplus_forkdata startup_file; } GRUB_PACKED; struct grub_hfsplus_compress_index { grub_uint32_t start; grub_uint32_t size; }; struct grub_hfsplus_file { struct grub_hfsplus_data *data; struct grub_hfsplus_extent extents[8]; struct grub_hfsplus_extent resource_extents[8]; grub_uint64_t size; grub_uint64_t resource_size; grub_uint32_t fileid; grub_int32_t mtime; int compressed; char *cbuf; void *file; struct grub_hfsplus_compress_index *compress_index; grub_uint32_t cbuf_block; grub_uint32_t compress_index_size; }; struct grub_hfsplus_btree { grub_uint32_t root; grub_size_t nodesize; /* Catalog file node. */ struct grub_hfsplus_file file; }; /* Information about a "mounted" HFS+ filesystem. */ struct grub_hfsplus_data { struct grub_hfsplus_volheader volheader; grub_disk_t disk; unsigned int log2blksize; struct grub_hfsplus_btree catalog_tree; struct grub_hfsplus_btree extoverflow_tree; struct grub_hfsplus_btree attr_tree; int extoverflow_tree_ready; struct grub_hfsplus_file dirroot; struct grub_hfsplus_file opened_file; /* This is the offset into the physical disk for an embedded HFS+ filesystem (one inside a plain HFS wrapper). */ grub_disk_addr_t embedded_offset; int case_sensitive; }; /* Internal representation of a catalog key. */ struct grub_hfsplus_catkey_internal { grub_uint32_t parent; const grub_uint16_t *name; grub_size_t namelen; }; /* Internal representation of an extent overflow key. */ struct grub_hfsplus_extkey_internal { grub_uint32_t fileid; grub_uint32_t start; grub_uint8_t type; }; struct grub_hfsplus_attrkey { grub_uint16_t keylen; grub_uint16_t unknown1[1]; grub_uint32_t cnid; grub_uint16_t unknown2[2]; grub_uint16_t namelen; grub_uint16_t name[0]; } GRUB_PACKED; struct grub_hfsplus_attrkey_internal { grub_uint32_t cnid; const grub_uint16_t *name; grub_size_t namelen; }; struct grub_hfsplus_key_internal { union { struct grub_hfsplus_extkey_internal extkey; struct grub_hfsplus_catkey_internal catkey; struct grub_hfsplus_attrkey_internal attrkey; }; }; /* The on disk layout of a catalog key. */ struct grub_hfsplus_catkey { grub_uint16_t keylen; grub_uint32_t parent; grub_uint16_t namelen; grub_uint16_t name[0]; } GRUB_PACKED; /* The on disk layout of an extent overflow file key. */ struct grub_hfsplus_extkey { grub_uint16_t keylen; grub_uint8_t type; grub_uint8_t unused; grub_uint32_t fileid; grub_uint32_t start; } GRUB_PACKED; struct grub_hfsplus_key { union { struct grub_hfsplus_extkey extkey; struct grub_hfsplus_catkey catkey; struct grub_hfsplus_attrkey attrkey; grub_uint16_t keylen; }; } GRUB_PACKED; struct grub_hfsplus_btnode { grub_uint32_t next; grub_uint32_t prev; grub_int8_t type; grub_uint8_t height; grub_uint16_t count; grub_uint16_t unused; } GRUB_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 grub_uint16_t grub_hfsplus_btree_recoffset (struct grub_hfsplus_btree *btree, struct grub_hfsplus_btnode *node, unsigned index) { char *cnode = (char *) node; void *recptr; if (btree->nodesize < index * sizeof (grub_uint16_t) + 2) index = 0; recptr = (&cnode[btree->nodesize - index * sizeof (grub_uint16_t) - 2]); return grub_be_to_cpu16 (grub_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 grub_hfsplus_key * grub_hfsplus_btree_recptr (struct grub_hfsplus_btree *btree, struct grub_hfsplus_btnode *node, unsigned index) { char *cnode = (char *) node; grub_uint16_t offset; offset = grub_hfsplus_btree_recoffset (btree, node, index); if (offset > btree->nodesize - sizeof (struct grub_hfsplus_key)) offset = 0; return (struct grub_hfsplus_key *) &cnode[offset]; } extern grub_err_t (*grub_hfsplus_open_compressed) (struct grub_hfsplus_file *node); extern grub_ssize_t (*grub_hfsplus_read_compressed) (struct grub_hfsplus_file *node, grub_off_t pos, grub_size_t len, char *buf); grub_ssize_t grub_hfsplus_read_file (struct grub_hfsplus_file *node, grub_disk_read_hook_t read_hook, void *read_hook_data, grub_off_t pos, grub_size_t len, char *buf); grub_err_t grub_hfsplus_btree_search (struct grub_hfsplus_btree *btree, struct grub_hfsplus_key_internal *key, int (*compare_keys) (struct grub_hfsplus_key *keya, struct grub_hfsplus_key_internal *keyb), struct grub_hfsplus_btnode **matchnode, grub_off_t *keyoffset); grub_err_t grub_mac_bless_inode (grub_device_t dev, grub_uint32_t inode, int is_dir, int intel); grub_err_t grub_mac_bless_file (grub_device_t dev, const char *path_in, int intel);