OSDN Git Service

Avoid compiler warnings with gcc -Wall -Wshadow.
[android-x86/external-parted.git] / libparted / fs / fat / clstdup.c
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 2 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, write to the Free Software
17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 */
19
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 */