+ struct ufs_super_block {
+ __u32 fs_link;
+ __u32 fs_rlink;
+ __u32 fs_sblkno;
+ __u32 fs_cblkno;
+ __u32 fs_iblkno;
+ __u32 fs_dblkno;
+ __u32 fs_cgoffset;
+ __u32 fs_cgmask;
+ __u32 fs_time;
+ __u32 fs_size;
+ __u32 fs_dsize;
+ __u32 fs_ncg;
+ __u32 fs_bsize;
+ __u32 fs_fsize;
+ __u32 fs_frag;
+ __u32 fs_minfree;
+ __u32 fs_rotdelay;
+ __u32 fs_rps;
+ __u32 fs_bmask;
+ __u32 fs_fmask;
+ __u32 fs_bshift;
+ __u32 fs_fshift;
+ __u32 fs_maxcontig;
+ __u32 fs_maxbpg;
+ __u32 fs_fragshift;
+ __u32 fs_fsbtodb;
+ __u32 fs_sbsize;
+ __u32 fs_csmask;
+ __u32 fs_csshift;
+ __u32 fs_nindir;
+ __u32 fs_inopb;
+ __u32 fs_nspf;
+ __u32 fs_optim;
+ __u32 fs_npsect_state;
+ __u32 fs_interleave;
+ __u32 fs_trackskew;
+ __u32 fs_id[2];
+ __u32 fs_csaddr;
+ __u32 fs_cssize;
+ __u32 fs_cgsize;
+ __u32 fs_ntrak;
+ __u32 fs_nsect;
+ __u32 fs_spc;
+ __u32 fs_ncyl;
+ __u32 fs_cpg;
+ __u32 fs_ipg;
+ __u32 fs_fpg;
+ struct ufs_csum {
+ __u32 cs_ndir;
+ __u32 cs_nbfree;
+ __u32 cs_nifree;
+ __u32 cs_nffree;
+ } __attribute__((__packed__)) fs_cstotal;
+ __s8 fs_fmod;
+ __s8 fs_clean;
+ __s8 fs_ronly;
+ __s8 fs_flags;
+ union {
+ struct {
+ __s8 fs_fsmnt[512];
+ __u32 fs_cgrotor;
+ __u32 fs_csp[31];
+ __u32 fs_maxcluster;
+ __u32 fs_cpc;
+ __u16 fs_opostbl[16][8];
+ } __attribute__((__packed__)) fs_u1;
+ struct {
+ __s8 fs_fsmnt[468];
+ __u8 fs_volname[32];
+ __u64 fs_swuid;
+ __s32 fs_pad;
+ __u32 fs_cgrotor;
+ __u32 fs_ocsp[28];
+ __u32 fs_contigdirs;
+ __u32 fs_csp;
+ __u32 fs_maxcluster;
+ __u32 fs_active;
+ __s32 fs_old_cpc;
+ __s32 fs_maxbsize;
+ __s64 fs_sparecon64[17];
+ __s64 fs_sblockloc;
+ struct ufs2_csum_total {
+ __u64 cs_ndir;
+ __u64 cs_nbfree;
+ __u64 cs_nifree;
+ __u64 cs_nffree;
+ __u64 cs_numclusters;
+ __u64 cs_spare[3];
+ } __attribute__((__packed__)) fs_cstotal;
+ struct ufs_timeval {
+ __s32 tv_sec;
+ __s32 tv_usec;
+ } __attribute__((__packed__)) fs_time;
+ __s64 fs_size;
+ __s64 fs_dsize;
+ __u64 fs_csaddr;
+ __s64 fs_pendingblocks;
+ __s32 fs_pendinginodes;
+ } __attribute__((__packed__)) fs_u2;
+ } fs_u11;
+ union {
+ struct {
+ __s32 fs_sparecon[53];
+ __s32 fs_reclaim;
+ __s32 fs_sparecon2[1];
+ __s32 fs_state;
+ __u32 fs_qbmask[2];
+ __u32 fs_qfmask[2];
+ } __attribute__((__packed__)) fs_sun;
+ struct {
+ __s32 fs_sparecon[53];
+ __s32 fs_reclaim;
+ __s32 fs_sparecon2[1];
+ __u32 fs_npsect;
+ __u32 fs_qbmask[2];
+ __u32 fs_qfmask[2];
+ } __attribute__((__packed__)) fs_sunx86;
+ struct {
+ __s32 fs_sparecon[50];
+ __s32 fs_contigsumsize;
+ __s32 fs_maxsymlinklen;
+ __s32 fs_inodefmt;
+ __u32 fs_maxfilesize[2];
+ __u32 fs_qbmask[2];
+ __u32 fs_qfmask[2];
+ __s32 fs_state;
+ } __attribute__((__packed__)) fs_44;
+ } fs_u2;
+ __s32 fs_postblformat;
+ __s32 fs_nrpos;
+ __s32 fs_postbloff;
+ __s32 fs_rotbloff;
+ __u32 fs_magic;
+ __u8 fs_space[1];
+ } __attribute__((__packed__)) *ufs;
+
+ __u32 magic;
+ int i;
+ int offsets[] = {0, 8, 64, 256, -1};
+
+ for (i = 0; offsets[i] >= 0; i++) {
+ ufs = (struct ufs_super_block *)
+ get_buffer(id, off + (offsets[i] * 0x400), 0x800);
+ if (ufs == NULL)
+ return -1;
+
+ dbg("offset 0x%x", offsets[i] * 0x400);
+ magic = be32_to_cpu(ufs->fs_magic);
+ if ((magic == UFS_MAGIC) ||
+ (magic == UFS2_MAGIC) ||
+ (magic == UFS_MAGIC_FEA) ||
+ (magic == UFS_MAGIC_LFN)) {
+ dbg("magic 0x%08x(be)", magic);
+ goto found;
+ }
+ magic = le32_to_cpu(ufs->fs_magic);
+ if ((magic == UFS_MAGIC) ||
+ (magic == UFS2_MAGIC) ||
+ (magic == UFS_MAGIC_FEA) ||
+ (magic == UFS_MAGIC_LFN)) {
+ dbg("magic 0x%08x(le)", magic);
+ goto found;
+ }
+ }
+ return -1;
+
+found:
+ id->usage_id = VOLUME_ID_FILESYSTEM;
+ id->type_id = VOLUME_ID_UFS;
+ id->type = "ufs";
+
+ return 0;
+}
+
+static int probe_mac_partition_map(struct volume_id *id, __u64 off)
+{
+ struct mac_driver_desc {
+ __u8 signature[2];
+ __u16 block_size;
+ __u32 block_count;
+ } __attribute__((__packed__)) *driver;
+
+ struct mac_partition {
+ __u8 signature[2];
+ __u16 res1;
+ __u32 map_count;
+ __u32 start_block;
+ __u32 block_count;
+ __u8 name[32];
+ __u8 type[32];
+ } __attribute__((__packed__)) *part;
+
+ const __u8 *buf;
+
+ buf = get_buffer(id, off, 0x200);
+ if (buf == NULL)
+ return -1;
+
+ part = (struct mac_partition *) buf;
+ if ((strncmp(part->signature, "PM", 2) == 0) &&
+ (strncmp(part->type, "Apple_partition_map", 19) == 0)) {
+ /* linux creates an own subdevice for the map
+ * just return the type if the drive header is missing */
+ id->usage_id = VOLUME_ID_PARTITIONTABLE;
+ id->type_id = VOLUME_ID_MACPARTMAP;
+ id->type = "mac_partition_map";
+ return 0;
+ }
+
+ driver = (struct mac_driver_desc *) buf;
+ if (strncmp(driver->signature, "ER", 2) == 0) {
+ /* we are on a main device, like a CD
+ * just try to probe the first partition from the map */
+ unsigned int bsize = be16_to_cpu(driver->block_size);
+ int part_count;
+ int i;
+
+ /* get first entry of partition table */
+ buf = get_buffer(id, off + bsize, 0x200);
+ if (buf == NULL)
+ return -1;
+
+ part = (struct mac_partition *) buf;
+ if (strncmp(part->signature, "PM", 2) != 0)
+ return -1;
+
+ part_count = be32_to_cpu(part->map_count);
+ dbg("expecting %d partition entries", part_count);
+
+ if (id->partitions != NULL)
+ free(id->partitions);
+ id->partitions =
+ malloc(part_count * sizeof(struct volume_id_partition));
+ if (id->partitions == NULL)
+ return -1;
+ memset(id->partitions, 0x00, sizeof(struct volume_id_partition));
+
+ id->partition_count = part_count;
+
+ for (i = 0; i < part_count; i++) {
+ __u64 poff;
+ __u64 plen;
+
+ buf = get_buffer(id, off + ((i+1) * bsize), 0x200);
+ if (buf == NULL)
+ return -1;
+
+ part = (struct mac_partition *) buf;
+ if (strncmp(part->signature, "PM", 2) != 0)
+ return -1;
+
+ poff = be32_to_cpu(part->start_block) * bsize;
+ plen = be32_to_cpu(part->block_count) * bsize;
+ dbg("found '%s' partition entry at 0x%llx, len 0x%llx",
+ part->type, poff, plen);
+
+ id->partitions[i].off = poff;
+ id->partitions[i].len = plen;
+
+ if (strncmp(part->type, "Apple_Free", 10) == 0) {
+ id->partitions[i].usage_id = VOLUME_ID_UNUSED;
+ } else if (strncmp(part->type, "Apple_partition_map", 19) == 0) {
+ id->partitions[i].usage_id = VOLUME_ID_PARTITIONTABLE;
+ id->partitions[i].type_id = VOLUME_ID_MACPARTMAP;
+ } else {
+ id->partitions[i].usage_id = VOLUME_ID_UNPROBED;
+ }
+ }
+ id->usage_id = VOLUME_ID_PARTITIONTABLE;
+ id->type_id = VOLUME_ID_MACPARTMAP;
+ id->type = "mac_partition_map";
+ return 0;
+ }
+
+ return -1;
+}
+
+#define HFS_SUPERBLOCK_OFFSET 0x400
+#define HFS_NODE_LEAF 0xff
+#define HFSPLUS_POR_CNID 1
+#define HFSPLUS_EXTENT_COUNT 8
+static int probe_hfs_hfsplus(struct volume_id *id, __u64 off)
+{
+ struct hfs_finder_info{
+ __u32 boot_folder;
+ __u32 start_app;
+ __u32 open_folder;
+ __u32 os9_folder;
+ __u32 reserved;
+ __u32 osx_folder;
+ __u8 id[8];
+ } __attribute__((__packed__));
+
+ struct hfs_mdb {
+ __u8 signature[2];
+ __u32 cr_date;
+ __u32 ls_Mod;
+ __u16 atrb;
+ __u16 nm_fls;
+ __u16 vbm_st;
+ __u16 alloc_ptr;
+ __u16 nm_al_blks;
+ __u32 al_blk_size;
+ __u32 clp_size;
+ __u16 al_bl_st;
+ __u32 nxt_cnid;
+ __u16 free_bks;
+ __u8 label_len;
+ __u8 label[27];
+ __u32 vol_bkup;
+ __u16 vol_seq_num;
+ __u32 wr_cnt;
+ __u32 xt_clump_size;
+ __u32 ct_clump_size;
+ __u16 num_root_dirs;
+ __u32 file_count;
+ __u32 dir_count;
+ struct hfs_finder_info finder_info;
+ __u8 embed_sig[2];
+ __u16 embed_startblock;
+ __u16 embed_blockcount;
+ } __attribute__((__packed__)) *hfs;
+
+ struct hfsplus_bnode_descriptor {
+ __u32 next;
+ __u32 prev;
+ __u8 type;
+ __u8 height;
+ __u16 num_recs;
+ __u16 reserved;
+ } __attribute__((__packed__));
+
+ struct hfsplus_bheader_record {
+ __u16 depth;
+ __u32 root;
+ __u32 leaf_count;
+ __u32 leaf_head;
+ __u32 leaf_tail;
+ __u16 node_size;
+ } __attribute__((__packed__));
+
+ struct hfsplus_catalog_key {
+ __u16 key_len;
+ __u32 parent_id;
+ __u16 unicode_len;
+ __u8 unicode[255 * 2];
+ } __attribute__((__packed__));
+
+ struct hfsplus_extent {
+ __u32 start_block;
+ __u32 block_count;
+ } __attribute__((__packed__));
+
+ struct hfsplus_fork {
+ __u64 total_size;
+ __u32 clump_size;
+ __u32 total_blocks;
+ struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT];
+ } __attribute__((__packed__));
+
+ struct hfsplus_vol_header {
+ __u8 signature[2];
+ __u16 version;
+ __u32 attributes;
+ __u32 last_mount_vers;
+ __u32 reserved;
+ __u32 create_date;
+ __u32 modify_date;
+ __u32 backup_date;
+ __u32 checked_date;
+ __u32 file_count;
+ __u32 folder_count;
+ __u32 blocksize;
+ __u32 total_blocks;
+ __u32 free_blocks;
+ __u32 next_alloc;
+ __u32 rsrc_clump_sz;
+ __u32 data_clump_sz;
+ __u32 next_cnid;
+ __u32 write_count;
+ __u64 encodings_bmp;
+ struct hfs_finder_info finder_info;
+ struct hfsplus_fork alloc_file;
+ struct hfsplus_fork ext_file;
+ struct hfsplus_fork cat_file;
+ struct hfsplus_fork attr_file;
+ struct hfsplus_fork start_file;
+ } __attribute__((__packed__)) *hfsplus;
+
+ unsigned int blocksize;
+ unsigned int cat_block;
+ unsigned int ext_block_start;
+ unsigned int ext_block_count;
+ int ext;
+ unsigned int leaf_node_head;
+ unsigned int leaf_node_count;
+ unsigned int leaf_node_size;
+ unsigned int leaf_block;
+ __u64 leaf_off;
+ unsigned int alloc_block_size;
+ unsigned int alloc_first_block;
+ unsigned int embed_first_block;
+ unsigned int record_count;
+ struct hfsplus_bnode_descriptor *descr;
+ struct hfsplus_bheader_record *bnode;
+ struct hfsplus_catalog_key *key;
+ unsigned int label_len;
+ struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT];
+ const __u8 *buf;
+
+ buf = get_buffer(id, off + HFS_SUPERBLOCK_OFFSET, 0x200);
+ if (buf == NULL)
+ return -1;
+
+ hfs = (struct hfs_mdb *) buf;
+ if (strncmp(hfs->signature, "BD", 2) != 0)
+ goto checkplus;
+
+ /* it may be just a hfs wrapper for hfs+ */
+ if (strncmp(hfs->embed_sig, "H+", 2) == 0) {
+ alloc_block_size = be32_to_cpu(hfs->al_blk_size);
+ dbg("alloc_block_size 0x%x", alloc_block_size);
+
+ alloc_first_block = be16_to_cpu(hfs->al_bl_st);
+ dbg("alloc_first_block 0x%x", alloc_first_block);
+
+ embed_first_block = be16_to_cpu(hfs->embed_startblock);
+ dbg("embed_first_block 0x%x", embed_first_block);
+
+ off += (alloc_first_block * 512) +
+ (embed_first_block * alloc_block_size);
+ dbg("hfs wrapped hfs+ found at offset 0x%llx", off);
+
+ buf = get_buffer(id, off + HFS_SUPERBLOCK_OFFSET, 0x200);
+ if (buf == NULL)
+ return -1;
+ goto checkplus;
+ }
+
+ if (hfs->label_len > 0 && hfs->label_len < 28) {
+ set_label_raw(id, hfs->label, hfs->label_len);
+ set_label_string(id, hfs->label, hfs->label_len) ;
+ }
+
+ set_uuid(id, hfs->finder_info.id, UUID_HFS);
+
+ id->usage_id = VOLUME_ID_FILESYSTEM;
+ id->type_id = VOLUME_ID_HFS;
+ id->type = "hfs";
+
+ return 0;
+
+checkplus:
+ hfsplus = (struct hfsplus_vol_header *) buf;
+ if (strncmp(hfsplus->signature, "H+", 2) == 0)
+ goto hfsplus;
+ if (strncmp(hfsplus->signature, "HX", 2) == 0)
+ goto hfsplus;
+ return -1;