1 /*
   2     libparted
   3     Copyright (C) 1998, 1999, 2000, 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 #include "traverse.h"
  22 #include "count.h"
  23 #include "fatio.h"
  24 #include "calc.h"
  25 
  26 #include <stdio.h>
  27 #include <stdlib.h>
  28 #include <sys/types.h>
  29 #include <sys/stat.h>
  30 #include <fcntl.h>
  31 #include <errno.h>
  32 #include <ctype.h>
  33 #include <stdarg.h>
  34 #include <string.h>
  35 
  36 #ifndef DISCOVER_ONLY
  37 
  38 /* Recursively builds (i.e. makes consistent) the duplicated directory tree
  39  * (leaving the original directory tree in tact)
  40  */
  41 static int
  42 fat_construct_directory (FatOpContext* ctx, FatTraverseInfo* trav_info)
  43 {
  44         FatTraverseInfo*        sub_dir_info;
  45         FatDirEntry*            dir_entry;
  46         FatCluster              old_first_cluster;
  47 
  48         while ( (dir_entry = fat_traverse_next_dir_entry (trav_info)) ) {
  49                 if (fat_dir_entry_is_null_term (dir_entry))
  50                         break;
  51                 if (!fat_dir_entry_has_first_cluster (dir_entry, ctx->old_fs))
  52                         continue;
  53 
  54                 fat_traverse_mark_dirty (trav_info);
  55 
  56                 old_first_cluster = fat_dir_entry_get_first_cluster (dir_entry,
  57                                                 ctx->old_fs);
  58                 fat_dir_entry_set_first_cluster (dir_entry, ctx->new_fs,
  59                         fat_op_context_map_cluster (ctx, old_first_cluster));
  60 
  61                 if (fat_dir_entry_is_directory (dir_entry)
  62                                 && dir_entry->name [0] != '.') {
  63                         sub_dir_info
  64                                 = fat_traverse_directory (trav_info, dir_entry);
  65                         if (!sub_dir_info)
  66                                 return 0;
  67                         if (!fat_construct_directory (ctx, sub_dir_info))
  68                                 return 0;
  69                 }
  70         }
  71         /* remove "stale" entries at the end */
  72         while ((dir_entry = fat_traverse_next_dir_entry (trav_info))) {
  73                 memset (dir_entry, 0, sizeof (FatDirEntry));
  74                 fat_traverse_mark_dirty (trav_info);
  75         }
  76         fat_traverse_complete (trav_info);
  77         return 1;
  78 }
  79 
  80 static int
  81 duplicate_legacy_root_dir (FatOpContext* ctx)
  82 {
  83         FatSpecific*            old_fs_info = FAT_SPECIFIC (ctx->old_fs);
  84         FatSpecific*            new_fs_info = FAT_SPECIFIC (ctx->new_fs);
  85 
  86         PED_ASSERT (old_fs_info->root_dir_sector_count
  87                         == new_fs_info->root_dir_sector_count, return 0);
  88 
  89         if (!ped_geometry_read (ctx->old_fs->geom, old_fs_info->buffer,
  90                                 old_fs_info->root_dir_offset,
  91                                 old_fs_info->root_dir_sector_count))
  92                 return 0;
  93 
  94         if (!ped_geometry_write (ctx->new_fs->geom, old_fs_info->buffer,
  95                                  new_fs_info->root_dir_offset,
  96                                  new_fs_info->root_dir_sector_count))
  97                 return 0;
  98 
  99         return 1;
 100 }
 101 
 102 /*
 103     Constructs the new directory tree for legacy (FAT16) file systems.
 104 */
 105 static int
 106 fat_construct_legacy_root (FatOpContext* ctx)
 107 {
 108         FatTraverseInfo*        trav_info;
 109 
 110         if (!duplicate_legacy_root_dir (ctx))
 111                 return 0;
 112         trav_info = fat_traverse_begin (ctx->new_fs, FAT_ROOT, "\\");
 113         return fat_construct_directory (ctx, trav_info);
 114 }
 115 
 116 /*
 117     Constructs the new directory tree for new (FAT32) file systems.
 118 */
 119 static int
 120 fat_construct_root (FatOpContext* ctx)
 121 {
 122         FatSpecific*            new_fs_info = FAT_SPECIFIC (ctx->new_fs);
 123         FatTraverseInfo*        trav_info;
 124 
 125         trav_info = fat_traverse_begin (ctx->new_fs, new_fs_info->root_cluster,
 126                                         "\\");
 127         fat_construct_directory (ctx, trav_info);
 128         return 1;
 129 }
 130 
 131 /* Converts the root directory between FAT16 and FAT32.  NOTE: this code
 132  * can also do no conversion.  I'm leaving fat_construct_directory(), because
 133  * it's really pretty :-)  It also leaves a higher chance of deleted file
 134  * recovery, because it doesn't remove redundant entries.  (We do this here,
 135  * because brain-damaged FAT16 has an arbitary limit on root directory entries,
 136  * so we save room)
 137  */
 138 static int
 139 fat_convert_directory (FatOpContext* ctx, FatTraverseInfo* old_trav,
 140                        FatTraverseInfo* new_trav)
 141 {
 142         FatTraverseInfo*        sub_old_dir_trav;
 143         FatTraverseInfo*        sub_new_dir_trav;
 144         FatDirEntry*            new_dir_entry;
 145         FatDirEntry*            old_dir_entry;
 146         FatCluster              old_first_cluster;
 147 
 148         while ( (old_dir_entry = fat_traverse_next_dir_entry (old_trav)) ) {
 149                 if (fat_dir_entry_is_null_term (old_dir_entry))
 150                         break;
 151                 if (!fat_dir_entry_is_active (old_dir_entry))
 152                         continue;
 153 
 154                 new_dir_entry = fat_traverse_next_dir_entry (new_trav);
 155                 if (!new_dir_entry) {
 156                         return ped_exception_throw (PED_EXCEPTION_ERROR,
 157                                 PED_EXCEPTION_IGNORE_CANCEL,
 158                                 _("There's not enough room in the root "
 159                                   "directory for all of the files.  Either "
 160                                   "cancel, or ignore to lose the files."))
 161                                         == PED_EXCEPTION_IGNORE;
 162                 }
 163 
 164                 *new_dir_entry = *old_dir_entry;
 165                 fat_traverse_mark_dirty (new_trav);
 166 
 167                 if (!fat_dir_entry_has_first_cluster (old_dir_entry,
 168                                                       ctx->old_fs))
 169                         continue;
 170 
 171                 old_first_cluster = fat_dir_entry_get_first_cluster (
 172                                                 old_dir_entry, ctx->old_fs);
 173                 fat_dir_entry_set_first_cluster (new_dir_entry, ctx->new_fs,
 174                         fat_op_context_map_cluster (ctx, old_first_cluster));
 175 
 176                 if (fat_dir_entry_is_directory (old_dir_entry)
 177                                 && old_dir_entry->name [0] != '.') {
 178                         sub_old_dir_trav
 179                             = fat_traverse_directory (old_trav, old_dir_entry);
 180                         sub_new_dir_trav
 181                             = fat_traverse_directory (new_trav, new_dir_entry);
 182                         if (!sub_old_dir_trav || !sub_new_dir_trav)
 183                                 return 0;
 184 
 185                         if (!fat_convert_directory (ctx, sub_old_dir_trav,
 186                                                     sub_new_dir_trav))
 187                                 return 0;
 188                 }
 189         }
 190 
 191         /* remove "stale" entries at the end, just in case there is some
 192          * overlap
 193          */
 194         while ((new_dir_entry = fat_traverse_next_dir_entry (new_trav))) {
 195                 memset (new_dir_entry, 0, sizeof (FatDirEntry));
 196                 fat_traverse_mark_dirty (new_trav);
 197         }
 198 
 199         fat_traverse_complete (old_trav);
 200         fat_traverse_complete (new_trav);
 201         return 1;
 202 }
 203 
 204 static void
 205 clear_cluster (PedFileSystem* fs, FatCluster cluster)
 206 {
 207         FatSpecific*            fs_info = FAT_SPECIFIC (fs);
 208 
 209         memset (fs_info->buffer, 0, fs_info->cluster_size);
 210         fat_write_cluster (fs, fs_info->buffer, cluster);
 211 }
 212 
 213 /* This MUST be called BEFORE the fat_construct_new_fat(), because cluster
 214  * allocation depend on the old FAT.  The reason is, old clusters may
 215  * still be needed during the resize, (particularly clusters in the directory
 216  * tree) even if they will be discarded later.
 217  */
 218 static int
 219 alloc_root_dir (FatOpContext* ctx)
 220 {
 221         FatSpecific*            old_fs_info = FAT_SPECIFIC (ctx->old_fs);
 222         FatSpecific*            new_fs_info = FAT_SPECIFIC (ctx->new_fs);
 223         FatCluster              i;
 224         FatCluster              cluster;
 225         FatCluster              cluster_count;
 226 
 227         PED_ASSERT (new_fs_info->fat_type == FAT_TYPE_FAT32, return 0);
 228 
 229         cluster_count = ped_div_round_up (
 230                            PED_MAX (16, old_fs_info->root_dir_sector_count),
 231                            new_fs_info->cluster_sectors);
 232 
 233         for (i = 0; i < cluster_count; i++) {
 234                 cluster = fat_table_alloc_check_cluster (new_fs_info->fat,
 235                                                          ctx->new_fs);
 236                 if (!cluster)
 237                         return 0;
 238                 ctx->new_root_dir [i] = cluster;
 239                 clear_cluster (ctx->new_fs, cluster);
 240         }
 241         ctx->new_root_dir [i] = 0;
 242         new_fs_info->root_cluster = ctx->new_root_dir [0];
 243         return 1;
 244 }
 245 
 246 /* when converting FAT32 -> FAT16
 247  * fat_duplicate clusters() duplicated the root directory unnecessarily.
 248  * Let's free it.
 249  *
 250  * This must be called AFTER fat_construct_new_fat().  (otherwise, our
 251  * changes just get overwritten)
 252  */
 253 static int
 254 free_root_dir (FatOpContext* ctx)
 255 {
 256         FatSpecific*            old_fs_info = FAT_SPECIFIC (ctx->old_fs);
 257         FatSpecific*            new_fs_info = FAT_SPECIFIC (ctx->new_fs);
 258         FatCluster              old_cluster;
 259         FatFragment             i;
 260 
 261         PED_ASSERT (old_fs_info->fat_type == FAT_TYPE_FAT32, return 0);
 262         PED_ASSERT (new_fs_info->fat_type == FAT_TYPE_FAT16, return 0);
 263 
 264         for (old_cluster = old_fs_info->root_cluster;
 265              !fat_table_is_eof (old_fs_info->fat, old_cluster);
 266              old_cluster = fat_table_get (old_fs_info->fat, old_cluster)) {
 267                 FatFragment old_frag;
 268                 old_frag = fat_cluster_to_frag (ctx->old_fs, old_cluster);
 269                 for (i = 0; i < new_fs_info->cluster_frags; i++) {
 270                         FatFragment new_frag;
 271                         FatCluster new_clst;
 272                         new_frag = fat_op_context_map_fragment (ctx,
 273                                                                 old_frag + i);
 274                         new_clst = fat_frag_to_cluster (ctx->old_fs, new_frag);
 275                         if (!fat_table_set_avail (new_fs_info->fat, new_clst))
 276                                 return 0;
 277                 }
 278         }
 279 
 280         return 1;
 281 }
 282 
 283 static int
 284 fat_clear_root_dir (PedFileSystem* fs)
 285 {
 286         FatSpecific*    fs_info = FAT_SPECIFIC (fs);
 287         int             i;
 288 
 289         PED_ASSERT (fs_info->fat_type == FAT_TYPE_FAT16, return 0);
 290         PED_ASSERT (fs_info->root_dir_sector_count, return 0);
 291 
 292         memset (fs_info->buffer, 0, 512);
 293 
 294         for (i = 0; i < fs_info->root_dir_sector_count; i++) {
 295                 if (!ped_geometry_write (fs->geom, fs_info->buffer,
 296                                          fs_info->root_dir_offset + i, 1)) {
 297                         if (ped_exception_throw (PED_EXCEPTION_ERROR,
 298                                 PED_EXCEPTION_IGNORE_CANCEL,
 299                                 _("Error writing to the root directory."))
 300                                         == PED_EXCEPTION_CANCEL)
 301                                 return 0;
 302                 }
 303         }
 304         return 1;
 305 }
 306 
 307 static int
 308 fat_construct_converted_tree (FatOpContext* ctx)
 309 {
 310         FatSpecific*            old_fs_info = FAT_SPECIFIC (ctx->old_fs);
 311         FatSpecific*            new_fs_info = FAT_SPECIFIC (ctx->new_fs);
 312         FatTraverseInfo*        old_trav_info;
 313         FatTraverseInfo*        new_trav_info;
 314 
 315         if (new_fs_info->fat_type == FAT_TYPE_FAT32) {
 316                 new_trav_info = fat_traverse_begin (ctx->new_fs,
 317                                             new_fs_info->root_cluster, "\\");
 318                 old_trav_info = fat_traverse_begin (ctx->old_fs, FAT_ROOT,
 319                                                     "\\");
 320         } else {
 321                 fat_clear_root_dir (ctx->new_fs);
 322                 new_trav_info = fat_traverse_begin (ctx->new_fs, FAT_ROOT,
 323                                                     "\\");
 324                 old_trav_info = fat_traverse_begin (ctx->old_fs,
 325                                             old_fs_info->root_cluster, "\\");
 326         }
 327         if (!new_trav_info || !old_trav_info)
 328                 return 0;
 329         if (!fat_convert_directory (ctx, old_trav_info, new_trav_info))
 330                 return 0;
 331         return 1;
 332 }
 333 
 334 /*
 335     Constructs the new directory tree to match the new file locations.
 336 */
 337 static int
 338 fat_construct_dir_tree (FatOpContext* ctx)
 339 {
 340         FatSpecific*            new_fs_info = FAT_SPECIFIC (ctx->new_fs);
 341         FatSpecific*            old_fs_info = FAT_SPECIFIC (ctx->old_fs);
 342 
 343         if (new_fs_info->fat_type == old_fs_info->fat_type) {
 344                 switch (old_fs_info->fat_type) {
 345                         case FAT_TYPE_FAT12:
 346                         PED_ASSERT (0, (void) 0);
 347                         break;
 348 
 349                         case FAT_TYPE_FAT16:
 350                         return fat_construct_legacy_root (ctx);
 351 
 352                         case FAT_TYPE_FAT32:
 353                         return fat_construct_root (ctx);
 354                 }
 355         } else {
 356                 return fat_construct_converted_tree (ctx);
 357         }
 358 
 359         return 0;
 360 }
 361 
 362 static FatFragment
 363 _get_next_old_frag (FatOpContext* ctx, FatFragment frag)
 364 {
 365         FatSpecific*    old_fs_info = FAT_SPECIFIC (ctx->old_fs);
 366         FatCluster      cluster;
 367         FatCluster      next_cluster;
 368 
 369         if ((frag + 1) % old_fs_info->cluster_frags != 0) {
 370                 if (fat_is_fragment_active (ctx->old_fs, frag + 1))
 371                         return frag + 1;
 372                 else
 373                         return -1;
 374         } else {
 375                 cluster = fat_frag_to_cluster (ctx->old_fs, frag);
 376                 next_cluster = fat_table_get (old_fs_info->fat, cluster);
 377 
 378                 if (fat_table_is_eof (old_fs_info->fat, next_cluster))
 379                         return -1;
 380                 else
 381                         return fat_cluster_to_frag (ctx->old_fs, next_cluster);
 382         }
 383 }
 384 
 385 /*
 386     Constructs the new fat for the resized file system.
 387 */
 388 static int
 389 fat_construct_new_fat (FatOpContext* ctx)
 390 {
 391         FatSpecific*    old_fs_info = FAT_SPECIFIC (ctx->old_fs);
 392         FatSpecific*    new_fs_info = FAT_SPECIFIC (ctx->new_fs);
 393         FatFragment     old_frag;
 394         FatCluster      new_cluster;
 395         FatFragment     new_frag;
 396         FatFragment     old_next_frag;
 397         FatFragment     new_next_frag;
 398         FatCluster      new_next_cluster;
 399         FatClusterFlag  flag;
 400         int             i;
 401 
 402         fat_table_clear (new_fs_info->fat);
 403         if (!fat_table_set_cluster_count (new_fs_info->fat,
 404                                           new_fs_info->cluster_count))
 405                 return 0;
 406 
 407         for (old_frag = 0; old_frag < old_fs_info->frag_count; old_frag++) {
 408                 flag = fat_get_fragment_flag (ctx->old_fs, old_frag);
 409                 if (flag == FAT_FLAG_FREE)
 410                         continue;
 411                 if (flag == FAT_FLAG_BAD) {
 412                         new_frag = fat_op_context_map_static_fragment (
 413                                                 ctx, old_frag);
 414                         if (new_frag == -1)
 415                                 continue;
 416                         new_cluster = fat_frag_to_cluster (ctx->new_fs,
 417                                                            new_frag);
 418                         fat_table_set_bad (new_fs_info->fat, new_cluster);
 419                         continue;
 420                 }
 421 
 422                 new_frag = fat_op_context_map_fragment (ctx, old_frag);
 423                 new_cluster = fat_frag_to_cluster (ctx->new_fs, new_frag);
 424 
 425                 old_next_frag = _get_next_old_frag (ctx, old_frag);
 426                 if (old_next_frag == -1) {
 427                         fat_table_set_eof (new_fs_info->fat, new_cluster);
 428                         continue;
 429                 }
 430 
 431                 new_next_frag = fat_op_context_map_fragment (ctx,
 432                                                              old_next_frag);
 433                 PED_ASSERT (new_next_frag != -1, return 0);
 434 
 435                 new_next_cluster = fat_frag_to_cluster (ctx->new_fs,
 436                                                         new_next_frag);
 437                 PED_ASSERT (new_next_cluster != new_cluster, return 0);
 438 
 439                 fat_table_set (new_fs_info->fat, new_cluster, new_next_cluster);
 440         }
 441 
 442 #if 0
 443 #ifdef PED_VERBOSE
 444         for (old_cluster=2; old_cluster < old_fs_info->cluster_count+2;
 445              old_cluster++) {
 446                 if (fat_table_is_available (old_fs_info->fat, old_cluster))
 447                         continue;
 448 
 449                 printf ("%d->%d\t(next: %d->%d)\n",
 450                         old_cluster,
 451                         ctx->remap [old_cluster],
 452                         fat_table_get (old_fs_info->fat, old_cluster),
 453                         fat_table_get (new_fs_info->fat,
 454                                        ctx->remap [old_cluster]));
 455         }
 456 #endif /* PED_VERBOSE */
 457 #endif
 458 
 459         if (old_fs_info->fat_type == FAT_TYPE_FAT32
 460             && new_fs_info->fat_type == FAT_TYPE_FAT32) {
 461                 new_fs_info->root_cluster
 462                         = fat_op_context_map_cluster (ctx,
 463                                         old_fs_info->root_cluster);
 464         }
 465 
 466         if (old_fs_info->fat_type == FAT_TYPE_FAT16
 467             && new_fs_info->fat_type == FAT_TYPE_FAT32) {
 468                 for (i=0; ctx->new_root_dir[i+1]; i++) {
 469                         fat_table_set (new_fs_info->fat,
 470                                        ctx->new_root_dir[i],
 471                                        ctx->new_root_dir[i+1]);
 472                 }
 473                 fat_table_set_eof (new_fs_info->fat, ctx->new_root_dir[i]);
 474         }
 475 
 476         return 1;
 477 }
 478 
 479 static int
 480 ask_type (PedFileSystem* fs, int fat16_ok, int fat32_ok, FatType* out_fat_type)
 481 {
 482         FatSpecific*            fs_info = FAT_SPECIFIC (fs);
 483         PedExceptionOption      status;
 484         char*                   fat16_msg;
 485         char*                   fat32_msg;
 486 
 487         if (fs_info->fat_type == FAT_TYPE_FAT16)
 488                 fat16_msg = _("If you leave your file system as FAT16, "
 489                               "then you will have no problems.");
 490         else
 491                 fat16_msg = _("If you convert to FAT16, and MS Windows "
 492                               "is installed on this partition, then "
 493                               "you must re-install the MS Windows boot "
 494                               "loader.  If you want to do this, you "
 495                               "should consult the Parted manual (or "
 496                               "your distribution's manual).");
 497 
 498         if (fs_info->fat_type == FAT_TYPE_FAT32)
 499                 fat32_msg = _("If you leave your file system as FAT32, "
 500                               "then you will not introduce any new "
 501                               "problems.");
 502         else
 503                 fat32_msg = _("If you convert to FAT32, and MS Windows "
 504                               "is installed on this partition, then "
 505                               "you must re-install the MS Windows boot "
 506                               "loader.  If you want to do this, you "
 507                               "should consult the Parted manual (or "
 508                               "your distribution's manual).  Also, "
 509                               "converting to FAT32 will make the file "
 510                               "system unreadable by MS DOS, MS Windows "
 511                               "95a, and MS Windows NT.");
 512 
 513         if (fat16_ok && fat32_ok) {
 514                 status = ped_exception_throw (
 515                          PED_EXCEPTION_INFORMATION,
 516                          PED_EXCEPTION_YES_NO_CANCEL,
 517                          _("%s  %s  %s"),
 518                          _("Would you like to use FAT32?"),
 519                          fat16_msg,
 520                          fat32_msg);
 521 
 522                 switch (status) {
 523                 case PED_EXCEPTION_YES:
 524                         *out_fat_type = FAT_TYPE_FAT32;
 525                         return 1;
 526 
 527                 case PED_EXCEPTION_NO:
 528                         *out_fat_type = FAT_TYPE_FAT16;
 529                         return 1;
 530 
 531                 case PED_EXCEPTION_UNHANDLED:
 532                         *out_fat_type = fs_info->fat_type;
 533                         return 1;
 534 
 535                 case PED_EXCEPTION_CANCEL:
 536                         return 0;
 537 
 538                 default:
 539                         PED_ASSERT (0, (void) 0);
 540                         break;
 541                 }
 542         }
 543 
 544         if (fat16_ok) {
 545                 if (fs_info->fat_type != FAT_TYPE_FAT16) {
 546                         status = ped_exception_throw (
 547                                 PED_EXCEPTION_WARNING,
 548                                 PED_EXCEPTION_OK_CANCEL,
 549                                 _("%s  %s"),
 550                                 _("The file system can only be resized to this "
 551                                   "size by converting to FAT16."),
 552                                 fat16_msg);
 553                         if (status == PED_EXCEPTION_CANCEL)
 554                                 return 0;
 555                 }
 556                 *out_fat_type = FAT_TYPE_FAT16;
 557                 return 1;
 558         }
 559 
 560         if (fat32_ok) {
 561                 if (fs_info->fat_type != FAT_TYPE_FAT32) {
 562                         status = ped_exception_throw (
 563                                 PED_EXCEPTION_WARNING,
 564                                 PED_EXCEPTION_OK_CANCEL,
 565                                 _("%s  %s"),
 566                                 _("The file system can only be resized to this "
 567                                   "size by converting to FAT32."),
 568                                 fat32_msg);
 569                         if (status == PED_EXCEPTION_CANCEL)
 570                                 return 0;
 571                 }
 572                 *out_fat_type = FAT_TYPE_FAT32;
 573                 return 1;
 574         }
 575         
 576         ped_exception_throw (
 577                 PED_EXCEPTION_NO_FEATURE,
 578                 PED_EXCEPTION_CANCEL,
 579                 _("GNU Parted cannot resize this partition to this size.  "
 580                   "We're working on it!"));
 581 
 582         return 0;
 583 }
 584 
 585 /*  For resize operations: determine if the file system must be FAT16 or FAT32,
 586  *  or either.  If the new file system must be FAT32, then query for
 587  *  confirmation.  If either file system can be used, query for which one.
 588  */
 589 static int
 590 get_fat_type (PedFileSystem* fs, const PedGeometry* new_geom,
 591               FatType* out_fat_type)
 592 {
 593         FatSpecific*            fs_info = FAT_SPECIFIC (fs);
 594         PedSector               fat16_cluster_sectors;
 595         PedSector               fat32_cluster_sectors;
 596         FatCluster              dummy_cluster_count;
 597         PedSector               dummy_fat_sectors;
 598         int                     fat16_ok;
 599         int                     fat32_ok;
 600 
 601         fat16_ok = fat_calc_resize_sizes (
 602                                     new_geom,
 603                                     fs_info->cluster_sectors,
 604                                     FAT_TYPE_FAT16,
 605                                     fs_info->root_dir_sector_count,
 606                                     fs_info->cluster_sectors,
 607                                     &fat16_cluster_sectors,
 608                                     &dummy_cluster_count,
 609                                     &dummy_fat_sectors);
 610 
 611         fat32_ok = fat_calc_resize_sizes (
 612                                     new_geom,
 613                                     fs_info->cluster_sectors,
 614                                     FAT_TYPE_FAT32,
 615                                     fs_info->root_dir_sector_count,
 616                                     fs_info->cluster_sectors,
 617                                     &fat32_cluster_sectors,
 618                                     &dummy_cluster_count,
 619                                     &dummy_fat_sectors);
 620 
 621         return ask_type (fs, fat16_ok, fat32_ok, out_fat_type);
 622 }
 623 
 624 /*  Creates the PedFileSystem struct for the new resized file system, and
 625     sticks it in a FatOpContext.  At the end of the process, the original
 626     (ctx->old_fs) is destroyed, and replaced with the new one (ctx->new_fs).
 627  */
 628 static FatOpContext*
 629 create_resize_context (PedFileSystem* fs, const PedGeometry* new_geom)
 630 {
 631         FatSpecific*    fs_info = FAT_SPECIFIC (fs);
 632         FatSpecific*    new_fs_info;
 633         PedFileSystem*  new_fs;
 634         PedSector       new_cluster_sectors;
 635         FatCluster      new_cluster_count;
 636         PedSector       new_fat_sectors;
 637         FatType         new_fat_type;
 638         PedSector       root_dir_sector_count;
 639         FatOpContext*   context;
 640 
 641         /* hypothetical number of root dir sectors, if we end up using
 642          * FAT16
 643          */
 644         if (fs_info->root_dir_sector_count)
 645                 root_dir_sector_count = fs_info->root_dir_sector_count;
 646         else
 647                 root_dir_sector_count = FAT_ROOT_DIR_ENTRY_COUNT
 648                                                 * sizeof (FatDirEntry) / 512;
 649 
 650         if (!get_fat_type (fs, new_geom, &new_fat_type))
 651                 return 0;
 652 
 653         fat_calc_resize_sizes (new_geom, fs_info->cluster_sectors, new_fat_type,
 654                 root_dir_sector_count, fs_info->cluster_sectors,
 655                 &new_cluster_sectors, &new_cluster_count, &new_fat_sectors);
 656 
 657         if (!fat_check_resize_geometry (fs, new_geom, new_cluster_sectors,
 658                                         new_cluster_count))
 659                 goto error;
 660 
 661         new_fs = fat_alloc (new_geom);
 662         if (!new_fs)
 663                 goto error;
 664 
 665         new_fs_info = FAT_SPECIFIC (new_fs);
 666         if (!new_fs_info)
 667                 goto error_free_new_fs;
 668 
 669 /* preserve boot code, etc. */
 670         memcpy (&new_fs_info->boot_sector, &fs_info->boot_sector,
 671                 sizeof (FatBootSector));
 672         memcpy (&new_fs_info->info_sector, &fs_info->info_sector,
 673                 sizeof (FatInfoSector));
 674 
 675         new_fs_info->logical_sector_size = fs_info->logical_sector_size;
 676         new_fs_info->sector_count = new_geom->length;
 677 
 678         new_fs_info->sectors_per_track = fs_info->sectors_per_track;
 679         new_fs_info->heads = fs_info->heads;
 680 
 681         new_fs_info->cluster_size = new_cluster_sectors * 512;
 682         new_fs_info->cluster_sectors = new_cluster_sectors;
 683         new_fs_info->cluster_count = new_cluster_count;
 684         new_fs_info->dir_entries_per_cluster = fs_info->dir_entries_per_cluster;
 685 
 686         new_fs_info->fat_type = new_fat_type; 
 687         new_fs_info->fat_table_count = 2;
 688         new_fs_info->fat_sectors = new_fat_sectors;
 689 
 690         /* what about copying? */
 691         new_fs_info->serial_number = fs_info->serial_number;
 692 
 693         if (new_fs_info->fat_type == FAT_TYPE_FAT32) {
 694                 new_fs_info->info_sector_offset      = 1;
 695                 new_fs_info->boot_sector_backup_offset = 6;
 696 
 697                 new_fs_info->root_dir_offset = 0;
 698                 new_fs_info->root_dir_entry_count = 0;
 699                 new_fs_info->root_dir_sector_count = 0;
 700 
 701                 /* we add calc_align_sectors to push the cluster_offset
 702                    forward, to keep the clusters aligned between the new
 703                    and old file systems
 704                  */
 705                 new_fs_info->fat_offset
 706                         = fat_min_reserved_sector_count (FAT_TYPE_FAT32)
 707                           + fat_calc_align_sectors (new_fs, fs);
 708 
 709                 new_fs_info->cluster_offset
 710                         = new_fs_info->fat_offset
 711                           + 2 * new_fs_info->fat_sectors;
 712         } else {
 713                 new_fs_info->root_dir_sector_count = root_dir_sector_count;
 714                 new_fs_info->root_dir_entry_count 
 715                         = root_dir_sector_count * 512 / sizeof (FatDirEntry);
 716 
 717                 new_fs_info->fat_offset
 718                         = fat_min_reserved_sector_count (FAT_TYPE_FAT16)
 719                           + fat_calc_align_sectors (new_fs, fs);
 720 
 721                 new_fs_info->root_dir_offset = new_fs_info->fat_offset
 722                                                + 2 * new_fs_info->fat_sectors;
 723 
 724                 new_fs_info->cluster_offset = new_fs_info->root_dir_offset
 725                                           + new_fs_info->root_dir_sector_count;
 726         }
 727         
 728         new_fs_info->total_dir_clusters = fs_info->total_dir_clusters;
 729 
 730         context = fat_op_context_new (new_fs, fs);
 731         if (!context)
 732                 goto error_free_new_fs_info;
 733 
 734         if (!fat_op_context_create_initial_fat (context))
 735                 goto error_free_context;
 736 
 737         if (!fat_alloc_buffers (new_fs))
 738                 goto error_free_fat;
 739 
 740         return context;
 741 
 742 error_free_fat:
 743         fat_table_destroy (new_fs_info->fat);
 744 error_free_context:
 745         ped_free (context);
 746 error_free_new_fs_info:
 747         ped_free (new_fs_info);
 748 error_free_new_fs:
 749         ped_free (new_fs);
 750 error:
 751         return NULL;
 752 }
 753 
 754 static int
 755 resize_context_assimilate (FatOpContext* ctx)
 756 {
 757         FatSpecific*    old_fs_info = FAT_SPECIFIC (ctx->old_fs);
 758         FatSpecific*    new_fs_info = FAT_SPECIFIC (ctx->new_fs);
 759 
 760         fat_free_buffers (ctx->old_fs);
 761         fat_table_destroy (old_fs_info->fat);
 762         ped_free (old_fs_info);
 763         ped_geometry_destroy (ctx->old_fs->geom);
 764 
 765         ctx->old_fs->type_specific = ctx->new_fs->type_specific;
 766         ctx->old_fs->geom = ctx->new_fs->geom;
 767         ctx->old_fs->type = (new_fs_info->fat_type == FAT_TYPE_FAT16)
 768                                 ? &fat16_type
 769                                 : &fat32_type;
 770 
 771         ped_free (ctx->new_fs);
 772 
 773         fat_op_context_destroy (ctx);
 774 
 775         return 1;
 776 }
 777 
 778 static int
 779 resize_context_abort (FatOpContext* ctx)
 780 {
 781         FatSpecific*    new_fs_info = FAT_SPECIFIC (ctx->new_fs);
 782 
 783         fat_free_buffers (ctx->new_fs);
 784         fat_table_destroy (new_fs_info->fat);
 785         ped_free (new_fs_info);
 786         ped_geometry_destroy (ctx->new_fs->geom);
 787         ped_free (ctx->new_fs);
 788 
 789         fat_op_context_destroy (ctx);
 790 
 791         return 1;
 792 }
 793 
 794 /* copies the "hidden" sectors, between the boot sector and the FAT.  Required,
 795  * for the Windows 98 FAT32 boot loader
 796  */
 797 int
 798 _copy_hidden_sectors (FatOpContext* ctx)
 799 {
 800         FatSpecific*    old_fs_info = FAT_SPECIFIC (ctx->old_fs);
 801         FatSpecific*    new_fs_info = FAT_SPECIFIC (ctx->new_fs);
 802         PedSector       first = 1;
 803         PedSector       last;
 804         PedSector       count;
 805 
 806         /* nothing to copy for FAT16 */
 807         if (old_fs_info->fat_type == FAT_TYPE_FAT16
 808                         || new_fs_info->fat_type == FAT_TYPE_FAT16)
 809                 return 1;
 810 
 811         last = PED_MIN (old_fs_info->fat_offset, new_fs_info->fat_offset) - 1;
 812         count = last - first + 1;
 813 
 814         PED_ASSERT (count < BUFFER_SIZE, return 0);
 815 
 816         if (!ped_geometry_read (ctx->old_fs->geom, old_fs_info->buffer,
 817                                 first, count))
 818                 return 0;
 819         if (!ped_geometry_write (ctx->new_fs->geom, old_fs_info->buffer,
 820                                  first, count))
 821                 return 0;
 822         return 1;
 823 }
 824 
 825 int
 826 fat_resize (PedFileSystem* fs, PedGeometry* geom, PedTimer* timer)
 827 {
 828         FatSpecific*    fs_info = FAT_SPECIFIC (fs);
 829         FatSpecific*    new_fs_info;
 830         FatOpContext*   ctx;
 831         PedFileSystem*  new_fs;
 832 
 833         ctx = create_resize_context (fs, geom);
 834         if (!ctx)
 835                 goto error;
 836         new_fs = ctx->new_fs;
 837         new_fs_info = FAT_SPECIFIC (new_fs);
 838 
 839         if (!fat_duplicate_clusters (ctx, timer))
 840                 goto error_abort_ctx;
 841         if (fs_info->fat_type == FAT_TYPE_FAT16
 842                         && new_fs_info->fat_type == FAT_TYPE_FAT32) {
 843                 if (!alloc_root_dir (ctx))
 844                         goto error_abort_ctx;
 845         }
 846         if (!fat_construct_new_fat (ctx))
 847                 goto error_abort_ctx;
 848         if (fs_info->fat_type == FAT_TYPE_FAT32
 849                         && new_fs_info->fat_type == FAT_TYPE_FAT16) {
 850                 if (!free_root_dir (ctx))
 851                         goto error_abort_ctx;
 852         }
 853         if (!fat_construct_dir_tree (ctx))
 854                 goto error_abort_ctx;
 855         if (!fat_table_write_all (new_fs_info->fat, new_fs))
 856                 goto error_abort_ctx;
 857 
 858         _copy_hidden_sectors (ctx);
 859         fat_boot_sector_generate (&new_fs_info->boot_sector, new_fs);
 860         fat_boot_sector_write (&new_fs_info->boot_sector, new_fs);
 861         if (new_fs_info->fat_type == FAT_TYPE_FAT32) {
 862                 fat_info_sector_generate (&new_fs_info->info_sector, new_fs);
 863                 fat_info_sector_write (&new_fs_info->info_sector, new_fs);
 864         }
 865 
 866         if (!resize_context_assimilate (ctx))
 867                 goto error;
 868 
 869         return 1;
 870 
 871 error_abort_ctx:
 872         resize_context_abort (ctx);
 873 error:
 874         return 0;
 875 }
 876 
 877 #endif /* !DISCOVER_ONLY */