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 */