From cb0c5d701a8852f72fe75c9bd223643fb5222399 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Tue, 19 Jun 2007 03:29:47 -0400 Subject: [PATCH] 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" --- lib/blkid/ChangeLog | 7 ++++ lib/blkid/probe.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++++++-- lib/blkid/probe.h | 47 ++++++++++++++++++++++ 3 files changed, 162 insertions(+), 3 deletions(-) diff --git a/lib/blkid/ChangeLog b/lib/blkid/ChangeLog index 28e0cbd..d2de7b9 100644 --- a/lib/blkid/ChangeLog +++ b/lib/blkid/ChangeLog @@ -1,3 +1,10 @@ +2007-06-19 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 --git a/lib/blkid/probe.c b/lib/blkid/probe.c index 3f0829c..211c8bd 100644 --- a/lib/blkid/probe.c +++ b/lib/blkid/probe.c @@ -46,7 +46,7 @@ static int figure_label_len(const unsigned char *label, int len) } 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 blkid_probe *pr, 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) @@ -398,6 +398,111 @@ static int probe_fat_nomagic(struct blkid_probe *probe, 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)), unsigned char *buf) @@ -709,7 +814,7 @@ static int probe_gfs2(struct blkid_probe *probe, 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 --git a/lib/blkid/probe.h b/lib/blkid/probe.h index 88bf311..f22fb2e 100644 --- a/lib/blkid/probe.h +++ b/lib/blkid/probe.h @@ -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 */ -- 1.8.3.1