int fat_dir_entry_has_first_cluster (FatDirEntry* dir_entry, PedFileSystem* fs) { FatSpecific* fs_info = FAT_SPECIFIC (fs); FatCluster first_cluster; if (!fat_dir_entry_is_file (dir_entry) && !fat_dir_entry_is_directory (dir_entry)) return 0; first_cluster = fat_dir_entry_get_first_cluster (dir_entry, fs); if (first_cluster == 0 || fat_table_is_eof (fs_info->fat, first_cluster)) return 0; return 1; }
/* Recursively builds (i.e. makes consistent) the duplicated directory tree * (leaving the original directory tree in tact) */ static int fat_construct_directory (FatOpContext* ctx, FatTraverseInfo* trav_info) { FatTraverseInfo* sub_dir_info; FatDirEntry* dir_entry; FatCluster old_first_cluster; while ( (dir_entry = fat_traverse_next_dir_entry (trav_info)) ) { if (fat_dir_entry_is_null_term (dir_entry)) break; if (!fat_dir_entry_has_first_cluster (dir_entry, ctx->old_fs)) continue; fat_traverse_mark_dirty (trav_info); old_first_cluster = fat_dir_entry_get_first_cluster (dir_entry, ctx->old_fs); fat_dir_entry_set_first_cluster (dir_entry, ctx->new_fs, fat_op_context_map_cluster (ctx, old_first_cluster)); if (fat_dir_entry_is_directory (dir_entry) && dir_entry->name [0] != '.') { sub_dir_info = fat_traverse_directory (trav_info, dir_entry); if (!sub_dir_info) return 0; if (!fat_construct_directory (ctx, sub_dir_info)) return 0; } } /* remove "stale" entries at the end */ while ((dir_entry = fat_traverse_next_dir_entry (trav_info))) { memset (dir_entry, 0, sizeof (FatDirEntry)); fat_traverse_mark_dirty (trav_info); } fat_traverse_complete (trav_info); return 1; }
/* Converts the root directory between FAT16 and FAT32. NOTE: this code * can also do no conversion. I'm leaving fat_construct_directory(), because * it's really pretty :-) It also leaves a higher chance of deleted file * recovery, because it doesn't remove redundant entries. (We do this here, * because brain-damaged FAT16 has an arbitary limit on root directory entries, * so we save room) */ static int fat_convert_directory (FatOpContext* ctx, FatTraverseInfo* old_trav, FatTraverseInfo* new_trav) { FatTraverseInfo* sub_old_dir_trav; FatTraverseInfo* sub_new_dir_trav; FatDirEntry* new_dir_entry; FatDirEntry* old_dir_entry; FatCluster old_first_cluster; while ( (old_dir_entry = fat_traverse_next_dir_entry (old_trav)) ) { if (fat_dir_entry_is_null_term (old_dir_entry)) break; if (!fat_dir_entry_is_active (old_dir_entry)) continue; new_dir_entry = fat_traverse_next_dir_entry (new_trav); if (!new_dir_entry) { return ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_IGNORE_CANCEL, _("There's not enough room in the root " "directory for all of the files. Either " "cancel, or ignore to lose the files.")) == PED_EXCEPTION_IGNORE; } *new_dir_entry = *old_dir_entry; fat_traverse_mark_dirty (new_trav); if (!fat_dir_entry_has_first_cluster (old_dir_entry, ctx->old_fs)) continue; old_first_cluster = fat_dir_entry_get_first_cluster ( old_dir_entry, ctx->old_fs); fat_dir_entry_set_first_cluster (new_dir_entry, ctx->new_fs, fat_op_context_map_cluster (ctx, old_first_cluster)); if (fat_dir_entry_is_directory (old_dir_entry) && old_dir_entry->name [0] != '.') { sub_old_dir_trav = fat_traverse_directory (old_trav, old_dir_entry); sub_new_dir_trav = fat_traverse_directory (new_trav, new_dir_entry); if (!sub_old_dir_trav || !sub_new_dir_trav) return 0; if (!fat_convert_directory (ctx, sub_old_dir_trav, sub_new_dir_trav)) return 0; } } /* remove "stale" entries at the end, just in case there is some * overlap */ while ((new_dir_entry = fat_traverse_next_dir_entry (new_trav))) { memset (new_dir_entry, 0, sizeof (FatDirEntry)); fat_traverse_mark_dirty (new_trav); } fat_traverse_complete (old_trav); fat_traverse_complete (new_trav); return 1; }