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 <string.h> 21 22 #include "fat.h" 23 24 #ifndef DISCOVER_ONLY 25 26 /* Note: this deals with file system start and end sectors, even if the physical 27 * devices are different (eg for fat_copy()) Perhaps this is a hack, but it 28 * works ;-) 29 */ 30 static int 31 calc_deltas (FatOpContext* ctx) 32 { 33 PedFileSystem* old_fs = ctx->old_fs; 34 PedFileSystem* new_fs = ctx->new_fs; 35 FatSpecific* old_fs_info = FAT_SPECIFIC (old_fs); 36 FatSpecific* new_fs_info = FAT_SPECIFIC (new_fs); 37 PedSector old_cluster_ofs; 38 PedSector new_cluster_ofs; 39 PedSector sector_delta; 40 41 old_cluster_ofs = old_fs->geom->start + old_fs_info->cluster_offset; 42 new_cluster_ofs = new_fs->geom->start + new_fs_info->cluster_offset; 43 44 if (new_cluster_ofs > old_cluster_ofs) { 45 ctx->start_move_dir = FAT_DIR_FORWARD; 46 sector_delta = new_cluster_ofs - old_cluster_ofs; 47 } else { 48 ctx->start_move_dir = FAT_DIR_BACKWARD; 49 sector_delta = old_cluster_ofs - new_cluster_ofs; 50 } 51 52 if (sector_delta % new_fs_info->cluster_sectors) { 53 ped_exception_throw ( 54 PED_EXCEPTION_BUG, PED_EXCEPTION_CANCEL, 55 _("Cluster start delta = %d, which is not a multiple " 56 "of the cluster size %d."), 57 (int) sector_delta, 58 (int) new_fs_info->cluster_sectors); 59 return 0; 60 } 61 62 ctx->start_move_delta = sector_delta / ctx->frag_sectors; 63 64 #ifdef PED_VERBOSE 65 printf ("Start move delta is: %d %s.\n", 66 (int) ctx->start_move_delta, 67 (ctx->start_move_dir == FAT_DIR_FORWARD)? 68 "forwards" : "backwards"); 69 #endif 70 71 return 1; 72 } 73 74 FatOpContext* 75 fat_op_context_new (PedFileSystem* new_fs, PedFileSystem* old_fs) 76 { 77 FatSpecific* old_fs_info = FAT_SPECIFIC (old_fs); 78 FatSpecific* new_fs_info = FAT_SPECIFIC (new_fs); 79 FatOpContext* ctx; 80 81 ctx = (FatOpContext*) ped_malloc (sizeof (FatOpContext)); 82 if (!ctx) 83 goto error; 84 85 ctx->frag_sectors = PED_MIN (old_fs_info->cluster_sectors, 86 new_fs_info->cluster_sectors); 87 if (!fat_set_frag_sectors (new_fs, ctx->frag_sectors)) 88 goto error; 89 if (!fat_set_frag_sectors (old_fs, ctx->frag_sectors)) 90 goto error; 91 92 ctx->buffer_frags = old_fs_info->buffer_sectors / ctx->frag_sectors; 93 ctx->buffer_map = (FatFragment*) ped_malloc (sizeof (FatFragment) 94 * ctx->buffer_frags); 95 if (!ctx->buffer_map) 96 goto error_free_ctx; 97 98 ctx->remap = (FatFragment*) ped_malloc (sizeof (FatFragment) 99 * old_fs_info->frag_count); 100 if (!ctx->remap) 101 goto error_free_buffer_map; 102 103 ctx->new_fs = new_fs; 104 ctx->old_fs = old_fs; 105 if (!calc_deltas (ctx)) 106 goto error_free_buffer_map; 107 108 return ctx; 109 110 error_free_buffer_map: 111 ped_free (ctx->buffer_map); 112 error_free_ctx: 113 ped_free (ctx); 114 error: 115 return NULL; 116 } 117 118 void 119 fat_op_context_destroy (FatOpContext* ctx) 120 { 121 ped_free (ctx->buffer_map); 122 ped_free (ctx->remap); 123 ped_free (ctx); 124 } 125 126 FatFragment 127 fat_op_context_map_static_fragment (const FatOpContext* ctx, FatFragment frag) 128 { 129 FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs); 130 FatFragment result; 131 132 if (ctx->new_fs->geom->dev != ctx->old_fs->geom->dev) 133 return -1; 134 135 if (ctx->start_move_dir == FAT_DIR_FORWARD) { 136 if (frag < ctx->start_move_delta) 137 return -1; 138 result = frag - ctx->start_move_delta; 139 } else { 140 result = frag + ctx->start_move_delta; 141 } 142 143 if (result >= new_fs_info->frag_count) 144 return -1; 145 146 return result; 147 } 148 149 FatCluster 150 fat_op_context_map_static_cluster (const FatOpContext* ctx, FatCluster clst) 151 { 152 FatFragment mapped_frag; 153 154 mapped_frag = fat_op_context_map_static_fragment (ctx, 155 fat_cluster_to_frag (ctx->old_fs, clst)); 156 if (mapped_frag != -1) 157 return fat_frag_to_cluster (ctx->new_fs, mapped_frag); 158 else 159 return 0; 160 } 161 162 FatFragment 163 fat_op_context_map_fragment (const FatOpContext* ctx, FatFragment frag) 164 { 165 return ctx->remap [frag]; 166 } 167 168 FatCluster 169 fat_op_context_map_cluster (const FatOpContext* ctx, FatCluster clst) 170 { 171 FatFragment mapped_frag; 172 173 mapped_frag = fat_op_context_map_fragment (ctx, 174 fat_cluster_to_frag (ctx->old_fs, clst)); 175 if (mapped_frag != -1) 176 return fat_frag_to_cluster (ctx->new_fs, mapped_frag); 177 else 178 return 0; 179 } 180 181 /* This function sets the initial fat for the new resized file system. 182 This is in *NO WAY* a proper FAT table - all it does is: 183 a) mark bad clusters as bad. 184 b) mark used clusters (that is, clusters from the original FS that are 185 reachable from the resized one). Marks as EOF (i.e. used, end of 186 file chain). 187 c) mark original file system metadata as EOF (i.e. used), to prevent 188 it from being clobbered. This will leave the original file system 189 intact, until the partition table is modified, if the start of 190 the partition is moved. 191 192 The FATs are rebuilt *properly* after cluster relocation. This here is 193 only to mark clusters as used, so when cluster relocation occurs, clusters 194 aren't relocated on top of ones marked in a, b or c. 195 */ 196 int 197 fat_op_context_create_initial_fat (FatOpContext* ctx) 198 { 199 FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs); 200 FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs); 201 FatCluster clst; 202 FatCluster new_clst; 203 PedSector sect; 204 PedSector new_sect; 205 FatFragment frag; 206 FatFragment new_frag; 207 FatClusterFlag frag_flag; 208 209 new_fs_info->fat = fat_table_new ( 210 new_fs_info->fat_type, 211 new_fs_info->fat_sectors * 512 212 / fat_table_entry_size (new_fs_info->fat_type)); 213 if (!new_fs_info->fat) 214 return 0; 215 216 if (!fat_table_set_cluster_count (new_fs_info->fat, 217 new_fs_info->cluster_count)) 218 return 0; 219 220 /* mark bad and used clusters */ 221 for (frag = 0; frag < old_fs_info->frag_count; frag++) { 222 frag_flag = fat_get_fragment_flag (ctx->old_fs, frag); 223 if (frag_flag == FAT_FLAG_FREE) 224 continue; 225 226 new_frag = fat_op_context_map_static_fragment (ctx, frag); 227 if (new_frag == -1) 228 continue; 229 230 new_clst = fat_frag_to_cluster (ctx->new_fs, new_frag); 231 PED_ASSERT (new_clst != 0, return 0); 232 233 if (frag_flag == FAT_FLAG_BAD) { 234 if (!fat_table_set_bad (new_fs_info->fat, new_clst)) 235 return 0; 236 } else { 237 if (!fat_table_set_eof (new_fs_info->fat, new_clst)) 238 return 0; 239 } 240 } 241 242 /* mark metadata regions that map to clusters on the new FS */ 243 for (sect = 0; sect < old_fs_info->cluster_offset; sect++) { 244 new_sect = ped_geometry_map (ctx->new_fs->geom, 245 ctx->old_fs->geom, sect); 246 if (new_sect == -1 247 || !fat_is_sector_in_clusters (ctx->new_fs, new_sect)) 248 continue; 249 250 clst = fat_sector_to_cluster (ctx->new_fs, new_sect); 251 PED_ASSERT (clst != 0, return 0); 252 253 if (!fat_table_set_eof (new_fs_info->fat, clst)) 254 return 0; 255 } 256 257 return 1; 258 } 259 260 #endif /* !DISCOVER_ONLY */