diff options
author | liminghao <liminghao@xiaomi.com> | 2017-03-01 17:54:42 +0800 |
---|---|---|
committer | liminghao <liminghao@xiaomi.com> | 2017-03-02 17:36:10 +0800 |
commit | 1206f6d8c5ed47ba19cfc30a19dba51fcd2cd5cb (patch) | |
tree | 2463642cd61bfbd53b132491b5443924160301df | |
parent | 98f63cd9de161ffae915910098cc0a4311e9177b (diff) | |
download | e2fsprogs-1206f6d8c5ed47ba19cfc30a19dba51fcd2cd5cb.tar.gz |
blkid: add support to recognize exfat to blkid.
we can now identify exfat filesystem.
Change-Id: I870e59a14b6bcd8b45562cdd02c2502d60a9eeff
Signed-off-by: liminghao <liminghao@xiaomi.com>
-rw-r--r-- | lib/blkid/probe.c | 101 | ||||
-rw-r--r-- | lib/blkid/probe.h | 42 |
2 files changed, 139 insertions, 4 deletions
diff --git a/lib/blkid/probe.c b/lib/blkid/probe.c index 66ecbc43..fae74a7f 100644 --- a/lib/blkid/probe.c +++ b/lib/blkid/probe.c @@ -106,7 +106,6 @@ static int check_mdraid(int fd, unsigned char *ret_uuid) if (blkid_llseek(fd, offset, 0) < 0 || read(fd, buf, 4096) != 4096) return -BLKID_ERR_IO; - /* Check for magic number */ if (memcmp("\251+N\374", buf, 4) && memcmp("\374N+\251", buf, 4)) return -BLKID_ERR_PARAM; @@ -330,7 +329,7 @@ static int probe_ext4dev(struct blkid_probe *probe, EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) return -BLKID_ERR_PARAM; - /* + /* * If the filesystem does not have a journal and ext2 and ext4 * is not present, then force this to be detected as an * ext4dev filesystem. @@ -374,7 +373,7 @@ static int probe_ext4(struct blkid_probe *probe, struct blkid_magic *id, EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) return -BLKID_ERR_PARAM; - /* + /* * If the filesystem does not have a journal and ext2 is not * present, then force this to be detected as an ext2 * filesystem. @@ -452,7 +451,7 @@ static int probe_ext2(struct blkid_probe *probe, struct blkid_magic *id, EXT2_FEATURE_INCOMPAT_UNSUPPORTED)) return -BLKID_ERR_PARAM; - /* + /* * If ext2 is not present, but ext4 or ext4dev are, then * disclaim we are ext2 */ @@ -1403,6 +1402,99 @@ static int probe_f2fs(struct blkid_probe *probe, return 0; } +static uint64_t exfat_block_to_offset(const struct exfat_super_block *sb, + uint64_t block) +{ + return block << sb->block_bits; +} + +static uint64_t exfat_cluster_to_block(const struct exfat_super_block *sb, + uint32_t cluster) +{ + return sb->cluster_block_start + + ((uint64_t)(cluster - EXFAT_FIRST_DATA_CLUSTER) << sb->bpc_bits); +} + +static uint64_t exfat_cluster_to_offset(const struct exfat_super_block *sb, + uint32_t cluster) +{ + return exfat_block_to_offset(sb, exfat_cluster_to_block(sb, cluster)); +} + +static uint32_t exfat_next_cluster(struct blkid_probe *probe, + const struct exfat_super_block *sb, + uint32_t cluster) +{ + uint32_t *next; + uint64_t offset; + + offset = exfat_block_to_offset(sb, sb->fat_block_start) + + (uint64_t) cluster * sizeof (cluster); + next = (uint32_t *)get_buffer(probe, offset, sizeof (uint32_t)); + + return next ? *next : 0; +} + +static struct exfat_entry_label *find_exfat_entry_label( + struct blkid_probe *probe, const struct exfat_super_block *sb) +{ + uint32_t cluster = sb->rootdir_cluster; + uint64_t offset = exfat_cluster_to_offset(sb, cluster); + uint8_t *entry; + const size_t max_iter = 10000; + size_t i = 0; + + for (; i < max_iter; ++i) { + entry = (uint8_t *)get_buffer(probe, offset, EXFAT_ENTRY_SIZE); + if (!entry) + return NULL; + if (entry[0] == EXFAT_ENTRY_EOD) + return NULL; + if (entry[0] == EXFAT_ENTRY_LABEL) + return (struct exfat_entry_label*) entry; + + offset += EXFAT_ENTRY_SIZE; + if (offset % CLUSTER_SIZE(sb) == 0) { + cluster = exfat_next_cluster(probe, sb, cluster); + if (cluster < EXFAT_FIRST_DATA_CLUSTER) + return NULL; + if (cluster > EXFAT_LAST_DATA_CLUSTER) + return NULL; + offset = exfat_cluster_to_offset(sb, cluster); + } + } + + return NULL; +} + +static int probe_exfat(struct blkid_probe *probe, struct blkid_magic *id, + unsigned char *buf) +{ + struct exfat_super_block *sb; + struct exfat_entry_label *label; + uuid_t uuid; + sb = (struct exfat_super_block *)buf; + if (!sb || !CLUSTER_SIZE(sb)) { + DBG(DEBUG_PROBE, printf("bad exfat superblock.\n")); + return errno ? - errno : 1; + } + + label = find_exfat_entry_label(probe, sb); + if (label) { + blkid_set_tag(probe->dev, "LABEL", label->name, label->length); + } else { + blkid_set_tag(probe->dev, "LABEL", "disk", 4); + } + + snprintf(uuid, sizeof (uuid), "%02hhX%02hhX-%02hhX%02hhX", + sb->volume_serial[3], sb->volume_serial[2], + sb->volume_serial[1], sb->volume_serial[0]); + + set_uuid(probe->dev, uuid, 0); + + return 0; +} + /* * Various filesystem magics that we can check for. Note that kboff and * sboff are in kilobytes and bytes respectively. All magics are in @@ -1512,6 +1604,7 @@ static struct blkid_magic type_array[] = { { "lvm2pv", 1, 0x218, 8, "LVM2 001", probe_lvm2 }, { "btrfs", 64, 0x40, 8, "_BHRfS_M", probe_btrfs }, { "f2fs", 1, 0, 4, "\x10\x20\xf5\xf2", probe_f2fs }, + { "exfat", 0, 3, 8, "EXFAT ", probe_exfat }, { NULL, 0, 0, 0, NULL, NULL } }; diff --git a/lib/blkid/probe.h b/lib/blkid/probe.h index 9d026952..c46a3325 100644 --- a/lib/blkid/probe.h +++ b/lib/blkid/probe.h @@ -14,6 +14,8 @@ #ifndef _BLKID_PROBE_H #define _BLKID_PROBE_H +#include <stdint.h> + #include <blkid/blkid_types.h> struct blkid_magic; @@ -763,6 +765,46 @@ struct f2fs_super_block { __u8 extension_list[F2FS_MAX_EXTENSION][8]; /* extension array */ } __attribute__((__packed__)); +struct exfat_super_block { + uint8_t jump[3]; + uint8_t oem_name[8]; + uint8_t __unused1[53]; + uint64_t block_start; + uint64_t block_count; + uint32_t fat_block_start; + uint32_t fat_block_count; + uint32_t cluster_block_start; + uint32_t cluster_count; + uint32_t rootdir_cluster; + uint8_t volume_serial[4]; + struct { + uint8_t vermin; + uint8_t vermaj; + } version; + uint16_t volume_state; + uint8_t block_bits; + uint8_t bpc_bits; + uint8_t fat_count; + uint8_t drive_no; + uint8_t allocated_percent; +} __attribute__((__packed__)); + +struct exfat_entry_label { + uint8_t type; + uint8_t length; + uint8_t name[30]; +} __attribute__((__packed__)); + +#define BLOCK_SIZE(sb) (1 << (sb)->block_bits) +#define CLUSTER_SIZE(sb) (BLOCK_SIZE(sb) << (sb)->bpc_bits) + +#define EXFAT_FIRST_DATA_CLUSTER 2 +#define EXFAT_LAST_DATA_CLUSTER 0xffffff6 +#define EXFAT_ENTRY_SIZE 32 + +#define EXFAT_ENTRY_EOD 0x00 +#define EXFAT_ENTRY_LABEL 0x83 + /* * Byte swap functions */ |