libblkid: Enhance support for MacOS's hfs, hfsplus, and hfsx filesystems

Add detection for hfsx filesystems.  Add label and uuid detetion for
hfs, hfsplus, and hfsx.

Addresses-Sourceforge-Feature-Requests: #2060292

Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
bitmap-optimize
Theodore Ts'o 2008-08-22 16:45:44 -04:00
parent 5b7adf0690
commit 9c460caae3
2 changed files with 240 additions and 6 deletions

View File

@ -1028,17 +1028,178 @@ static int probe_gfs2(struct blkid_probe *probe,
return 1;
}
static int probe_hfsplus(struct blkid_probe *probe __BLKID_ATTR((unused)),
void unicode_16be_to_utf8(unsigned char *str, int out_len,
const unsigned char *buf, int in_len)
{
int i, j;
unsigned int c;
for (i = j = 0; i + 2 <= in_len; i += 2) {
c = (buf[i] << 8) | buf[i+1];
if (c == 0) {
str[j] = '\0';
break;
} else if (c < 0x80) {
if (j+1 >= out_len)
break;
str[j++] = (unsigned char) c;
} else if (c < 0x800) {
if (j+2 >= out_len)
break;
str[j++] = (unsigned char) (0xc0 | (c >> 6));
str[j++] = (unsigned char) (0x80 | (c & 0x3f));
} else {
if (j+3 >= out_len)
break;
str[j++] = (unsigned char) (0xe0 | (c >> 12));
str[j++] = (unsigned char) (0x80 | ((c >> 6) & 0x3f));
str[j++] = (unsigned char) (0x80 | (c & 0x3f));
}
}
str[j] = '\0';
}
static int probe_hfs(struct blkid_probe *probe __BLKID_ATTR((unused)),
struct blkid_magic *id __BLKID_ATTR((unused)),
unsigned char *buf)
{
struct hfs_mdb *sbd = (struct hfs_mdb *)buf;
struct hfs_mdb *hfs = (struct hfs_mdb *) buf;
char uuid_str[17];
__u64 uuid;
if ((memcmp(hfs->embed_sig, "H+", 2) == 0) ||
(memcmp(hfs->embed_sig, "HX", 2) == 0))
return 1; /* Not hfs, but an embedded HFS+ */
uuid = blkid_le64(*((unsigned long long *) hfs->finder_info.id));
if (uuid) {
sprintf(uuid_str, "%016llX", uuid);
blkid_set_tag(probe->dev, "UUID", uuid_str, 0);
}
blkid_set_tag(probe->dev, "LABEL", hfs->label, hfs->label_len);
return 0;
}
static int probe_hfsplus(struct blkid_probe *probe,
struct blkid_magic *id,
unsigned char *buf)
{
struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT];
struct hfsplus_bnode_descriptor *descr;
struct hfsplus_bheader_record *bnode;
struct hfsplus_catalog_key *key;
struct hfsplus_vol_header *hfsplus;
struct hfs_mdb *sbd = (struct hfs_mdb *) buf;
unsigned int alloc_block_size;
unsigned int alloc_first_block;
unsigned int embed_first_block;
unsigned int off = 0;
unsigned int blocksize;
unsigned int cat_block;
unsigned int ext_block_start;
unsigned int ext_block_count;
unsigned int record_count;
unsigned int leaf_node_head;
unsigned int leaf_node_count;
unsigned int leaf_node_size;
unsigned int leaf_block;
unsigned int label_len;
int ext;
__u64 leaf_off, uuid;
char uuid_str[17], label[512];
/* Check for a HFS+ volume embedded in a HFS volume */
if (memcmp(sbd->embed_sig, "H+", 2) == 0)
if (memcmp(sbd->signature, "BD", 2) == 0) {
if ((memcmp(sbd->embed_sig, "H+", 2) != 0) &&
(memcmp(sbd->embed_sig, "HX", 2) != 0))
/* This must be an HFS volume, so fail */
return 1;
alloc_block_size = blkid_be32(sbd->al_blk_size);
alloc_first_block = blkid_be16(sbd->al_bl_st);
embed_first_block = blkid_be16(sbd->embed_startblock);
off = (alloc_first_block * 512) +
(embed_first_block * alloc_block_size);
buf = get_buffer(probe, off + (id->bim_kboff * 1024),
sizeof(sbd));
if (!buf)
return 1;
hfsplus = (struct hfsplus_vol_header *) buf;
}
hfsplus = (struct hfsplus_vol_header *) buf;
if ((memcmp(hfsplus->signature, "H+", 2) != 0) &&
(memcmp(hfsplus->signature, "HX", 2) != 0))
return 1;
uuid = blkid_le64(*((unsigned long long *) hfsplus->finder_info.id));
if (uuid) {
sprintf(uuid_str, "%016llX", uuid);
blkid_set_tag(probe->dev, "UUID", uuid_str, 0);
}
blocksize = blkid_be32(hfsplus->blocksize);
memcpy(extents, hfsplus->cat_file.extents, sizeof(extents));
cat_block = blkid_be32(extents[0].start_block);
buf = get_buffer(probe, off + (cat_block * blocksize), 0x2000);
if (!buf)
return 0;
return 1;
bnode = (struct hfsplus_bheader_record *)
&buf[sizeof(struct hfsplus_bnode_descriptor)];
leaf_node_head = blkid_be32(bnode->leaf_head);
leaf_node_size = blkid_be16(bnode->node_size);
leaf_node_count = blkid_be32(bnode->leaf_count);
if (leaf_node_count == 0)
return 0;
leaf_block = (leaf_node_head * leaf_node_size) / blocksize;
/* get physical location */
for (ext = 0; ext < HFSPLUS_EXTENT_COUNT; ext++) {
ext_block_start = blkid_be32(extents[ext].start_block);
ext_block_count = blkid_be32(extents[ext].block_count);
if (ext_block_count == 0)
return 0;
/* this is our extent */
if (leaf_block < ext_block_count)
break;
leaf_block -= ext_block_count;
}
if (ext == HFSPLUS_EXTENT_COUNT)
return 0;
leaf_off = (ext_block_start + leaf_block) * blocksize;
buf = get_buffer(probe, off + leaf_off, leaf_node_size);
if (!buf)
return 0;
descr = (struct hfsplus_bnode_descriptor *) buf;
record_count = blkid_be16(descr->num_recs);
if (record_count == 0)
return 0;
if (descr->type != HFS_NODE_LEAF)
return 0;
key = (struct hfsplus_catalog_key *)
&buf[sizeof(struct hfsplus_bnode_descriptor)];
if (blkid_be32(key->parent_id) != HFSPLUS_POR_CNID)
return 0;
label_len = blkid_be16(key->unicode_len) * 2;
unicode_16be_to_utf8(label, sizeof(label), key->unicode, label_len);
blkid_set_tag(probe->dev, "LABEL", label, 0);
return 0;
}
#define LVM2_LABEL_SIZE 512
@ -1162,8 +1323,9 @@ static struct blkid_magic type_array[] = {
{ "zfs", 264, 0, 8, "\0\0\x02\xf5\xb0\x07\xb1\x0c", probe_zfs },
{ "zfs", 264, 0, 8, "\x0c\xb1\x07\xb0\xf5\x02\0\0", probe_zfs },
{ "hfsplus", 1, 0, 2, "BD", probe_hfsplus },
{ "hfsplus", 1, 0, 2, "H+", 0 },
{ "hfs", 1, 0, 2, "BD", 0 },
{ "hfsplus", 1, 0, 2, "H+", probe_hfsplus },
{ "hfsplus", 1, 0, 2, "HX", probe_hfsplus },
{ "hfs", 1, 0, 2, "BD", probe_hfs },
{ "ufs", 8, 0x55c, 4, "T\031\001\000", 0 },
{ "hpfs", 8, 0, 4, "I\350\225\371", 0 },
{ "sysv", 0, 0x3f8, 4, "\020~\030\375", 0 },

View File

@ -531,6 +531,78 @@ struct hfs_mdb {
__u16 embed_blockcount;
} __attribute__((packed));
#define HFS_NODE_LEAF 0xff
#define HFSPLUS_POR_CNID 1
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));
#define HFSPLUS_EXTENT_COUNT 8
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));
/* this is lvm's label_header & pv_header combined. */
#define LVM2_ID_LEN 32