X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=extras%2Fvolume_id%2Flib%2Ffat.c;h=9a2e4784d8cee165ca97f5b5a0d65c99e4456d92;hb=ac77e95948edc199cdd690de38f08e4d1e615840;hp=74336b4e6d0df79ca773e382d04d4f4ba5d6e7d3;hpb=f7dd3a57a40282f1c3fb9ad90a30d58b31b64ff8;p=elogind.git diff --git a/extras/volume_id/lib/fat.c b/extras/volume_id/lib/fat.c index 74336b4e6..9a2e4784d 100644 --- a/extras/volume_id/lib/fat.c +++ b/extras/volume_id/lib/fat.c @@ -63,7 +63,7 @@ struct vfat_super_block { uint16_t flags; uint8_t version[2]; uint32_t root_cluster; - uint16_t insfo_sector; + uint16_t fsinfo_sector; uint16_t backup_boot; uint16_t reserved2[6]; uint8_t unknown[3]; @@ -76,6 +76,15 @@ struct vfat_super_block { } PACKED type; } PACKED; +struct fat32_fsinfo { + uint8_t signature1[4]; + uint32_t reserved1[120]; + uint8_t signature2[4]; + uint32_t free_clusters; + uint32_t next_cluster; + uint32_t reserved2[4]; +} PACKED; + struct vfat_dir_entry { uint8_t name[11]; uint8_t attr; @@ -124,10 +133,11 @@ static uint8_t *get_attr_volume_id(struct vfat_dir_entry *dir, unsigned int coun return NULL; } -int volume_id_probe_vfat(struct volume_id *id, uint64_t off) +int volume_id_probe_vfat(struct volume_id *id, uint64_t off, uint64_t size) { struct vfat_super_block *vs; struct vfat_dir_entry *dir; + struct fat32_fsinfo *fsinfo; uint16_t sector_size; uint16_t dir_entries; uint32_t sect_count; @@ -141,6 +151,7 @@ int volume_id_probe_vfat(struct volume_id *id, uint64_t off) uint64_t root_start; uint32_t start_data_sect; uint16_t root_dir_entries; + uint16_t fsinfo_sect; uint8_t *buf; uint32_t buf_size; uint8_t *label = NULL; @@ -149,16 +160,19 @@ int volume_id_probe_vfat(struct volume_id *id, uint64_t off) info("probing at offset 0x%llx", (unsigned long long) off); - vs = (struct vfat_super_block *) volume_id_get_buffer(id, off, 0x200); - if (vs == NULL) + buf = volume_id_get_buffer(id, off, 0x400); + if (buf == NULL) + return -1; + + /* check signature */ + if (buf[510] != 0x55 || buf[511] != 0xaa) return -1; - /* believe only that's fat, don't trust the version - * the cluster_count will tell us - */ + vs = (struct vfat_super_block *) buf; if (memcmp(vs->sysid, "NTFS", 4) == 0) return -1; + /* believe only that's fat, don't trust the version */ if (memcmp(vs->type.fat32.magic, "MSWIN", 5) == 0) goto magic; @@ -174,9 +188,7 @@ int volume_id_probe_vfat(struct volume_id *id, uint64_t off) if (memcmp(vs->type.fat.magic, "FAT12 ", 8) == 0) goto magic; - /* some old floppies don't have a magic, so we expect the boot code to match */ - - /* boot jump address check */ + /* some old floppies don't have a magic, expect the boot jump address to match */ if ((vs->boot_jump[0] != 0xeb || vs->boot_jump[2] != 0x90) && vs->boot_jump[0] != 0xe9) return -1; @@ -280,6 +292,21 @@ magic: goto found; fat32: + /* FAT32 should have a valid signature in the fsinfo block */ + fsinfo_sect = le16_to_cpu(vs->type.fat32.fsinfo_sector); + buf = volume_id_get_buffer(id, off + (fsinfo_sect * sector_size), 0x200); + if (buf == NULL) + return -1; + fsinfo = (struct fat32_fsinfo *) buf; + if (memcmp(fsinfo->signature1, "\x52\x52\x61\x41", 4) != 0) + return -1; + if (memcmp(fsinfo->signature2, "\x72\x72\x41\x61", 4) != 0) + return -1 ; + + vs = (struct vfat_super_block *) volume_id_get_buffer(id, off, 0x200); + if (vs == NULL) + return -1; + strcpy(id->type_version, "FAT32"); /* FAT32 root dir is a cluster chain like any other directory */ @@ -322,7 +349,7 @@ fat32: /* set next cluster */ next = le32_to_cpu(*((uint32_t *) buf)) & 0x0fffffff; - if (next == 0) + if (next < 2 || next >= 0x0ffffff0) break; } if (maxloop == 0)