2
* Copyright (C) 2010 Andrew Nayenko <resver@gmail.com>
4
* This file may be redistributed under the terms of the
5
* GNU Lesser General Public License.
7
#include "superblocks.h"
9
struct exfat_super_block {
12
uint8_t __unused1[53];
15
uint32_t fat_block_start;
16
uint32_t fat_block_count;
17
uint32_t cluster_block_start;
18
uint32_t cluster_count;
19
uint32_t rootdir_cluster;
20
uint8_t volume_serial[4];
25
uint16_t volume_state;
30
uint8_t allocated_percent;
31
} __attribute__((__packed__));
33
struct exfat_entry_label {
37
} __attribute__((__packed__));
39
#define BLOCK_SIZE(sb) (1 << (sb)->block_bits)
40
#define CLUSTER_SIZE(sb) (BLOCK_SIZE(sb) << (sb)->bpc_bits)
41
#define EXFAT_FIRST_DATA_CLUSTER 2
42
#define EXFAT_LAST_DATA_CLUSTER 0xffffff6
43
#define EXFAT_ENTRY_SIZE 32
45
#define EXFAT_ENTRY_EOD 0x00
46
#define EXFAT_ENTRY_LABEL 0x83
48
static blkid_loff_t block_to_offset(const struct exfat_super_block *sb,
51
return (blkid_loff_t) block << sb->block_bits;
54
static blkid_loff_t cluster_to_block(const struct exfat_super_block *sb,
57
return le32_to_cpu(sb->cluster_block_start) +
58
((blkid_loff_t) (cluster - EXFAT_FIRST_DATA_CLUSTER)
62
static blkid_loff_t cluster_to_offset(const struct exfat_super_block *sb,
65
return block_to_offset(sb, cluster_to_block(sb, cluster));
68
static uint32_t next_cluster(blkid_probe pr,
69
const struct exfat_super_block *sb, uint32_t cluster)
72
blkid_loff_t fat_offset;
74
fat_offset = block_to_offset(sb, le32_to_cpu(sb->fat_block_start))
75
+ (blkid_loff_t) cluster * sizeof(cluster);
76
next = (uint32_t *) blkid_probe_get_buffer(pr, fat_offset,
80
return le32_to_cpu(*next);
83
static struct exfat_entry_label *find_label(blkid_probe pr,
84
const struct exfat_super_block *sb)
86
uint32_t cluster = le32_to_cpu(sb->rootdir_cluster);
87
blkid_loff_t offset = cluster_to_offset(sb, cluster);
91
entry = (uint8_t *) blkid_probe_get_buffer(pr, offset,
95
if (entry[0] == EXFAT_ENTRY_EOD)
97
if (entry[0] == EXFAT_ENTRY_LABEL)
98
return (struct exfat_entry_label *) entry;
99
offset += EXFAT_ENTRY_SIZE;
100
if (offset % CLUSTER_SIZE(sb) == 0) {
101
cluster = next_cluster(pr, sb, cluster);
102
if (cluster < EXFAT_FIRST_DATA_CLUSTER)
104
if (cluster > EXFAT_LAST_DATA_CLUSTER)
106
offset = cluster_to_offset(sb, cluster);
111
static int probe_exfat(blkid_probe pr, const struct blkid_idmag *mag)
113
struct exfat_super_block *sb;
114
struct exfat_entry_label *label;
116
sb = blkid_probe_get_sb(pr, mag, struct exfat_super_block);
120
label = find_label(pr, sb);
122
blkid_probe_set_utf8label(pr, label->name,
123
min(label->length * 2, 30), BLKID_ENC_UTF16LE);
125
blkid_probe_sprintf_uuid(pr, sb->volume_serial, 4,
126
"%02hhX%02hhX-%02hhX%02hhX",
127
sb->volume_serial[3], sb->volume_serial[2],
128
sb->volume_serial[1], sb->volume_serial[0]);
130
blkid_probe_sprintf_version(pr, "%hu.%hu",
131
sb->version.major, sb->version.minor);
136
const struct blkid_idinfo exfat_idinfo =
139
.usage = BLKID_USAGE_FILESYSTEM,
140
.probefunc = probe_exfat,
143
{ .magic = "EXFAT ", .len = 8, .sboff = 3 },