~ubuntu-branches/ubuntu/vivid/parted/vivid

« back to all changes in this revision

Viewing changes to libparted/fs/r/fat/clstdup.c

  • Committer: Package Import Robot
  • Author(s): Colin Watson
  • Date: 2014-07-21 10:23:16 UTC
  • mfrom: (7.2.32 sid)
  • Revision ID: package-import@ubuntu.com-20140721102316-jsyv3yzmbo8vlde5
Tags: 3.1-3
Upload to unstable.

Show diffs side-by-side

added added

removed removed

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