# HG changeset patch # User tytso@mit.edu # Date 1182238187 14400 # Node ID ee079e7cb509d2da74a65411e670efaa5e88850a # Parent 5c00c21991974cc750efa2474fab484b0a1f1522 Add more paranoid NTFS probing and fetch UUID and LABEL information Hopefully this addresses false positives by the blkid library when detecting NTFS partitions. Addresses Launchpad Bug: #110138 Signed-off-by: "Theodore Ts'o" diff -r 5c00c2199197 -r ee079e7cb509 lib/blkid/ChangeLog --- a/lib/blkid/ChangeLog Mon Jun 18 18:26:50 2007 -0400 +++ b/lib/blkid/ChangeLog Tue Jun 19 03:29:47 2007 -0400 @@ -1,3 +1,10 @@ 2007-05-23 Theodore Tso + + * probe.c (probe_ntfs): Add probe function which is more paranoid + about checking for a valid NTFS partition, and which sets + the UUID and LABEL information. (Addresses Launchpad Bug + #110138) + 2007-05-23 Theodore Tso * getsize.c (main), read.c (parse_dev), tst_types.c (main): Fix diff -r 5c00c2199197 -r ee079e7cb509 lib/blkid/probe.c --- a/lib/blkid/probe.c Mon Jun 18 18:26:50 2007 -0400 +++ b/lib/blkid/probe.c Tue Jun 19 03:29:47 2007 -0400 @@ -46,7 +46,7 @@ static int figure_label_len(const unsign } static unsigned char *get_buffer(struct blkid_probe *pr, - unsigned off, size_t len) + blkid_loff_t off, size_t len) { ssize_t ret_read; unsigned char *newbuf; @@ -74,7 +74,7 @@ static unsigned char *get_buffer(struct pr->buf = newbuf; pr->buf_max = len; } - if (lseek(pr->fd, off, SEEK_SET) < 0) + if (blkid_llseek(pr->fd, off, SEEK_SET) < 0) return NULL; ret_read = read(pr->fd, pr->buf, len); if (ret_read != (ssize_t) len) @@ -397,6 +397,111 @@ static int probe_fat_nomagic(struct blki return probe_fat(probe, id, buf); } + +static int probe_ntfs(struct blkid_probe *probe, + struct blkid_magic *id __BLKID_ATTR((unused)), + unsigned char *buf) +{ + struct ntfs_super_block *ns; + struct master_file_table_record *mft; + struct file_attribute *attr; + char uuid_str[17], label_str[129], *cp; + int bytes_per_sector, sectors_per_cluster; + int mft_record_size, attr_off, attr_len; + unsigned int i, attr_type, val_len; + int val_off; + __u64 nr_clusters; + blkid_loff_t off; + unsigned char *buf_mft, *val; + + ns = (struct ntfs_super_block *) buf; + + bytes_per_sector = ns->bios_parameter_block[0] + + (ns->bios_parameter_block[1] << 8); + sectors_per_cluster = ns->bios_parameter_block[2]; + + if (ns->cluster_per_mft_record < 0) + mft_record_size = 1 << - ns->cluster_per_mft_record; + else + mft_record_size = ns->cluster_per_mft_record * + sectors_per_cluster * bytes_per_sector; + nr_clusters = blkid_le64(ns->number_of_sectors) / sectors_per_cluster; + + if ((blkid_le64(ns->mft_cluster_location) > nr_clusters) || + (blkid_le64(ns->mft_mirror_cluster_location) > nr_clusters)) + return 1; + + off = blkid_le64(ns->mft_mirror_cluster_location) * + bytes_per_sector * sectors_per_cluster; + + buf_mft = get_buffer(probe, off, mft_record_size); + if (!buf_mft) + return 1; + + if (memcmp(buf_mft, "FILE", 4)) + return 1; + + off = blkid_le64(ns->mft_cluster_location) * bytes_per_sector * + sectors_per_cluster; + + buf_mft = get_buffer(probe, off, mft_record_size); + if (!buf_mft) + return 1; + + if (memcmp(buf_mft, "FILE", 4)) + return 1; + + off += MFT_RECORD_VOLUME * mft_record_size; + + buf_mft = get_buffer(probe, off, mft_record_size); + if (!buf_mft) + return 1; + + if (memcmp(buf_mft, "FILE", 4)) + return 1; + + mft = (struct master_file_table_record *) buf_mft; + + attr_off = blkid_le16(mft->attrs_offset); + label_str[0] = 0; + + while (1) { + attr = (struct file_attribute *) (buf_mft + attr_off); + attr_len = blkid_le16(attr->len); + attr_type = blkid_le32(attr->type); + val_off = blkid_le16(attr->value_offset); + val_len = blkid_le32(attr->value_len); + + attr_off += attr_len; + + if ((attr_off > mft_record_size) || + (attr_len == 0)) + break; + + if (attr_type == MFT_RECORD_ATTR_END) + break; + + if (attr_type == MFT_RECORD_ATTR_VOLUME_NAME) { + if (val_len > sizeof(label_str)) + val_len = sizeof(label_str)-1; + + for (i=0, cp=label_str; i < val_len; i+=2,cp++) { + val = ((__u8 *) attr) + val_off + i; + *cp = val[0]; + if (val[1]) + *cp = '?'; + } + *cp = 0; + } + } + + sprintf(uuid_str, "%llX", blkid_le64(ns->volume_serial)); + blkid_set_tag(probe->dev, "UUID", uuid_str, 0); + if (label_str[0]) + blkid_set_tag(probe->dev, "LABEL", label_str, 0); + return 0; +} + static int probe_xfs(struct blkid_probe *probe, struct blkid_magic *id __BLKID_ATTR((unused)), @@ -709,7 +814,7 @@ static struct blkid_magic type_array[] = static struct blkid_magic type_array[] = { /* type kboff sboff len magic probe */ { "oracleasm", 0, 32, 8, "ORCLDISK", probe_oracleasm }, - { "ntfs", 0, 3, 8, "NTFS ", 0 }, + { "ntfs", 0, 3, 8, "NTFS ", probe_ntfs }, { "jbd", 1, 0x38, 2, "\123\357", probe_jbd }, { "ext3", 1, 0x38, 2, "\123\357", probe_ext3 }, { "ext2", 1, 0x38, 2, "\123\357", probe_ext2 }, diff -r 5c00c2199197 -r ee079e7cb509 lib/blkid/probe.h --- a/lib/blkid/probe.h Mon Jun 18 18:26:50 2007 -0400 +++ b/lib/blkid/probe.h Tue Jun 19 03:29:47 2007 -0400 @@ -393,6 +393,53 @@ struct gfs2_sb { /* In gfs1, quota and license dinodes followed */ }; +struct ntfs_super_block { + __u8 jump[3]; + __u8 oem_id[8]; + __u8 bios_parameter_block[25]; + __u16 unused[2]; + __u64 number_of_sectors; + __u64 mft_cluster_location; + __u64 mft_mirror_cluster_location; + __s8 cluster_per_mft_record; + __u8 reserved1[3]; + __s8 cluster_per_index_record; + __u8 reserved2[3]; + __u64 volume_serial; + __u16 checksum; +}; + +struct master_file_table_record { + __u32 magic; + __u16 usa_ofs; + __u16 usa_count; + __u64 lsn; + __u16 sequence_number; + __u16 link_count; + __u16 attrs_offset; + __u16 flags; + __u32 bytes_in_use; + __u32 bytes_allocated; +} __attribute__((__packed__)); + +struct file_attribute { + __u32 type; + __u32 len; + __u8 non_resident; + __u8 name_len; + __u16 name_offset; + __u16 flags; + __u16 instance; + __u32 value_len; + __u16 value_offset; +} __attribute__((__packed__)); + +#define MFT_RECORD_VOLUME 3 +#define MFT_RECORD_ATTR_VOLUME_NAME 0x60 +#define MFT_RECORD_ATTR_VOLUME_INFO 0x70 +#define MFT_RECORD_ATTR_OBJECT_ID 0x40 +#define MFT_RECORD_ATTR_END 0xffffffffu + /* * Byte swap functions */