/* * This function is used by MBR partition table parser to avoid * misinterpretation of FAT filesystem. */ int blkid_probe_is_vfat(blkid_probe pr) { struct vfat_super_block *vs; struct msdos_super_block *ms; const struct blkid_idmag *mag = NULL; if (blkid_probe_get_idmag(pr, &vfat_idinfo, NULL, &mag) || !mag) return 0; ms = blkid_probe_get_sb(pr, mag, struct msdos_super_block); if (!ms) return 0; vs = blkid_probe_get_sb(pr, mag, struct vfat_super_block); if (!vs) return 0; return fat_valid_superblock(mag, ms, vs, NULL, NULL); }
/* * This function is used by MBR partition table parser to avoid * misinterpretation of FAT filesystem. */ int blkid_probe_is_vfat(blkid_probe pr) { struct vfat_super_block *vs; struct msdos_super_block *ms; const struct blkid_idmag *mag = NULL; int rc; rc = blkid_probe_get_idmag(pr, &vfat_idinfo, NULL, &mag); if (rc < 0) return rc; /* error */ if (rc != BLKID_PROBE_OK || !mag) return 0; ms = blkid_probe_get_sb(pr, mag, struct msdos_super_block); if (!ms) return errno ? -errno : 0; vs = blkid_probe_get_sb(pr, mag, struct vfat_super_block); if (!vs) return errno ? -errno : 0; return fat_valid_superblock(pr, mag, ms, vs, NULL, NULL); }
/* FAT label extraction from the root directory taken from Kay * Sievers's volume_id library */ static int probe_vfat(blkid_probe pr, const struct blkid_idmag *mag) { struct vfat_super_block *vs; struct msdos_super_block *ms; const unsigned char *vol_label = 0; unsigned char *vol_serno = NULL, vol_label_buf[11]; uint16_t sector_size = 0, reserved; uint32_t cluster_count, fat_size; const char *version = NULL; ms = blkid_probe_get_sb(pr, mag, struct msdos_super_block); if (!ms) return errno ? -errno : 1; vs = blkid_probe_get_sb(pr, mag, struct vfat_super_block); if (!vs) return errno ? -errno : 1; if (!fat_valid_superblock(pr, mag, ms, vs, &cluster_count, &fat_size)) return 1; sector_size = unaligned_le16(&ms->ms_sector_size); reserved = le16_to_cpu(ms->ms_reserved); if (ms->ms_fat_length) { /* the label may be an attribute in the root directory */ uint32_t root_start = (reserved + fat_size) * sector_size; uint32_t root_dir_entries = unaligned_le16(&vs->vs_dir_entries); vol_label = search_fat_label(pr, root_start, root_dir_entries); if (vol_label) { memcpy(vol_label_buf, vol_label, 11); vol_label = vol_label_buf; } if (!vol_label || !memcmp(vol_label, no_name, 11)) vol_label = ms->ms_label; vol_serno = ms->ms_serno; blkid_probe_set_value(pr, "SEC_TYPE", (unsigned char *) "msdos", sizeof("msdos")); if (cluster_count < FAT12_MAX) version = "FAT12"; else if (cluster_count < FAT16_MAX) version = "FAT16"; } else if (vs->vs_fat32_length) { unsigned char *buf; uint16_t fsinfo_sect; int maxloop = 100; /* Search the FAT32 root dir for the label attribute */ uint32_t buf_size = vs->vs_cluster_size * sector_size; uint32_t start_data_sect = reserved + fat_size; uint32_t entries = le32_to_cpu(vs->vs_fat32_length) * sector_size / sizeof(uint32_t); uint32_t next = le32_to_cpu(vs->vs_root_cluster); while (next && next < entries && --maxloop) { uint32_t next_sect_off; uint64_t next_off, fat_entry_off; int count; next_sect_off = (next - 2) * vs->vs_cluster_size; next_off = (uint64_t)(start_data_sect + next_sect_off) * sector_size; count = buf_size / sizeof(struct vfat_dir_entry); vol_label = search_fat_label(pr, next_off, count); if (vol_label) { memcpy(vol_label_buf, vol_label, 11); vol_label = vol_label_buf; break; } /* get FAT entry */ fat_entry_off = ((uint64_t) reserved * sector_size) + (next * sizeof(uint32_t)); buf = blkid_probe_get_buffer(pr, fat_entry_off, buf_size); if (buf == NULL) break; /* set next cluster */ next = le32_to_cpu(*((uint32_t *) buf)) & 0x0fffffff; } version = "FAT32"; if (!vol_label || !memcmp(vol_label, no_name, 11)) vol_label = vs->vs_label; vol_serno = vs->vs_serno; /* * FAT32 should have a valid signature in the fsinfo block, * but also allow all bytes set to '\0', because some volumes * do not set the signature at all. */ fsinfo_sect = le16_to_cpu(vs->vs_fsinfo_sector); if (fsinfo_sect) { struct fat32_fsinfo *fsinfo; buf = blkid_probe_get_buffer(pr, (blkid_loff_t) fsinfo_sect * sector_size, sizeof(struct fat32_fsinfo)); if (buf == NULL) return errno ? -errno : 1; fsinfo = (struct fat32_fsinfo *) buf; if (memcmp(fsinfo->signature1, "\x52\x52\x61\x41", 4) != 0 && memcmp(fsinfo->signature1, "\x52\x52\x64\x41", 4) != 0 && memcmp(fsinfo->signature1, "\x00\x00\x00\x00", 4) != 0) return 1; if (memcmp(fsinfo->signature2, "\x72\x72\x41\x61", 4) != 0 && memcmp(fsinfo->signature2, "\x00\x00\x00\x00", 4) != 0) return 1; } } if (vol_label && memcmp(vol_label, no_name, 11)) blkid_probe_set_label(pr, (unsigned char *) vol_label, 11); /* We can't just print them as %04X, because they are unaligned */ if (vol_serno) blkid_probe_sprintf_uuid(pr, vol_serno, 4, "%02X%02X-%02X%02X", vol_serno[3], vol_serno[2], vol_serno[1], vol_serno[0]); if (version) blkid_probe_set_version(pr, version); return 0; }