1 /*
   2     libparted
   3     Copyright (C) 1998, 1999, 2000, 2001, 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 <string.h>
  21 #include <uuid/uuid.h>
  22 
  23 #include "fat.h"
  24 #include "calc.h"
  25 
  26 PedFileSystem*
  27 fat_alloc (const PedGeometry* geom)
  28 {
  29         PedFileSystem*          fs;
  30 
  31         fs = (PedFileSystem*) ped_malloc (sizeof (PedFileSystem));
  32         if (!fs)
  33                 goto error;
  34 
  35         fs->type_specific = (FatSpecific*) ped_malloc (sizeof (FatSpecific));
  36         if (!fs->type_specific)
  37                 goto error_free_fs;
  38 
  39         fs->geom = ped_geometry_duplicate (geom);
  40         if (!fs->geom)
  41                 goto error_free_type_specific;
  42 
  43         fs->checked = 0;
  44         return fs;
  45 
  46 error_free_type_specific:
  47         ped_free (fs->type_specific);
  48 error_free_fs:
  49         ped_free (fs);
  50 error:
  51         return NULL;
  52 }
  53 
  54 /* Requires the boot sector to be analysed */
  55 int
  56 fat_alloc_buffers (PedFileSystem* fs)
  57 {
  58         FatSpecific*    fs_info = FAT_SPECIFIC (fs);
  59 
  60         fs_info->buffer_sectors = BUFFER_SIZE;
  61         fs_info->buffer = ped_malloc (fs_info->buffer_sectors * 512);
  62         if (!fs_info->buffer)
  63                 goto error;
  64 
  65         fs_info->cluster_info = ped_malloc (fs_info->cluster_count + 2);
  66         if (!fs_info->cluster_info)
  67                 goto error_free_buffer;
  68 
  69         return 1;
  70 
  71 error_free_buffer:
  72         ped_free (fs_info->buffer);
  73 error:
  74         return 0;
  75 }
  76 
  77 void
  78 fat_free_buffers (PedFileSystem* fs)
  79 {
  80         FatSpecific*    fs_info = FAT_SPECIFIC (fs);
  81 
  82         ped_free (fs_info->cluster_info);
  83         ped_free (fs_info->buffer);
  84 }
  85 
  86 void
  87 fat_free (PedFileSystem* fs)
  88 {
  89         ped_geometry_destroy (fs->geom);
  90         ped_free (fs->type_specific);
  91         ped_free (fs);
  92 }
  93 
  94 int
  95 fat_set_frag_sectors (PedFileSystem* fs, PedSector frag_sectors)
  96 {
  97         FatSpecific*    fs_info = FAT_SPECIFIC (fs);
  98 
  99         PED_ASSERT (fs_info->cluster_sectors % frag_sectors == 0
 100                         && frag_sectors <= fs_info->cluster_sectors,
 101                     return 0);
 102 
 103         fs_info->frag_size = frag_sectors * 512;
 104         fs_info->frag_sectors = frag_sectors;
 105         fs_info->buffer_frags = fs_info->buffer_sectors / frag_sectors;
 106         fs_info->cluster_frags = fs_info->cluster_sectors / frag_sectors;
 107         fs_info->frag_count = fs_info->cluster_count * fs_info->cluster_frags;
 108 
 109         return 1;
 110 }
 111 
 112 PedGeometry*
 113 fat_probe (PedGeometry* geom, FatType* fat_type)
 114 {
 115         PedFileSystem*          fs;
 116         FatSpecific*            fs_info;
 117         PedGeometry*            result;
 118 
 119         fs = fat_alloc (geom);
 120         if (!fs)
 121                 goto error;
 122         fs_info = (FatSpecific*) fs->type_specific;
 123 
 124         if (!fat_boot_sector_read (&fs_info->boot_sector, geom))
 125                 goto error_free_fs;
 126         if (!fat_boot_sector_analyse (&fs_info->boot_sector, fs))
 127                 goto error_free_fs;
 128 
 129         *fat_type = fs_info->fat_type;
 130         result = ped_geometry_new (geom->dev, geom->start,
 131                                    fs_info->sector_count);
 132 
 133         fat_free (fs);
 134         return result;
 135 
 136 error_free_fs:
 137         fat_free (fs);
 138 error:
 139         return NULL;
 140 }
 141 
 142 PedGeometry*
 143 fat_probe_fat16 (PedGeometry* geom)
 144 {
 145         FatType         fat_type;
 146         PedGeometry*    probed_geom = fat_probe (geom, &fat_type);
 147 
 148         if (probed_geom) {
 149                 if (fat_type == FAT_TYPE_FAT16)
 150                         return probed_geom;
 151                 ped_geometry_destroy (probed_geom);
 152         }
 153         return NULL;
 154 }
 155 
 156 PedGeometry*
 157 fat_probe_fat32 (PedGeometry* geom)
 158 {
 159         FatType         fat_type;
 160         PedGeometry*    probed_geom = fat_probe (geom, &fat_type);
 161 
 162         if (probed_geom) {
 163                 if (fat_type == FAT_TYPE_FAT32)
 164                         return probed_geom;
 165                 ped_geometry_destroy (probed_geom);
 166         }
 167         return NULL;
 168 }
 169 
 170 #ifndef DISCOVER_ONLY
 171 int
 172 fat_clobber (PedGeometry* geom)
 173 {
 174         FatBootSector           boot_sector;
 175 
 176         if (!fat_boot_sector_read (&boot_sector, geom))
 177                 return 1;
 178 
 179         boot_sector.system_id[0] = 0;
 180         boot_sector.boot_sign = 0;
 181         if (boot_sector.u.fat16.fat_name[0] == 'F')
 182                 boot_sector.u.fat16.fat_name[0] = 0;
 183         if (boot_sector.u.fat32.fat_name[0] == 'F')
 184                 boot_sector.u.fat32.fat_name[0] = 0;
 185 
 186         return ped_geometry_write (geom, &boot_sector, 0, 1);
 187 }
 188 
 189 static int
 190 _init_fats (PedFileSystem* fs)
 191 {
 192         FatSpecific*    fs_info = FAT_SPECIFIC (fs);
 193         FatCluster      table_size;
 194 
 195         table_size = fs_info->fat_sectors * 512
 196                      / fat_table_entry_size (fs_info->fat_type);
 197         fs_info->fat = fat_table_new (fs_info->fat_type, table_size);
 198         if (!fs_info->fat)
 199                 goto error;
 200 
 201         if (!fat_table_read (fs_info->fat, fs, 0))
 202                 goto error_free_fat;
 203 
 204         return 1;
 205 
 206 error_free_fat:
 207         fat_table_destroy (fs_info->fat);
 208 error:
 209         return 0;
 210 }
 211 
 212 PedFileSystem*
 213 fat_open (PedGeometry* geom)
 214 {
 215         PedFileSystem*          fs;
 216         FatSpecific*            fs_info;
 217 
 218         fs = fat_alloc (geom);
 219         if (!fs)
 220                 goto error;
 221         fs_info = (FatSpecific*) fs->type_specific;
 222 
 223         if (!fat_boot_sector_read (&fs_info->boot_sector, geom))
 224                 goto error_free_fs;
 225         if (!fat_boot_sector_analyse (&fs_info->boot_sector, fs))
 226                 goto error_free_fs;
 227         fs->type = (fs_info->fat_type == FAT_TYPE_FAT16)
 228                                 ? &fat16_type
 229                                 : &fat32_type;
 230         if (fs_info->fat_type == FAT_TYPE_FAT32) {
 231                 if (!fat_info_sector_read (&fs_info->info_sector, fs))
 232                         goto error_free_fs;
 233         }
 234 
 235         if (!_init_fats (fs))
 236                 goto error_free_fs;
 237         if (!fat_alloc_buffers (fs)) 
 238                 goto error_free_fat_table;
 239         if (!fat_collect_cluster_info (fs))
 240                 goto error_free_buffers;
 241 
 242         return fs;
 243 
 244 error_free_buffers:
 245         fat_free_buffers (fs);
 246 error_free_fat_table:
 247         fat_table_destroy (fs_info->fat);
 248 error_free_fs:
 249         fat_free (fs);
 250 error:
 251         return NULL;
 252 }
 253 
 254 static int
 255 fat_root_dir_clear (PedFileSystem* fs)
 256 {
 257         FatSpecific*            fs_info = FAT_SPECIFIC (fs);
 258         memset (fs_info->buffer, 0, 512 * fs_info->root_dir_sector_count);
 259         return ped_geometry_write (fs->geom, fs_info->buffer,
 260                                    fs_info->root_dir_offset,
 261                                    fs_info->root_dir_sector_count);
 262 }
 263 
 264 /* hack: use the ext2 uuid library to generate a reasonably random (hopefully
 265  * with /dev/random) number.  Unfortunately, we can only use 4 bytes of it
 266  */
 267 static uint32_t
 268 _gen_new_serial_number ()
 269 {
 270         uuid_t          uuid;
 271 
 272         uuid_generate (uuid);
 273         return * (uint32_t*) &uuid [0];
 274 }
 275 
 276 PedFileSystem*
 277 fat_create (PedGeometry* geom, FatType fat_type, PedTimer* timer)
 278 {
 279         PedFileSystem*          fs;
 280         FatSpecific*            fs_info;
 281         FatCluster              table_size;
 282 
 283         fs = fat_alloc (geom);
 284         if (!fs)
 285                 goto error;
 286         fs_info = (FatSpecific*) fs->type_specific;
 287 
 288         fs_info->logical_sector_size = 1;
 289         fs_info->sectors_per_track = geom->dev->bios_geom.sectors;
 290         fs_info->heads = geom->dev->bios_geom.heads;
 291         fs_info->sector_count = fs->geom->length;
 292         fs_info->fat_table_count = 2;
 293 /* some initial values, to be changed later */
 294         fs_info->root_dir_sector_count = FAT_ROOT_DIR_ENTRY_COUNT
 295                                           / (512 / sizeof (FatDirEntry));
 296         fs_info->root_dir_entry_count = FAT_ROOT_DIR_ENTRY_COUNT;
 297 
 298         fs_info->fat_type = fat_type;
 299         if (!fat_calc_sizes (fs->geom->length, 0,
 300                         fs_info->fat_type,
 301                         fs_info->root_dir_sector_count,
 302                         &fs_info->cluster_sectors,
 303                         &fs_info->cluster_count,
 304                         &fs_info->fat_sectors)) {
 305                 ped_exception_throw (PED_EXCEPTION_ERROR,
 306                         PED_EXCEPTION_CANCEL,
 307                         _("Partition too big/small for a %s file system."),
 308                         (fat_type == FAT_TYPE_FAT16)
 309                                 ? fat16_type.name
 310                                 : fat32_type.name);
 311                 goto error_free_fs;
 312         }
 313 
 314         fs_info->cluster_size = fs_info->cluster_sectors * 512;
 315 
 316         fs_info->fat_offset = fat_min_reserved_sector_count (fs_info->fat_type);
 317         fs_info->dir_entries_per_cluster
 318                 = fs_info->cluster_size / sizeof (FatDirEntry);
 319 
 320         if (fs_info->fat_type == FAT_TYPE_FAT16) {
 321                 /* FAT16 */
 322                 fs->type = &fat16_type;
 323 
 324                 if (fs_info->cluster_count
 325                         > fat_max_cluster_count (fs_info->fat_type)) {
 326                         fs_info->cluster_count
 327                                 = fat_max_cluster_count (fs_info->fat_type);
 328                 }
 329 
 330                 fs_info->root_dir_sector_count
 331                         = FAT_ROOT_DIR_ENTRY_COUNT
 332                                 / (512 / sizeof (FatDirEntry));
 333                 fs_info->root_dir_entry_count = FAT_ROOT_DIR_ENTRY_COUNT;
 334                 fs_info->root_dir_offset
 335                         = fs_info->fat_offset
 336                         + fs_info->fat_sectors * fs_info->fat_table_count;
 337                 fs_info->cluster_offset
 338                         = fs_info->root_dir_offset
 339                           + fs_info->root_dir_sector_count;
 340         } else {
 341                 /* FAT32 */
 342                 fs->type = &fat32_type;
 343 
 344                 fs_info->info_sector_offset = 1;
 345                 fs_info->boot_sector_backup_offset = 6;
 346 
 347                 fs_info->root_dir_sector_count = 0;
 348                 fs_info->root_dir_entry_count = 0;
 349                 fs_info->root_dir_offset = 0;
 350 
 351                 fs_info->cluster_offset
 352                         = fs_info->fat_offset
 353                           + fs_info->fat_sectors * fs_info->fat_table_count;
 354         }
 355 
 356         table_size = fs_info->fat_sectors * 512
 357                      / fat_table_entry_size (fs_info->fat_type);
 358         fs_info->fat = fat_table_new (fs_info->fat_type, table_size);
 359         if (!fs_info->fat)
 360                 goto error_free_fs;
 361         fat_table_set_cluster_count (fs_info->fat, fs_info->cluster_count);
 362         if (!fat_alloc_buffers (fs)) 
 363                 goto error_free_fat_table;
 364 
 365         if (fs_info->fat_type == FAT_TYPE_FAT32) {
 366                 fs_info->root_cluster
 367                         = fat_table_alloc_cluster (fs_info->fat);
 368                 fat_table_set_eof (fs_info->fat, fs_info->root_cluster);
 369                 memset (fs_info->buffer, 0, fs_info->cluster_size);
 370                 if (!fat_write_cluster (fs, fs_info->buffer,
 371                                         fs_info->root_cluster))
 372                         return 0;
 373         }
 374 
 375         fs_info->serial_number = _gen_new_serial_number ();
 376 
 377         if (!fat_boot_sector_set_boot_code (&fs_info->boot_sector))
 378                 goto error_free_buffers;
 379         if (!fat_boot_sector_generate (&fs_info->boot_sector, fs))
 380                 goto error_free_buffers;
 381         if (!fat_boot_sector_write (&fs_info->boot_sector, fs))
 382                 goto error_free_buffers;
 383         if (fs_info->fat_type == FAT_TYPE_FAT32) {
 384                 if (!fat_info_sector_generate (&fs_info->info_sector, fs))
 385                         goto error_free_buffers;
 386                 if (!fat_info_sector_write (&fs_info->info_sector, fs))
 387                         goto error_free_buffers;
 388         }
 389 
 390         if (!fat_table_write_all (fs_info->fat, fs))
 391                 goto error_free_buffers;
 392 
 393         if (fs_info->fat_type == FAT_TYPE_FAT16) {
 394                 if (!fat_root_dir_clear (fs))
 395                         goto error_free_buffers;
 396         }
 397 
 398         return fs;
 399 
 400 error_free_buffers:
 401         fat_free_buffers (fs);
 402 error_free_fat_table:
 403         fat_table_destroy (fs_info->fat);
 404 error_free_fs:
 405         fat_free (fs);
 406 error:
 407         return NULL;
 408 }
 409 
 410 PedFileSystem*
 411 fat_create_fat16 (PedGeometry* geom, PedTimer* timer)
 412 {
 413         return fat_create (geom, FAT_TYPE_FAT16, timer);
 414 }
 415 
 416 PedFileSystem*
 417 fat_create_fat32 (PedGeometry* geom, PedTimer* timer)
 418 {
 419         return fat_create (geom, FAT_TYPE_FAT32, timer);
 420 }
 421 
 422 int
 423 fat_close (PedFileSystem* fs)
 424 {
 425         FatSpecific*    fs_info = FAT_SPECIFIC (fs);
 426 
 427         fat_free_buffers (fs);
 428         fat_table_destroy (fs_info->fat);
 429         fat_free (fs);
 430         return 1;
 431 }
 432 
 433 /* Hack: just resize the file system outside of its boundaries! */
 434 PedFileSystem*
 435 fat_copy (const PedFileSystem* fs, PedGeometry* geom, PedTimer* timer)
 436 {
 437         PedFileSystem*          new_fs;
 438 
 439         new_fs = ped_file_system_open (fs->geom);
 440         if (!new_fs)
 441                 goto error;
 442         if (!ped_file_system_resize (new_fs, geom, timer))
 443                 goto error_close_new_fs;
 444         return new_fs;
 445 
 446 error_close_new_fs:
 447         ped_file_system_close (new_fs);
 448 error:
 449         return 0;
 450 }
 451 
 452 static int
 453 _compare_fats (PedFileSystem* fs)
 454 {
 455         FatSpecific*    fs_info = FAT_SPECIFIC (fs);
 456         FatTable*       table_copy;
 457         FatCluster      table_size;
 458         int             i;
 459 
 460         table_size = fs_info->fat_sectors * 512
 461                      / fat_table_entry_size (fs_info->fat_type);
 462 
 463         table_copy = fat_table_new (fs_info->fat_type, table_size);
 464         if (!table_copy)
 465                 goto error;
 466 
 467         for (i = 1; i < fs_info->fat_table_count; i++) {
 468                 if (!fat_table_read (table_copy, fs, i))
 469                         goto error_free_table_copy;
 470                 if (!fat_table_compare (fs_info->fat, table_copy)) {
 471                         if (ped_exception_throw (PED_EXCEPTION_ERROR,
 472                                 PED_EXCEPTION_IGNORE_CANCEL,
 473                                 _("The FATs don't match.  If you don't know "
 474                                   "what this means, then select cancel, run "
 475                                   "scandisk on the file system, and then come "
 476                                   "back."))
 477                             != PED_EXCEPTION_IGNORE)
 478                                 goto error_free_table_copy;
 479                 }
 480         }
 481 
 482         fat_table_destroy (table_copy);
 483         return 1;
 484 
 485 error_free_table_copy:
 486         fat_table_destroy (table_copy);
 487 error:
 488         return 0;
 489 }
 490 
 491 int
 492 fat_check (PedFileSystem* fs, PedTimer* timer)
 493 {
 494         FatSpecific*    fs_info = FAT_SPECIFIC (fs);
 495         PedSector       cluster_sectors;
 496         FatCluster      cluster_count;
 497         PedSector       fat_sectors;
 498         PedSector       align_sectors;
 499         FatCluster      info_free_clusters;
 500 
 501         align_sectors = fs_info->fat_offset
 502                         - fat_min_reserved_sector_count (fs_info->fat_type);
 503 
 504         if (!fat_calc_sizes (fs->geom->length,
 505                              align_sectors,
 506                              fs_info->fat_type,
 507                              fs_info->root_dir_sector_count,
 508                              &cluster_sectors,
 509                              &cluster_count,
 510                              &fat_sectors)) {
 511                 if (ped_exception_throw (PED_EXCEPTION_BUG,
 512                         PED_EXCEPTION_IGNORE_CANCEL,
 513                         _("There are no possible configurations for this FAT "
 514                           "type."))
 515                                 != PED_EXCEPTION_IGNORE)
 516                         goto error;
 517         }
 518 
 519         if (fs_info->fat_type == FAT_TYPE_FAT16) {
 520                 if (cluster_sectors != fs_info->cluster_sectors
 521                     || cluster_count != fs_info->cluster_count
 522                     || fat_sectors != fs_info->fat_sectors) {
 523                         if (ped_exception_throw (PED_EXCEPTION_WARNING,
 524                                 PED_EXCEPTION_IGNORE_CANCEL,
 525                                 _("File system doesn't have expected sizes for "
 526                                   "Windows to like it.  "
 527                                   "Cluster size is %dk (%dk expected); "
 528                                   "number of clusters is %d (%d expected); "
 529                                   "size of FATs is %d sectors (%d expected)."),
 530                                 (int) fs_info->cluster_sectors / 2,
 531                                         (int) cluster_sectors / 2,
 532                                 (int) fs_info->cluster_count,
 533                                         (int) cluster_count,
 534                                 (int) fs_info->fat_sectors,
 535                                         (int) fat_sectors)
 536                                         != PED_EXCEPTION_IGNORE)
 537                                 goto error;
 538                 }
 539         } 
 540 
 541         if (fs_info->fat_type == FAT_TYPE_FAT32) {
 542                 info_free_clusters
 543                         = PED_LE32_TO_CPU (fs_info->info_sector.free_clusters);
 544                 if (info_free_clusters != (FatCluster) -1
 545                     && info_free_clusters != fs_info->fat->free_cluster_count) {
 546                         if (ped_exception_throw (PED_EXCEPTION_WARNING,
 547                                 PED_EXCEPTION_IGNORE_CANCEL,
 548                                 _("File system is reporting the free space as "
 549                                   "%d clusters, not %d clusters."),
 550                                 info_free_clusters,
 551                                 fs_info->fat->free_cluster_count)
 552                                         != PED_EXCEPTION_IGNORE)
 553                                 goto error;
 554                 }
 555         }
 556 
 557         if (!_compare_fats (fs))
 558                 goto error;
 559 
 560         fs->checked = 1;
 561         return 1;       /* existence of fs implies consistency ;-) */
 562 
 563 error:
 564         return 0;
 565 }
 566 
 567 /* Calculates how much space there will be in clusters in:
 568  *      old_fs intersect the-new-fs
 569  */
 570 static PedSector
 571 _calc_resize_data_size (
 572         const PedFileSystem* old_fs,
 573         PedSector new_cluster_sectors,
 574         FatCluster new_cluster_count,
 575         PedSector new_fat_size)
 576 {
 577         FatSpecific*    old_fs_info = FAT_SPECIFIC (old_fs);
 578         PedSector       fat_size_delta;
 579 
 580         fat_size_delta = old_fs_info->fat_sectors - new_fat_size;
 581         return new_cluster_sectors * new_cluster_count - fat_size_delta * 2;
 582 }
 583 
 584 static int
 585 _test_resize_size (const PedFileSystem* fs,
 586                    PedSector length, PedSector min_data_size)
 587 {
 588         FatSpecific*    fs_info = FAT_SPECIFIC (fs);
 589         PedGeometry     geom;
 590         PedSector       _cluster_sectors;
 591         FatCluster      _cluster_count;
 592         PedSector       _fat_size;
 593 
 594         ped_geometry_init (&geom, fs->geom->dev, fs->geom->start, length);
 595 
 596         if (fat_calc_resize_sizes (
 597                                 &geom,
 598                                 fs_info->cluster_sectors,
 599                                 FAT_TYPE_FAT16,
 600                                 fs_info->root_dir_sector_count,
 601                                 fs_info->cluster_sectors,
 602                                 &_cluster_sectors,
 603                                 &_cluster_count,
 604                                 &_fat_size)
 605             && _calc_resize_data_size (fs, _cluster_sectors, _cluster_count,
 606                                        _fat_size)
 607                         >= min_data_size)
 608                 return 1;
 609 
 610         if (fat_calc_resize_sizes (
 611                                 &geom,
 612                                 fs_info->cluster_sectors,
 613                                 FAT_TYPE_FAT32,
 614                                 0,
 615                                 fs_info->cluster_sectors,
 616                                 &_cluster_sectors,
 617                                 &_cluster_count,
 618                                 &_fat_size)
 619             && _calc_resize_data_size (fs, _cluster_sectors, _cluster_count,
 620                                        _fat_size)
 621                         >= min_data_size)
 622                 return 1;
 623 
 624         return 0;
 625 }
 626 
 627 /* does a binary search (!) for the mininum size.  Too hard to compute directly
 628  * (see calc_sizes() for why!)
 629  */
 630 static PedSector
 631 _get_min_resize_size (const PedFileSystem* fs, PedSector min_data_size)
 632 {
 633         PedSector       min_length = 0;
 634         PedSector       max_length = fs->geom->length;
 635         PedSector       length;
 636 
 637         while (min_length < max_length - 1) {
 638                 length = (min_length + max_length) / 2;
 639                 if (_test_resize_size (fs, length, min_data_size))
 640                         max_length = length;
 641                 else
 642                         min_length = length;
 643         }
 644 
 645 /* adds a bit of leeway (64 sectors), for resolving extra issues, like root
 646  * directory allocation, that aren't covered here. 
 647  */
 648         return max_length + 64;
 649 }
 650 
 651 PedConstraint*
 652 fat_get_copy_constraint (const PedFileSystem* fs, const PedDevice* dev)
 653 {
 654         FatSpecific*    fs_info = FAT_SPECIFIC (fs);
 655         PedGeometry     full_dev;
 656         PedSector       min_cluster_count;
 657         FatCluster      used_clusters;
 658         PedSector       min_data_size;
 659 
 660         if (!ped_geometry_init (&full_dev, dev, 0, dev->length - 1))
 661                 return NULL;
 662 
 663         used_clusters = fs_info->fat->cluster_count
 664                         - fs_info->fat->free_cluster_count;
 665         min_cluster_count = used_clusters + fs_info->total_dir_clusters;
 666         min_data_size = min_cluster_count * fs_info->cluster_sectors;
 667 
 668         return ped_constraint_new (ped_alignment_any, ped_alignment_any,
 669                                    &full_dev, &full_dev,
 670                                    _get_min_resize_size (fs, min_data_size),
 671                                    dev->length);
 672 }
 673 
 674 PedConstraint*
 675 fat_get_resize_constraint (const PedFileSystem* fs)
 676 {
 677         return fat_get_copy_constraint (fs, fs->geom->dev);
 678 }
 679 
 680 /* FIXME: fat_calc_sizes() needs to say "too big" or "too small", or
 681  * something.  This is a really difficult (maths) problem to do
 682  * nicely...
 683  *      So, this algorithm works if dev->length / 2 is a valid fat_type
 684  * size.  (Which is how I got the magic numbers below)
 685  */
 686 #if 0
 687 /* returns: -1 too small, 0 ok, 1 too big */
 688 static int
 689 _test_create_size (PedSector length, FatType fat_type,
 690                    PedSector cluster_sectors, PedSector cluster_count)
 691 {
 692         PedSector       rootdir_sectors;
 693         PedSector       _cluster_sectors;
 694         FatCluster      _cluster_count;
 695         PedSector       _fat_size;
 696 
 697         rootdir_sectors = (fat_type == FAT_TYPE_FAT16) ? 16 : 0;
 698 
 699         if (!fat_calc_sizes (length, 0, fat_type, rootdir_sectors,
 700                              &_cluster_sectors, &_cluster_count, &_fat_size))
 701                 return -1; // XXX: doesn't work... can't see a better way!
 702 
 703         if (_cluster_sectors < cluster_sectors)
 704                 return -1;
 705         if (_cluster_sectors > cluster_sectors)
 706                 return 1;
 707 
 708         if (_cluster_count < cluster_count)
 709                 return -1;
 710         if (_cluster_count > cluster_count)
 711                 return 1;
 712 
 713         return 0;
 714 }
 715 
 716 static PedSector
 717 _get_create_size (PedSector upper_bound, FatType fat_type,
 718                   PedSector cluster_sectors, FatCluster cluster_count)
 719 {
 720         PedSector       min_length = 0;
 721         PedSector       max_length = upper_bound;
 722         PedSector       length;
 723 
 724         while (1) {
 725                 length = (min_length + max_length) / 2;
 726                 switch (_test_create_size (length, fat_type, cluster_sectors,
 727                                            cluster_count)) {
 728                         case -1: min_length = length; break;
 729                         case 0: return length;
 730                         case 1: max_length = length; break;
 731                 }
 732                 /* hack... won't always be able to get max cluster count
 733                  * with max cluster size, etc. */
 734                 if (max_length - min_length == 1)
 735                         return min_length;
 736         }
 737 
 738         return 0;       /* shut gcc up */
 739 }
 740 #endif
 741 
 742 PedConstraint*
 743 fat_get_create_constraint_fat16 (const PedDevice* dev)
 744 {
 745         PedGeometry     full_dev;
 746         PedSector       min_size;
 747         PedSector       max_size;
 748 
 749         if (!ped_geometry_init (&full_dev, dev, 0, dev->length - 1))
 750                 return NULL;
 751 
 752 #if 0
 753         min_size = _get_create_size (dev->length, FAT_TYPE_FAT16,
 754                                      fat_min_cluster_size (FAT_TYPE_FAT16),
 755                                      fat_min_cluster_count (FAT_TYPE_FAT16));
 756         max_size = _get_create_size (dev->length, FAT_TYPE_FAT16,
 757                                      fat_max_cluster_size (FAT_TYPE_FAT16),
 758                                      fat_max_cluster_count (FAT_TYPE_FAT16));
 759         if (!min_size)
 760                 return NULL;
 761 #else
 762         min_size = 65794;
 763         max_size = 2097153;
 764 #endif
 765 
 766         return ped_constraint_new (
 767                         ped_alignment_any, ped_alignment_any,
 768                         &full_dev, &full_dev,
 769                         min_size, max_size);
 770 }
 771 
 772 PedConstraint*
 773 fat_get_create_constraint_fat32 (const PedDevice* dev)
 774 {
 775         PedGeometry     full_dev;
 776         PedSector       min_size;
 777 
 778         if (!ped_geometry_init (&full_dev, dev, 0, dev->length - 1))
 779                 return NULL;
 780 
 781 #if 0
 782         min_size = _get_create_size (dev->length, FAT_TYPE_FAT32,
 783                                      fat_min_cluster_size (FAT_TYPE_FAT32),
 784                                      fat_min_cluster_count (FAT_TYPE_FAT32));
 785         if (!min_size)
 786                 return NULL;
 787 #else
 788         min_size = 525224;
 789 #endif
 790 
 791         return ped_constraint_new (
 792                         ped_alignment_any, ped_alignment_any,
 793                         &full_dev, &full_dev,
 794                         min_size, dev->length);
 795 }
 796 #endif /* !DISCOVER_ONLY */
 797 
 798 static PedFileSystemOps fat16_ops = {
 799         .probe =                fat_probe_fat16,
 800 #ifndef DISCOVER_ONLY
 801         .clobber =      fat_clobber,
 802         .open =         fat_open,
 803         .create =               fat_create_fat16,
 804         .close =                fat_close,
 805         .check =                fat_check,
 806         .resize =               fat_resize,
 807         .copy =         fat_copy,
 808         .get_create_constraint =        fat_get_create_constraint_fat16,
 809         .get_resize_constraint =        fat_get_resize_constraint,
 810         .get_copy_constraint =  fat_get_copy_constraint,
 811 #else /* !DISCOVER_ONLY */
 812         .clobber =      NULL,
 813         .open =         NULL,
 814         .create =               NULL,
 815         .close =                NULL,
 816         .check =                NULL,
 817         .resize =               NULL,
 818         .copy =         NULL,
 819         .get_create_constraint =        NULL,
 820         .get_resize_constraint =        NULL,
 821         .get_copy_constraint =  NULL,
 822 #endif /* !DISCOVER_ONLY */
 823 };
 824 
 825 static PedFileSystemOps fat32_ops = {
 826         .probe =                fat_probe_fat32,
 827 #ifndef DISCOVER_ONLY
 828         .clobber =      fat_clobber,
 829         .open =         fat_open,
 830         .create =               fat_create_fat32,
 831         .close =                fat_close,
 832         .check =                fat_check,
 833         .resize =               fat_resize,
 834         .copy =         fat_copy,
 835         .get_create_constraint =        fat_get_create_constraint_fat32,
 836         .get_resize_constraint =        fat_get_resize_constraint,
 837         .get_copy_constraint =  fat_get_copy_constraint,
 838 #else /* !DISCOVER_ONLY */
 839         .clobber =      NULL,
 840         .open =         NULL,
 841         .create =               NULL,
 842         .close =                NULL,
 843         .check =                NULL,
 844         .resize =               NULL,
 845         .copy =         NULL,
 846         .get_create_constraint =        NULL,
 847         .get_resize_constraint =        NULL,
 848         .get_copy_constraint =  NULL,
 849 #endif /* !DISCOVER_ONLY */
 850 };
 851 
 852 #define FAT_BLOCK_SIZES ((int[2]){512, 0})
 853 
 854 PedFileSystemType fat16_type = {
 855         .next =         NULL,
 856         .ops =          &fat16_ops,
 857         .name =         "fat16",
 858         .block_sizes =    FAT_BLOCK_SIZES
 859 };
 860 
 861 PedFileSystemType fat32_type = {
 862         .next =         NULL,
 863         .ops =          &fat32_ops,
 864         .name =         "fat32",
 865         .block_sizes =    FAT_BLOCK_SIZES
 866 };
 867 
 868 void
 869 ped_file_system_fat_init ()
 870 {
 871         if (sizeof (FatBootSector) != 512) {
 872                 ped_exception_throw (PED_EXCEPTION_BUG, PED_EXCEPTION_CANCEL,
 873                         _("GNU Parted was miscompiled: the FAT boot sector "
 874                         "should be 512 bytes.  FAT support will be disabled."));
 875         } else {
 876                 ped_file_system_type_register (&fat16_type);
 877                 ped_file_system_type_register (&fat32_type);
 878         }
 879 }
 880 
 881 void
 882 ped_file_system_fat_done ()
 883 {
 884         ped_file_system_type_unregister (&fat16_type);
 885         ped_file_system_type_unregister (&fat32_type);
 886 }
 887