OSDN Git Service

dba0edb6da17a65e24e93fc72a431a1772453700
[android-x86/external-parted.git] / libparted / fs / fat / count.c
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 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     I can also be contacted at:
20
21     Andrew Clausen
22     18 Shaw St
23     Ashwood, 3147
24     Victoria, Australia
25
26 */
27
28 #include "fat.h"
29 #include "traverse.h"
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 #ifndef DISCOVER_ONLY
36
37 #if 0
38 /* extremely ugly hack: stick everything that obviously isn't an unmovable file
39  * in here.  Note: DAT is a bit dubious.  Unfortunately, it's used by the
40  * registry, so it'll be all over the place :-(
41  */
42 static char*    movable_extensions[] = {
43         "",
44         "1ST",
45         "AVI",
46         "BAK", "BAT", "BMP",
47         "CFG", "COM", "CSS",
48         "DAT", "DLL", "DOC", "DRV",
49         "EXE",
50         "FAQ", "FLT", "FON",
51         "GID", "GIF",
52         "HLP", "HTT", "HTM",
53         "ICO", "INI",
54         "JPG",
55         "LNK", "LOG",
56         "KBD",
57         "ME", "MID", "MSG",
58         "OCX", "OLD",
59         "PIF", "PNG", "PRV",
60         "RTF",
61         "SCR", "SYS",
62         "TMP", "TTF", "TXT",
63         "URL",
64         "WAV",
65         "VBX", "VOC", "VXD",
66         NULL
67 };
68
69 static char*
70 get_extension (char* file_name)
71 {
72         char*           ext;
73
74         ext = strrchr (file_name, '.');
75         if (!ext)
76                 return "";
77         if (strchr (ext, '\\'))
78                 return "";
79         return ext + 1;
80 }
81
82 static int
83 is_movable_system_file (char* file_name)
84 {
85         char*           ext = get_extension (file_name);
86         int             i;
87
88         for (i = 0; movable_extensions [i]; i++) {
89                 if (strcasecmp (ext, movable_extensions [i]) == 0)
90                         return 1;
91         }
92
93         return 0;
94 }
95 #endif /* 0 */
96
97 /*
98     prints out the sequence of clusters for a given file chain, beginning
99     at start_cluster.
100 */
101 #ifdef PED_VERBOSE
102 static void
103 print_chain (PedFileSystem* fs, FatCluster start)
104 {
105         FatSpecific*    fs_info = FAT_SPECIFIC (fs);
106         FatCluster      clst;
107         int             this_row;
108
109         this_row = 0;
110         for (clst = start; !fat_table_is_eof (fs_info->fat, clst);
111              clst = fat_table_get (fs_info->fat, clst)) {
112                 printf ("  %d", (int) clst);
113                 if (++this_row == 7) {
114                         printf ("\n");
115                         this_row = 0;
116                 }
117         }
118         printf ("\n");
119 }
120 #endif /* PED_VERBOSE */
121
122 static PedSector
123 remainder_round_up (PedSector a, PedSector b)
124 {
125         PedSector       result;
126
127         result = a % b;
128         if (!result)
129                 result = b;
130         return result;
131 }
132
133 /*
134     traverse the FAT for a file/directory, marking each entry's flag
135     to "flag".
136 */
137 static int
138 flag_traverse_fat (PedFileSystem* fs, const char* chain_name, FatCluster start,
139                    FatClusterFlag flag, PedSector size)
140 {
141         FatSpecific*    fs_info = FAT_SPECIFIC (fs);
142         FatCluster      clst;
143         FatCluster      prev_clst;
144         int             last_cluster_usage;
145         FatCluster      chain_length = 0;
146
147         if (fat_table_is_eof (fs_info->fat, start)) {
148                 if (ped_exception_throw (
149                         PED_EXCEPTION_ERROR,
150                         PED_EXCEPTION_IGNORE_CANCEL,
151                         _("Bad directory entry for %s: first cluster is the "
152                           "end of file marker."),
153                         chain_name)
154                                 != PED_EXCEPTION_IGNORE)
155                         return 0;
156         }
157
158         for (prev_clst = clst = start; !fat_table_is_eof (fs_info->fat, clst);
159              prev_clst = clst, clst = fat_table_get (fs_info->fat, clst)) {
160                 chain_length++;
161                 if (!clst) {
162                         ped_exception_throw (PED_EXCEPTION_FATAL,
163                                 PED_EXCEPTION_CANCEL,
164                                 _("Bad FAT: unterminated chain for %s.  You "
165                                   "should run dosfsck or scandisk."),
166                                 chain_name);
167                         return 0;
168                 }
169
170                 if (clst >= fs_info->fat->cluster_count + 2) {
171                         ped_exception_throw (PED_EXCEPTION_FATAL,
172                                 PED_EXCEPTION_CANCEL,
173                                 _("Bad FAT: cluster %d outside file system "
174                                   "in chain for %s.  You should run dosfsck "
175                                   "or scandisk."),
176                                 (int) clst, chain_name);
177                         return 0;
178                 }
179
180                 if (fs_info->cluster_info [clst].flag != FAT_FLAG_FREE ) {
181                         ped_exception_throw (PED_EXCEPTION_FATAL,
182                                 PED_EXCEPTION_CANCEL,
183                                 _("Bad FAT: cluster %d is cross-linked for "
184                                   "%s.  You should run dosfsck or scandisk."),
185                                 (int) clst, chain_name);
186                         return 0;
187                 }
188
189                 if (flag == FAT_FLAG_DIRECTORY)
190                         fs_info->total_dir_clusters++;
191
192                 fs_info->cluster_info [clst].flag = flag;
193                 fs_info->cluster_info [clst].units_used = 0;    /* 0 == 64 */
194         }
195
196         if (size
197             && chain_length
198                         != ped_div_round_up (size, fs_info->cluster_sectors)) {
199                 if (ped_exception_throw (
200                         PED_EXCEPTION_ERROR,
201                         PED_EXCEPTION_IGNORE_CANCEL,
202                         _("%s is %dk, but it has %d clusters (%dk)."),
203                         chain_name,
204                         (int) size / 2,
205                         (int) chain_length,
206                         (int) chain_length * fs_info->cluster_sectors / 2)
207                                 != PED_EXCEPTION_IGNORE)
208                         return 0;
209         }
210
211         last_cluster_usage
212                 = ped_div_round_up (64 * remainder_round_up (size,
213                                                 fs_info->cluster_sectors),
214                                 fs_info->cluster_sectors);
215
216         fs_info->cluster_info [prev_clst].units_used = last_cluster_usage;
217
218         return 1;
219 }
220
221 /*
222     recursively traverses a directory, flagging all clusters in the process.
223     It frees the traverse_info structure before returning.
224 */
225 static int
226 flag_traverse_dir (FatTraverseInfo* trav_info) {
227         PedFileSystem*          fs = trav_info->fs;
228         FatDirEntry*            this_entry;
229         FatTraverseInfo*        subdir_trav_info;
230         char                    file_name [512];
231         char*                   file_name_start;
232         FatCluster              first_cluster;
233         PedSector               size;
234
235         PED_ASSERT (trav_info != NULL, return 0);
236
237         strcpy (file_name, trav_info->dir_name);
238         file_name_start = file_name + strlen (file_name);
239
240         while ( (this_entry = fat_traverse_next_dir_entry (trav_info)) ) {
241                 if (fat_dir_entry_is_null_term (this_entry))
242                         break;
243                 if (!fat_dir_entry_has_first_cluster (this_entry, fs))
244                         continue;
245                 if (this_entry->name [0] == '.')
246                         continue;       /* skip . and .. entries */
247
248                 fat_dir_entry_get_name (this_entry, file_name_start);
249                 first_cluster = fat_dir_entry_get_first_cluster(this_entry, fs);
250                 size = ped_div_round_up (fat_dir_entry_get_length (this_entry),
251                                          512);
252
253 #ifdef PED_VERBOSE
254                 printf ("%s: ", file_name);
255                 print_chain (fs, first_cluster);
256 #endif
257
258 #if 0
259                 if (fat_dir_entry_is_system_file (this_entry)
260                     && !is_movable_system_file (file_name)) {
261                         PedExceptionOption ex_status;
262                         ex_status = ped_exception_throw (
263                                 PED_EXCEPTION_WARNING,
264                                 PED_EXCEPTION_IGNORE_CANCEL,
265                                 _("The file %s is marked as a system file.  "
266                                 "This means moving it could cause some "
267                                 "programs to stop working."),
268                                 file_name);
269
270                         switch (ex_status) {
271                                 case PED_EXCEPTION_CANCEL:
272                                         return 0;
273
274                                 case PED_EXCEPTION_UNHANDLED:
275                                         ped_exception_catch ();
276                                 case PED_EXCEPTION_IGNORE:
277                         }
278                 }
279 #endif /* 0 */
280
281                 if (fat_dir_entry_is_directory (this_entry)) {
282                         if (!flag_traverse_fat (fs, file_name, first_cluster,
283                                                 FAT_FLAG_DIRECTORY, size))
284                                 return 0;
285
286                         subdir_trav_info = fat_traverse_directory (trav_info,
287                                                                    this_entry);
288                         if (!subdir_trav_info)
289                                 return 0;
290                         if (!flag_traverse_dir (subdir_trav_info))
291                                 return 0;
292                 } else if (fat_dir_entry_is_file (this_entry)) {
293                         if (!flag_traverse_fat (fs, file_name, first_cluster,
294                                                 FAT_FLAG_FILE, size)) 
295                                 return 0;
296                 }
297         }
298
299         fat_traverse_complete (trav_info);
300         return 1;
301 }
302
303 static void
304 _mark_bad_clusters (PedFileSystem* fs)
305 {
306         FatSpecific*    fs_info = FAT_SPECIFIC (fs);
307         FatCluster      cluster;
308
309         for (cluster = 2; cluster < fs_info->cluster_count + 2; cluster++) {
310                 if (fat_table_is_bad (fs_info->fat, cluster))
311                         fs_info->cluster_info [cluster].flag = FAT_FLAG_BAD;
312         }
313 }
314
315 /*  
316     fills in cluster_info.  Each FAT entry (= cluster) is flagged as either
317     FAT_FLAG_FREE, FAT_FLAG_FILE or FAT_FLAG_DIRECTORY.
318
319     Also, the fraction of each cluster (x/64) is recorded
320 */
321 int
322 fat_collect_cluster_info (PedFileSystem* fs) {
323         FatSpecific*            fs_info = FAT_SPECIFIC (fs);
324         FatTraverseInfo*        trav_info;
325     
326         /* set all clusters to unused as a default */
327         memset (fs_info->cluster_info, 0, fs_info->fat->cluster_count + 2);
328         fs_info->total_dir_clusters = 0;
329
330         if (fs_info->fat_type == FAT_TYPE_FAT32) {
331                 trav_info = fat_traverse_begin (fs, fs_info->root_cluster,
332                                                 "\\");
333                 if (!flag_traverse_dir (trav_info))
334                         return 0;
335                 if (!flag_traverse_fat (fs, "\\", fs_info->root_cluster,
336                                         FAT_FLAG_DIRECTORY, 0))
337                         return 0;
338         } else {
339                 trav_info = fat_traverse_begin (fs, FAT_ROOT, "\\");
340                 if (!flag_traverse_dir (trav_info))
341                         return 0;
342         }
343
344         _mark_bad_clusters (fs);
345         return 1;
346 }
347
348 FatClusterFlag
349 fat_get_cluster_flag (PedFileSystem* fs, FatCluster cluster)
350 {
351         FatSpecific*            fs_info = FAT_SPECIFIC (fs);
352
353         return fs_info->cluster_info [cluster].flag;
354 }
355
356 PedSector
357 fat_get_cluster_usage (PedFileSystem* fs, FatCluster cluster)
358 {
359         FatSpecific*            fs_info = FAT_SPECIFIC (fs);
360         int                     fraction;
361
362         if (fs_info->cluster_info [cluster].flag == FAT_FLAG_FREE)
363                 return 0;
364
365         fraction = fs_info->cluster_info [cluster].units_used;
366         if (fraction == 0)
367                 fraction = 64;
368
369         return fraction * fs_info->cluster_sectors / 64;
370 }
371
372 FatClusterFlag
373 fat_get_fragment_flag (PedFileSystem* fs, FatFragment frag)
374 {
375         FatSpecific*    fs_info = FAT_SPECIFIC (fs);
376         FatCluster      cluster = fat_frag_to_cluster (fs, frag);
377         FatFragment     offset = frag % fs_info->cluster_frags;
378         FatFragment     last_frag_used;
379         FatClusterFlag  flag;
380
381         PED_ASSERT (cluster >= 2 && cluster < fs_info->cluster_count + 2,
382                     return 0);
383
384         flag = fat_get_cluster_flag (fs, cluster);
385         if (flag != FAT_FLAG_FILE && flag != FAT_FLAG_DIRECTORY)
386                 return flag;
387         last_frag_used = (fat_get_cluster_usage (fs, cluster) - 1)
388                                 / fs_info->frag_sectors;
389         if (offset > last_frag_used)
390                 return FAT_FLAG_FREE;
391         else
392                 return flag;
393 }
394
395 int
396 fat_is_fragment_active (PedFileSystem* fs, FatFragment frag)
397 {
398         switch (fat_get_fragment_flag (fs, frag)) {
399                 case FAT_FLAG_FREE:
400                 case FAT_FLAG_BAD:
401                         return 0;
402
403                 case FAT_FLAG_FILE:
404                 case FAT_FLAG_DIRECTORY:
405                         return 1;
406         }
407         return 0;
408 }
409
410 #endif /* !DISCOVER_ONLY */
411