static void show_macos_type(const char *filename) { int err; FSRef ref; FSCatalogInfo info; FInfo *finfo; err = FSPathMakeRef(filename, &ref, NULL); if (err == 0) { err = FSGetCatalogInfo(&ref, kFSCatInfoFinderInfo, &info, NULL, NULL, NULL); } if (err == 0) { finfo = (FInfo *)(info.finderInfo); if (finfo->fdType != 0 || finfo->fdCreator != 0) { char typecode[5], creatorcode[5], s1[256], s2[256]; memcpy(typecode, &finfo->fdType, 4); typecode[4] = 0; format_ascii(typecode, s1); memcpy(creatorcode, &finfo->fdCreator, 4); creatorcode[4] = 0; format_ascii(creatorcode, s2); print_line(0, "Type code \"%s\", creator code \"%s\"", s1, s2); } else { print_line(0, "No type and creator code"); } } if (err) { print_line(0, "Type and creator code unknown (error %d)", err); } }
void detect_apple_volume(SECTION *section, int level) { char s[256], t[514]; unsigned char *buf; u2 magic, version, volnamelen; u4 blocksize, blockstart; u8 blockcount, offset; u8 catalogstart, cataloglength; u4 firstleafnode, nodesize; if (get_buffer(section, 1024, 512, (void **)&buf) < 512) return; magic = get_be_short(buf); version = get_be_short(buf + 2); if (magic == 0xD2D7) { print_line(level, "MFS file system"); } else if (magic == 0x4244) { print_line(level, "HFS file system"); blockcount = get_be_short(buf + 18); blocksize = get_be_long(buf + 20); blockstart = get_be_short(buf + 28); get_pstring(buf + 36, s); format_ascii(s, t); print_line(level + 1, "Volume name \"%s\"", t); format_blocky_size(s, blockcount, blocksize, "blocks", NULL); print_line(level + 1, "Volume size %s", s); if (get_be_short(buf + 0x7c) == 0x482B) { print_line(level, "HFS wrapper for HFS Plus"); offset = (u8)get_be_short(buf + 0x7e) * blocksize + (u8)blockstart * 512; /* TODO: size */ analyze_recursive(section, level + 1, offset, 0, 0); } } else if (magic == 0x482B) { print_line(level, "HFS Plus file system"); blocksize = get_be_long(buf + 40); blockcount = get_be_long(buf + 44); format_blocky_size(s, blockcount, blocksize, "blocks", NULL); print_line(level + 1, "Volume size %s", s); /* To read the volume name, we have to parse some structures... This code makes many assumptions which are usually true, but don't have to be. */ /* get catalog file location on disk */ /* ASSUMPTION: This reads the location of the first extent of the catalog file. If the catalog file is fragmented, we'll be working with only the first fragment, which may not include the node we're looking for. */ catalogstart = get_be_long(buf + 288) * blocksize; cataloglength = get_be_long(buf + 292) * blocksize; /* limit to actual length (byte count instead of block count) */ if (cataloglength > get_be_quad(buf + 272)) cataloglength = get_be_quad(buf + 272); /* read header node of B-tree (4096 is the minimum node size) */ if (get_buffer(section, catalogstart, 4096, (void **)&buf) < 4096) return; firstleafnode = get_be_long(buf + 24); nodesize = get_be_short(buf + 32); if (nodesize < 4096) return; /* illegal value */ /* read first lead node */ if ((firstleafnode + 1) * nodesize > cataloglength) return; /* the location is beyond the end of the catalog */ if (get_buffer(section, catalogstart + firstleafnode * nodesize, nodesize, (void **)&buf) < nodesize) return; /* the first record in this leaf node should be for parent id 1 */ if (buf[8] != 0xff) return; /* not a leaf node */ if (get_be_short(buf + 14) <= 6) return; /* key of first record is too short to contain a name */ if (get_be_long(buf + 16) != 1) return; /* parent folder id is not "root parent" */ volnamelen = get_be_short(buf + 20); format_utf16_be(buf + 22, volnamelen * 2, t); print_line(level + 1, "Volume name \"%s\"", t); } }