/* libparted Copyright (C) 1998, 1999, 2000, 2007 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "fat.h" #include "traverse.h" #include "count.h" #include "fatio.h" #include "calc.h" #include #include #include #include #include #include #include #include #include #ifndef DISCOVER_ONLY /* Recursively builds (i.e. makes consistent) the duplicated directory tree * (leaving the original directory tree in tact) */ static int fat_construct_directory (FatOpContext* ctx, FatTraverseInfo* trav_info) { FatTraverseInfo* sub_dir_info; FatDirEntry* dir_entry; FatCluster old_first_cluster; while ( (dir_entry = fat_traverse_next_dir_entry (trav_info)) ) { if (fat_dir_entry_is_null_term (dir_entry)) break; if (!fat_dir_entry_has_first_cluster (dir_entry, ctx->old_fs)) continue; fat_traverse_mark_dirty (trav_info); old_first_cluster = fat_dir_entry_get_first_cluster (dir_entry, ctx->old_fs); fat_dir_entry_set_first_cluster (dir_entry, ctx->new_fs, fat_op_context_map_cluster (ctx, old_first_cluster)); if (fat_dir_entry_is_directory (dir_entry) && dir_entry->name [0] != '.') { sub_dir_info = fat_traverse_directory (trav_info, dir_entry); if (!sub_dir_info) return 0; if (!fat_construct_directory (ctx, sub_dir_info)) return 0; } } /* remove "stale" entries at the end */ while ((dir_entry = fat_traverse_next_dir_entry (trav_info))) { memset (dir_entry, 0, sizeof (FatDirEntry)); fat_traverse_mark_dirty (trav_info); } fat_traverse_complete (trav_info); return 1; } static int duplicate_legacy_root_dir (FatOpContext* ctx) { FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs); FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs); PED_ASSERT (old_fs_info->root_dir_sector_count == new_fs_info->root_dir_sector_count, return 0); if (!ped_geometry_read (ctx->old_fs->geom, old_fs_info->buffer, old_fs_info->root_dir_offset, old_fs_info->root_dir_sector_count)) return 0; if (!ped_geometry_write (ctx->new_fs->geom, old_fs_info->buffer, new_fs_info->root_dir_offset, new_fs_info->root_dir_sector_count)) return 0; return 1; } /* Constructs the new directory tree for legacy (FAT16) file systems. */ static int fat_construct_legacy_root (FatOpContext* ctx) { FatTraverseInfo* trav_info; if (!duplicate_legacy_root_dir (ctx)) return 0; trav_info = fat_traverse_begin (ctx->new_fs, FAT_ROOT, "\\"); return fat_construct_directory (ctx, trav_info); } /* Constructs the new directory tree for new (FAT32) file systems. */ static int fat_construct_root (FatOpContext* ctx) { FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs); FatTraverseInfo* trav_info; trav_info = fat_traverse_begin (ctx->new_fs, new_fs_info->root_cluster, "\\"); fat_construct_directory (ctx, trav_info); return 1; } /* Converts the root directory between FAT16 and FAT32. NOTE: this code * can also do no conversion. I'm leaving fat_construct_directory(), because * it's really pretty :-) It also leaves a higher chance of deleted file * recovery, because it doesn't remove redundant entries. (We do this here, * because brain-damaged FAT16 has an arbitary limit on root directory entries, * so we save room) */ static int fat_convert_directory (FatOpContext* ctx, FatTraverseInfo* old_trav, FatTraverseInfo* new_trav) { FatTraverseInfo* sub_old_dir_trav; FatTraverseInfo* sub_new_dir_trav; FatDirEntry* new_dir_entry; FatDirEntry* old_dir_entry; FatCluster old_first_cluster; while ( (old_dir_entry = fat_traverse_next_dir_entry (old_trav)) ) { if (fat_dir_entry_is_null_term (old_dir_entry)) break; if (!fat_dir_entry_is_active (old_dir_entry)) continue; new_dir_entry = fat_traverse_next_dir_entry (new_trav); if (!new_dir_entry) { return ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_IGNORE_CANCEL, _("There's not enough room in the root " "directory for all of the files. Either " "cancel, or ignore to lose the files.")) == PED_EXCEPTION_IGNORE; } *new_dir_entry = *old_dir_entry; fat_traverse_mark_dirty (new_trav); if (!fat_dir_entry_has_first_cluster (old_dir_entry, ctx->old_fs)) continue; old_first_cluster = fat_dir_entry_get_first_cluster ( old_dir_entry, ctx->old_fs); fat_dir_entry_set_first_cluster (new_dir_entry, ctx->new_fs, fat_op_context_map_cluster (ctx, old_first_cluster)); if (fat_dir_entry_is_directory (old_dir_entry) && old_dir_entry->name [0] != '.') { sub_old_dir_trav = fat_traverse_directory (old_trav, old_dir_entry); sub_new_dir_trav = fat_traverse_directory (new_trav, new_dir_entry); if (!sub_old_dir_trav || !sub_new_dir_trav) return 0; if (!fat_convert_directory (ctx, sub_old_dir_trav, sub_new_dir_trav)) return 0; } } /* remove "stale" entries at the end, just in case there is some * overlap */ while ((new_dir_entry = fat_traverse_next_dir_entry (new_trav))) { memset (new_dir_entry, 0, sizeof (FatDirEntry)); fat_traverse_mark_dirty (new_trav); } fat_traverse_complete (old_trav); fat_traverse_complete (new_trav); return 1; } static void clear_cluster (PedFileSystem* fs, FatCluster cluster) { FatSpecific* fs_info = FAT_SPECIFIC (fs); memset (fs_info->buffer, 0, fs_info->cluster_size); fat_write_cluster (fs, fs_info->buffer, cluster); } /* This MUST be called BEFORE the fat_construct_new_fat(), because cluster * allocation depend on the old FAT. The reason is, old clusters may * still be needed during the resize, (particularly clusters in the directory * tree) even if they will be discarded later. */ static int alloc_root_dir (FatOpContext* ctx) { FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs); FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs); FatCluster i; FatCluster cluster; FatCluster cluster_count; PED_ASSERT (new_fs_info->fat_type == FAT_TYPE_FAT32, return 0); cluster_count = ped_div_round_up ( PED_MAX (16, old_fs_info->root_dir_sector_count), new_fs_info->cluster_sectors); for (i = 0; i < cluster_count; i++) { cluster = fat_table_alloc_check_cluster (new_fs_info->fat, ctx->new_fs); if (!cluster) return 0; ctx->new_root_dir [i] = cluster; clear_cluster (ctx->new_fs, cluster); } ctx->new_root_dir [i] = 0; new_fs_info->root_cluster = ctx->new_root_dir [0]; return 1; } /* when converting FAT32 -> FAT16 * fat_duplicate clusters() duplicated the root directory unnecessarily. * Let's free it. * * This must be called AFTER fat_construct_new_fat(). (otherwise, our * changes just get overwritten) */ static int free_root_dir (FatOpContext* ctx) { FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs); FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs); FatCluster old_cluster; FatFragment i; PED_ASSERT (old_fs_info->fat_type == FAT_TYPE_FAT32, return 0); PED_ASSERT (new_fs_info->fat_type == FAT_TYPE_FAT16, return 0); for (old_cluster = old_fs_info->root_cluster; !fat_table_is_eof (old_fs_info->fat, old_cluster); old_cluster = fat_table_get (old_fs_info->fat, old_cluster)) { FatFragment old_frag; old_frag = fat_cluster_to_frag (ctx->old_fs, old_cluster); for (i = 0; i < new_fs_info->cluster_frags; i++) { FatFragment new_frag; FatCluster new_clst; new_frag = fat_op_context_map_fragment (ctx, old_frag + i); new_clst = fat_frag_to_cluster (ctx->old_fs, new_frag); if (!fat_table_set_avail (new_fs_info->fat, new_clst)) return 0; } } return 1; } static int fat_clear_root_dir (PedFileSystem* fs) { FatSpecific* fs_info = FAT_SPECIFIC (fs); int i; PED_ASSERT (fs_info->fat_type == FAT_TYPE_FAT16, return 0); PED_ASSERT (fs_info->root_dir_sector_count, return 0); memset (fs_info->buffer, 0, 512); for (i = 0; i < fs_info->root_dir_sector_count; i++) { if (!ped_geometry_write (fs->geom, fs_info->buffer, fs_info->root_dir_offset + i, 1)) { if (ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_IGNORE_CANCEL, _("Error writing to the root directory.")) == PED_EXCEPTION_CANCEL) return 0; } } return 1; } static int fat_construct_converted_tree (FatOpContext* ctx) { FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs); FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs); FatTraverseInfo* old_trav_info; FatTraverseInfo* new_trav_info; if (new_fs_info->fat_type == FAT_TYPE_FAT32) { new_trav_info = fat_traverse_begin (ctx->new_fs, new_fs_info->root_cluster, "\\"); old_trav_info = fat_traverse_begin (ctx->old_fs, FAT_ROOT, "\\"); } else { fat_clear_root_dir (ctx->new_fs); new_trav_info = fat_traverse_begin (ctx->new_fs, FAT_ROOT, "\\"); old_trav_info = fat_traverse_begin (ctx->old_fs, old_fs_info->root_cluster, "\\"); } if (!new_trav_info || !old_trav_info) return 0; if (!fat_convert_directory (ctx, old_trav_info, new_trav_info)) return 0; return 1; } /* Constructs the new directory tree to match the new file locations. */ static int fat_construct_dir_tree (FatOpContext* ctx) { FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs); FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs); if (new_fs_info->fat_type == old_fs_info->fat_type) { switch (old_fs_info->fat_type) { case FAT_TYPE_FAT12: PED_ASSERT (0, (void) 0); break; case FAT_TYPE_FAT16: return fat_construct_legacy_root (ctx); case FAT_TYPE_FAT32: return fat_construct_root (ctx); } } else { return fat_construct_converted_tree (ctx); } return 0; } static FatFragment _get_next_old_frag (FatOpContext* ctx, FatFragment frag) { FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs); FatCluster cluster; FatCluster next_cluster; if ((frag + 1) % old_fs_info->cluster_frags != 0) { if (fat_is_fragment_active (ctx->old_fs, frag + 1)) return frag + 1; else return -1; } else { cluster = fat_frag_to_cluster (ctx->old_fs, frag); next_cluster = fat_table_get (old_fs_info->fat, cluster); if (fat_table_is_eof (old_fs_info->fat, next_cluster)) return -1; else return fat_cluster_to_frag (ctx->old_fs, next_cluster); } } /* Constructs the new fat for the resized file system. */ static int fat_construct_new_fat (FatOpContext* ctx) { FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs); FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs); FatFragment old_frag; FatCluster new_cluster; FatFragment new_frag; FatFragment old_next_frag; FatFragment new_next_frag; FatCluster new_next_cluster; FatClusterFlag flag; int i; fat_table_clear (new_fs_info->fat); if (!fat_table_set_cluster_count (new_fs_info->fat, new_fs_info->cluster_count)) return 0; for (old_frag = 0; old_frag < old_fs_info->frag_count; old_frag++) { flag = fat_get_fragment_flag (ctx->old_fs, old_frag); if (flag == FAT_FLAG_FREE) continue; if (flag == FAT_FLAG_BAD) { new_frag = fat_op_context_map_static_fragment ( ctx, old_frag); if (new_frag == -1) continue; new_cluster = fat_frag_to_cluster (ctx->new_fs, new_frag); fat_table_set_bad (new_fs_info->fat, new_cluster); continue; } new_frag = fat_op_context_map_fragment (ctx, old_frag); new_cluster = fat_frag_to_cluster (ctx->new_fs, new_frag); old_next_frag = _get_next_old_frag (ctx, old_frag); if (old_next_frag == -1) { fat_table_set_eof (new_fs_info->fat, new_cluster); continue; } new_next_frag = fat_op_context_map_fragment (ctx, old_next_frag); PED_ASSERT (new_next_frag != -1, return 0); new_next_cluster = fat_frag_to_cluster (ctx->new_fs, new_next_frag); PED_ASSERT (new_next_cluster != new_cluster, return 0); fat_table_set (new_fs_info->fat, new_cluster, new_next_cluster); } #if 0 #ifdef PED_VERBOSE for (old_cluster=2; old_cluster < old_fs_info->cluster_count+2; old_cluster++) { if (fat_table_is_available (old_fs_info->fat, old_cluster)) continue; printf ("%d->%d\t(next: %d->%d)\n", old_cluster, ctx->remap [old_cluster], fat_table_get (old_fs_info->fat, old_cluster), fat_table_get (new_fs_info->fat, ctx->remap [old_cluster])); } #endif /* PED_VERBOSE */ #endif if (old_fs_info->fat_type == FAT_TYPE_FAT32 && new_fs_info->fat_type == FAT_TYPE_FAT32) { new_fs_info->root_cluster = fat_op_context_map_cluster (ctx, old_fs_info->root_cluster); } if (old_fs_info->fat_type == FAT_TYPE_FAT16 && new_fs_info->fat_type == FAT_TYPE_FAT32) { for (i=0; ctx->new_root_dir[i+1]; i++) { fat_table_set (new_fs_info->fat, ctx->new_root_dir[i], ctx->new_root_dir[i+1]); } fat_table_set_eof (new_fs_info->fat, ctx->new_root_dir[i]); } return 1; } static int ask_type (PedFileSystem* fs, int fat16_ok, int fat32_ok, FatType* out_fat_type) { FatSpecific* fs_info = FAT_SPECIFIC (fs); PedExceptionOption status; char* fat16_msg; char* fat32_msg; if (fs_info->fat_type == FAT_TYPE_FAT16) fat16_msg = _("If you leave your file system as FAT16, " "then you will have no problems."); else fat16_msg = _("If you convert to FAT16, and MS Windows " "is installed on this partition, then " "you must re-install the MS Windows boot " "loader. If you want to do this, you " "should consult the Parted manual (or " "your distribution's manual)."); if (fs_info->fat_type == FAT_TYPE_FAT32) fat32_msg = _("If you leave your file system as FAT32, " "then you will not introduce any new " "problems."); else fat32_msg = _("If you convert to FAT32, and MS Windows " "is installed on this partition, then " "you must re-install the MS Windows boot " "loader. If you want to do this, you " "should consult the Parted manual (or " "your distribution's manual). Also, " "converting to FAT32 will make the file " "system unreadable by MS DOS, MS Windows " "95a, and MS Windows NT."); if (fat16_ok && fat32_ok) { status = ped_exception_throw ( PED_EXCEPTION_INFORMATION, PED_EXCEPTION_YES_NO_CANCEL, _("%s %s %s"), _("Would you like to use FAT32?"), fat16_msg, fat32_msg); switch (status) { case PED_EXCEPTION_YES: *out_fat_type = FAT_TYPE_FAT32; return 1; case PED_EXCEPTION_NO: *out_fat_type = FAT_TYPE_FAT16; return 1; case PED_EXCEPTION_UNHANDLED: *out_fat_type = fs_info->fat_type; return 1; case PED_EXCEPTION_CANCEL: return 0; default: PED_ASSERT (0, (void) 0); break; } } if (fat16_ok) { if (fs_info->fat_type != FAT_TYPE_FAT16) { status = ped_exception_throw ( PED_EXCEPTION_WARNING, PED_EXCEPTION_OK_CANCEL, _("%s %s"), _("The file system can only be resized to this " "size by converting to FAT16."), fat16_msg); if (status == PED_EXCEPTION_CANCEL) return 0; } *out_fat_type = FAT_TYPE_FAT16; return 1; } if (fat32_ok) { if (fs_info->fat_type != FAT_TYPE_FAT32) { status = ped_exception_throw ( PED_EXCEPTION_WARNING, PED_EXCEPTION_OK_CANCEL, _("%s %s"), _("The file system can only be resized to this " "size by converting to FAT32."), fat32_msg); if (status == PED_EXCEPTION_CANCEL) return 0; } *out_fat_type = FAT_TYPE_FAT32; return 1; } ped_exception_throw ( PED_EXCEPTION_NO_FEATURE, PED_EXCEPTION_CANCEL, _("GNU Parted cannot resize this partition to this size. " "We're working on it!")); return 0; } /* For resize operations: determine if the file system must be FAT16 or FAT32, * or either. If the new file system must be FAT32, then query for * confirmation. If either file system can be used, query for which one. */ static int get_fat_type (PedFileSystem* fs, const PedGeometry* new_geom, FatType* out_fat_type) { FatSpecific* fs_info = FAT_SPECIFIC (fs); PedSector fat16_cluster_sectors; PedSector fat32_cluster_sectors; FatCluster dummy_cluster_count; PedSector dummy_fat_sectors; int fat16_ok; int fat32_ok; fat16_ok = fat_calc_resize_sizes ( new_geom, fs_info->cluster_sectors, FAT_TYPE_FAT16, fs_info->root_dir_sector_count, fs_info->cluster_sectors, &fat16_cluster_sectors, &dummy_cluster_count, &dummy_fat_sectors); fat32_ok = fat_calc_resize_sizes ( new_geom, fs_info->cluster_sectors, FAT_TYPE_FAT32, fs_info->root_dir_sector_count, fs_info->cluster_sectors, &fat32_cluster_sectors, &dummy_cluster_count, &dummy_fat_sectors); return ask_type (fs, fat16_ok, fat32_ok, out_fat_type); } /* Creates the PedFileSystem struct for the new resized file system, and sticks it in a FatOpContext. At the end of the process, the original (ctx->old_fs) is destroyed, and replaced with the new one (ctx->new_fs). */ static FatOpContext* create_resize_context (PedFileSystem* fs, const PedGeometry* new_geom) { FatSpecific* fs_info = FAT_SPECIFIC (fs); FatSpecific* new_fs_info; PedFileSystem* new_fs; PedSector new_cluster_sectors; FatCluster new_cluster_count; PedSector new_fat_sectors; FatType new_fat_type; PedSector root_dir_sector_count; FatOpContext* context; /* hypothetical number of root dir sectors, if we end up using * FAT16 */ if (fs_info->root_dir_sector_count) root_dir_sector_count = fs_info->root_dir_sector_count; else root_dir_sector_count = FAT_ROOT_DIR_ENTRY_COUNT * sizeof (FatDirEntry) / 512; if (!get_fat_type (fs, new_geom, &new_fat_type)) return 0; fat_calc_resize_sizes (new_geom, fs_info->cluster_sectors, new_fat_type, root_dir_sector_count, fs_info->cluster_sectors, &new_cluster_sectors, &new_cluster_count, &new_fat_sectors); if (!fat_check_resize_geometry (fs, new_geom, new_cluster_sectors, new_cluster_count)) goto error; new_fs = fat_alloc (new_geom); if (!new_fs) goto error; new_fs_info = FAT_SPECIFIC (new_fs); if (!new_fs_info) goto error_free_new_fs; /* preserve boot code, etc. */ memcpy (&new_fs_info->boot_sector, &fs_info->boot_sector, sizeof (FatBootSector)); memcpy (&new_fs_info->info_sector, &fs_info->info_sector, sizeof (FatInfoSector)); new_fs_info->logical_sector_size = fs_info->logical_sector_size; new_fs_info->sector_count = new_geom->length; new_fs_info->sectors_per_track = fs_info->sectors_per_track; new_fs_info->heads = fs_info->heads; new_fs_info->cluster_size = new_cluster_sectors * 512; new_fs_info->cluster_sectors = new_cluster_sectors; new_fs_info->cluster_count = new_cluster_count; new_fs_info->dir_entries_per_cluster = fs_info->dir_entries_per_cluster; new_fs_info->fat_type = new_fat_type; new_fs_info->fat_table_count = 2; new_fs_info->fat_sectors = new_fat_sectors; /* what about copying? */ new_fs_info->serial_number = fs_info->serial_number; if (new_fs_info->fat_type == FAT_TYPE_FAT32) { new_fs_info->info_sector_offset = 1; new_fs_info->boot_sector_backup_offset = 6; new_fs_info->root_dir_offset = 0; new_fs_info->root_dir_entry_count = 0; new_fs_info->root_dir_sector_count = 0; /* we add calc_align_sectors to push the cluster_offset forward, to keep the clusters aligned between the new and old file systems */ new_fs_info->fat_offset = fat_min_reserved_sector_count (FAT_TYPE_FAT32) + fat_calc_align_sectors (new_fs, fs); new_fs_info->cluster_offset = new_fs_info->fat_offset + 2 * new_fs_info->fat_sectors; } else { new_fs_info->root_dir_sector_count = root_dir_sector_count; new_fs_info->root_dir_entry_count = root_dir_sector_count * 512 / sizeof (FatDirEntry); new_fs_info->fat_offset = fat_min_reserved_sector_count (FAT_TYPE_FAT16) + fat_calc_align_sectors (new_fs, fs); new_fs_info->root_dir_offset = new_fs_info->fat_offset + 2 * new_fs_info->fat_sectors; new_fs_info->cluster_offset = new_fs_info->root_dir_offset + new_fs_info->root_dir_sector_count; } new_fs_info->total_dir_clusters = fs_info->total_dir_clusters; context = fat_op_context_new (new_fs, fs); if (!context) goto error_free_new_fs_info; if (!fat_op_context_create_initial_fat (context)) goto error_free_context; if (!fat_alloc_buffers (new_fs)) goto error_free_fat; return context; error_free_fat: fat_table_destroy (new_fs_info->fat); error_free_context: ped_free (context); error_free_new_fs_info: ped_free (new_fs_info); error_free_new_fs: ped_free (new_fs); error: return NULL; } static int resize_context_assimilate (FatOpContext* ctx) { FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs); FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs); fat_free_buffers (ctx->old_fs); fat_table_destroy (old_fs_info->fat); ped_free (old_fs_info); ped_geometry_destroy (ctx->old_fs->geom); ctx->old_fs->type_specific = ctx->new_fs->type_specific; ctx->old_fs->geom = ctx->new_fs->geom; ctx->old_fs->type = (new_fs_info->fat_type == FAT_TYPE_FAT16) ? &fat16_type : &fat32_type; ped_free (ctx->new_fs); fat_op_context_destroy (ctx); return 1; } static int resize_context_abort (FatOpContext* ctx) { FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs); fat_free_buffers (ctx->new_fs); fat_table_destroy (new_fs_info->fat); ped_free (new_fs_info); ped_geometry_destroy (ctx->new_fs->geom); ped_free (ctx->new_fs); fat_op_context_destroy (ctx); return 1; } /* copies the "hidden" sectors, between the boot sector and the FAT. Required, * for the Windows 98 FAT32 boot loader */ int _copy_hidden_sectors (FatOpContext* ctx) { FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs); FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs); PedSector first = 1; PedSector last; PedSector count; /* nothing to copy for FAT16 */ if (old_fs_info->fat_type == FAT_TYPE_FAT16 || new_fs_info->fat_type == FAT_TYPE_FAT16) return 1; last = PED_MIN (old_fs_info->fat_offset, new_fs_info->fat_offset) - 1; count = last - first + 1; PED_ASSERT (count < BUFFER_SIZE, return 0); if (!ped_geometry_read (ctx->old_fs->geom, old_fs_info->buffer, first, count)) return 0; if (!ped_geometry_write (ctx->new_fs->geom, old_fs_info->buffer, first, count)) return 0; return 1; } int fat_resize (PedFileSystem* fs, PedGeometry* geom, PedTimer* timer) { FatSpecific* fs_info = FAT_SPECIFIC (fs); FatSpecific* new_fs_info; FatOpContext* ctx; PedFileSystem* new_fs; ctx = create_resize_context (fs, geom); if (!ctx) goto error; new_fs = ctx->new_fs; new_fs_info = FAT_SPECIFIC (new_fs); if (!fat_duplicate_clusters (ctx, timer)) goto error_abort_ctx; if (fs_info->fat_type == FAT_TYPE_FAT16 && new_fs_info->fat_type == FAT_TYPE_FAT32) { if (!alloc_root_dir (ctx)) goto error_abort_ctx; } if (!fat_construct_new_fat (ctx)) goto error_abort_ctx; if (fs_info->fat_type == FAT_TYPE_FAT32 && new_fs_info->fat_type == FAT_TYPE_FAT16) { if (!free_root_dir (ctx)) goto error_abort_ctx; } if (!fat_construct_dir_tree (ctx)) goto error_abort_ctx; if (!fat_table_write_all (new_fs_info->fat, new_fs)) goto error_abort_ctx; _copy_hidden_sectors (ctx); fat_boot_sector_generate (&new_fs_info->boot_sector, new_fs); fat_boot_sector_write (&new_fs_info->boot_sector, new_fs); if (new_fs_info->fat_type == FAT_TYPE_FAT32) { fat_info_sector_generate (&new_fs_info->info_sector, new_fs); fat_info_sector_write (&new_fs_info->info_sector, new_fs); } if (!resize_context_assimilate (ctx)) goto error; return 1; error_abort_ctx: resize_context_abort (ctx); error: return 0; } #endif /* !DISCOVER_ONLY */