1/* 2 * volume_id - reads filesystem label and uuid 3 * 4 * Copyright (C) 2004-2007 Kay Sievers <kay.sievers@vrfy.org> 5 * Copyright (C) 2007 Ryan Lortie <desrt@desrt.ca> 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License as published by the 9 * Free Software Foundation version 2 of the License. 10 */ 11 12#ifndef _GNU_SOURCE 13#define _GNU_SOURCE 1 14#endif 15 16#ifdef HAVE_CONFIG_H 17# include <config.h> 18#endif 19 20#include <stdio.h> 21#include <stdlib.h> 22#include <unistd.h> 23#include <string.h> 24#include <errno.h> 25#include <ctype.h> 26 27#include "libvolume_id.h" 28#include "util.h" 29 30#define FAT12_MAX 0xff5 31#define FAT16_MAX 0xfff5 32#define FAT_ATTR_VOLUME_ID 0x08 33#define FAT_ATTR_DIR 0x10 34#define FAT_ATTR_LONG_NAME 0x0f 35#define FAT_ATTR_MASK 0x3f 36#define FAT_ENTRY_FREE 0xe5 37 38#define VFAT_LFN_SEQ_MASK 0x3f 39#define VFAT_LFN_SEQ_LAST 0x40 40#define VFAT_LFN_SEQ_MAX 20 41#define VFAT_LFN_CHARS_PER_ENTRY (5 + 6 + 2) 42#define VFAT_LOWERCASE_NAME 0x10 43#define VFAT_LOWERCASE_EXT 0x08 44 45struct vfat_super_block { 46 uint8_t boot_jump[3]; 47 uint8_t sysid[8]; 48 uint16_t sector_size; 49 uint8_t sectors_per_cluster; 50 uint16_t reserved; 51 uint8_t fats; 52 uint16_t dir_entries; 53 uint16_t sectors; 54 uint8_t media; 55 uint16_t fat_length; 56 uint16_t secs_track; 57 uint16_t heads; 58 uint32_t hidden; 59 uint32_t total_sect; 60 union { 61 struct fat_super_block { 62 uint8_t unknown[3]; 63 uint8_t serno[4]; 64 uint8_t label[11]; 65 uint8_t magic[8]; 66 uint8_t dummy2[192]; 67 uint8_t pmagic[2]; 68 } PACKED fat; 69 struct fat32_super_block { 70 uint32_t fat32_length; 71 uint16_t flags; 72 uint8_t version[2]; 73 uint32_t root_cluster; 74 uint16_t fsinfo_sector; 75 uint16_t backup_boot; 76 uint16_t reserved2[6]; 77 uint8_t unknown[3]; 78 uint8_t serno[4]; 79 uint8_t label[11]; 80 uint8_t magic[8]; 81 uint8_t dummy2[164]; 82 uint8_t pmagic[2]; 83 } PACKED fat32; 84 } PACKED type; 85} PACKED; 86 87struct fat32_fsinfo { 88 uint8_t signature1[4]; 89 uint32_t reserved1[120]; 90 uint8_t signature2[4]; 91 uint32_t free_clusters; 92 uint32_t next_cluster; 93 uint32_t reserved2[4]; 94} PACKED; 95 96struct vfat_dir_entry { 97 uint8_t name[11]; 98 uint8_t attr; 99 uint8_t lowercase; 100 uint8_t fine_time_creat; 101 uint16_t time_creat; 102 uint16_t date_creat; 103 uint16_t date_acc; 104 uint16_t cluster_high; 105 uint16_t time_write; 106 uint16_t date_write; 107 uint16_t cluster_low; 108 uint32_t size; 109} PACKED; 110 111 112struct vfat_lfn_entry { 113 uint8_t seq; 114 uint16_t name0[5]; 115 uint8_t attr; 116 uint8_t reserved; 117 uint8_t cksum; 118 uint16_t name1[6]; 119 uint16_t cluster; 120 uint16_t name2[2]; 121} PACKED; 122 123static uint8_t fat_lfn_checksum(const uint8_t name[11]) 124{ 125 uint8_t cksum = 0; 126 int i; 127 128 /* http://en.wikipedia.org/wiki/File_Allocation_Table */ 129 for (i = 0; i < 11; i++) 130 cksum = ((cksum & 1) ? 0x80 : 0) + (cksum >> 1) + name[i]; 131 132 return cksum; 133} 134 135static size_t fat_read_lfn(uint8_t *filename, size_t fnsize, 136 struct vfat_dir_entry *dir, 137 struct vfat_dir_entry *entry) 138{ 139 uint8_t buffer[VFAT_LFN_SEQ_MAX * VFAT_LFN_CHARS_PER_ENTRY * 2]; 140 uint8_t expected_seq = 1; 141 uint8_t cksum; 142 size_t len = 0; 143 size_t fnlen = 0; 144 145 cksum = fat_lfn_checksum(entry->name); 146 147 while (--entry >= dir) { 148 struct vfat_lfn_entry *lfn = (struct vfat_lfn_entry *) entry; 149 150 if (expected_seq > VFAT_LFN_SEQ_MAX) 151 break; 152 153 if ((lfn->attr & FAT_ATTR_MASK) != FAT_ATTR_LONG_NAME) 154 break; 155 156 if (lfn->cksum != cksum) 157 break; 158 159 if ((lfn->seq & VFAT_LFN_SEQ_MASK) != expected_seq++) 160 break; 161 162 if (lfn->cluster != 0) 163 break; 164 165 /* extra paranoia -- should never happen */ 166 if (len + sizeof(lfn->name0) + sizeof(lfn->name1) + 167 sizeof(lfn->name2) > sizeof(buffer)) 168 break; 169 170 memcpy (&buffer[len], lfn->name0, sizeof(lfn->name0)); 171 len += sizeof(lfn->name0); 172 memcpy (&buffer[len], lfn->name1, sizeof(lfn->name1)); 173 len += sizeof(lfn->name1); 174 memcpy (&buffer[len], lfn->name2, sizeof(lfn->name2)); 175 len += sizeof(lfn->name2); 176 177 if (lfn->seq & VFAT_LFN_SEQ_LAST) { 178 fnlen = volume_id_set_unicode16(filename, fnsize, buffer, LE, len); 179 break; 180 } 181 } 182 183 return fnlen; 184} 185 186static size_t fat_read_filename(uint8_t *filename, size_t fnsize, 187 struct vfat_dir_entry *dir, struct vfat_dir_entry *entry) 188{ 189 size_t len; 190 int i; 191 192 /* check if maybe we have LFN entries */ 193 len = fat_read_lfn(filename, fnsize, dir, entry); 194 if (len > 0) 195 goto out; 196 197 /* else, read the normal 8.3 name */ 198 for (i = 0; i < 11; i++) { 199 if (entry->lowercase & ((i < 8) ? VFAT_LOWERCASE_NAME : VFAT_LOWERCASE_EXT)) 200 filename[i] = tolower(entry->name[i]); 201 else 202 filename[i] = entry->name[i]; 203 } 204 len = 11; 205 206out: 207 filename[len] = '\0'; 208 return len; 209} 210 211/* fills filename, returns string length */ 212static size_t get_fat_attr_volume_id(uint8_t *filename, size_t fnsize, 213 struct vfat_dir_entry *dir, unsigned int count) 214{ 215 unsigned int i; 216 217 for (i = 0; i < count; i++) { 218 /* end marker */ 219 if (dir[i].name[0] == 0x00) { 220 dbg("end of dir"); 221 break; 222 } 223 224 /* empty entry */ 225 if (dir[i].name[0] == FAT_ENTRY_FREE) 226 continue; 227 228 /* long name */ 229 if ((dir[i].attr & FAT_ATTR_MASK) == FAT_ATTR_LONG_NAME) 230 continue; 231 232 if ((dir[i].attr & (FAT_ATTR_VOLUME_ID | FAT_ATTR_DIR)) == FAT_ATTR_VOLUME_ID) { 233 /* labels do not have file data */ 234 if (dir[i].cluster_high != 0 || dir[i].cluster_low != 0) 235 continue; 236 237 dbg("found ATTR_VOLUME_ID id in root dir"); 238 return fat_read_filename(filename, fnsize, dir, &dir[i]); 239 } 240 241 dbg("skip dir entry"); 242 } 243 244 return 0; 245} 246 247int volume_id_probe_vfat(struct volume_id *id, uint64_t off, uint64_t size) 248{ 249 uint8_t filename[255 * 3]; 250 struct vfat_super_block *vs; 251 struct vfat_dir_entry *dir; 252 struct fat32_fsinfo *fsinfo; 253 uint16_t sector_size; 254 uint16_t dir_entries; 255 uint32_t sect_count; 256 uint16_t reserved; 257 uint32_t fat_size; 258 uint32_t root_cluster; 259 uint32_t dir_size; 260 uint32_t cluster_count; 261 uint16_t fat_length; 262 uint32_t fat32_length; 263 uint64_t root_start; 264 uint32_t start_data_sect; 265 uint16_t root_dir_entries; 266 uint16_t fsinfo_sect; 267 uint8_t *buf; 268 uint32_t buf_size; 269 uint32_t next; 270 int maxloop; 271 size_t fnlen; 272 273 info("probing at offset 0x%llx", (unsigned long long) off); 274 275 buf = volume_id_get_buffer(id, off, 0x400); 276 if (buf == NULL) 277 return -1; 278 279 /* check signature */ 280 if (buf[510] != 0x55 || buf[511] != 0xaa) 281 return -1; 282 283 vs = (struct vfat_super_block *) buf; 284 if (memcmp(vs->sysid, "NTFS", 4) == 0) 285 return -1; 286 287 /* believe only that's fat, don't trust the version */ 288 if (memcmp(vs->type.fat32.magic, "MSWIN", 5) == 0) 289 goto magic; 290 291 if (memcmp(vs->type.fat32.magic, "FAT32 ", 8) == 0) 292 goto magic; 293 294 if (memcmp(vs->type.fat.magic, "FAT16 ", 8) == 0) 295 goto magic; 296 297 if (memcmp(vs->type.fat.magic, "MSDOS", 5) == 0) 298 goto magic; 299 300 if (memcmp(vs->type.fat.magic, "FAT12 ", 8) == 0) 301 goto magic; 302 303 /* some old floppies don't have a magic, expect the boot jump address to match */ 304 if ((vs->boot_jump[0] != 0xeb || vs->boot_jump[2] != 0x90) && 305 vs->boot_jump[0] != 0xe9) 306 return -1; 307 308magic: 309 /* reserverd sector count */ 310 if (!vs->reserved) 311 return -1; 312 313 /* fat count*/ 314 if (!vs->fats) 315 return -1; 316 317 /* media check */ 318 if (vs->media < 0xf8 && vs->media != 0xf0) 319 return -1; 320 321 /* cluster size check*/ 322 if (vs->sectors_per_cluster == 0 || 323 (vs->sectors_per_cluster & (vs->sectors_per_cluster-1))) 324 return -1; 325 326 /* sector size check */ 327 sector_size = le16_to_cpu(vs->sector_size); 328 if (sector_size != 0x200 && sector_size != 0x400 && 329 sector_size != 0x800 && sector_size != 0x1000) 330 return -1; 331 332 dbg("sector_size 0x%x", sector_size); 333 dbg("sectors_per_cluster 0x%x", vs->sectors_per_cluster); 334 335 dir_entries = le16_to_cpu(vs->dir_entries); 336 reserved = le16_to_cpu(vs->reserved); 337 dbg("reserved 0x%x", reserved); 338 339 sect_count = le16_to_cpu(vs->sectors); 340 if (sect_count == 0) 341 sect_count = le32_to_cpu(vs->total_sect); 342 dbg("sect_count 0x%x", sect_count); 343 344 fat_length = le16_to_cpu(vs->fat_length); 345 dbg("fat_length 0x%x", fat_length); 346 fat32_length = le32_to_cpu(vs->type.fat32.fat32_length); 347 dbg("fat32_length 0x%x", fat32_length); 348 349 if (fat_length) 350 fat_size = fat_length * vs->fats; 351 else if (fat32_length) 352 fat_size = fat32_length * vs->fats; 353 else 354 return -1; 355 dbg("fat_size 0x%x", fat_size); 356 357 dir_size = ((dir_entries * sizeof(struct vfat_dir_entry)) + 358 (sector_size-1)) / sector_size; 359 dbg("dir_size 0x%x", dir_size); 360 361 cluster_count = sect_count - (reserved + fat_size + dir_size); 362 cluster_count /= vs->sectors_per_cluster; 363 dbg("cluster_count 0x%x", cluster_count); 364 365 /* must be FAT32 */ 366 if (!fat_length && fat32_length) 367 goto fat32; 368 369 /* cluster_count tells us the format */ 370 if (cluster_count < FAT12_MAX) 371 strcpy(id->type_version, "FAT12"); 372 else if (cluster_count < FAT16_MAX) 373 strcpy(id->type_version, "FAT16"); 374 else 375 goto fat32; 376 377 /* the label may be an attribute in the root directory */ 378 root_start = (reserved + fat_size) * sector_size; 379 dbg("root dir start 0x%llx", (unsigned long long) root_start); 380 root_dir_entries = le16_to_cpu(vs->dir_entries); 381 dbg("expected entries 0x%x", root_dir_entries); 382 383 buf_size = root_dir_entries * sizeof(struct vfat_dir_entry); 384 buf = volume_id_get_buffer(id, off + root_start, buf_size); 385 if (buf == NULL) 386 goto found; 387 388 dir = (struct vfat_dir_entry*) buf; 389 390 fnlen = get_fat_attr_volume_id(filename, sizeof(filename), dir, root_dir_entries); 391 392 vs = (struct vfat_super_block *) volume_id_get_buffer(id, off, 0x200); 393 if (vs == NULL) 394 return -1; 395 396 if (fnlen > 0 && memcmp(filename, "NO NAME ", 11) != 0) { 397 volume_id_set_label_raw(id, filename, fnlen); 398 volume_id_set_label_string(id, filename, fnlen); 399 } else if (memcmp(vs->type.fat.label, "NO NAME ", 11) != 0) { 400 volume_id_set_label_raw(id, vs->type.fat.label, 11); 401 volume_id_set_label_string(id, vs->type.fat.label, 11); 402 } 403 volume_id_set_uuid(id, vs->type.fat.serno, 0, UUID_DOS); 404 goto found; 405 406fat32: 407 /* FAT32 should have a valid signature in the fsinfo block */ 408 fsinfo_sect = le16_to_cpu(vs->type.fat32.fsinfo_sector); 409 buf = volume_id_get_buffer(id, off + (fsinfo_sect * sector_size), 0x200); 410 if (buf == NULL) 411 return -1; 412 fsinfo = (struct fat32_fsinfo *) buf; 413 if (memcmp(fsinfo->signature1, "\x52\x52\x61\x41", 4) != 0) 414 return -1; 415 if (memcmp(fsinfo->signature2, "\x72\x72\x41\x61", 4) != 0) 416 return -1 ; 417 418 vs = (struct vfat_super_block *) volume_id_get_buffer(id, off, 0x200); 419 if (vs == NULL) 420 return -1; 421 422 strcpy(id->type_version, "FAT32"); 423 424 /* FAT32 root dir is a cluster chain like any other directory */ 425 buf_size = vs->sectors_per_cluster * sector_size; 426 root_cluster = le32_to_cpu(vs->type.fat32.root_cluster); 427 dbg("root dir cluster %u", root_cluster); 428 start_data_sect = reserved + fat_size; 429 430 next = root_cluster; 431 maxloop = 100; 432 while (--maxloop) { 433 uint32_t next_sect_off; 434 uint64_t next_off; 435 uint64_t fat_entry_off; 436 int count; 437 438 dbg("next cluster %u", next); 439 next_sect_off = (next - 2) * vs->sectors_per_cluster; 440 next_off = (start_data_sect + next_sect_off) * sector_size; 441 dbg("cluster offset 0x%llx", (unsigned long long) next_off); 442 443 /* get cluster */ 444 buf = volume_id_get_buffer(id, off + next_off, buf_size); 445 if (buf == NULL) 446 goto found; 447 448 dir = (struct vfat_dir_entry*) buf; 449 count = buf_size / sizeof(struct vfat_dir_entry); 450 dbg("expected entries 0x%x", count); 451 452 fnlen = get_fat_attr_volume_id(filename, sizeof(filename), dir, count); 453 if (fnlen > 0) 454 break; 455 456 /* get FAT entry */ 457 fat_entry_off = (reserved * sector_size) + (next * sizeof(uint32_t)); 458 buf = volume_id_get_buffer(id, off + fat_entry_off, buf_size); 459 if (buf == NULL) 460 goto found; 461 462 /* set next cluster */ 463 next = le32_to_cpu(*((uint32_t *) buf)) & 0x0fffffff; 464 if (next < 2 || next >= 0x0ffffff0) 465 break; 466 } 467 if (maxloop == 0) 468 dbg("reached maximum follow count of root cluster chain, give up"); 469 470 vs = (struct vfat_super_block *) volume_id_get_buffer(id, off, 0x200); 471 if (vs == NULL) 472 return -1; 473 474 if (fnlen > 0 && memcmp(filename, "NO NAME ", 11) != 0) { 475 volume_id_set_label_raw(id, filename, fnlen); 476 volume_id_set_label_string(id, filename, fnlen); 477 } else if (memcmp(vs->type.fat32.label, "NO NAME ", 11) != 0) { 478 volume_id_set_label_raw(id, vs->type.fat32.label, 11); 479 volume_id_set_label_string(id, vs->type.fat32.label, 11); 480 } 481 volume_id_set_uuid(id, vs->type.fat32.serno, 0, UUID_DOS); 482 483found: 484 volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); 485 id->type = "vfat"; 486 487 return 0; 488} 489