3 Copyright (C) 1998, 1999, 2000, 2007 Free Software Foundation, Inc.
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.
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.
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
19 I can also be contacted at:
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 :-(
42 static char* movable_extensions[] = {
48 "DAT", "DLL", "DOC", "DRV",
70 get_extension (char* file_name)
74 ext = strrchr (file_name, '.');
77 if (strchr (ext, '\\'))
83 is_movable_system_file (char* file_name)
85 char* ext = get_extension (file_name);
88 for (i = 0; movable_extensions [i]; i++) {
89 if (strcasecmp (ext, movable_extensions [i]) == 0)
98 prints out the sequence of clusters for a given file chain, beginning
103 print_chain (PedFileSystem* fs, FatCluster start)
105 FatSpecific* fs_info = FAT_SPECIFIC (fs);
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) {
120 #endif /* PED_VERBOSE */
123 remainder_round_up (PedSector a, PedSector b)
134 traverse the FAT for a file/directory, marking each entry's flag
138 flag_traverse_fat (PedFileSystem* fs, const char* chain_name, FatCluster start,
139 FatClusterFlag flag, PedSector size)
141 FatSpecific* fs_info = FAT_SPECIFIC (fs);
143 FatCluster prev_clst;
144 int last_cluster_usage;
145 FatCluster chain_length = 0;
147 if (fat_table_is_eof (fs_info->fat, start)) {
148 if (ped_exception_throw (
150 PED_EXCEPTION_IGNORE_CANCEL,
151 _("Bad directory entry for %s: first cluster is the "
152 "end of file marker."),
154 != PED_EXCEPTION_IGNORE)
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)) {
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."),
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 "
176 (int) clst, chain_name);
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);
189 if (flag == FAT_FLAG_DIRECTORY)
190 fs_info->total_dir_clusters++;
192 fs_info->cluster_info [clst].flag = flag;
193 fs_info->cluster_info [clst].units_used = 0; /* 0 == 64 */
198 != ped_div_round_up (size, fs_info->cluster_sectors)) {
199 if (ped_exception_throw (
201 PED_EXCEPTION_IGNORE_CANCEL,
202 _("%s is %dk, but it has %d clusters (%dk)."),
206 (int) chain_length * fs_info->cluster_sectors / 2)
207 != PED_EXCEPTION_IGNORE)
212 = ped_div_round_up (64 * remainder_round_up (size,
213 fs_info->cluster_sectors),
214 fs_info->cluster_sectors);
216 fs_info->cluster_info [prev_clst].units_used = last_cluster_usage;
222 recursively traverses a directory, flagging all clusters in the process.
223 It frees the traverse_info structure before returning.
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;
235 PED_ASSERT (trav_info != NULL, return 0);
237 strcpy (file_name, trav_info->dir_name);
238 file_name_start = file_name + strlen (file_name);
240 while ( (this_entry = fat_traverse_next_dir_entry (trav_info)) ) {
241 if (fat_dir_entry_is_null_term (this_entry))
243 if (!fat_dir_entry_has_first_cluster (this_entry, fs))
245 if (this_entry->name [0] == '.')
246 continue; /* skip . and .. entries */
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),
254 printf ("%s: ", file_name);
255 print_chain (fs, first_cluster);
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."),
271 case PED_EXCEPTION_CANCEL:
274 case PED_EXCEPTION_UNHANDLED:
275 ped_exception_catch ();
276 case PED_EXCEPTION_IGNORE:
281 if (fat_dir_entry_is_directory (this_entry)) {
282 if (!flag_traverse_fat (fs, file_name, first_cluster,
283 FAT_FLAG_DIRECTORY, size))
286 subdir_trav_info = fat_traverse_directory (trav_info,
288 if (!subdir_trav_info)
290 if (!flag_traverse_dir (subdir_trav_info))
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))
299 fat_traverse_complete (trav_info);
304 _mark_bad_clusters (PedFileSystem* fs)
306 FatSpecific* fs_info = FAT_SPECIFIC (fs);
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;
316 fills in cluster_info. Each FAT entry (= cluster) is flagged as either
317 FAT_FLAG_FREE, FAT_FLAG_FILE or FAT_FLAG_DIRECTORY.
319 Also, the fraction of each cluster (x/64) is recorded
322 fat_collect_cluster_info (PedFileSystem* fs) {
323 FatSpecific* fs_info = FAT_SPECIFIC (fs);
324 FatTraverseInfo* trav_info;
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;
330 if (fs_info->fat_type == FAT_TYPE_FAT32) {
331 trav_info = fat_traverse_begin (fs, fs_info->root_cluster,
333 if (!flag_traverse_dir (trav_info))
335 if (!flag_traverse_fat (fs, "\\", fs_info->root_cluster,
336 FAT_FLAG_DIRECTORY, 0))
339 trav_info = fat_traverse_begin (fs, FAT_ROOT, "\\");
340 if (!flag_traverse_dir (trav_info))
344 _mark_bad_clusters (fs);
349 fat_get_cluster_flag (PedFileSystem* fs, FatCluster cluster)
351 FatSpecific* fs_info = FAT_SPECIFIC (fs);
353 return fs_info->cluster_info [cluster].flag;
357 fat_get_cluster_usage (PedFileSystem* fs, FatCluster cluster)
359 FatSpecific* fs_info = FAT_SPECIFIC (fs);
362 if (fs_info->cluster_info [cluster].flag == FAT_FLAG_FREE)
365 fraction = fs_info->cluster_info [cluster].units_used;
369 return fraction * fs_info->cluster_sectors / 64;
373 fat_get_fragment_flag (PedFileSystem* fs, FatFragment frag)
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;
381 PED_ASSERT (cluster >= 2 && cluster < fs_info->cluster_count + 2,
384 flag = fat_get_cluster_flag (fs, cluster);
385 if (flag != FAT_FLAG_FILE && flag != FAT_FLAG_DIRECTORY)
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;
396 fat_is_fragment_active (PedFileSystem* fs, FatFragment frag)
398 switch (fat_get_fragment_flag (fs, frag)) {
404 case FAT_FLAG_DIRECTORY:
410 #endif /* !DISCOVER_ONLY */