static int check_part_gpt(disk_t *disk, const int verbose,partition_t *partition, const int saveheader) { int ret=0; unsigned int old_levels; old_levels=log_set_levels(0); if(guid_cmp(partition->part_type_gpt, GPT_ENT_TYPE_MS_BASIC_DATA)==0 || guid_cmp(partition->part_type_gpt, GPT_ENT_TYPE_MS_RESERVED)==0) { ret=check_FAT(disk,partition,verbose); if(ret!=0) ret=check_EXFAT(disk, partition); if(ret!=0) ret=check_NTFS(disk,partition,verbose,0); if(ret!=0) ret=check_ReFS(disk, partition); if(ret!=0) ret=check_linux(disk, partition, verbose); if(ret!=0) screen_buffer_add("No FAT, NTFS, ext2, JFS, Reiser, cramfs or XFS marker\n"); } else if(guid_cmp(partition->part_type_gpt, GPT_ENT_TYPE_LINUX_RAID)==0) { ret=check_MD(disk, partition, verbose); if(ret!=0) screen_buffer_add("Invalid RAID superblock\n"); } else if(guid_cmp(partition->part_type_gpt, GPT_ENT_TYPE_LINUX_LVM)==0) { ret=check_LVM(disk, partition, verbose); if(ret!=0) ret=check_LVM2(disk, partition, verbose); if(ret!=0) screen_buffer_add("No LVM or LVM2 structure\n"); } else if(guid_cmp(partition->part_type_gpt, GPT_ENT_TYPE_MAC_HFS)==0) { ret=check_HFS(disk, partition, verbose); if(ret!=0) ret=check_HFSP(disk, partition, verbose); if(ret!=0) screen_buffer_add("No HFS or HFS+ structure\n"); } log_set_levels(old_levels); if(ret!=0) { log_error("check_part_gpt failed for partition\n"); log_partition(disk, partition); aff_part_buffer(AFF_PART_ORDER|AFF_PART_STATUS,disk,partition); if(saveheader>0) { save_header(disk, partition, verbose); } } return ret; }
int repair_MFT(disk_t *disk_car, partition_t *partition, const int verbose, const unsigned int expert, char **current_cmd) { struct ntfs_boot_sector *ntfs_header; unsigned char *buffer_mft; unsigned char *buffer_mftmirr; unsigned int cluster_size; unsigned int mft_record_size; unsigned int mftmirr_size_bytes; unsigned int use_MFT=0; /* 0: do nothing * 1: fix MFT mirror using MFT * 2: fix MFT using MFT mirror */ uint64_t mft_pos; uint64_t mftmirr_pos; log_trace("repair_MFT\n"); if(check_NTFS(disk_car, partition, verbose, 0)!=0) { display_message("Boot sector not valid, can't repair MFT.\n"); return -1; } ntfs_header=(struct ntfs_boot_sector *)MALLOC(DEFAULT_SECTOR_SIZE); if(disk_car->pread(disk_car, ntfs_header, DEFAULT_SECTOR_SIZE, partition->part_offset) != DEFAULT_SECTOR_SIZE) { free(ntfs_header); display_message("Can't read NTFS boot sector.\n"); return -1; } mft_pos=partition->part_offset+(uint64_t)(le16(ntfs_header->reserved)+le64(ntfs_header->mft_lcn)*ntfs_header->sectors_per_cluster)*ntfs_sector_size(ntfs_header); mftmirr_pos=partition->part_offset+(uint64_t)(le16(ntfs_header->reserved)+le64(ntfs_header->mftmirr_lcn)*ntfs_header->sectors_per_cluster)*ntfs_sector_size(ntfs_header); if(ntfs_header->clusters_per_mft_record>0) mft_record_size=ntfs_header->sectors_per_cluster*ntfs_header->clusters_per_mft_record; else mft_record_size=1<<(-ntfs_header->clusters_per_mft_record); cluster_size=ntfs_header->sectors_per_cluster; mftmirr_size_bytes = (cluster_size <= 4 * mft_record_size ? 4 * mft_record_size : cluster_size) * ntfs_sector_size(ntfs_header); #ifdef DEBUG_REPAIR_MFT log_debug("mft_pos %lu\n",(unsigned long)(mft_pos/disk_car->sector_size)); log_debug("mftmirr_pos %lu\n",(unsigned long)(mftmirr_pos/disk_car->sector_size)); log_debug("cluster_size %u\n", cluster_size); log_debug("mft_record_size %u\n", mft_record_size); log_debug("ntfs_sector_size %u\n", ntfs_sector_size(ntfs_header)); log_debug("mftmirr_size_bytes %u\n", mftmirr_size_bytes); #endif if(mftmirr_size_bytes==0) { display_message("Invalid NTFS MFT size.\n"); log_error("Invalid NTFS MFT size.\n"); free(ntfs_header); return -1; } /* Check if MFT mirror is identical to the beginning of MFT */ buffer_mft=(unsigned char *)MALLOC(mftmirr_size_bytes); if((unsigned)disk_car->pread(disk_car, buffer_mft, mftmirr_size_bytes, mft_pos) != mftmirr_size_bytes) { display_message("Can't read NTFS MFT.\n"); log_error("Can't read NTFS MFT.\n"); free(buffer_mft); free(ntfs_header); return -1; } buffer_mftmirr=(unsigned char *)MALLOC(mftmirr_size_bytes); if((unsigned)disk_car->pread(disk_car, buffer_mftmirr, mftmirr_size_bytes, mftmirr_pos) != mftmirr_size_bytes) { display_message("Can't read NTFS MFT mirror.\n"); log_error("Can't read NTFS MFT mirror.\n"); free(buffer_mftmirr); free(buffer_mft); free(ntfs_header); return -1; } if(memcmp(buffer_mft, buffer_mftmirr, mftmirr_size_bytes)==0) { log_info("MFT and MFT mirror match perfectly.\n"); if(*current_cmd==NULL) display_message("MFT and MFT mirror match perfectly.\n"); free(buffer_mftmirr); free(buffer_mft); free(ntfs_header); return 0; } if(partition->sb_offset!=0) { log_info("Please quit TestDisk and reboot your computer before trying to fix the MFT.\n"); display_message("Please quit TestDisk and reboot your computer before trying to fix the MFT.\n"); free(buffer_mftmirr); free(buffer_mft); free(ntfs_header); return -1; } /* log_debug("MFT\n"); dump_log(buffer_mft, mftmirr_size_bytes); log_debug("MFT mirror\n"); dump_log(buffer_mftmirr, mftmirr_size_bytes); */ /* The idea is to use the internal IO redirector built-in TestDisk to redirect read access to the MFT to the MFT backup instead (or vice-versa) when listing the NTFS files. If TestDisk can get a file listing, it also knows which MFT to use. */ { int res1,res2; dir_data_t dir_data; /* Use MFT */ io_redir_add_redir(disk_car, mftmirr_pos, mftmirr_size_bytes, 0, buffer_mft); res1=dir_partition_ntfs_init(disk_car,partition,&dir_data,verbose); if(res1==DIR_PART_ENOSYS) { display_message("Can't determine which MFT is correct, ntfslib is missing.\n"); log_error("Can't determine which MFT is correct, ntfslib is missing.\n"); free(buffer_mftmirr); free(buffer_mft); free(ntfs_header); io_redir_del_redir(disk_car,mftmirr_pos); return 0; } if(res1==DIR_PART_OK) { file_info_t dir_list; TD_INIT_LIST_HEAD(&dir_list.list); dir_data.get_dir(disk_car,partition,&dir_data,dir_data.current_inode, &dir_list); if(!td_list_empty(&dir_list.list)) { log_info("NTFS listing using MFT:\n"); dir_aff_log(&dir_data, &dir_list); if(delete_list_file(&dir_list)>2) res1++; } dir_data.close(&dir_data); } io_redir_del_redir(disk_car,mftmirr_pos); /* Use MFT mirror */ io_redir_add_redir(disk_car, mft_pos, mftmirr_size_bytes, 0, buffer_mftmirr); res2=dir_partition_ntfs_init(disk_car,partition,&dir_data,verbose); if(res2==DIR_PART_OK) { file_info_t dir_list; TD_INIT_LIST_HEAD(&dir_list.list); dir_data.get_dir(disk_car,partition,&dir_data,dir_data.current_inode, &dir_list); if(!td_list_empty(&dir_list.list)) { log_info("NTFS listing using MFT mirror:\n"); dir_aff_log(&dir_data, &dir_list); if(delete_list_file(&dir_list)>2) res2++; } dir_data.close(&dir_data); } io_redir_del_redir(disk_car,mft_pos); /* */ if(res1>res2 && res1>DIR_PART_OK) { /* Use MFT */ #ifdef HAVE_NCURSES if(ask_confirmation("Fix MFT mirror using MFT ? (Y/N)")!=0) use_MFT=1; else #endif log_info("Don't fix MFT mirror.\n"); } else if(res1<res2 && res2>DIR_PART_OK) { /* Use MFT mirror */ #ifdef HAVE_NCURSES if(ask_confirmation("Fix MFT using its mirror ? (Y/N) - DANGEROUS NON REVERSIBLE OPERATION\nUse it ONLY IF Windows failed to access this filesystem.")!=0) use_MFT=2; else #endif log_info("Don't fix MFT.\n"); } else { /* res1==res2 */ if(res1>DIR_PART_OK && res2>DIR_PART_OK) log_error("Both MFT seems ok but they don't match, use chkdsk.\n"); else log_error("MFT and MFT mirror are bad. Failed to repair them.\n"); if(expert==0) { if(res1>DIR_PART_OK && res2>DIR_PART_OK) display_message("Both MFT seems ok but they don't match, use chkdsk.\n"); else display_message("MFT and MFT mirror are bad. Failed to repair them.\n"); } else { #ifdef HAVE_NCURSES unsigned int menu=2; int real_key; int command; static const struct MenuItem menuMFT[]= { {'B',"MFT", "Fix MFT using MFT mirror"}, {'M',"MFT Mirror", "Fix MFT mirror using MFT"}, {'Q',"Quit","Return to NTFS functions"}, {0,NULL,NULL} }; aff_copy(stdscr); wmove(stdscr,4,0); wprintw(stdscr,"%s",disk_car->description(disk_car)); mvwaddstr(stdscr,5,0,msg_PART_HEADER_LONG); wmove(stdscr,6,0); aff_part(stdscr,AFF_PART_ORDER|AFF_PART_STATUS,disk_car,partition); wmove(stdscr,8,0); if(res1>0 && res2>0) wprintw(stdscr, "Both MFT seem ok but they don't match.\n"); else wprintw(stdscr, "MFT and MFT mirror are bad.\n"); command=wmenuSelect_ext(stdscr, 23, INTER_MFT_Y, INTER_MFT_X, menuMFT, 10, "MBQ", MENU_VERT | MENU_VERT_WARN | MENU_BUTTON, &menu, &real_key); switch(command) { case 'b': case 'B': use_MFT=2; break; case 'm': case 'M': use_MFT=1; break; default: use_MFT=0; break; } #endif } } } if(use_MFT==2) { if((unsigned)disk_car->pwrite(disk_car, buffer_mftmirr, mftmirr_size_bytes, mft_pos) != mftmirr_size_bytes) { display_message("Failed to fix MFT: write error.\n"); } else { disk_car->sync(disk_car); display_message("MFT fixed.\n"); } } else if(use_MFT==1) { if((unsigned)disk_car->pwrite(disk_car, buffer_mft, mftmirr_size_bytes, mftmirr_pos) != mftmirr_size_bytes) { display_message("Failed to fix MFT mirror: write error.\n"); } else { disk_car->sync(disk_car); display_message("MFT mirror fixed.\n"); } } free(buffer_mftmirr); free(buffer_mft); free(ntfs_header); return 0; }
static int check_part_none(disk_t *disk_car,const int verbose,partition_t *partition, const int saveheader) { int ret=0; switch(partition->upart_type) { case UP_BEOS: ret=check_BeFS(disk_car,partition); break; case UP_BTRFS: ret=check_btrfs(disk_car, partition); break; case UP_CRAMFS: ret=check_cramfs(disk_car,partition,verbose); break; case UP_EXT2: case UP_EXT3: case UP_EXT4: ret=check_EXT2(disk_car,partition,verbose); break; case UP_EXTENDED: break; case UP_EXFAT: ret=check_EXFAT(disk_car, partition); break; case UP_FAT12: case UP_FAT16: case UP_FAT32: ret=check_FAT(disk_car,partition,verbose); break; case UP_FATX: ret=check_FATX(disk_car, partition); break; case UP_FREEBSD: ret=check_BSD(disk_car,partition,verbose,BSD_MAXPARTITIONS); break; case UP_GFS2: ret=check_gfs2(disk_car, partition); break; case UP_HFS: ret=check_HFS(disk_car,partition,verbose); break; case UP_HFSP: case UP_HFSX: ret=check_HFSP(disk_car,partition,verbose); break; case UP_HPFS: ret=check_HPFS(disk_car,partition,verbose); break; case UP_ISO: ret=check_ISO(disk_car, partition); break; case UP_JFS: ret=check_JFS(disk_car, partition); break; case UP_LINSWAP: case UP_LINSWAP2: case UP_LINSWAP_8K: case UP_LINSWAP2_8K: case UP_LINSWAP2_8KBE: ret=check_Linux_SWAP(disk_car, partition); break; case UP_LUKS: ret=check_LUKS(disk_car, partition); break; case UP_LVM: ret=check_LVM(disk_car,partition,verbose); break; case UP_LVM2: ret=check_LVM2(disk_car,partition,verbose); break; case UP_NETWARE: ret=check_netware(disk_car, partition); break; case UP_NTFS: ret=check_NTFS(disk_car,partition,verbose,0); if(ret!=0) { screen_buffer_add("Invalid NTFS boot\n"); } break; case UP_OPENBSD: ret=check_BSD(disk_car,partition,verbose,OPENBSD_MAXPARTITIONS); break; case UP_OS2MB: ret=check_OS2MB(disk_car,partition,verbose); break; case UP_MD: case UP_MD1: ret=check_MD(disk_car,partition,verbose); if(ret!=0) { screen_buffer_add("Invalid RAID superblock\n"); } break; case UP_RFS: case UP_RFS2: case UP_RFS3: case UP_RFS4: ret=check_rfs(disk_car,partition,verbose); break; case UP_SUN: ret=check_sun_i386(disk_car,partition,verbose); break; case UP_SYSV4: ret=check_sysv(disk_car,partition,verbose); break; case UP_UFS: case UP_UFS2: case UP_UFS_LE: case UP_UFS2_LE: ret=check_ufs(disk_car,partition,verbose); break; case UP_VMFS: ret=check_VMFS(disk_car, partition); break; case UP_WBFS: ret=check_WBFS(disk_car, partition); break; case UP_XFS: case UP_XFS2: case UP_XFS3: case UP_XFS4: ret=check_xfs(disk_car,partition,verbose); break; case UP_ZFS: ret=check_ZFS(disk_car, partition); break; case UP_UNK: break; } return ret; }