diff options
author | Kay Sievers <kay@pim> | 2005-10-23 19:15:07 +0200 |
---|---|---|
committer | Kay Sievers <kay@pim> | 2005-10-23 19:15:07 +0200 |
commit | 04b222b4b0369f3f0861f3911bacc928d18c0b00 (patch) | |
tree | e6d3c9638abaeaf52ebb73dcb600315525c3ad92 /extras | |
parent | 1305b47167388297b33b073989ae3b70a26ca71a (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>
Diffstat (limited to 'extras')
-rw-r--r-- | extras/volume_id/volume_id/fat.c | 31 |
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); |