1 /*
   2     libparted
   3     Copyright (C) 1998, 1999, 2000, 2001, 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 static int
  27 needs_duplicating (const FatOpContext* ctx, FatFragment frag)
  28 {
  29         FatSpecific*    old_fs_info = FAT_SPECIFIC (ctx->old_fs);
  30         FatCluster      cluster = fat_frag_to_cluster (ctx->old_fs, frag);
  31         FatClusterFlag  flag;
  32 
  33         PED_ASSERT (cluster >= 2 && cluster < old_fs_info->cluster_count + 2,
  34                     return 0);
  35 
  36         flag = fat_get_fragment_flag (ctx->old_fs, frag);
  37         switch (flag) {
  38         case FAT_FLAG_FREE:
  39                 return 0;
  40 
  41         case FAT_FLAG_DIRECTORY:
  42                 return 1;
  43 
  44         case FAT_FLAG_FILE:
  45                 return fat_op_context_map_static_fragment (ctx, frag) == -1;
  46         
  47         case FAT_FLAG_BAD:
  48                 return 0;
  49         }
  50 
  51         return 0;
  52 }
  53 
  54 static int
  55 search_next_fragment (FatOpContext* ctx)
  56 {
  57         FatSpecific*    fs_info = FAT_SPECIFIC (ctx->old_fs);
  58 
  59         for (; ctx->buffer_offset < fs_info->frag_count; ctx->buffer_offset++) {
  60                 if (needs_duplicating (ctx, ctx->buffer_offset))
  61                         return 1;
  62         }
  63         return 0;       /* all done! */
  64 }
  65 
  66 static int
  67 read_marked_fragments (FatOpContext* ctx, FatFragment length)
  68 {
  69         FatSpecific*            fs_info = FAT_SPECIFIC (ctx->old_fs);
  70         int                     status;
  71         FatFragment             i;
  72 
  73         ped_exception_fetch_all ();
  74         status = fat_read_fragments (ctx->old_fs, fs_info->buffer,
  75                                      ctx->buffer_offset, length);
  76         ped_exception_leave_all ();
  77         if (status)
  78                 return 1;
  79 
  80         ped_exception_catch ();
  81 
  82 /* something bad happened, so read fragments one by one.  (The error may
  83    have occurred on an unused fragment: who cares) */
  84         for (i = 0; i < length; i++) {
  85                 if (ctx->buffer_map [i]) {
  86                         if (!fat_read_fragment (ctx->old_fs,
  87                               fs_info->buffer + i * fs_info->frag_size,
  88                               ctx->buffer_offset + i))
  89                                 return 0;
  90                 }
  91         }
  92 
  93         return 1;
  94 }
  95 
  96 static int
  97 fetch_fragments (FatOpContext* ctx)
  98 {
  99         FatSpecific*    old_fs_info = FAT_SPECIFIC (ctx->old_fs);
 100         FatFragment     fetch_length = 0;
 101         FatFragment     frag;
 102 
 103         for (frag = 0; frag < ctx->buffer_frags; frag++)
 104                 ctx->buffer_map [frag] = -1;
 105 
 106         for (frag = 0;
 107              frag < ctx->buffer_frags
 108                 && ctx->buffer_offset + frag < old_fs_info->frag_count;
 109              frag++) {
 110                 if (needs_duplicating (ctx, ctx->buffer_offset + frag)) {
 111                         ctx->buffer_map [frag] = 1;
 112                         fetch_length = frag + 1;
 113                 }
 114         }
 115 
 116         if (!read_marked_fragments (ctx, fetch_length))
 117                 return 0;
 118 
 119         return 1;
 120 }
 121 
 122 /*****************************************************************************
 123  * here starts the write code.  All assumes that ctx->buffer_map [first] and
 124  * ctx->buffer_map [last] are occupied by fragments that need to be duplicated.
 125  *****************************************************************************/
 126 
 127 /* finds the first fragment that is not going to get overwritten (that needs to
 128    get read in) */
 129 static FatFragment
 130 get_first_underlay (const FatOpContext* ctx, int first, int last)
 131 {
 132         int             old;
 133         FatFragment     new;
 134 
 135         PED_ASSERT (first <= last, return 0);
 136 
 137         new = ctx->buffer_map [first];
 138         for (old = first + 1; old <= last; old++) {
 139                 if (ctx->buffer_map [old] == -1)
 140                         continue;
 141                 new++;
 142                 if (ctx->buffer_map [old] != new)
 143                         return new;
 144         }
 145         return -1;
 146 }
 147 
 148 /* finds the last fragment that is not going to get overwritten (that needs to
 149    get read in) */
 150 static FatFragment
 151 get_last_underlay (const FatOpContext* ctx, int first, int last)
 152 {
 153         int             old;
 154         FatFragment     new;
 155 
 156         PED_ASSERT (first <= last, return 0);
 157 
 158         new = ctx->buffer_map [last];
 159         for (old = last - 1; old >= first; old--) {
 160                 if (ctx->buffer_map [old] == -1)
 161                         continue;
 162                 new--;
 163                 if (ctx->buffer_map [old] != new)
 164                         return new;
 165         }
 166         return -1;
 167 }
 168 
 169 /* "underlay" refers to the "static" fragments, that remain unchanged.
 170  * when writing large chunks at a time, we don't want to clobber these,
 171  * so we read them in, and write them back again.  MUCH quicker that way.
 172  */
 173 static int
 174 quick_group_write_read_underlay (FatOpContext* ctx, int first, int last)
 175 {
 176         FatSpecific*    new_fs_info = FAT_SPECIFIC (ctx->new_fs);
 177         FatFragment     first_underlay;
 178         FatFragment     last_underlay;
 179         FatFragment     underlay_length;
 180 
 181         PED_ASSERT (first <= last, return 0);
 182 
 183         first_underlay = get_first_underlay (ctx, first, last);
 184         if (first_underlay == -1)
 185                 return 1;
 186         last_underlay = get_last_underlay (ctx, first, last);
 187 
 188         PED_ASSERT (first_underlay <= last_underlay, return 0);
 189 
 190         underlay_length = last_underlay - first_underlay + 1;
 191         if (!fat_read_fragments (ctx->new_fs,
 192                                 new_fs_info->buffer 
 193                                    + (first_underlay - ctx->buffer_map [first])
 194                                         * new_fs_info->frag_size,
 195                                 first_underlay,
 196                                 underlay_length))
 197                 return 0;
 198         return 1;
 199 }
 200 
 201 /* quick_group_write() makes no attempt to recover from errors - just
 202  * does things fast.  If there is an error, slow_group_write() is
 203  * called.
 204  *    Note: we do syncing writes, to make sure there isn't any
 205  * error writing out.  It's rather difficult recovering from errors
 206  * further on.
 207  */
 208 static int
 209 quick_group_write (FatOpContext* ctx, int first, int last)
 210 {
 211         FatSpecific*            old_fs_info = FAT_SPECIFIC (ctx->old_fs);
 212         FatSpecific*            new_fs_info = FAT_SPECIFIC (ctx->new_fs);
 213         int                     active_length;
 214         int                     i;
 215         int                     offset;
 216 
 217         PED_ASSERT (first <= last, return 0);
 218 
 219         ped_exception_fetch_all ();
 220         if (!quick_group_write_read_underlay (ctx, first, last))
 221                 goto error;
 222 
 223         for (i = first; i <= last; i++) {
 224                 if (ctx->buffer_map [i] == -1)
 225                         continue;
 226 
 227                 offset = ctx->buffer_map [i] - ctx->buffer_map [first];
 228                 memcpy (new_fs_info->buffer + offset * new_fs_info->frag_size,
 229                         old_fs_info->buffer + i * new_fs_info->frag_size,
 230                         new_fs_info->frag_size);
 231         }
 232 
 233         active_length = ctx->buffer_map [last] - ctx->buffer_map [first] + 1;
 234         if (!fat_write_sync_fragments (ctx->new_fs, new_fs_info->buffer,
 235                                        ctx->buffer_map [first], active_length))
 236                 goto error;
 237 
 238         ped_exception_leave_all ();
 239         return 1;
 240 
 241 error:
 242         ped_exception_catch ();
 243         ped_exception_leave_all ();
 244         return 0;
 245 }
 246 
 247 /* Writes fragments out, one at a time, avoiding errors on redundant writes
 248  * on damaged parts of the disk we already know about.  If there's an error
 249  * on one of the required fragments, it gets marked as bad, and a replacement
 250  * is found.
 251  */
 252 static int
 253 slow_group_write (FatOpContext* ctx, int first, int last)
 254 {
 255         FatSpecific*            old_fs_info = FAT_SPECIFIC (ctx->old_fs);
 256         FatSpecific*            new_fs_info = FAT_SPECIFIC (ctx->new_fs);
 257         int                     i;
 258 
 259         PED_ASSERT (first <= last, return 0);
 260 
 261         for (i = first; i <= last; i++) {
 262                 if (ctx->buffer_map [i] == -1)
 263                         continue;
 264 
 265                 while (!fat_write_sync_fragment (ctx->new_fs,
 266                               old_fs_info->buffer + i * old_fs_info->frag_size,
 267                               ctx->buffer_map [i])) {
 268                         fat_table_set_bad (new_fs_info->fat,
 269                                            ctx->buffer_map [i]);
 270                         ctx->buffer_map [i] = fat_table_alloc_cluster
 271                                                 (new_fs_info->fat);
 272                         if (ctx->buffer_map [i] == 0)
 273                                 return 0;
 274                 }
 275         }
 276         return 1;
 277 }
 278 
 279 static int
 280 update_remap (FatOpContext* ctx, int first, int last)
 281 {
 282         int             i;
 283 
 284         PED_ASSERT (first <= last, return 0);
 285 
 286         for (i = first; i <= last; i++) {
 287                 if (ctx->buffer_map [i] == -1)
 288                         continue;
 289                 ctx->remap [ctx->buffer_offset + i] = ctx->buffer_map [i];
 290         }
 291 
 292         return 1;
 293 }
 294 
 295 static int
 296 group_write (FatOpContext* ctx, int first, int last)
 297 {
 298         PED_ASSERT (first <= last, return 0);
 299 
 300         if (!quick_group_write (ctx, first, last)) {
 301                 if (!slow_group_write (ctx, first, last))
 302                         return 0;
 303         }
 304         if (!update_remap (ctx, first, last))
 305                 return 0;
 306         return 1;
 307 }
 308 
 309 /* assumes fragment size and new_fs's cluster size are equal */
 310 static int
 311 write_fragments (FatOpContext* ctx)
 312 {
 313         FatSpecific*            old_fs_info = FAT_SPECIFIC (ctx->old_fs);
 314         FatSpecific*            new_fs_info = FAT_SPECIFIC (ctx->new_fs);
 315         int                     group_start;
 316         int                     group_end = -1; /* shut gcc up! */
 317         FatFragment             mapped_length;
 318         FatFragment             i;
 319         FatCluster              new_cluster;
 320 
 321         PED_ASSERT (ctx->buffer_offset < old_fs_info->frag_count, return 0);
 322 
 323         group_start = -1;
 324         for (i = 0; i < ctx->buffer_frags; i++) {
 325                 if (ctx->buffer_map [i] == -1)
 326                         continue;
 327 
 328                 ctx->frags_duped++;
 329 
 330                 new_cluster = fat_table_alloc_cluster (new_fs_info->fat);
 331                 if (!new_cluster)
 332                         return 0;
 333                 fat_table_set_eof (new_fs_info->fat, new_cluster);
 334                 ctx->buffer_map [i] = fat_cluster_to_frag (ctx->new_fs,
 335                                                            new_cluster);
 336 
 337                 if (group_start == -1)
 338                         group_start = group_end = i;
 339 
 340                 PED_ASSERT (ctx->buffer_map [i]
 341                                 >= ctx->buffer_map [group_start],
 342                             return 0);
 343 
 344                 mapped_length = ctx->buffer_map [i]
 345                                 - ctx->buffer_map [group_start] + 1;
 346                 if (mapped_length <= ctx->buffer_frags) {
 347                         group_end = i;
 348                 } else {
 349                         /* ran out of room in the buffer, so write this group,
 350                          * and start a new one...
 351                          */
 352                         if (!group_write (ctx, group_start, group_end))
 353                                 return 0;
 354                         group_start = group_end = i;
 355                 }
 356         }
 357 
 358         PED_ASSERT (group_start != -1, return 0);
 359 
 360         if (!group_write (ctx, group_start, group_end))
 361                 return 0;
 362         return 1;
 363 }
 364 
 365 /*  default all fragments to unmoved
 366  */
 367 static void
 368 init_remap (FatOpContext* ctx)
 369 {
 370         FatSpecific*            old_fs_info = FAT_SPECIFIC (ctx->old_fs);
 371         FatFragment             i;
 372 
 373         for (i = 0; i < old_fs_info->frag_count; i++)
 374                 ctx->remap[i] = fat_op_context_map_static_fragment (ctx, i);
 375 }
 376 
 377 static FatFragment
 378 count_frags_to_dup (FatOpContext* ctx)
 379 {
 380         FatSpecific*    fs_info = FAT_SPECIFIC (ctx->old_fs);
 381         FatFragment     i;
 382         FatFragment     total;
 383 
 384         total = 0;
 385 
 386         for (i = 0; i < fs_info->frag_count; i++) {
 387                 if (needs_duplicating (ctx, i))
 388                         total++;
 389         }
 390 
 391         return total;
 392 }
 393 
 394 /*  duplicates unreachable file clusters, and all directory clusters
 395  */
 396 int
 397 fat_duplicate_clusters (FatOpContext* ctx, PedTimer* timer)
 398 {
 399         FatFragment     total_frags_to_dup;
 400 
 401         init_remap (ctx);
 402         total_frags_to_dup = count_frags_to_dup (ctx);
 403 
 404         ped_timer_reset (timer);
 405         ped_timer_set_state_name (timer, "moving data");
 406 
 407         ctx->buffer_offset = 0;
 408         ctx->frags_duped = 0;
 409         while (search_next_fragment (ctx)) {
 410                 ped_timer_update (
 411                         timer, 1.0 * ctx->frags_duped / total_frags_to_dup);
 412 
 413                 if (!fetch_fragments (ctx))
 414                         return 0;
 415                 if (!write_fragments (ctx))
 416                         return 0;
 417                 ctx->buffer_offset += ctx->buffer_frags;
 418         }
 419 
 420         ped_timer_update (timer, 1.0);
 421         return 1;
 422 }
 423 
 424 #endif /* !DISCOVER_ONLY */