Whamcloud - gitweb
Improve VFAT detection to support filesystems w/o a magic string in the superblock
authorKarel Zak <kzak@redhat.com>
Tue, 6 Sep 2005 12:13:35 +0000 (08:13 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Tue, 6 Sep 2005 12:13:35 +0000 (08:13 -0400)
The current libblkid code expects that there's magic string in FAT super
block (like "FAT12", "FAT16", ...). It's very often right, but valid FAT
super block may be without magic string too :-(

The patch from attachment fix this problem. It's inspired by HAL and
Linux kernel.

Signed-off-by: Karel Zak <kzak@redhat.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
lib/blkid/ChangeLog
lib/blkid/probe.c
lib/blkid/probe.h

index e60ce6a..8f1aab7 100644 (file)
@@ -1,5 +1,9 @@
 2005-09-05  Karel Zak <kzak@redhat.com>
 
+       * probe.c (probe_vfat_nomagic): Add support for detecting VFAT
+               filesystems even when the magic string isn't in the FAT
+               super block.
+
        * probe.c: Add support for detecting software suspend partitions
 
        * probe.c (probe_ext2): Check to see if a journal has been added
index fd076ca..f503894 100644 (file)
@@ -229,6 +229,84 @@ static int probe_msdos(int fd __BLKID_ATTR((unused)),
        return 0;
 }
 
+/*
+ * The FAT filesystem could be without a magic string in superblock
+ * (e.g. old floppies).  This heuristic for FAT detection is inspired
+ * by http://vrfy.org/projects/volume_id/ and Linux kernel.
+ * [7-Jul-2005, Karel Zak <kzak@redhat.com>]
+ */
+static int probe_vfat_nomagic(int fd __BLKID_ATTR((unused)), 
+                     blkid_cache cache __BLKID_ATTR((unused)), 
+                     blkid_dev dev,
+                     struct blkid_magic *id __BLKID_ATTR((unused)), 
+                     unsigned char *buf)
+{
+       struct vfat_super_block *vs;
+       __u16 sector_size;
+       __u16 dir_entries;
+       __u32 sect_count;
+       __u16 reserved;
+       __u32 fat_size;
+       __u32 dir_size;
+       __u32 cluster_count;
+       __u32 fat_length;
+
+       vs = (struct vfat_super_block *)buf;
+
+       /* boot jump address check */
+       if ((vs->vs_ignored[0] != 0xeb || vs->vs_ignored[2] != 0x90) &&
+            vs->vs_ignored[0] != 0xe9)
+               return 1;
+
+       /* heads check */
+       if (vs->vs_heads == 0)
+               return 1;
+
+       /* cluster size check*/ 
+       if (vs->vs_cluster_size == 0 ||
+           (vs->vs_cluster_size & (vs->vs_cluster_size-1)))
+               return 1;
+
+       /* media check */
+       if (vs->vs_media < 0xf8 && vs->vs_media != 0xf0)
+               return 1;
+
+       /* fat counts(Linux kernel expects at least 1 FAT table) */
+       if (!vs->vs_fats)
+               return 1;
+
+       /* sector size check */
+       sector_size = blkid_le16(*((__u16 *) &vs->vs_sector_size));
+       if (sector_size != 0x200 && sector_size != 0x400 &&
+           sector_size != 0x800 && sector_size != 0x1000)
+               return 1;
+
+       dir_entries = blkid_le16(*((__u16 *) &vs->vs_dir_entries));
+       reserved =  blkid_le16(vs->vs_reserved);
+       sect_count = blkid_le16(*((__u16 *) &vs->vs_sectors));
+       if (sect_count == 0)
+               sect_count = blkid_le32(vs->vs_total_sect);
+
+       fat_length = blkid_le16(vs->vs_fat_length);
+       if (fat_length == 0)
+               fat_length = blkid_le32(vs->vs_fat32_length);
+
+       fat_size = fat_length * vs->vs_fats;
+       dir_size = ((dir_entries * sizeof(struct vfat_dir_entry)) +
+                       (sector_size-1)) / sector_size;
+
+       cluster_count = sect_count - (reserved + fat_size + dir_size);
+       cluster_count /= vs->vs_cluster_size;
+
+       if (cluster_count <= FAT12_MAX || cluster_count <= FAT16_MAX)
+               return probe_msdos(fd, cache, dev, id, buf);
+
+       else if (cluster_count <= FAT32_MAX)
+               return probe_vfat(fd, cache, dev, id, buf);
+       
+       return 1;       /* FAT detection failed */
+}
+
 static int probe_xfs(int fd __BLKID_ATTR((unused)), 
                     blkid_cache cache __BLKID_ATTR((unused)), 
                     blkid_dev dev,
@@ -503,6 +581,8 @@ static struct blkid_magic type_array[] = {
   { "vfat",      0,   0x36,  5, "MSDOS",                probe_msdos },
   { "vfat",      0,   0x36,  8, "FAT16   ",             probe_msdos },
   { "vfat",      0,   0x36,  8, "FAT12   ",             probe_msdos },
+  { "vfat",      0,      0,  1, "\353",                 probe_vfat_nomagic },
+  { "vfat",      0,      0,  1, "\351",                 probe_vfat_nomagic },
   { "minix",     1,   0x10,  2, "\177\023",             0 },
   { "minix",     1,   0x10,  2, "\217\023",             0 },
   { "minix",    1,   0x10,  2, "\150\044",             0 },
index ab175ea..efb9968 100644 (file)
@@ -189,6 +189,25 @@ struct msdos_super_block {
 /*1fe*/        unsigned char   ms_pmagic[2];
 };
 
+struct vfat_dir_entry {
+       __u8    name[11];
+       __u8    attr;
+       __u16   time_creat;
+       __u16   date_creat;
+       __u16   time_acc;
+       __u16   date_acc;
+       __u16   cluster_high;
+       __u16   time_write;
+       __u16   date_write;
+       __u16   cluster_low;
+       __u32   size;
+};
+
+/* maximum number of clusters */
+#define FAT12_MAX 0xFF4
+#define FAT16_MAX 0xFFF4
+#define FAT32_MAX 0x0FFFFFF6
+
 struct minix_super_block {
        __u16           ms_ninodes;
        __u16           ms_nzones;