void read_fat(DOS_FS *fs) { int eff_size; unsigned long i; void *first,*second,*use; int first_ok,second_ok; eff_size = ((fs->clusters+2)*fs->fat_bits+7)/8; first = alloc(eff_size); second = alloc(eff_size); fs_read(fs->fat_start,eff_size,first); fs_read(fs->fat_start+fs->fat_size,eff_size,second); use = first; if (memcmp(first,second,eff_size) != 0) { FAT_ENTRY first_media, second_media; get_fat(&first_media,first,0,fs); get_fat(&second_media,second,0,fs); first_ok = (first_media.value & FAT_EXTD(fs)) == FAT_EXTD(fs); second_ok = (second_media.value & FAT_EXTD(fs)) == FAT_EXTD(fs); if (first_ok && !second_ok) { printf("FATs differ - using first FAT.\n"); fs_write(fs->fat_start+fs->fat_size,eff_size,use = first); } if (!first_ok && second_ok) { printf("FATs differ - using second FAT.\n"); fs_write(fs->fat_start,eff_size,use = second); } if (first_ok && second_ok) { if (interactive) { printf("FATs differ but appear to be intact. Use which FAT ?\n" "1) Use first FAT\n2) Use second FAT\n"); if (get_key("12","?") == '1') fs_write(fs->fat_start+fs->fat_size,eff_size,use = first); else fs_write(fs->fat_start,eff_size,use = second); } else { printf("FATs differ but appear to be intact. Using first " "FAT.\n"); fs_write(fs->fat_start+fs->fat_size,eff_size,use = first); } } if (!first_ok && !second_ok) { printf("Both FATs appear to be corrupt. Giving up.\n"); exit(1); } } fs->fat = qalloc(&mem_queue,sizeof(FAT_ENTRY)*(fs->clusters+2)); for (i = 2; i < fs->clusters+2; i++) get_fat(&fs->fat[i],use,i,fs); for (i = 2; i < fs->clusters+2; i++) if (fs->fat[i].value >= fs->clusters+2 && (fs->fat[i].value < FAT_MIN_BAD(fs))) { printf("Cluster %ld out of range (%ld > %ld). Setting to EOF.\n", i-2,fs->fat[i].value,fs->clusters+2-1); set_fat(fs,i,-1); } free(first); free(second); }
/** * Build a bookkeeping structure from the partition's FAT table. * If the partition has multiple FATs and they don't agree, try to pick a winner, * and queue a command to overwrite the loser. * One error that is fixed here is a cluster that links to something out of range. * * @param[inout] fs Information about the filesystem */ void read_fat(DOS_FS * fs) { int eff_size; unsigned long i; void *first, *second = NULL; int first_ok, second_ok; unsigned long total_num_clusters; /* Clean up from previous pass */ if (fs->fat) free(fs->fat); if (fs->cluster_owner) free(fs->cluster_owner); fs->fat = NULL; fs->cluster_owner = NULL; total_num_clusters = fs->clusters + 2UL; eff_size = (total_num_clusters * fs->fat_bits + 7) / 8ULL; first = alloc(eff_size); fs_read(fs->fat_start, eff_size, first); if (fs->nfats > 1) { second = alloc(eff_size); fs_read(fs->fat_start + fs->fat_size, eff_size, second); } if (second && memcmp(first, second, eff_size) != 0) { FAT_ENTRY first_media, second_media; get_fat(&first_media, first, 0, fs); get_fat(&second_media, second, 0, fs); first_ok = (first_media.value & FAT_EXTD(fs)) == FAT_EXTD(fs); second_ok = (second_media.value & FAT_EXTD(fs)) == FAT_EXTD(fs); if (first_ok && !second_ok) { printf("FATs differ - using first FAT.\n"); fs_write(fs->fat_start + fs->fat_size, eff_size, first); } if (!first_ok && second_ok) { printf("FATs differ - using second FAT.\n"); fs_write(fs->fat_start, eff_size, second); memcpy(first, second, eff_size); } if (first_ok && second_ok) { if (interactive) { printf("FATs differ but appear to be intact. Use which FAT ?\n" "1) Use first FAT\n2) Use second FAT\n"); if (get_key("12", "?") == '1') { fs_write(fs->fat_start + fs->fat_size, eff_size, first); } else { fs_write(fs->fat_start, eff_size, second); memcpy(first, second, eff_size); } } else { printf("FATs differ but appear to be intact. Using first " "FAT.\n"); fs_write(fs->fat_start + fs->fat_size, eff_size, first); } } if (!first_ok && !second_ok) { printf("Both FATs appear to be corrupt. Giving up.\n"); exit(1); } } if (second) { free(second); } fs->fat = (unsigned char *)first; fs->cluster_owner = alloc(total_num_clusters * sizeof(DOS_FILE *)); memset(fs->cluster_owner, 0, (total_num_clusters * sizeof(DOS_FILE *))); /* Truncate any cluster chains that link to something out of range */ for (i = 2; i < fs->clusters + 2; i++) { FAT_ENTRY curEntry; get_fat(&curEntry, fs->fat, i, fs); if (curEntry.value == 1) { printf("Cluster %ld out of range (1). Setting to EOF.\n", i - 2); set_fat(fs, i, -1); } if (curEntry.value >= fs->clusters + 2 && (curEntry.value < FAT_MIN_BAD(fs))) { printf("Cluster %ld out of range (%ld > %ld). Setting to EOF.\n", i - 2, curEntry.value, fs->clusters + 2 - 1); set_fat(fs, i, -1); } } }