static int calc_sizes (PedSector size, PedSector align, FatType fat_type, PedSector root_dir_sectors, PedSector cluster_sectors, FatCluster* out_cluster_count, PedSector* out_fat_size) { PedSector data_fat_space; /* space available to clusters + FAT */ PedSector fat_space; /* space taken by each FAT */ PedSector cluster_space; /* space taken by clusters */ FatCluster cluster_count; int i; PED_ASSERT (out_cluster_count != NULL); PED_ASSERT (out_fat_size != NULL); data_fat_space = size - fat_min_reserved_sector_count (fat_type) - align; if (fat_type == FAT_TYPE_FAT16) data_fat_space -= root_dir_sectors; fat_space = 0; for (i = 0; i < 2; i++) { if (fat_type == FAT_TYPE_FAT32) cluster_space = data_fat_space - fat_space; else cluster_space = data_fat_space - 2 * fat_space; cluster_count = cluster_space / cluster_sectors; fat_space = ped_div_round_up (cluster_count + 2, entries_per_sector (fat_type)); } cluster_space = data_fat_space - 2 * fat_space; cluster_count = cluster_space / cluster_sectors; /* looks like this should be part of the loop condition? * Need to build the Big Table TM again to check */ if (fat_space < ped_div_round_up (cluster_count + 2, entries_per_sector (fat_type))) { fat_space = ped_div_round_up (cluster_count + 2, entries_per_sector (fat_type)); } if (cluster_count > fat_max_cluster_count (fat_type) || cluster_count < fat_min_cluster_count (fat_type)) return 0; *out_cluster_count = cluster_count; *out_fat_size = fat_space; return 1; }
/* Calculates the number of sectors needed to be added to cluster_offset, to make the cluster on the new file system match up with the ones on the old file system. However, some space is reserved by fat_calc_resize_sizes() and friends, to allow room for this space. If too much of this space is left over, everyone will complain, so we have to be greedy, and use it all up... */ PedSector fat_calc_align_sectors (const PedFileSystem* new_fs, const PedFileSystem* old_fs) { FatSpecific* old_fs_info = FAT_SPECIFIC (old_fs); FatSpecific* new_fs_info = FAT_SPECIFIC (new_fs); PedSector raw_old_meta_data_end; PedSector new_meta_data_size; PedSector min_new_meta_data_end; PedSector new_data_size; PedSector new_clusters_size; PedSector align; new_meta_data_size = fat_min_reserved_sector_count (new_fs_info->fat_type) + new_fs_info->fat_sectors * 2; if (new_fs_info->fat_type == FAT_TYPE_FAT16) new_meta_data_size += new_fs_info->root_dir_sector_count; raw_old_meta_data_end = old_fs->geom->start + old_fs_info->cluster_offset; min_new_meta_data_end = new_fs->geom->start + new_meta_data_size; if (raw_old_meta_data_end > min_new_meta_data_end) align = (raw_old_meta_data_end - min_new_meta_data_end) % new_fs_info->cluster_sectors; else align = (new_fs_info->cluster_sectors - ( (min_new_meta_data_end - raw_old_meta_data_end) % new_fs_info->cluster_sectors )) % new_fs_info->cluster_sectors; new_data_size = new_fs->geom->length - new_meta_data_size; new_clusters_size = new_fs_info->cluster_count * new_fs_info->cluster_sectors; while (new_clusters_size + align + new_fs_info->cluster_sectors <= new_data_size) align += new_fs_info->cluster_sectors; return align; }
/* 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: free (context); error_free_new_fs_info: free (new_fs_info); error_free_new_fs: free (new_fs); error: return NULL; }