1 /* 2 libparted 3 Copyright (C) 1998, 1999, 2000, 2002, 2004, 2007 Free Software Foundation, Inc. 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 3 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 #include <config.h> 20 #include "fat.h" 21 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <string.h> 25 #include <sys/types.h> 26 #include <sys/stat.h> 27 #include <fcntl.h> 28 #include <errno.h> 29 30 /* Reads in the boot sector (superblock), and does a minimum of sanity 31 * checking. The goals are: 32 * - to detect fat file systems, even if they are damaged [i.e. not 33 * return an error / throw an exception] 34 * - to fail detection if there's not enough information for 35 * fat_boot_sector_probe_type() to work (or possibly crash on a divide-by-zero) 36 */ 37 int 38 fat_boot_sector_read (FatBootSector* bs, const PedGeometry *geom) 39 { 40 PED_ASSERT (bs != NULL, return 0); 41 PED_ASSERT (geom != NULL, return 0); 42 43 if (!ped_geometry_read (geom, bs, 0, 1)) 44 return 0; 45 46 if (PED_LE16_TO_CPU (bs->boot_sign) != 0xAA55) { 47 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, 48 _("File system has an invalid signature for a FAT " 49 "file system.")); 50 return 0; 51 } 52 53 if (!bs->system_id[0]) { 54 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, 55 _("File system has an invalid signature for a FAT " 56 "file system.")); 57 return 0; 58 } 59 60 if (!bs->sector_size 61 || PED_LE16_TO_CPU (bs->sector_size) % PED_SECTOR_SIZE_DEFAULT) { 62 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, 63 _("File system has an invalid sector size for a FAT " 64 "file system.")); 65 return 0; 66 } 67 68 if (!bs->cluster_size) { 69 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, 70 _("File system has an invalid cluster size for a FAT " 71 "file system.")); 72 return 0; 73 } 74 75 if (!bs->reserved) { 76 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, 77 _("File system has an invalid number of reserved " 78 "sectors for a FAT file system.")); 79 return 0; 80 } 81 82 if (bs->fats < 1 || bs->fats > 4) { 83 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, 84 _("File system has an invalid number of FATs.")); 85 return 0; 86 } 87 88 return 1; 89 } 90 91 /* 92 Don't trust the FAT12, FAT16 or FAT32 label string. 93 */ 94 FatType 95 fat_boot_sector_probe_type (const FatBootSector* bs, const PedGeometry* geom) 96 { 97 PedSector logical_sector_size; 98 PedSector first_cluster_sector; 99 FatCluster cluster_count; 100 101 if (!PED_LE16_TO_CPU (bs->dir_entries)) 102 return FAT_TYPE_FAT32; 103 104 logical_sector_size = PED_LE16_TO_CPU (bs->sector_size) / 512; 105 106 first_cluster_sector 107 = PED_LE16_TO_CPU (bs->reserved) * logical_sector_size 108 + 2 * PED_LE16_TO_CPU (bs->fat_length) * logical_sector_size 109 + PED_LE16_TO_CPU (bs->dir_entries) 110 / (512 / sizeof (FatDirEntry)); 111 cluster_count = (geom->length - first_cluster_sector) 112 / bs->cluster_size / logical_sector_size; 113 if (cluster_count > MAX_FAT12_CLUSTERS) 114 return FAT_TYPE_FAT16; 115 else 116 return FAT_TYPE_FAT12; 117 } 118 119 /* Analyses the boot sector, and sticks appropriate numbers in 120 fs->type_specific. 121 122 Note: you need to subtract (2 * cluster_sectors) off cluster offset, 123 because the first cluster is number 2. (0 and 1 are not real clusters, 124 and referencing them is a bug) 125 */ 126 int 127 fat_boot_sector_analyse (FatBootSector* bs, PedFileSystem* fs) 128 { 129 FatSpecific* fs_info = FAT_SPECIFIC (fs); 130 int fat_entry_size; 131 132 PED_ASSERT (bs != NULL, return 0); 133 134 if (PED_LE16_TO_CPU (bs->sector_size) != 512) { 135 if (ped_exception_throw ( 136 PED_EXCEPTION_BUG, 137 PED_EXCEPTION_IGNORE_CANCEL, 138 _("This file system has a logical sector size of %d. " 139 "GNU Parted is known not to work properly with sector " 140 "sizes other than 512 bytes."), 141 (int) PED_LE16_TO_CPU (bs->sector_size)) 142 != PED_EXCEPTION_IGNORE) 143 return 0; 144 } 145 146 fs_info->logical_sector_size = PED_LE16_TO_CPU (bs->sector_size) / 512; 147 148 fs_info->sectors_per_track = PED_LE16_TO_CPU (bs->secs_track); 149 fs_info->heads = PED_LE16_TO_CPU (bs->heads); 150 if (fs_info->sectors_per_track < 1 || fs_info->sectors_per_track > 63 151 || fs_info->heads < 1 || fs_info->heads > 255) { 152 PedCHSGeometry* bios_geom = &fs->geom->dev->bios_geom; 153 int cyl_count = 0; 154 155 if (fs_info->heads > 0 && fs_info->sectors_per_track > 0) 156 cyl_count = fs->geom->dev->length / fs_info->heads 157 / fs_info->sectors_per_track; 158 159 switch (ped_exception_throw ( 160 PED_EXCEPTION_ERROR, 161 PED_EXCEPTION_FIX + PED_EXCEPTION_IGNORE 162 + PED_EXCEPTION_CANCEL, 163 _("The file system's CHS geometry is (%d, %d, %d), " 164 "which is invalid. The partition table's CHS " 165 "geometry is (%d, %d, %d). If you select Ignore, " 166 "the file system's CHS geometry will be left " 167 "unchanged. If you select Fix, the file system's " 168 "CHS geometry will be set to match the partition " 169 "table's CHS geometry."), 170 cyl_count, fs_info->heads, fs_info->sectors_per_track, 171 bios_geom->cylinders, bios_geom->heads, 172 bios_geom->sectors)) { 173 174 case PED_EXCEPTION_FIX: 175 fs_info->sectors_per_track = bios_geom->sectors; 176 fs_info->heads = bios_geom->heads; 177 bs->secs_track 178 = PED_CPU_TO_LE16 (fs_info->sectors_per_track); 179 bs->heads = PED_CPU_TO_LE16 (fs_info->heads); 180 if (!fat_boot_sector_write (bs, fs)) 181 return 0; 182 break; 183 184 case PED_EXCEPTION_CANCEL: 185 return 0; 186 187 case PED_EXCEPTION_IGNORE: 188 break; 189 190 default: 191 break; 192 } 193 } 194 195 if (bs->sectors) 196 fs_info->sector_count = PED_LE16_TO_CPU (bs->sectors) 197 * fs_info->logical_sector_size; 198 else 199 fs_info->sector_count = PED_LE32_TO_CPU (bs->sector_count) 200 * fs_info->logical_sector_size; 201 202 fs_info->fat_table_count = bs->fats; 203 fs_info->root_dir_entry_count = PED_LE16_TO_CPU (bs->dir_entries); 204 fs_info->fat_offset = PED_LE16_TO_CPU (bs->reserved) 205 * fs_info->logical_sector_size; 206 fs_info->cluster_sectors = bs->cluster_size 207 * fs_info->logical_sector_size; 208 fs_info->cluster_size = fs_info->cluster_sectors * 512; 209 210 if (fs_info->logical_sector_size == 0) { 211 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, 212 _("FAT boot sector says logical sector size is 0. " 213 "This is weird. ")); 214 return 0; 215 } 216 if (fs_info->fat_table_count == 0) { 217 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, 218 _("FAT boot sector says there are no FAT tables. This " 219 "is weird. ")); 220 return 0; 221 } 222 if (fs_info->cluster_sectors == 0) { 223 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, 224 _("FAT boot sector says clusters are 0 sectors. This " 225 "is weird. ")); 226 return 0; 227 } 228 229 fs_info->fat_type = fat_boot_sector_probe_type (bs, fs->geom); 230 if (fs_info->fat_type == FAT_TYPE_FAT12) { 231 ped_exception_throw ( 232 PED_EXCEPTION_NO_FEATURE, 233 PED_EXCEPTION_CANCEL, 234 _("File system is FAT12, which is unsupported.")); 235 return 0; 236 } 237 if (fs_info->fat_type == FAT_TYPE_FAT16) { 238 fs_info->fat_sectors = PED_LE16_TO_CPU (bs->fat_length) 239 * fs_info->logical_sector_size; 240 fs_info->serial_number 241 = PED_LE32_TO_CPU (bs->u.fat16.serial_number); 242 fs_info->root_cluster = 0; 243 fs_info->root_dir_offset 244 = fs_info->fat_offset 245 + fs_info->fat_sectors * fs_info->fat_table_count; 246 fs_info->root_dir_sector_count 247 = fs_info->root_dir_entry_count * sizeof (FatDirEntry) 248 / (512 * fs_info->logical_sector_size); 249 fs_info->cluster_offset 250 = fs_info->root_dir_offset 251 + fs_info->root_dir_sector_count; 252 } 253 if (fs_info->fat_type == FAT_TYPE_FAT32) { 254 fs_info->fat_sectors = PED_LE32_TO_CPU (bs->u.fat32.fat_length) 255 * fs_info->logical_sector_size; 256 fs_info->serial_number 257 = PED_LE32_TO_CPU (bs->u.fat32.serial_number); 258 fs_info->info_sector_offset 259 = PED_LE16_TO_CPU (fs_info->boot_sector.u.fat32.info_sector) 260 * fs_info->logical_sector_size; 261 fs_info->boot_sector_backup_offset 262 = PED_LE16_TO_CPU (fs_info->boot_sector.u.fat32.backup_sector) 263 * fs_info->logical_sector_size; 264 fs_info->root_cluster 265 = PED_LE32_TO_CPU (bs->u.fat32.root_dir_cluster); 266 fs_info->root_dir_offset = 0; 267 fs_info->root_dir_sector_count = 0; 268 fs_info->cluster_offset 269 = fs_info->fat_offset 270 + fs_info->fat_sectors * fs_info->fat_table_count; 271 } 272 273 fs_info->cluster_count 274 = (fs_info->sector_count - fs_info->cluster_offset) 275 / fs_info->cluster_sectors; 276 277 fat_entry_size = fat_table_entry_size (fs_info->fat_type); 278 if (fs_info->cluster_count + 2 279 > fs_info->fat_sectors * 512 / fat_entry_size) 280 fs_info->cluster_count 281 = fs_info->fat_sectors * 512 / fat_entry_size - 2; 282 283 fs_info->dir_entries_per_cluster 284 = fs_info->cluster_size / sizeof (FatDirEntry); 285 return 1; 286 } 287 288 #ifndef DISCOVER_ONLY 289 int 290 fat_boot_sector_set_boot_code (FatBootSector* bs) 291 { 292 PED_ASSERT (bs != NULL, return 0); 293 294 memset (bs, 0, 512); 295 memcpy (bs->boot_jump, FAT_BOOT_JUMP, 3); 296 memcpy (bs->u.fat32.boot_code, FAT_BOOT_CODE, FAT_BOOT_CODE_LENGTH); 297 return 1; 298 } 299 300 int 301 fat_boot_sector_generate (FatBootSector* bs, const PedFileSystem* fs) 302 { 303 FatSpecific* fs_info = FAT_SPECIFIC (fs); 304 305 PED_ASSERT (bs != NULL, return 0); 306 307 memcpy (bs->system_id, "MSWIN4.1", 8); 308 bs->sector_size = PED_CPU_TO_LE16 (fs_info->logical_sector_size * 512); 309 bs->cluster_size = fs_info->cluster_sectors 310 / fs_info->logical_sector_size; 311 bs->reserved = PED_CPU_TO_LE16 (fs_info->fat_offset 312 / fs_info->logical_sector_size); 313 bs->fats = fs_info->fat_table_count; 314 315 bs->dir_entries = (fs_info->fat_type == FAT_TYPE_FAT16) 316 ? PED_CPU_TO_LE16 (fs_info->root_dir_entry_count) 317 : 0; 318 319 if (fs_info->sector_count / fs_info->logical_sector_size > 0xffff 320 || fs_info->fat_type == FAT_TYPE_FAT32) { 321 bs->sectors = 0; 322 bs->sector_count = PED_CPU_TO_LE32 (fs_info->sector_count 323 / fs_info->logical_sector_size); 324 } else { 325 bs->sectors = PED_CPU_TO_LE16 (fs_info->sector_count 326 / fs_info->logical_sector_size); 327 bs->sector_count = 0; 328 } 329 330 bs->media = 0xf8; 331 332 bs->secs_track = PED_CPU_TO_LE16 (fs_info->sectors_per_track); 333 bs->heads = PED_CPU_TO_LE16 (fs_info->heads); 334 bs->hidden = PED_CPU_TO_LE32 (fs->geom->start); 335 336 if (fs_info->fat_type == FAT_TYPE_FAT32) { 337 bs->fat_length = 0; 338 bs->u.fat32.fat_length = PED_CPU_TO_LE32 (fs_info->fat_sectors 339 / fs_info->logical_sector_size); 340 bs->u.fat32.flags = 0; /* FIXME: what the hell are these? */ 341 bs->u.fat32.version = 0; /* must be 0, for Win98 bootstrap */ 342 bs->u.fat32.root_dir_cluster 343 = PED_CPU_TO_LE32 (fs_info->root_cluster); 344 bs->u.fat32.info_sector 345 = PED_CPU_TO_LE16 (fs_info->info_sector_offset 346 / fs_info->logical_sector_size); 347 bs->u.fat32.backup_sector 348 = PED_CPU_TO_LE16 (fs_info->boot_sector_backup_offset 349 / fs_info->logical_sector_size); 350 351 bs->u.fat32.drive_num = 0x80; /* _ALWAYS_ 0x80. silly DOS */ 352 353 memset (bs->u.fat32.empty_1, 0, 12); 354 355 bs->u.fat32.ext_signature = 0x29; 356 bs->u.fat32.serial_number 357 = PED_CPU_TO_LE32 (fs_info->serial_number); 358 memcpy (bs->u.fat32.volume_name, "NO NAME ", 11); 359 memcpy (bs->u.fat32.fat_name, "FAT32 ", 8); 360 } else { 361 bs->fat_length 362 = PED_CPU_TO_LE16 (fs_info->fat_sectors 363 / fs_info->logical_sector_size); 364 365 bs->u.fat16.drive_num = 0x80; /* _ALWAYS_ 0x80. silly DOS */ 366 367 bs->u.fat16.ext_signature = 0x29; 368 bs->u.fat16.serial_number 369 = PED_CPU_TO_LE32 (fs_info->serial_number); 370 memcpy (bs->u.fat16.volume_name, "NO NAME ", 11); 371 memcpy (bs->u.fat16.fat_name, "FAT16 ", 8); 372 } 373 374 bs->boot_sign = PED_CPU_TO_LE16 (0xaa55); 375 376 return 1; 377 } 378 379 int 380 fat_boot_sector_write (const FatBootSector* bs, PedFileSystem* fs) 381 { 382 FatSpecific* fs_info = FAT_SPECIFIC (fs); 383 384 PED_ASSERT (bs != NULL, return 0); 385 386 if (!ped_geometry_write (fs->geom, bs, 0, 1)) 387 return 0; 388 if (fs_info->fat_type == FAT_TYPE_FAT32) { 389 if (!ped_geometry_write (fs->geom, bs, 390 fs_info->boot_sector_backup_offset, 1)) 391 return 0; 392 } 393 return ped_geometry_sync (fs->geom); 394 } 395 396 int 397 fat_info_sector_read (FatInfoSector* is, const PedFileSystem* fs) 398 { 399 FatSpecific* fs_info = FAT_SPECIFIC (fs); 400 int status; 401 402 PED_ASSERT (is != NULL, return 0); 403 404 if (!ped_geometry_read (fs->geom, is, fs_info->info_sector_offset, 1)) 405 return 0; 406 407 if (PED_LE32_TO_CPU (is->signature_2) != FAT32_INFO_MAGIC2) { 408 status = ped_exception_throw (PED_EXCEPTION_WARNING, 409 PED_EXCEPTION_IGNORE_CANCEL, 410 _("The information sector has the wrong " 411 "signature (%x). Select cancel for now, " 412 "and send in a bug report. If you're " 413 "desperate, it's probably safe to ignore."), 414 PED_LE32_TO_CPU (is->signature_2)); 415 if (status == PED_EXCEPTION_CANCEL) return 0; 416 } 417 return 1; 418 } 419 420 int 421 fat_info_sector_generate (FatInfoSector* is, const PedFileSystem* fs) 422 { 423 FatSpecific* fs_info = FAT_SPECIFIC (fs); 424 425 PED_ASSERT (is != NULL, return 0); 426 427 fat_table_count_stats (fs_info->fat); 428 429 memset (is, 0, 512); 430 431 is->signature_1 = PED_CPU_TO_LE32 (FAT32_INFO_MAGIC1); 432 is->signature_2 = PED_CPU_TO_LE32 (FAT32_INFO_MAGIC2); 433 is->free_clusters = PED_CPU_TO_LE32 (fs_info->fat->free_cluster_count); 434 is->next_cluster = PED_CPU_TO_LE32 (fs_info->fat->last_alloc); 435 is->signature_3 = PED_CPU_TO_LE16 (FAT32_INFO_MAGIC3); 436 437 return 1; 438 } 439 440 int 441 fat_info_sector_write (const FatInfoSector* is, PedFileSystem *fs) 442 { 443 FatSpecific* fs_info = FAT_SPECIFIC (fs); 444 445 PED_ASSERT (is != NULL, return 0); 446 447 if (!ped_geometry_write (fs->geom, is, fs_info->info_sector_offset, 1)) 448 return 0; 449 return ped_geometry_sync (fs->geom); 450 } 451 #endif /* !DISCOVER_ONLY */ 452