From 8604c25570baaaf814b95199fd0592147d8616c1 Mon Sep 17 00:00:00 2001 From: Andrew Nayenko Date: Fri, 28 May 2010 23:22:00 +0400 Subject: [PATCH] libblkid: add exFAT file system detection support Add exFAT file system detection support. Signed-off-by: Andrew Nayenko --- shlibs/blkid/src/superblocks/Makefile.am | 3 +- shlibs/blkid/src/superblocks/exfat.c | 146 +++++++++++++++++++++ shlibs/blkid/src/superblocks/superblocks.c | 3 +- shlibs/blkid/src/superblocks/superblocks.h | 1 + tests/expected/blkid/low-probe-exfat | 7 + tests/ts/blkid/images-fs/exfat.img.bz2 | Bin 0 -> 6301 bytes 6 files changed, 158 insertions(+), 2 deletions(-) create mode 100644 shlibs/blkid/src/superblocks/exfat.c create mode 100644 tests/expected/blkid/low-probe-exfat create mode 100644 tests/ts/blkid/images-fs/exfat.img.bz2 diff --git a/shlibs/blkid/src/superblocks/Makefile.am b/shlibs/blkid/src/superblocks/Makefile.am index f5b88b8e..39b074ba 100644 --- a/shlibs/blkid/src/superblocks/Makefile.am +++ b/shlibs/blkid/src/superblocks/Makefile.am @@ -46,4 +46,5 @@ libblkid_superblocks_la_SOURCES = \ bfs.c \ drbd.c \ vmfs.c \ - befs.c + befs.c \ + exfat.c diff --git a/shlibs/blkid/src/superblocks/exfat.c b/shlibs/blkid/src/superblocks/exfat.c new file mode 100644 index 00000000..bada3a83 --- /dev/null +++ b/shlibs/blkid/src/superblocks/exfat.c @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2010 Andrew Nayenko + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include "superblocks.h" + +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 minor; + uint8_t major; + } 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 + +static blkid_loff_t block_to_offset(const struct exfat_super_block *sb, + blkid_loff_t block) +{ + return (blkid_loff_t) block << sb->block_bits; +} + +static blkid_loff_t cluster_to_block(const struct exfat_super_block *sb, + uint32_t cluster) +{ + return le32_to_cpu(sb->cluster_block_start) + + ((blkid_loff_t) (cluster - EXFAT_FIRST_DATA_CLUSTER) + << sb->bpc_bits); +} + +static blkid_loff_t cluster_to_offset(const struct exfat_super_block *sb, + uint32_t cluster) +{ + return block_to_offset(sb, cluster_to_block(sb, cluster)); +} + +static uint32_t next_cluster(blkid_probe pr, + const struct exfat_super_block *sb, uint32_t cluster) +{ + uint32_t *next; + blkid_loff_t fat_offset; + + fat_offset = block_to_offset(sb, le32_to_cpu(sb->fat_block_start)) + + (blkid_loff_t) cluster * sizeof(cluster); + next = (uint32_t *) blkid_probe_get_buffer(pr, fat_offset, + sizeof(uint32_t)); + if (!next) + return 0; + return le32_to_cpu(*next); +} + +static struct exfat_entry_label *find_label(blkid_probe pr, + const struct exfat_super_block *sb) +{ + uint32_t cluster = le32_to_cpu(sb->rootdir_cluster); + blkid_loff_t offset = cluster_to_offset(sb, cluster); + uint8_t *entry; + + for (;;) { + entry = (uint8_t *) blkid_probe_get_buffer(pr, 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 = next_cluster(pr, sb, cluster); + if (cluster < EXFAT_FIRST_DATA_CLUSTER) + return NULL; + if (cluster > EXFAT_LAST_DATA_CLUSTER) + return NULL; + offset = cluster_to_offset(sb, cluster); + } + } +} + +static int probe_exfat(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct exfat_super_block *sb; + struct exfat_entry_label *label; + + sb = blkid_probe_get_sb(pr, mag, struct exfat_super_block); + if (!sb) + return -1; + + label = find_label(pr, sb); + if (label) + blkid_probe_set_utf8label(pr, label->name, + min(label->length * 2, 30), BLKID_ENC_UTF16LE); + + blkid_probe_sprintf_uuid(pr, sb->volume_serial, 4, + "%02hhX%02hhX-%02hhX%02hhX", + sb->volume_serial[3], sb->volume_serial[2], + sb->volume_serial[1], sb->volume_serial[0]); + + blkid_probe_sprintf_version(pr, "%hu.%hu", + sb->version.major, sb->version.minor); + + return 0; +} + +const struct blkid_idinfo exfat_idinfo = +{ + .name = "exfat", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_exfat, + .magics = + { + { .magic = "EXFAT ", .len = 8, .sboff = 3 }, + { NULL } + } +}; diff --git a/shlibs/blkid/src/superblocks/superblocks.c b/shlibs/blkid/src/superblocks/superblocks.c index caa169fa..b80c10b7 100644 --- a/shlibs/blkid/src/superblocks/superblocks.c +++ b/shlibs/blkid/src/superblocks/superblocks.c @@ -139,7 +139,8 @@ static const struct blkid_idinfo *idinfos[] = &ubifs_idinfo, &bfs_idinfo, &vmfs_fs_idinfo, - &befs_idinfo + &befs_idinfo, + &exfat_idinfo }; /* diff --git a/shlibs/blkid/src/superblocks/superblocks.h b/shlibs/blkid/src/superblocks/superblocks.h index b1fa49d5..74cb9743 100644 --- a/shlibs/blkid/src/superblocks/superblocks.h +++ b/shlibs/blkid/src/superblocks/superblocks.h @@ -65,6 +65,7 @@ extern const struct blkid_idinfo vmfs_volume_idinfo; extern const struct blkid_idinfo vmfs_fs_idinfo; extern const struct blkid_idinfo drbd_idinfo; extern const struct blkid_idinfo befs_idinfo; +extern const struct blkid_idinfo exfat_idinfo; /* * superblock functions diff --git a/tests/expected/blkid/low-probe-exfat b/tests/expected/blkid/low-probe-exfat new file mode 100644 index 00000000..b9defbdf --- /dev/null +++ b/tests/expected/blkid/low-probe-exfat @@ -0,0 +1,7 @@ +ID_FS_LABEL=Новый_том +ID_FS_LABEL_ENC=Новый\x20том +ID_FS_TYPE=exfat +ID_FS_USAGE=filesystem +ID_FS_UUID=9C23-8877 +ID_FS_UUID_ENC=9C23-8877 +ID_FS_VERSION=1.0 diff --git a/tests/ts/blkid/images-fs/exfat.img.bz2 b/tests/ts/blkid/images-fs/exfat.img.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..f96c3f06e6363bc464906c6d0a2585c76b2d6425 GIT binary patch literal 6301 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