summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKay Sievers <kay@pim>2005-10-23 19:15:07 +0200
committerKay Sievers <kay@pim>2005-10-23 19:15:07 +0200
commit04b222b4b0369f3f0861f3911bacc928d18c0b00 (patch)
treee6d3c9638abaeaf52ebb73dcb600315525c3ad92
parent1305b47167388297b33b073989ae3b70a26ca71a (diff)
volume_id: make FAT32 recognition more robust
FAT32 volumes should never have a cluster count, that fits into a 16 bit value, but mkdosfs can create such volumes. No sane formatter or Windows will ever do this, but the Linux kernel as Windows can read/write it. Thanks to Ted Ts'o <tytso@mit.edu> for convincing me. Signed-off-by: Kay Sievers <kay.sievers@suse.de>
-rw-r--r--extras/volume_id/volume_id/fat.c31
1 files changed, 22 insertions, 9 deletions
diff --git a/extras/volume_id/volume_id/fat.c b/extras/volume_id/volume_id/fat.c
index d5f84ece4c..74f2bb9194 100644
--- a/extras/volume_id/volume_id/fat.c
+++ b/extras/volume_id/volume_id/fat.c
@@ -138,7 +138,8 @@ int volume_id_probe_vfat(struct volume_id *id, uint64_t off)
uint32_t root_cluster;
uint32_t dir_size;
uint32_t cluster_count;
- uint32_t fat_length;
+ uint16_t fat_length;
+ uint32_t fat32_length;
uint64_t root_start;
uint32_t start_data_sect;
uint16_t root_dir_entries;
@@ -222,11 +223,18 @@ valid:
dbg("sect_count 0x%x", sect_count);
fat_length = le16_to_cpu(vs->fat_length);
- if (fat_length == 0)
- fat_length = le32_to_cpu(vs->type.fat32.fat32_length);
dbg("fat_length 0x%x", fat_length);
+ fat32_length = le32_to_cpu(vs->type.fat32.fat32_length);
+ dbg("fat32_length 0x%x", fat32_length);
+
+ if (fat_length)
+ fat_size = fat_length * vs->fats;
+ else if (fat32_length)
+ fat_size = fat32_length * vs->fats;
+ else
+ return -1;
+ dbg("fat_size 0x%x", fat_size);
- fat_size = fat_length * vs->fats;
dir_size = ((dir_entries * sizeof(struct vfat_dir_entry)) +
(sector_size-1)) / sector_size;
dbg("dir_size 0x%x", dir_size);
@@ -235,14 +243,17 @@ valid:
cluster_count /= vs->sectors_per_cluster;
dbg("cluster_count 0x%x", cluster_count);
- if (cluster_count < FAT12_MAX) {
+ /* must be FAT32 */
+ if (!fat_length && fat32_length)
+ goto fat32;
+
+ /* cluster_count tells us the format */
+ if (cluster_count < FAT12_MAX)
strcpy(id->type_version, "FAT12");
- } else if (cluster_count < FAT16_MAX) {
+ else if (cluster_count < FAT16_MAX)
strcpy(id->type_version, "FAT16");
- } else {
- strcpy(id->type_version, "FAT32");
+ else
goto fat32;
- }
/* the label may be an attribute in the root directory */
root_start = (reserved + fat_size) * sector_size;
@@ -274,6 +285,8 @@ valid:
goto found;
fat32:
+ strcpy(id->type_version, "FAT32");
+
/* FAT32 root dir is a cluster chain like any other directory */
buf_size = vs->sectors_per_cluster * sector_size;
root_cluster = le32_to_cpu(vs->type.fat32.root_cluster);