1 /* 2 * Copyright (C) 2004-2008 Kay Sievers <kay.sievers@vrfy.org> 3 * Copyright (C) 2008 Karel Zak <kzak@redhat.com> 4 * 5 * This file may be redistributed under the terms of the 6 * GNU Lesser General Public License. 7 */ 8 #include <stdio.h> 9 #include <stdlib.h> 10 #include <unistd.h> 11 #include <string.h> 12 #include <inttypes.h> 13 14 #include "superblocks.h" 15 16 #if 0 17 #include "md5.h" 18 #endif 19 20 /* HFS / HFS+ */ 21 struct hfs_finder_info { 22 uint32_t boot_folder; 23 uint32_t start_app; 24 uint32_t open_folder; 25 uint32_t os9_folder; 26 uint32_t reserved; 27 uint32_t osx_folder; 28 uint8_t id[8]; 29 } __attribute__((packed)); 30 31 struct hfs_mdb { 32 uint8_t signature[2]; 33 uint32_t cr_date; 34 uint32_t ls_Mod; 35 uint16_t atrb; 36 uint16_t nm_fls; 37 uint16_t vbm_st; 38 uint16_t alloc_ptr; 39 uint16_t nm_al_blks; 40 uint32_t al_blk_size; 41 uint32_t clp_size; 42 uint16_t al_bl_st; 43 uint32_t nxt_cnid; 44 uint16_t free_bks; 45 uint8_t label_len; 46 uint8_t label[27]; 47 uint32_t vol_bkup; 48 uint16_t vol_seq_num; 49 uint32_t wr_cnt; 50 uint32_t xt_clump_size; 51 uint32_t ct_clump_size; 52 uint16_t num_root_dirs; 53 uint32_t file_count; 54 uint32_t dir_count; 55 struct hfs_finder_info finder_info; 56 uint8_t embed_sig[2]; 57 uint16_t embed_startblock; 58 uint16_t embed_blockcount; 59 } __attribute__((packed)); 60 61 62 #define HFS_NODE_LEAF 0xff 63 #define HFSPLUS_POR_CNID 1 64 65 struct hfsplus_bnode_descriptor { 66 uint32_t next; 67 uint32_t prev; 68 uint8_t type; 69 uint8_t height; 70 uint16_t num_recs; 71 uint16_t reserved; 72 } __attribute__((packed)); 73 74 struct hfsplus_bheader_record { 75 uint16_t depth; 76 uint32_t root; 77 uint32_t leaf_count; 78 uint32_t leaf_head; 79 uint32_t leaf_tail; 80 uint16_t node_size; 81 } __attribute__((packed)); 82 83 struct hfsplus_catalog_key { 84 uint16_t key_len; 85 uint32_t parent_id; 86 uint16_t unicode_len; 87 uint8_t unicode[255 * 2]; 88 } __attribute__((packed)); 89 90 struct hfsplus_extent { 91 uint32_t start_block; 92 uint32_t block_count; 93 } __attribute__((packed)); 94 95 #define HFSPLUS_EXTENT_COUNT 8 96 struct hfsplus_fork { 97 uint64_t total_size; 98 uint32_t clump_size; 99 uint32_t total_blocks; 100 struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT]; 101 } __attribute__((packed)); 102 103 struct hfsplus_vol_header { 104 uint8_t signature[2]; 105 uint16_t version; 106 uint32_t attributes; 107 uint32_t last_mount_vers; 108 uint32_t reserved; 109 uint32_t create_date; 110 uint32_t modify_date; 111 uint32_t backup_date; 112 uint32_t checked_date; 113 uint32_t file_count; 114 uint32_t folder_count; 115 uint32_t blocksize; 116 uint32_t total_blocks; 117 uint32_t free_blocks; 118 uint32_t next_alloc; 119 uint32_t rsrc_clump_sz; 120 uint32_t data_clump_sz; 121 uint32_t next_cnid; 122 uint32_t write_count; 123 uint64_t encodings_bmp; 124 struct hfs_finder_info finder_info; 125 struct hfsplus_fork alloc_file; 126 struct hfsplus_fork ext_file; 127 struct hfsplus_fork cat_file; 128 struct hfsplus_fork attr_file; 129 struct hfsplus_fork start_file; 130 } __attribute__((packed)); 131 132 #define HFSPLUS_SECTOR_SIZE 512 133 134 static int hfs_set_uuid(blkid_probe pr, unsigned char const *hfs_info, size_t len) 135 { 136 #if 0 137 static unsigned char const hash_init[MD5LENGTH] = { 138 0xb3, 0xe2, 0x0f, 0x39, 0xf2, 0x92, 0x11, 0xd6, 139 0x97, 0xa4, 0x00, 0x30, 0x65, 0x43, 0xec, 0xac 140 }; 141 unsigned char uuid[MD5LENGTH]; 142 struct MD5Context md5c; 143 144 if (memcmp(hfs_info, "\0\0\0\0\0\0\0\0", len) == 0) 145 return -1; 146 MD5Init(&md5c); 147 MD5Update(&md5c, hash_init, MD5LENGTH); 148 MD5Update(&md5c, hfs_info, len); 149 MD5Final(uuid, &md5c); 150 uuid[6] = 0x30 | (uuid[6] & 0x0f); 151 uuid[8] = 0x80 | (uuid[8] & 0x3f); 152 return blkid_probe_set_uuid(pr, uuid); 153 #else 154 return -ENOSYS; 155 #endif 156 } 157 158 static int probe_hfs(blkid_probe pr, const struct blkid_idmag *mag) 159 { 160 struct hfs_mdb *hfs; 161 162 hfs = blkid_probe_get_sb(pr, mag, struct hfs_mdb); 163 if (!hfs) 164 return errno ? -errno : 1; 165 166 if ((memcmp(hfs->embed_sig, "H+", 2) == 0) || 167 (memcmp(hfs->embed_sig, "HX", 2) == 0)) 168 return 1; /* Not hfs, but an embedded HFS+ */ 169 170 hfs_set_uuid(pr, hfs->finder_info.id, sizeof(hfs->finder_info.id)); 171 172 blkid_probe_set_label(pr, hfs->label, hfs->label_len); 173 return 0; 174 } 175 176 static int probe_hfsplus(blkid_probe pr, const struct blkid_idmag *mag) 177 { 178 struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT]; 179 struct hfsplus_bnode_descriptor *descr; 180 struct hfsplus_bheader_record *bnode; 181 struct hfsplus_catalog_key *key; 182 struct hfsplus_vol_header *hfsplus; 183 struct hfs_mdb *sbd; 184 unsigned int alloc_block_size; 185 unsigned int alloc_first_block; 186 unsigned int embed_first_block; 187 unsigned int off = 0; 188 unsigned int blocksize; 189 unsigned int cat_block; 190 unsigned int ext_block_start; 191 unsigned int ext_block_count; 192 unsigned int record_count; 193 unsigned int leaf_node_head; 194 unsigned int leaf_node_count; 195 unsigned int leaf_node_size; 196 unsigned int leaf_block; 197 int ext; 198 uint64_t leaf_off; 199 unsigned char *buf; 200 201 sbd = blkid_probe_get_sb(pr, mag, struct hfs_mdb); 202 if (!sbd) 203 return errno ? -errno : 1; 204 205 /* Check for a HFS+ volume embedded in a HFS volume */ 206 if (memcmp(sbd->signature, "BD", 2) == 0) { 207 if ((memcmp(sbd->embed_sig, "H+", 2) != 0) && 208 (memcmp(sbd->embed_sig, "HX", 2) != 0)) 209 /* This must be an HFS volume, so fail */ 210 return 1; 211 212 alloc_block_size = be32_to_cpu(sbd->al_blk_size); 213 alloc_first_block = be16_to_cpu(sbd->al_bl_st); 214 embed_first_block = be16_to_cpu(sbd->embed_startblock); 215 off = (alloc_first_block * 512) + 216 (embed_first_block * alloc_block_size); 217 218 buf = blkid_probe_get_buffer(pr, 219 off + (mag->kboff * 1024), 220 sizeof(struct hfsplus_vol_header)); 221 hfsplus = (struct hfsplus_vol_header *) buf; 222 223 } else 224 hfsplus = blkid_probe_get_sb(pr, mag, 225 struct hfsplus_vol_header); 226 227 if (!hfsplus) 228 return errno ? -errno : 1; 229 230 if ((memcmp(hfsplus->signature, "H+", 2) != 0) && 231 (memcmp(hfsplus->signature, "HX", 2) != 0)) 232 return 1; 233 234 hfs_set_uuid(pr, hfsplus->finder_info.id, sizeof(hfsplus->finder_info.id)); 235 236 blocksize = be32_to_cpu(hfsplus->blocksize); 237 if (blocksize < HFSPLUS_SECTOR_SIZE) 238 return 1; 239 240 memcpy(extents, hfsplus->cat_file.extents, sizeof(extents)); 241 cat_block = be32_to_cpu(extents[0].start_block); 242 243 buf = blkid_probe_get_buffer(pr, 244 off + ((blkid_loff_t) cat_block * blocksize), 0x2000); 245 if (!buf) 246 return errno ? -errno : 0; 247 248 bnode = (struct hfsplus_bheader_record *) 249 &buf[sizeof(struct hfsplus_bnode_descriptor)]; 250 251 leaf_node_head = be32_to_cpu(bnode->leaf_head); 252 leaf_node_size = be16_to_cpu(bnode->node_size); 253 leaf_node_count = be32_to_cpu(bnode->leaf_count); 254 if (leaf_node_count == 0) 255 return 0; 256 257 leaf_block = (leaf_node_head * leaf_node_size) / blocksize; 258 259 /* get physical location */ 260 for (ext = 0; ext < HFSPLUS_EXTENT_COUNT; ext++) { 261 ext_block_start = be32_to_cpu(extents[ext].start_block); 262 ext_block_count = be32_to_cpu(extents[ext].block_count); 263 if (ext_block_count == 0) 264 return 0; 265 266 /* this is our extent */ 267 if (leaf_block < ext_block_count) 268 break; 269 270 leaf_block -= ext_block_count; 271 } 272 if (ext == HFSPLUS_EXTENT_COUNT) 273 return 0; 274 275 leaf_off = ((uint64_t) ext_block_start + leaf_block) * blocksize; 276 277 buf = blkid_probe_get_buffer(pr, 278 (blkid_loff_t) off + leaf_off, 279 leaf_node_size); 280 if (!buf) 281 return errno ? -errno : 0; 282 283 descr = (struct hfsplus_bnode_descriptor *) buf; 284 record_count = be16_to_cpu(descr->num_recs); 285 if (record_count == 0) 286 return 0; 287 288 if (descr->type != HFS_NODE_LEAF) 289 return 0; 290 291 key = (struct hfsplus_catalog_key *) 292 &buf[sizeof(struct hfsplus_bnode_descriptor)]; 293 294 if (be32_to_cpu(key->parent_id) != HFSPLUS_POR_CNID) 295 return 0; 296 297 blkid_probe_set_utf8label(pr, key->unicode, 298 be16_to_cpu(key->unicode_len) * 2, 299 BLKID_ENC_UTF16BE); 300 301 return 0; 302 } 303 304 const struct blkid_idinfo hfs_idinfo = 305 { 306 .name = "hfs", 307 .usage = BLKID_USAGE_FILESYSTEM, 308 .probefunc = probe_hfs, 309 .flags = BLKID_IDINFO_TOLERANT, 310 .magics = 311 { 312 { .magic = "BD", .len = 2, .kboff = 1 }, 313 { NULL } 314 } 315 }; 316 317 const struct blkid_idinfo hfsplus_idinfo = 318 { 319 .name = "hfsplus", 320 .usage = BLKID_USAGE_FILESYSTEM, 321 .probefunc = probe_hfsplus, 322 .magics = 323 { 324 { .magic = "BD", .len = 2, .kboff = 1 }, 325 { .magic = "H+", .len = 2, .kboff = 1 }, 326 { .magic = "HX", .len = 2, .kboff = 1 }, 327 { NULL } 328 } 329 }; 330
This page was automatically generated by LXR 0.3.1. • OpenWrt